drm_drv.c revision 152909
1/* drm_drv.h -- Generic driver template -*- linux-c -*- 2 * Created: Thu Nov 23 03:10:50 2000 by gareth@valinux.com 3 */ 4/*- 5 * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. 6 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. 7 * All Rights Reserved. 8 * 9 * Permission is hereby granted, free of charge, to any person obtaining a 10 * copy of this software and associated documentation files (the "Software"), 11 * to deal in the Software without restriction, including without limitation 12 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 13 * and/or sell copies of the Software, and to permit persons to whom the 14 * Software is furnished to do so, subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice (including the next 17 * paragraph) shall be included in all copies or substantial portions of the 18 * Software. 19 * 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 23 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 24 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 26 * OTHER DEALINGS IN THE SOFTWARE. 27 * 28 * Authors: 29 * Rickard E. (Rik) Faith <faith@valinux.com> 30 * Gareth Hughes <gareth@valinux.com> 31 * 32 */ 33 34#include <sys/cdefs.h> 35__FBSDID("$FreeBSD: head/sys/dev/drm/drm_drv.c 152909 2005-11-28 23:13:57Z anholt $"); 36 37#include "dev/drm/drmP.h" 38#include "dev/drm/drm.h" 39#include "dev/drm/drm_sarea.h" 40 41int drm_debug_flag = 0; 42 43static int drm_load(drm_device_t *dev); 44static void drm_unload(drm_device_t *dev); 45static drm_pci_id_list_t *drm_find_description(int vendor, int device, 46 drm_pci_id_list_t *idlist); 47 48#ifdef __FreeBSD__ 49#define DRIVER_SOFTC(unit) \ 50 ((drm_device_t *)devclass_get_softc(drm_devclass, unit)) 51 52MODULE_VERSION(drm, 1); 53MODULE_DEPEND(drm, agp, 1, 1, 1); 54MODULE_DEPEND(drm, pci, 1, 1, 1); 55#if __FreeBSD_version > 502127 56MODULE_DEPEND(drm, mem, 1, 1, 1); 57#endif 58#endif /* __FreeBSD__ */ 59 60#if defined(__NetBSD__) || defined(__OpenBSD__) 61#define DRIVER_SOFTC(unit) \ 62 ((drm_device_t *)device_lookup(&drm_cd, unit)) 63#endif /* __NetBSD__ || __OpenBSD__ */ 64 65static drm_ioctl_desc_t drm_ioctls[256] = { 66 [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { drm_version, 0 }, 67 [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = { drm_getunique, 0 }, 68 [DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = { drm_getmagic, 0 }, 69 [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = { drm_irq_by_busid, DRM_MASTER|DRM_ROOT_ONLY}, 70 [DRM_IOCTL_NR(DRM_IOCTL_GET_MAP)] = { drm_getmap, 0 }, 71 [DRM_IOCTL_NR(DRM_IOCTL_GET_CLIENT)] = { drm_getclient, 0 }, 72 [DRM_IOCTL_NR(DRM_IOCTL_GET_STATS)] = { drm_getstats, 0 }, 73 [DRM_IOCTL_NR(DRM_IOCTL_SET_VERSION)] = { drm_setversion, DRM_MASTER|DRM_ROOT_ONLY }, 74 75 [DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = { drm_setunique, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, 76 [DRM_IOCTL_NR(DRM_IOCTL_BLOCK)] = { drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, 77 [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)] = { drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, 78 [DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = { drm_authmagic, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, 79 80 [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = { drm_addmap_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, 81 [DRM_IOCTL_NR(DRM_IOCTL_RM_MAP)] = { drm_rmmap_ioctl, DRM_AUTH }, 82 83 [DRM_IOCTL_NR(DRM_IOCTL_SET_SAREA_CTX)] = { drm_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, 84 [DRM_IOCTL_NR(DRM_IOCTL_GET_SAREA_CTX)] = { drm_getsareactx, DRM_AUTH }, 85 86 [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { drm_addctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, 87 [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { drm_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, 88 [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { drm_modctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, 89 [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { drm_getctx, DRM_AUTH }, 90 [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { drm_switchctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, 91 [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { drm_newctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, 92 [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { drm_resctx, DRM_AUTH }, 93 94 [DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)] = { drm_adddraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, 95 [DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)] = { drm_rmdraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, 96 97 [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = { drm_lock, DRM_AUTH }, 98 [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { drm_unlock, DRM_AUTH }, 99 [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { drm_noop, DRM_AUTH }, 100 101 [DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)] = { drm_addbufs_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, 102 [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)] = { drm_markbufs, DRM_AUTH|DRM_MASTER }, 103 [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = { drm_infobufs, DRM_AUTH }, 104 [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = { drm_mapbufs, DRM_AUTH }, 105 [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = { drm_freebufs, DRM_AUTH }, 106 [DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { drm_dma, DRM_AUTH }, 107 108 [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = { drm_control, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, 109 110 [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = { drm_agp_acquire_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, 111 [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = { drm_agp_release_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, 112 [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)] = { drm_agp_enable_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, 113 [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)] = { drm_agp_info_ioctl, DRM_AUTH }, 114 [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)] = { drm_agp_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, 115 [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = { drm_agp_free_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, 116 [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = { drm_agp_bind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, 117 [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = { drm_agp_unbind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, 118 119 [DRM_IOCTL_NR(DRM_IOCTL_SG_ALLOC)] = { drm_sg_alloc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, 120 [DRM_IOCTL_NR(DRM_IOCTL_SG_FREE)] = { drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, 121 122 [DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = { drm_wait_vblank, 0 }, 123}; 124 125#ifdef __FreeBSD__ 126static struct cdevsw drm_cdevsw = { 127#if __FreeBSD_version >= 502103 128 .d_version = D_VERSION, 129#endif 130 .d_open = drm_open, 131 .d_close = drm_close, 132 .d_read = drm_read, 133 .d_ioctl = drm_ioctl, 134 .d_poll = drm_poll, 135 .d_mmap = drm_mmap, 136 .d_name = "drm", 137#if __FreeBSD_version >= 502103 138 .d_flags = D_TRACKCLOSE | D_NEEDGIANT, 139#else 140 .d_maj = 145, 141 .d_flags = D_TRACKCLOSE, 142#endif 143#if __FreeBSD_version < 500000 144 .d_bmaj = -1 145#endif 146}; 147 148int drm_probe(device_t dev, drm_pci_id_list_t *idlist) 149{ 150 drm_pci_id_list_t *id_entry; 151 int vendor, device; 152 153 vendor = pci_get_vendor(dev); 154 device = pci_get_device(dev); 155 156 id_entry = drm_find_description(vendor, device, idlist); 157 if (id_entry != NULL) { 158 device_set_desc(dev, id_entry->name); 159 return 0; 160 } 161 162 return ENXIO; 163} 164 165int drm_attach(device_t nbdev, drm_pci_id_list_t *idlist) 166{ 167 drm_device_t *dev; 168 drm_pci_id_list_t *id_entry; 169 int unit; 170 171 unit = device_get_unit(nbdev); 172 dev = device_get_softc(nbdev); 173 174 if (!strcmp(device_get_name(nbdev), "drmsub")) 175 dev->device = device_get_parent(nbdev); 176 else 177 dev->device = nbdev; 178 179 dev->devnode = make_dev(&drm_cdevsw, 180 unit, 181 DRM_DEV_UID, 182 DRM_DEV_GID, 183 DRM_DEV_MODE, 184 "dri/card%d", unit); 185#if __FreeBSD_version >= 500000 186 mtx_init(&dev->dev_lock, "drm device", NULL, MTX_DEF); 187#endif 188 189 id_entry = drm_find_description(pci_get_vendor(nbdev), 190 pci_get_device(nbdev), idlist); 191 dev->id_entry = id_entry; 192 193 return drm_load(dev); 194} 195 196int drm_detach(device_t dev) 197{ 198 drm_unload(device_get_softc(dev)); 199 return 0; 200} 201 202#ifndef DRM_DEV_NAME 203#define DRM_DEV_NAME "drm" 204#endif 205 206devclass_t drm_devclass; 207 208#elif defined(__NetBSD__) || defined(__OpenBSD__) 209 210static struct cdevsw drm_cdevsw = { 211 drm_open, 212 drm_close, 213 drm_read, 214 nowrite, 215 drm_ioctl, 216 nostop, 217 notty, 218 drm_poll, 219 drm_mmap, 220 nokqfilter, 221 D_TTY 222}; 223 224int drm_refcnt = 0; 225 226#if defined(__NetBSD__) && __NetBSD_Version__ >= 106080000 227MOD_DEV("drm", DRIVER_NAME, NULL, -1, &drm_cdevsw, CDEV_MAJOR); 228#else 229MOD_DEV("drm", LM_DT_CHAR, CDEV_MAJOR, &drm_cdevsw); 230#endif 231 232int drm_lkmentry(struct lkm_table *lkmtp, int cmd, int ver); 233static int drm_lkmhandle(struct lkm_table *lkmtp, int cmd); 234 235int drm_modprobe(void); 236int drm_probe(struct pci_attach_args *pa); 237void drm_attach(struct pci_attach_args *pa, dev_t kdev); 238 239int drm_lkmentry(struct lkm_table *lkmtp, int cmd, int ver) { 240 DISPATCH(lkmtp, cmd, ver, drm_lkmhandle, drm_lkmhandle, drm_lkmhandle); 241} 242 243static int drm_lkmhandle(struct lkm_table *lkmtp, int cmd) 244{ 245 int error = 0; 246 247 switch(cmd) { 248 case LKM_E_LOAD: 249 if (lkmexists(lkmtp)) 250 return EEXIST; 251 252 if(drm_modprobe()) 253 return 0; 254 255 return 1; 256 257 case LKM_E_UNLOAD: 258 if (drm_refcnt > 0) 259 return (EBUSY); 260 break; 261 case LKM_E_STAT: 262 break; 263 264 default: 265 error = EIO; 266 break; 267 } 268 269 return error; 270} 271 272int drm_modprobe(void) 273{ 274 struct pci_attach_args pa; 275 int error; 276 277 error = pci_find_device(&pa, drm_probe, idlist); 278 if (error != 0) 279 drm_attach(&pa, 0); 280 281 return error; 282} 283 284int drm_probe(struct pci_attach_args *pa, drm_pci_id_list_t idlist) 285{ 286 const char *desc; 287 drm_pci_id_list_t *id_entry; 288 289 id_entry = drm_find_description(PCI_VENDOR(pa->pa_id), 290 PCI_PRODUCT(pa->pa_id), idlist); 291 if (id_entry != NULL) { 292 return 1; 293 } 294 295 return 0; 296} 297 298void drm_attach(struct pci_attach_args *pa, dev_t kdev, 299 drm_pci_id_list_t *idlist) 300{ 301 int i; 302 drm_device_t *dev; 303 drm_pci_id_list_t *id_entry; 304 305 config_makeroom(kdev, &drm_cd); 306 drm_cd.cd_devs[(kdev)] = malloc(sizeof(drm_device_t), M_DRM, M_WAITOK); 307 dev = DRIVER_SOFTC(kdev); 308 309 memset(dev, 0, sizeof(drm_device_t)); 310 memcpy(&dev->pa, pa, sizeof(dev->pa)); 311 312 dev->irq = pa->pa_intrline; 313 dev->pci_domain = 0; 314 dev->pci_bus = pa->pa_bus; 315 dev->pci_slot = pa->pa_device; 316 dev->pci_func = pa->pa_function; 317 dev->dma_tag = pa->pa_dmat; 318 319 id_entry = drm_find_description(PCI_VENDOR(pa->pa_id), 320 PCI_PRODUCT(pa->pa_id), idlist); 321 dev->driver.pci_id_entry = id_entry; 322 323 DRM_INFO("%s", id_entry->name); 324 drm_load(dev); 325} 326 327int drm_detach(struct device *self, int flags) 328{ 329 drm_unload((drm_device_t *)self); 330 return 0; 331} 332 333int drm_activate(struct device *self, enum devact act) 334{ 335 switch (act) { 336 case DVACT_ACTIVATE: 337 return (EOPNOTSUPP); 338 break; 339 340 case DVACT_DEACTIVATE: 341 /* FIXME */ 342 break; 343 } 344 return (0); 345} 346#endif /* __NetBSD__ || __OpenBSD__ */ 347 348drm_pci_id_list_t *drm_find_description(int vendor, int device, 349 drm_pci_id_list_t *idlist) 350{ 351 int i = 0; 352 353 for (i = 0; idlist[i].vendor != 0; i++) { 354 if ((idlist[i].vendor == vendor) && 355 (idlist[i].device == device)) { 356 return &idlist[i]; 357 } 358 } 359 return NULL; 360} 361 362static int drm_firstopen(drm_device_t *dev) 363{ 364 drm_local_map_t *map; 365 int i; 366 367 DRM_SPINLOCK_ASSERT(&dev->dev_lock); 368 369 /* prebuild the SAREA */ 370 i = drm_addmap(dev, 0, SAREA_MAX, _DRM_SHM, 371 _DRM_CONTAINS_LOCK, &map); 372 if (i != 0) 373 return i; 374 375 if (dev->driver.firstopen) 376 dev->driver.firstopen(dev); 377 378 dev->buf_use = 0; 379 380 if (dev->driver.use_dma) { 381 i = drm_dma_setup(dev); 382 if (i != 0) 383 return i; 384 } 385 386 dev->counters = 6; 387 dev->types[0] = _DRM_STAT_LOCK; 388 dev->types[1] = _DRM_STAT_OPENS; 389 dev->types[2] = _DRM_STAT_CLOSES; 390 dev->types[3] = _DRM_STAT_IOCTLS; 391 dev->types[4] = _DRM_STAT_LOCKS; 392 dev->types[5] = _DRM_STAT_UNLOCKS; 393 394 for ( i = 0 ; i < DRM_ARRAY_SIZE(dev->counts) ; i++ ) 395 atomic_set( &dev->counts[i], 0 ); 396 397 for ( i = 0 ; i < DRM_HASH_SIZE ; i++ ) { 398 dev->magiclist[i].head = NULL; 399 dev->magiclist[i].tail = NULL; 400 } 401 402 dev->lock.lock_queue = 0; 403 dev->irq_enabled = 0; 404 dev->context_flag = 0; 405 dev->last_context = 0; 406 dev->if_version = 0; 407 408#ifdef __FreeBSD__ 409 dev->buf_sigio = NULL; 410#elif defined(__NetBSD__) || defined(__OpenBSD__) 411 dev->buf_pgid = 0; 412#endif 413 414 DRM_DEBUG( "\n" ); 415 416 return 0; 417} 418 419static int drm_lastclose(drm_device_t *dev) 420{ 421 drm_magic_entry_t *pt, *next; 422 drm_local_map_t *map, *mapsave; 423 int i; 424 425 DRM_SPINLOCK_ASSERT(&dev->dev_lock); 426 427 DRM_DEBUG( "\n" ); 428 429 if (dev->driver.lastclose != NULL) 430 dev->driver.lastclose(dev); 431 432 if (dev->irq_enabled) 433 drm_irq_uninstall(dev); 434 435 if ( dev->unique ) { 436 free(dev->unique, M_DRM); 437 dev->unique = NULL; 438 dev->unique_len = 0; 439 } 440 /* Clear pid list */ 441 for ( i = 0 ; i < DRM_HASH_SIZE ; i++ ) { 442 for ( pt = dev->magiclist[i].head ; pt ; pt = next ) { 443 next = pt->next; 444 free(pt, M_DRM); 445 } 446 dev->magiclist[i].head = dev->magiclist[i].tail = NULL; 447 } 448 449 /* Clear AGP information */ 450 if ( dev->agp ) { 451 drm_agp_mem_t *entry; 452 drm_agp_mem_t *nexte; 453 454 /* Remove AGP resources, but leave dev->agp intact until 455 * drm_unload is called. 456 */ 457 for ( entry = dev->agp->memory ; entry ; entry = nexte ) { 458 nexte = entry->next; 459 if ( entry->bound ) 460 drm_agp_unbind_memory(entry->handle); 461 drm_agp_free_memory(entry->handle); 462 free(entry, M_DRM); 463 } 464 dev->agp->memory = NULL; 465 466 if (dev->agp->acquired) 467 drm_agp_release(dev); 468 469 dev->agp->acquired = 0; 470 dev->agp->enabled = 0; 471 } 472 if (dev->sg != NULL) { 473 drm_sg_cleanup(dev->sg); 474 dev->sg = NULL; 475 } 476 477 TAILQ_FOREACH_SAFE(map, &dev->maplist, link, mapsave) { 478 drm_rmmap(dev, map); 479 } 480 481 482 drm_dma_takedown(dev); 483 if ( dev->lock.hw_lock ) { 484 dev->lock.hw_lock = NULL; /* SHM removed */ 485 dev->lock.filp = NULL; 486 DRM_WAKEUP_INT((void *)&dev->lock.lock_queue); 487 } 488 489 return 0; 490} 491 492static int drm_load(drm_device_t *dev) 493{ 494 int retcode; 495 496 DRM_DEBUG( "\n" ); 497 498 dev->irq = pci_get_irq(dev->device); 499 /* XXX Fix domain number (alpha hoses) */ 500 dev->pci_domain = 0; 501 dev->pci_bus = pci_get_bus(dev->device); 502 dev->pci_slot = pci_get_slot(dev->device); 503 dev->pci_func = pci_get_function(dev->device); 504 505 TAILQ_INIT(&dev->maplist); 506 507 drm_mem_init(); 508#ifdef __FreeBSD__ 509 drm_sysctl_init(dev); 510#endif 511 TAILQ_INIT(&dev->files); 512 513 if (dev->driver.load != NULL) { 514 DRM_LOCK(); 515 retcode = dev->driver.load(dev, dev->id_entry->driver_private); 516 DRM_UNLOCK(); 517 if (retcode != 0) 518 goto error; 519 } 520 521 if (dev->driver.use_agp) { 522 if (drm_device_is_agp(dev)) 523 dev->agp = drm_agp_init(); 524 if (dev->driver.require_agp && dev->agp == NULL) { 525 DRM_ERROR("Card isn't AGP, or couldn't initialize " 526 "AGP.\n"); 527 retcode = DRM_ERR(ENOMEM); 528 goto error; 529 } 530 if (dev->agp != NULL) { 531 if (drm_mtrr_add(dev->agp->info.ai_aperture_base, 532 dev->agp->info.ai_aperture_size, DRM_MTRR_WC) == 0) 533 dev->agp->mtrr = 1; 534 } 535 } 536 537 retcode = drm_ctxbitmap_init(dev); 538 if (retcode != 0) { 539 DRM_ERROR("Cannot allocate memory for context bitmap.\n"); 540 goto error; 541 } 542 543 DRM_INFO("Initialized %s %d.%d.%d %s\n", 544 dev->driver.name, 545 dev->driver.major, 546 dev->driver.minor, 547 dev->driver.patchlevel, 548 dev->driver.date); 549 550 return 0; 551 552error: 553#ifdef __FreeBSD__ 554 drm_sysctl_cleanup(dev); 555#endif 556 DRM_LOCK(); 557 drm_lastclose(dev); 558 DRM_UNLOCK(); 559#ifdef __FreeBSD__ 560 destroy_dev(dev->devnode); 561#if __FreeBSD_version >= 500000 562 mtx_destroy(&dev->dev_lock); 563#endif 564#endif 565 return retcode; 566} 567 568static void drm_unload(drm_device_t *dev) 569{ 570 int i; 571 572 DRM_DEBUG( "\n" ); 573 574#ifdef __FreeBSD__ 575 drm_sysctl_cleanup(dev); 576 destroy_dev(dev->devnode); 577#endif 578 579 drm_ctxbitmap_cleanup(dev); 580 581 if (dev->agp && dev->agp->mtrr) { 582 int __unused retcode; 583 584 retcode = drm_mtrr_del(0, dev->agp->info.ai_aperture_base, 585 dev->agp->info.ai_aperture_size, DRM_MTRR_WC); 586 DRM_DEBUG("mtrr_del = %d", retcode); 587 } 588 589 DRM_LOCK(); 590 drm_lastclose(dev); 591 DRM_UNLOCK(); 592 593 /* Clean up PCI resources allocated by drm_bufs.c. We're not really 594 * worried about resource consumption while the DRM is inactive (between 595 * lastclose and firstopen or unload) because these aren't actually 596 * taking up KVA, just keeping the PCI resource allocated. 597 */ 598 for (i = 0; i < DRM_MAX_PCI_RESOURCE; i++) { 599 if (dev->pcir[i] == NULL) 600 continue; 601 bus_release_resource(dev->device, SYS_RES_MEMORY, 602 dev->pcirid[i], dev->pcir[i]); 603 dev->pcir[i] = NULL; 604 } 605 606 if ( dev->agp ) { 607 free(dev->agp, M_DRM); 608 dev->agp = NULL; 609 } 610 611 if (dev->driver.unload != NULL) 612 dev->driver.unload(dev); 613 614 drm_mem_uninit(); 615#if defined(__FreeBSD__) && __FreeBSD_version >= 500000 616 mtx_destroy(&dev->dev_lock); 617#endif 618} 619 620 621int drm_version(DRM_IOCTL_ARGS) 622{ 623 DRM_DEVICE; 624 drm_version_t version; 625 int len; 626 627 DRM_COPY_FROM_USER_IOCTL( version, (drm_version_t *)data, sizeof(version) ); 628 629#define DRM_COPY( name, value ) \ 630 len = strlen( value ); \ 631 if ( len > name##_len ) len = name##_len; \ 632 name##_len = strlen( value ); \ 633 if ( len && name ) { \ 634 if ( DRM_COPY_TO_USER( name, value, len ) ) \ 635 return DRM_ERR(EFAULT); \ 636 } 637 638 version.version_major = dev->driver.major; 639 version.version_minor = dev->driver.minor; 640 version.version_patchlevel = dev->driver.patchlevel; 641 642 DRM_COPY(version.name, dev->driver.name); 643 DRM_COPY(version.date, dev->driver.date); 644 DRM_COPY(version.desc, dev->driver.desc); 645 646 DRM_COPY_TO_USER_IOCTL( (drm_version_t *)data, version, sizeof(version) ); 647 648 return 0; 649} 650 651int drm_open(struct cdev *kdev, int flags, int fmt, DRM_STRUCTPROC *p) 652{ 653 drm_device_t *dev = NULL; 654 int retcode = 0; 655 656 dev = DRIVER_SOFTC(minor(kdev)); 657 658 DRM_DEBUG( "open_count = %d\n", dev->open_count ); 659 660 retcode = drm_open_helper(kdev, flags, fmt, p, dev); 661 662 if ( !retcode ) { 663 atomic_inc( &dev->counts[_DRM_STAT_OPENS] ); 664 DRM_LOCK(); 665#ifdef __FreeBSD__ 666 device_busy(dev->device); 667#endif 668 if ( !dev->open_count++ ) 669 retcode = drm_firstopen(dev); 670 DRM_UNLOCK(); 671 } 672 673 return retcode; 674} 675 676int drm_close(struct cdev *kdev, int flags, int fmt, DRM_STRUCTPROC *p) 677{ 678 drm_file_t *priv; 679 DRM_DEVICE; 680 int retcode = 0; 681 DRMFILE filp = (void *)(uintptr_t)(DRM_CURRENTPID); 682 683 DRM_DEBUG( "open_count = %d\n", dev->open_count ); 684 685 DRM_LOCK(); 686 687 priv = drm_find_file_by_proc(dev, p); 688 if (!priv) { 689 DRM_UNLOCK(); 690 DRM_ERROR("can't find authenticator\n"); 691 return EINVAL; 692 } 693 694 if (dev->driver.preclose != NULL) 695 dev->driver.preclose(dev, filp); 696 697 /* ======================================================== 698 * Begin inline drm_release 699 */ 700 701#ifdef __FreeBSD__ 702 DRM_DEBUG( "pid = %d, device = 0x%lx, open_count = %d\n", 703 DRM_CURRENTPID, (long)dev->device, dev->open_count ); 704#elif defined(__NetBSD__) || defined(__OpenBSD__) 705 DRM_DEBUG( "pid = %d, device = 0x%lx, open_count = %d\n", 706 DRM_CURRENTPID, (long)&dev->device, dev->open_count); 707#endif 708 709 if (dev->lock.hw_lock && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) 710 && dev->lock.filp == filp) { 711 DRM_DEBUG("Process %d dead, freeing lock for context %d\n", 712 DRM_CURRENTPID, 713 _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); 714 if (dev->driver.reclaim_buffers_locked != NULL) 715 dev->driver.reclaim_buffers_locked(dev, filp); 716 717 drm_lock_free(dev, &dev->lock.hw_lock->lock, 718 _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); 719 720 /* FIXME: may require heavy-handed reset of 721 hardware at this point, possibly 722 processed via a callback to the X 723 server. */ 724 } else if (dev->driver.reclaim_buffers_locked != NULL && 725 dev->lock.hw_lock != NULL) { 726 /* The lock is required to reclaim buffers */ 727 for (;;) { 728 if ( !dev->lock.hw_lock ) { 729 /* Device has been unregistered */ 730 retcode = DRM_ERR(EINTR); 731 break; 732 } 733 if (drm_lock_take(&dev->lock.hw_lock->lock, 734 DRM_KERNEL_CONTEXT)) { 735 dev->lock.filp = filp; 736 dev->lock.lock_time = jiffies; 737 atomic_inc( &dev->counts[_DRM_STAT_LOCKS] ); 738 break; /* Got lock */ 739 } 740 /* Contention */ 741#if defined(__FreeBSD__) && __FreeBSD_version > 500000 742 retcode = msleep((void *)&dev->lock.lock_queue, 743 &dev->dev_lock, PZERO | PCATCH, "drmlk2", 0); 744#else 745 retcode = tsleep((void *)&dev->lock.lock_queue, 746 PZERO | PCATCH, "drmlk2", 0); 747#endif 748 if (retcode) 749 break; 750 } 751 if (retcode == 0) { 752 dev->driver.reclaim_buffers_locked(dev, filp); 753 drm_lock_free(dev, &dev->lock.hw_lock->lock, 754 DRM_KERNEL_CONTEXT); 755 } 756 } 757 758 if (dev->driver.use_dma && !dev->driver.reclaim_buffers_locked) 759 drm_reclaim_buffers(dev, filp); 760 761#if defined (__FreeBSD__) && (__FreeBSD_version >= 500000) 762 funsetown(&dev->buf_sigio); 763#elif defined(__FreeBSD__) 764 funsetown(dev->buf_sigio); 765#elif defined(__NetBSD__) || defined(__OpenBSD__) 766 dev->buf_pgid = 0; 767#endif /* __NetBSD__ || __OpenBSD__ */ 768 769 if (--priv->refs == 0) { 770 if (dev->driver.postclose != NULL) 771 dev->driver.postclose(dev, priv); 772 TAILQ_REMOVE(&dev->files, priv, link); 773 free(priv, M_DRM); 774 } 775 776 /* ======================================================== 777 * End inline drm_release 778 */ 779 780 atomic_inc( &dev->counts[_DRM_STAT_CLOSES] ); 781#ifdef __FreeBSD__ 782 device_unbusy(dev->device); 783#endif 784 if (--dev->open_count == 0) { 785 retcode = drm_lastclose(dev); 786 } 787 788 DRM_UNLOCK(); 789 790 return retcode; 791} 792 793/* drm_ioctl is called whenever a process performs an ioctl on /dev/drm. 794 */ 795int drm_ioctl(struct cdev *kdev, u_long cmd, caddr_t data, int flags, 796 DRM_STRUCTPROC *p) 797{ 798 DRM_DEVICE; 799 int retcode = 0; 800 drm_ioctl_desc_t *ioctl; 801 int (*func)(DRM_IOCTL_ARGS); 802 int nr = DRM_IOCTL_NR(cmd); 803 int is_driver_ioctl = 0; 804 drm_file_t *priv; 805 DRMFILE filp = (DRMFILE)(uintptr_t)DRM_CURRENTPID; 806 807 DRM_LOCK(); 808 priv = drm_find_file_by_proc(dev, p); 809 DRM_UNLOCK(); 810 if (priv == NULL) { 811 DRM_ERROR("can't find authenticator\n"); 812 return EINVAL; 813 } 814 815 atomic_inc( &dev->counts[_DRM_STAT_IOCTLS] ); 816 ++priv->ioctl_count; 817 818#ifdef __FreeBSD__ 819 DRM_DEBUG( "pid=%d, cmd=0x%02lx, nr=0x%02x, dev 0x%lx, auth=%d\n", 820 DRM_CURRENTPID, cmd, nr, (long)dev->device, priv->authenticated ); 821#elif defined(__NetBSD__) || defined(__OpenBSD__) 822 DRM_DEBUG( "pid=%d, cmd=0x%02lx, nr=0x%02x, dev 0x%lx, auth=%d\n", 823 DRM_CURRENTPID, cmd, nr, (long)&dev->device, priv->authenticated ); 824#endif 825 826 switch (cmd) { 827 case FIONBIO: 828 case FIOASYNC: 829 return 0; 830 831#ifdef __FreeBSD__ 832 case FIOSETOWN: 833 return fsetown(*(int *)data, &dev->buf_sigio); 834 835 case FIOGETOWN: 836#if (__FreeBSD_version >= 500000) 837 *(int *) data = fgetown(&dev->buf_sigio); 838#else 839 *(int *) data = fgetown(dev->buf_sigio); 840#endif 841 return 0; 842#endif /* __FreeBSD__ */ 843#if defined(__NetBSD__) || defined(__OpenBSD__) 844 case TIOCSPGRP: 845 dev->buf_pgid = *(int *)data; 846 return 0; 847 848 case TIOCGPGRP: 849 *(int *)data = dev->buf_pgid; 850 return 0; 851#endif /* __NetBSD__ */ 852 } 853 854 if (IOCGROUP(cmd) != DRM_IOCTL_BASE) { 855 DRM_DEBUG("Bad ioctl group 0x%x\n", (int)IOCGROUP(cmd)); 856 return EINVAL; 857 } 858 859 ioctl = &drm_ioctls[nr]; 860 /* It's not a core DRM ioctl, try driver-specific. */ 861 if (ioctl->func == NULL && nr >= DRM_COMMAND_BASE) { 862 /* The array entries begin at DRM_COMMAND_BASE ioctl nr */ 863 nr -= DRM_COMMAND_BASE; 864 if (nr > dev->driver.max_ioctl) { 865 DRM_DEBUG("Bad driver ioctl number, 0x%x (of 0x%x)\n", 866 nr, dev->driver.max_ioctl); 867 return EINVAL; 868 } 869 ioctl = &dev->driver.ioctls[nr]; 870 is_driver_ioctl = 1; 871 } 872 func = ioctl->func; 873 874 if (func == NULL) { 875 DRM_DEBUG( "no function\n" ); 876 return EINVAL; 877 } 878 /* ioctl->master check should be against something in the filp set up 879 * for the first opener, but it doesn't matter yet. 880 */ 881 if (((ioctl->flags & DRM_ROOT_ONLY) && !DRM_SUSER(p)) || 882 ((ioctl->flags & DRM_AUTH) && !priv->authenticated) || 883 ((ioctl->flags & DRM_MASTER) && !priv->master)) 884 return EACCES; 885 886 if (is_driver_ioctl) 887 DRM_LOCK(); 888 retcode = func(kdev, cmd, data, flags, p, filp); 889 if (is_driver_ioctl) 890 DRM_UNLOCK(); 891 892 if (retcode != 0) 893 DRM_DEBUG(" returning %d\n", retcode); 894 895 return DRM_ERR(retcode); 896} 897 898 899#if DRM_LINUX 900 901#include <sys/sysproto.h> 902 903MODULE_DEPEND(DRIVER_NAME, linux, 1, 1, 1); 904 905#define LINUX_IOCTL_DRM_MIN 0x6400 906#define LINUX_IOCTL_DRM_MAX 0x64ff 907 908static linux_ioctl_function_t drm_linux_ioctl; 909static struct linux_ioctl_handler drm_handler = {drm_linux_ioctl, 910 LINUX_IOCTL_DRM_MIN, LINUX_IOCTL_DRM_MAX}; 911 912SYSINIT(drm_register, SI_SUB_KLD, SI_ORDER_MIDDLE, 913 linux_ioctl_register_handler, &drm_handler); 914SYSUNINIT(drm_unregister, SI_SUB_KLD, SI_ORDER_MIDDLE, 915 linux_ioctl_unregister_handler, &drm_handler); 916 917/* The bits for in/out are switched on Linux */ 918#define LINUX_IOC_IN IOC_OUT 919#define LINUX_IOC_OUT IOC_IN 920 921static int 922drm_linux_ioctl(DRM_STRUCTPROC *p, struct linux_ioctl_args* args) 923{ 924 int error; 925 int cmd = args->cmd; 926 927 args->cmd &= ~(LINUX_IOC_IN | LINUX_IOC_OUT); 928 if (cmd & LINUX_IOC_IN) 929 args->cmd |= IOC_IN; 930 if (cmd & LINUX_IOC_OUT) 931 args->cmd |= IOC_OUT; 932 933 error = ioctl(p, (struct ioctl_args *)args); 934 935 return error; 936} 937#endif /* DRM_LINUX */ 938