Remove trailing space.
[dragonfly.git] / sys / dev / drm / drm_drv.h
1 /* drm_drv.h -- Generic driver template -*- linux-c -*-
2  * Created: Thu Nov 23 03:10:50 2000 by gareth@valinux.com
3  *
4  * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
5  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
6  * All Rights Reserved.
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the "Software"),
10  * to deal in the Software without restriction, including without limitation
11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons to whom the
13  * Software is furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice (including the next
16  * paragraph) shall be included in all copies or substantial portions of the
17  * Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25  * OTHER DEALINGS IN THE SOFTWARE.
26  *
27  * Authors:
28  *    Rickard E. (Rik) Faith <faith@valinux.com>
29  *    Gareth Hughes <gareth@valinux.com>
30  *
31  * $FreeBSD: src/sys/dev/drm/drm_drv.h,v 1.13.2.1 2003/04/26 07:05:28 anholt Exp $
32  * $DragonFly: src/sys/dev/drm/Attic/drm_drv.h,v 1.16 2007/04/30 07:18:48 dillon Exp $
33  */
34
35 /*
36  * To use this template, you must at least define the following (samples
37  * given for the MGA driver):
38  *
39  * #define DRIVER_AUTHOR        "VA Linux Systems, Inc."
40  *
41  * #define DRIVER_NAME          "mga"
42  * #define DRIVER_DESC          "Matrox G200/G400"
43  * #define DRIVER_DATE          "20001127"
44  *
45  * #define DRIVER_MAJOR         2
46  * #define DRIVER_MINOR         0
47  * #define DRIVER_PATCHLEVEL    2
48  *
49  * #define DRIVER_IOCTL_COUNT   DRM_ARRAY_SIZE( mga_ioctls )
50  *
51  * #define DRM(x)               mga_##x
52  */
53
54 #ifndef __MUST_HAVE_AGP
55 #define __MUST_HAVE_AGP                 0
56 #endif
57 #ifndef __HAVE_CTX_BITMAP
58 #define __HAVE_CTX_BITMAP               0
59 #endif
60 #ifndef __HAVE_DMA_IRQ
61 #define __HAVE_DMA_IRQ                  0
62 #endif
63 #ifndef __HAVE_DMA_QUEUE
64 #define __HAVE_DMA_QUEUE                0
65 #endif
66 #ifndef __HAVE_DMA_SCHEDULE
67 #define __HAVE_DMA_SCHEDULE             0
68 #endif
69 #ifndef __HAVE_DMA_QUIESCENT
70 #define __HAVE_DMA_QUIESCENT            0
71 #endif
72 #ifndef __HAVE_RELEASE
73 #define __HAVE_RELEASE                  0
74 #endif
75 #ifndef __HAVE_COUNTERS
76 #define __HAVE_COUNTERS                 0
77 #endif
78 #ifndef __HAVE_SG
79 #define __HAVE_SG                       0
80 #endif
81
82 #ifndef DRIVER_PREINIT
83 #define DRIVER_PREINIT()
84 #endif
85 #ifndef DRIVER_POSTINIT
86 #define DRIVER_POSTINIT()
87 #endif
88 #ifndef DRIVER_PRERELEASE
89 #define DRIVER_PRERELEASE()
90 #endif
91 #ifndef DRIVER_PRETAKEDOWN
92 #define DRIVER_PRETAKEDOWN()
93 #endif
94 #ifndef DRIVER_POSTCLEANUP
95 #define DRIVER_POSTCLEANUP()
96 #endif
97 #ifndef DRIVER_PRESETUP
98 #define DRIVER_PRESETUP()
99 #endif
100 #ifndef DRIVER_POSTSETUP
101 #define DRIVER_POSTSETUP()
102 #endif
103 #ifndef DRIVER_IOCTLS
104 #define DRIVER_IOCTLS
105 #endif
106 #ifndef DRIVER_FOPS
107 #endif
108
109 #if 1 && DRM_DEBUG_CODE
110 int DRM(flags) = DRM_FLAG_DEBUG;
111 #else
112 int DRM(flags) = 0;
113 #endif
114
115 static int DRM(init)(device_t nbdev);
116 static void DRM(cleanup)(device_t nbdev);
117
118 #if defined(__DragonFly__) || defined(__FreeBSD__)
119 #define DRIVER_SOFTC(unit) \
120         ((drm_device_t *) devclass_get_softc(DRM(devclass), unit))
121
122 #if __REALLY_HAVE_AGP
123 MODULE_DEPEND(DRIVER_NAME, agp, 1, 1, 1);
124 #endif
125 #endif /* __FreeBSD__ */
126
127 #ifdef __NetBSD__
128 #define DRIVER_SOFTC(unit) \
129         ((drm_device_t *) device_lookup(&DRM(cd), unit))
130 #endif /* __NetBSD__ */
131
132 static drm_ioctl_desc_t           DRM(ioctls)[] = {
133         [DRM_IOCTL_NR(DRM_IOCTL_VERSION)]       = { DRM(version),     0, 0 },
134         [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)]    = { DRM(getunique),   0, 0 },
135         [DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)]     = { DRM(getmagic),    0, 0 },
136         [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)]     = { DRM(irq_busid),   0, 1 },
137         [DRM_IOCTL_NR(DRM_IOCTL_GET_MAP)]       = { DRM(getmap),      0, 0 },
138         [DRM_IOCTL_NR(DRM_IOCTL_GET_CLIENT)]    = { DRM(getclient),   0, 0 },
139         [DRM_IOCTL_NR(DRM_IOCTL_GET_STATS)]     = { DRM(getstats),    0, 0 },
140
141         [DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)]    = { DRM(setunique),   1, 1 },
142         [DRM_IOCTL_NR(DRM_IOCTL_BLOCK)]         = { DRM(noop),        1, 1 },
143         [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)]       = { DRM(noop),        1, 1 },
144         [DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)]    = { DRM(authmagic),   1, 1 },
145
146         [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)]       = { DRM(addmap),      1, 1 },
147         [DRM_IOCTL_NR(DRM_IOCTL_RM_MAP)]        = { DRM(rmmap),       1, 0 },
148
149 #if __HAVE_CTX_BITMAP
150         [DRM_IOCTL_NR(DRM_IOCTL_SET_SAREA_CTX)] = { DRM(setsareactx), 1, 1 },
151         [DRM_IOCTL_NR(DRM_IOCTL_GET_SAREA_CTX)] = { DRM(getsareactx), 1, 0 },
152 #endif
153
154         [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)]       = { DRM(addctx),      1, 1 },
155         [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)]        = { DRM(rmctx),       1, 1 },
156         [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)]       = { DRM(modctx),      1, 1 },
157         [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)]       = { DRM(getctx),      1, 0 },
158         [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)]    = { DRM(switchctx),   1, 1 },
159         [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)]       = { DRM(newctx),      1, 1 },
160         [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)]       = { DRM(resctx),      1, 0 },
161
162         [DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)]      = { DRM(adddraw),     1, 1 },
163         [DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)]       = { DRM(rmdraw),      1, 1 },
164
165         [DRM_IOCTL_NR(DRM_IOCTL_LOCK)]          = { DRM(lock),        1, 0 },
166         [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)]        = { DRM(unlock),      1, 0 },
167         [DRM_IOCTL_NR(DRM_IOCTL_FINISH)]        = { DRM(noop),        1, 0 },
168
169 #if __HAVE_DMA
170         [DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)]      = { DRM(addbufs),     1, 1 },
171         [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)]     = { DRM(markbufs),    1, 1 },
172         [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)]     = { DRM(infobufs),    1, 0 },
173         [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)]      = { DRM(mapbufs),     1, 0 },
174         [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)]     = { DRM(freebufs),    1, 0 },
175
176         /* The DRM_IOCTL_DMA ioctl should be defined by the driver.
177          */
178         [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)]       = { DRM(control),     1, 1 },
179 #endif
180
181 #if __REALLY_HAVE_AGP
182         [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)]   = { DRM(agp_acquire), 1, 1 },
183         [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)]   = { DRM(agp_release), 1, 1 },
184         [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)]    = { DRM(agp_enable),  1, 1 },
185         [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)]      = { DRM(agp_info),    1, 0 },
186         [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)]     = { DRM(agp_alloc),   1, 1 },
187         [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)]      = { DRM(agp_free),    1, 1 },
188         [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)]      = { DRM(agp_bind),    1, 1 },
189         [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)]    = { DRM(agp_unbind),  1, 1 },
190 #endif
191
192 #if __HAVE_SG
193         [DRM_IOCTL_NR(DRM_IOCTL_SG_ALLOC)]      = { DRM(sg_alloc),    1, 1 },
194         [DRM_IOCTL_NR(DRM_IOCTL_SG_FREE)]       = { DRM(sg_free),     1, 1 },
195 #endif
196
197 #if __HAVE_VBL_IRQ
198         [DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)]   = { DRM(wait_vblank), 0, 0 },
199 #endif
200
201         DRIVER_IOCTLS
202 };
203
204 #define DRIVER_IOCTL_COUNT      DRM_ARRAY_SIZE( DRM(ioctls) )
205
206 const char *DRM(find_description)(int vendor, int device);
207
208 #if defined(__DragonFly__) || defined(__FreeBSD__)
209 static struct dev_ops DRM(ops) = {
210         { DRIVER_NAME, CDEV_MAJOR, D_TTY | D_TRACKCLOSE },
211         .d_open =       DRM(open),
212         .d_close =      DRM(close),
213         .d_read =       DRM(read),
214         .d_ioctl =      DRM(ioctl),
215         .d_poll =       DRM(poll),
216         .d_mmap =       DRM(mmap)
217 };
218
219 static int DRM(probe)(device_t dev)
220 {
221         const char *s = NULL;
222
223         int pciid=pci_get_devid(dev);
224         int vendor = (pciid & 0x0000ffff);
225         int device = (pciid & 0xffff0000) >> 16;
226         
227         s = DRM(find_description)(vendor, device);
228         if (s) {
229                 device_set_desc(dev, s);
230                 return 0;
231         }
232
233         return ENXIO;
234 }
235
236 static int DRM(attach)(device_t dev)
237 {
238         return DRM(init)(dev);
239 }
240
241 static int DRM(detach)(device_t dev)
242 {
243         DRM(cleanup)(dev);
244         return 0;
245 }
246 static device_method_t DRM(methods)[] = {
247         /* Device interface */
248         DEVMETHOD(device_probe,         DRM( probe)),
249         DEVMETHOD(device_attach,        DRM( attach)),
250         DEVMETHOD(device_detach,        DRM( detach)),
251
252         { 0, 0 }
253 };
254
255 static driver_t DRM(driver) = {
256         "drm",
257         DRM(methods),
258         sizeof(drm_device_t),
259 };
260
261 static devclass_t DRM(devclass);
262
263 #elif defined(__NetBSD__)
264
265 static struct cdevsw DRM(cdevsw) = {
266         DRM(open),
267         DRM(close),
268         DRM(read),
269         nowrite,
270         DRM(ioctl),
271         nostop,
272         notty,
273         DRM(poll),
274         DRM(mmap),
275         nokqfilter,
276         D_TTY
277 };
278
279 int DRM(refcnt) = 0;
280 #if __NetBSD_Version__ >= 106080000
281 MOD_DEV( DRIVER_NAME, DRIVER_NAME, NULL, -1, &DRM(cdevsw), CDEV_MAJOR);
282 #else
283 MOD_DEV( DRIVER_NAME, LM_DT_CHAR, CDEV_MAJOR, &DRM(cdevsw) );
284 #endif
285
286 int DRM(lkmentry)(struct lkm_table *lkmtp, int cmd, int ver);
287 static int DRM(lkmhandle)(struct lkm_table *lkmtp, int cmd);
288
289 int DRM(modprobe)();
290 int DRM(probe)(struct pci_attach_args *pa);
291 void DRM(attach)(struct pci_attach_args *pa, cdev_t kdev);
292
293 int DRM(lkmentry)(struct lkm_table *lkmtp, int cmd, int ver) {
294         DISPATCH(lkmtp, cmd, ver, DRM(lkmhandle), DRM(lkmhandle), DRM(lkmhandle));
295 }
296
297 static int DRM(lkmhandle)(struct lkm_table *lkmtp, int cmd)
298 {
299         int j, error = 0;
300 #if defined(__NetBSD__) && (__NetBSD_Version__ > 106080000)
301         struct lkm_dev *args = lkmtp->private.lkm_dev;
302 #endif
303
304         switch(cmd) {
305         case LKM_E_LOAD:
306                 if (lkmexists(lkmtp))
307                         return EEXIST;
308
309                 if(DRM(modprobe)())
310                         return 0;
311
312                 return 1;
313
314         case LKM_E_UNLOAD:
315                 if (DRM(refcnt) > 0)
316                         return (EBUSY);
317                 break;
318         case LKM_E_STAT:
319                 break;
320
321         default:
322                 error = EIO;
323                 break;
324         }
325         
326         return error;
327 }
328
329 int DRM(modprobe)() {
330         struct pci_attach_args pa;
331         int error = 0;
332         if((error = pci_find_device(&pa, DRM(probe))) != 0)
333                 DRM(attach)(&pa, 0);
334
335         return error;
336 }
337
338 int DRM(probe)(struct pci_attach_args *pa)
339 {
340         const char *desc;
341
342         desc = DRM(find_description)(PCI_VENDOR(pa->pa_id), PCI_PRODUCT(pa->pa_id));
343         if (desc != NULL) {
344                 return 1;
345         }
346
347         return 0;
348 }
349
350 void DRM(attach)(struct pci_attach_args *pa, cdev_t kdev)
351 {
352         int i;
353         drm_device_t *dev;
354
355         config_makeroom(kdev, &DRM(cd));
356         DRM(cd).cd_devs[(kdev)] = DRM(alloc)(sizeof(drm_device_t),
357             DRM_MEM_DRIVER);
358         dev = DRIVER_SOFTC(kdev);
359
360         memset(dev, 0, sizeof(drm_device_t));
361         memcpy(&dev->pa, pa, sizeof(dev->pa));
362
363         DRM_INFO("%s", DRM(find_description)(PCI_VENDOR(pa->pa_id), PCI_PRODUCT(pa->pa_id)));
364         DRM(init)(dev);
365 }
366
367 int DRM(detach)(struct device *self, int flags)
368 {
369         DRM(cleanup)((drm_device_t *)self);
370         return 0;
371 }
372
373 int DRM(activate)(struct device *self, enum devact act)
374 {
375         switch (act) {
376         case DVACT_ACTIVATE:
377                 return (EOPNOTSUPP);
378                 break;
379
380         case DVACT_DEACTIVATE:
381                 /* FIXME */
382                 break;
383         }
384         return (0);
385 }
386 #endif /* __NetBSD__ */
387
388 const char *DRM(find_description)(int vendor, int device) {
389         const char *s = NULL;
390         int i=0, done=0;
391         
392         while ( !done && (DRM(devicelist)[i].vendor != 0 ) ) {
393                 if ( (DRM(devicelist)[i].vendor == vendor) &&
394                      (DRM(devicelist)[i].device == device) ) {
395                         done=1;
396                         if ( DRM(devicelist)[i].supported )
397                                 s = DRM(devicelist)[i].name;
398                         else
399                                 DRM_INFO("%s not supported\n", DRM(devicelist)[i].name);
400                 }
401                 i++;
402         }
403         return s;
404 }
405
406 static int DRM(setup)( drm_device_t *dev )
407 {
408         int i;
409
410         DRIVER_PRESETUP();
411         dev->buf_use = 0;
412         dev->buf_alloc = 0;
413
414 #if __HAVE_DMA
415         i = DRM(dma_setup)( dev );
416         if ( i < 0 )
417                 return i;
418 #endif
419
420         dev->counters  = 6 + __HAVE_COUNTERS;
421         dev->types[0]  = _DRM_STAT_LOCK;
422         dev->types[1]  = _DRM_STAT_OPENS;
423         dev->types[2]  = _DRM_STAT_CLOSES;
424         dev->types[3]  = _DRM_STAT_IOCTLS;
425         dev->types[4]  = _DRM_STAT_LOCKS;
426         dev->types[5]  = _DRM_STAT_UNLOCKS;
427 #ifdef __HAVE_COUNTER6
428         dev->types[6]  = __HAVE_COUNTER6;
429 #endif
430 #ifdef __HAVE_COUNTER7
431         dev->types[7]  = __HAVE_COUNTER7;
432 #endif
433 #ifdef __HAVE_COUNTER8
434         dev->types[8]  = __HAVE_COUNTER8;
435 #endif
436 #ifdef __HAVE_COUNTER9
437         dev->types[9]  = __HAVE_COUNTER9;
438 #endif
439 #ifdef __HAVE_COUNTER10
440         dev->types[10] = __HAVE_COUNTER10;
441 #endif
442 #ifdef __HAVE_COUNTER11
443         dev->types[11] = __HAVE_COUNTER11;
444 #endif
445 #ifdef __HAVE_COUNTER12
446         dev->types[12] = __HAVE_COUNTER12;
447 #endif
448 #ifdef __HAVE_COUNTER13
449         dev->types[13] = __HAVE_COUNTER13;
450 #endif
451 #ifdef __HAVE_COUNTER14
452         dev->types[14] = __HAVE_COUNTER14;
453 #endif
454 #ifdef __HAVE_COUNTER15
455         dev->types[14] = __HAVE_COUNTER14;
456 #endif
457
458         for ( i = 0 ; i < DRM_ARRAY_SIZE(dev->counts) ; i++ )
459                 atomic_set( &dev->counts[i], 0 );
460
461         for ( i = 0 ; i < DRM_HASH_SIZE ; i++ ) {
462                 dev->magiclist[i].head = NULL;
463                 dev->magiclist[i].tail = NULL;
464         }
465
466         dev->maplist = DRM(alloc)(sizeof(*dev->maplist),
467                                   DRM_MEM_MAPS);
468         if(dev->maplist == NULL) return DRM_ERR(ENOMEM);
469         memset(dev->maplist, 0, sizeof(*dev->maplist));
470         TAILQ_INIT(dev->maplist);
471
472         dev->lock.hw_lock = NULL;
473         dev->lock.lock_queue = 0;
474         dev->irq = 0;
475         dev->context_flag = 0;
476         dev->last_context = 0;
477 #if defined(__FreeBSD__) && __FreeBSD_version >= 500000
478         callout_init( &dev->timer, 1 );
479 #else
480         callout_init( &dev->timer );
481 #endif
482
483 #if defined(__DragonFly__) || defined(__FreeBSD__)
484         dev->buf_sigio = NULL;
485 #elif defined(__NetBSD__)
486         dev->buf_pgid = 0;
487 #endif
488
489         DRM_DEBUG( "\n" );
490
491         DRIVER_POSTSETUP();
492         return 0;
493 }
494
495
496 static int DRM(takedown)( drm_device_t *dev )
497 {
498         drm_magic_entry_t *pt, *next;
499         drm_local_map_t *map;
500         drm_map_list_entry_t *list;
501         int i;
502
503         DRM_DEBUG( "\n" );
504
505         DRIVER_PRETAKEDOWN();
506 #if __HAVE_DMA_IRQ
507         if ( dev->irq ) DRM(irq_uninstall)( dev );
508 #endif
509
510         DRM_LOCK;
511         callout_stop( &dev->timer );
512
513         if ( dev->unique ) {
514                 DRM(free)( dev->unique, strlen( dev->unique ) + 1,
515                            DRM_MEM_DRIVER );
516                 dev->unique = NULL;
517                 dev->unique_len = 0;
518         }
519                                 /* Clear pid list */
520         for ( i = 0 ; i < DRM_HASH_SIZE ; i++ ) {
521                 for ( pt = dev->magiclist[i].head ; pt ; pt = next ) {
522                         next = pt->next;
523                         DRM(free)( pt, sizeof(*pt), DRM_MEM_MAGIC );
524                 }
525                 dev->magiclist[i].head = dev->magiclist[i].tail = NULL;
526         }
527
528 #if __REALLY_HAVE_AGP
529                                 /* Clear AGP information */
530         if ( dev->agp ) {
531                 drm_agp_mem_t *entry;
532                 drm_agp_mem_t *nexte;
533
534                                 /* Remove AGP resources, but leave dev->agp
535                                    intact until drv_cleanup is called. */
536                 for ( entry = dev->agp->memory ; entry ; entry = nexte ) {
537                         nexte = entry->next;
538                         if ( entry->bound ) DRM(unbind_agp)( entry->handle );
539                         DRM(free_agp)( entry->handle, entry->pages );
540                         DRM(free)( entry, sizeof(*entry), DRM_MEM_AGPLISTS );
541                 }
542                 dev->agp->memory = NULL;
543
544                 if ( dev->agp->acquired ) DRM(agp_do_release)();
545
546                 dev->agp->acquired = 0;
547                 dev->agp->enabled  = 0;
548         }
549 #endif
550
551         if( dev->maplist ) {
552                 while ((list=TAILQ_FIRST(dev->maplist))) {
553                         map = list->map;
554                         switch ( map->type ) {
555                         case _DRM_REGISTERS:
556                         case _DRM_FRAME_BUFFER:
557 #if __REALLY_HAVE_MTRR
558                                 if ( map->mtrr >= 0 ) {
559                                         int retcode;
560 #if defined(__DragonFly__) || defined(__FreeBSD__)
561                                         int act;
562                                         struct mem_range_desc mrdesc;
563                                         mrdesc.mr_base = map->offset;
564                                         mrdesc.mr_len = map->size;
565                                         mrdesc.mr_flags = MDF_WRITECOMBINE;
566                                         act = MEMRANGE_SET_UPDATE;
567                                         bcopy(DRIVER_NAME, &mrdesc.mr_owner, strlen(DRIVER_NAME));
568                                         retcode = mem_range_attr_set(&mrdesc, &act);
569                                         map->mtrr=1;
570 #elif defined __NetBSD__
571                                         struct mtrr mtrrmap;
572                                         int one = 1;
573                                         mtrrmap.base = map->offset;
574                                         mtrrmap.len = map->size;
575                                         mtrrmap.type = MTRR_TYPE_WC;
576                                         mtrrmap.flags = 0;
577                                         retcode = mtrr_set( &mtrrmap, &one, 
578                                                 DRM_CURPROC, MTRR_GETSET_KERNEL);
579 #endif
580                                         DRM_DEBUG( "mtrr_del=%d\n", retcode );
581                                 }
582 #endif
583                                 DRM(ioremapfree)( map );
584                                 break;
585                         case _DRM_SHM:
586                                 DRM(free)(map->handle,
587                                                map->size,
588                                                DRM_MEM_SAREA);
589                                 break;
590
591                         case _DRM_AGP:
592                                 /* Do nothing here, because this is all
593                                  * handled in the AGP/GART driver.
594                                  */
595                                 break;
596                        case _DRM_SCATTER_GATHER:
597                                 /* Handle it, but do nothing, if REALLY_HAVE_SG
598                                  * isn't defined.
599                                  */
600 #if __REALLY_HAVE_SG
601                                 if(dev->sg) {
602                                         DRM(sg_cleanup)(dev->sg);
603                                         dev->sg = NULL;
604                                 }
605 #endif
606                                 break;
607                         }
608                         TAILQ_REMOVE(dev->maplist, list, link);
609                         DRM(free)(list, sizeof(*list), DRM_MEM_MAPS);
610                         DRM(free)(map, sizeof(*map), DRM_MEM_MAPS);
611                 }
612                 DRM(free)(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
613                 dev->maplist   = NULL;
614         }
615
616 #if __HAVE_DMA
617         DRM(dma_takedown)( dev );
618 #endif
619         if ( dev->lock.hw_lock ) {
620                 dev->lock.hw_lock = NULL; /* SHM removed */
621                 dev->lock.filp = NULL;
622                 DRM_WAKEUP_INT((void *)&dev->lock.lock_queue);
623         }
624         DRM_UNLOCK;
625
626         return 0;
627 }
628
629 /* linux: drm_init is called via init_module at module load time, or via
630  *        linux/init/main.c (this is not currently supported).
631  * bsd:   drm_init is called via the attach function per device.
632  */
633 static int DRM(init)( device_t nbdev )
634 {
635         int unit;
636 #if defined(__DragonFly__) || defined(__FreeBSD__)
637         drm_device_t *dev;
638 #elif defined(__NetBSD__)
639         drm_device_t *dev = nbdev;
640 #endif
641 #if __HAVE_CTX_BITMAP
642         int retcode;
643 #endif
644         DRM_DEBUG( "\n" );
645         DRIVER_PREINIT();
646
647 #if defined(__DragonFly__) || defined(__FreeBSD__)
648         unit = device_get_unit(nbdev);
649         dev = device_get_softc(nbdev);
650         memset( (void *)dev, 0, sizeof(*dev) );
651         dev->device = nbdev;
652         dev_ops_add(&DRM(ops), -1, unit);
653         dev->devnode = make_dev( &DRM(ops),
654                         unit,
655                         DRM_DEV_UID,
656                         DRM_DEV_GID,
657                         DRM_DEV_MODE,
658                         "dri/card%d", unit );
659         reference_dev(dev->devnode);
660 #elif defined(__NetBSD__)
661         unit = minor(dev->device.dv_unit);
662 #endif
663         DRM_SPININIT(dev->count_lock, "drm device");
664         lockinit(&dev->dev_lock, "drmlk", 0, 0);
665         dev->name = DRIVER_NAME;
666         DRM(mem_init)();
667         DRM(sysctl_init)(dev);
668         TAILQ_INIT(&dev->files);
669
670 #if __REALLY_HAVE_AGP
671         dev->agp = DRM(agp_init)();
672 #if __MUST_HAVE_AGP
673         if ( dev->agp == NULL ) {
674                 DRM_ERROR( "Cannot initialize the agpgart module.\n" );
675                 DRM(sysctl_cleanup)( dev );
676 #if defined(__DragonFly__) || defined(__FreeBSD__)
677                 destroy_dev(dev->devnode);
678 #endif
679                 DRM(takedown)( dev );
680                 return DRM_ERR(ENOMEM);
681         }
682 #endif /* __MUST_HAVE_AGP */
683 #if __REALLY_HAVE_MTRR
684         if (dev->agp) {
685 #if defined(__DragonFly__) || defined(__FreeBSD__)
686                 int retcode = 0, act;
687                 struct mem_range_desc mrdesc;
688                 mrdesc.mr_base = dev->agp->info.ai_aperture_base;
689                 mrdesc.mr_len = dev->agp->info.ai_aperture_size;
690                 mrdesc.mr_flags = MDF_WRITECOMBINE;
691                 act = MEMRANGE_SET_UPDATE;
692                 bcopy(DRIVER_NAME, &mrdesc.mr_owner, strlen(DRIVER_NAME));
693                 retcode = mem_range_attr_set(&mrdesc, &act);
694                 dev->agp->agp_mtrr=1;
695 #elif defined __NetBSD__
696                 struct mtrr mtrrmap;
697                 int one = 1;
698                 mtrrmap.base = dev->agp->info.ai_aperture_base;
699                 mtrrmap.len = dev->agp->info.ai_aperture_size;
700                 mtrrmap.type = MTRR_TYPE_WC;
701                 mtrrmap.flags = MTRR_VALID;
702                 dev->agp->agp_mtrr = mtrr_set( &mtrrmap, &one, NULL, MTRR_GETSET_KERNEL);
703 #endif /* __NetBSD__ */
704         }
705 #endif /* __REALLY_HAVE_MTRR */
706 #endif /* __REALLY_HAVE_AGP */
707
708 #if __HAVE_CTX_BITMAP
709         retcode = DRM(ctxbitmap_init)( dev );
710         if( retcode ) {
711                 DRM_ERROR( "Cannot allocate memory for context bitmap.\n" );
712                 DRM(sysctl_cleanup)( dev );
713 #if defined(__DragonFly__) || defined(__FreeBSD__)
714                 destroy_dev(dev->devnode);
715 #endif
716                 DRM(takedown)( dev );
717                 return retcode;
718         }
719 #endif
720         DRM_INFO( "Initialized %s %d.%d.%d %s on minor %d\n",
721                 DRIVER_NAME,
722                 DRIVER_MAJOR,
723                 DRIVER_MINOR,
724                 DRIVER_PATCHLEVEL,
725                 DRIVER_DATE,
726                 unit );
727
728         DRIVER_POSTINIT();
729
730         return 0;
731 }
732
733 /* linux: drm_cleanup is called via cleanup_module at module unload time.
734  * bsd:   drm_cleanup is called per device at module unload time.
735  * FIXME: NetBSD
736  */
737 static void DRM(cleanup)(device_t nbdev)
738 {
739         drm_device_t *dev;
740 #ifdef __NetBSD__
741 #if __REALLY_HAVE_MTRR
742         struct mtrr mtrrmap;
743         int one = 1;
744 #endif /* __REALLY_HAVE_MTRR */
745         dev = nbdev;
746 #endif /* __NetBSD__ */
747
748         DRM_DEBUG( "\n" );
749
750 #if defined(__DragonFly__) || defined(__FreeBSD__)
751         dev = device_get_softc(nbdev);
752 #endif
753         DRM(sysctl_cleanup)( dev );
754 #if defined(__DragonFly__) || defined(__FreeBSD__)
755         destroy_dev(dev->devnode);
756 #endif
757 #if __HAVE_CTX_BITMAP
758         DRM(ctxbitmap_cleanup)( dev );
759 #endif
760
761 #if __REALLY_HAVE_AGP && __REALLY_HAVE_MTRR
762         if ( dev->agp && dev->agp->agp_mtrr >= 0) {
763 #if defined(__NetBSD__)
764                 mtrrmap.base = dev->agp->info.ai_aperture_base;
765                 mtrrmap.len = dev->agp->info.ai_aperture_size;
766                 mtrrmap.type = 0;
767                 mtrrmap.flags = 0;
768                 mtrr_set( &mtrrmap, &one, NULL, MTRR_GETSET_KERNEL);
769 #endif
770         }
771 #endif
772         dev_ops_remove(&DRM(ops), -1, device_get_unit(nbdev));
773
774         DRM(takedown)( dev );
775
776 #if __REALLY_HAVE_AGP
777         if ( dev->agp ) {
778                 DRM(agp_uninit)();
779                 DRM(free)( dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS );
780                 dev->agp = NULL;
781         }
782 #endif
783         DRIVER_POSTCLEANUP();
784         DRM(mem_uninit)();
785         DRM_SPINUNINIT(dev->count_lock);
786 }
787
788
789 int DRM(version)( DRM_IOCTL_ARGS )
790 {
791         drm_version_t version;
792         int len;
793
794         DRM_COPY_FROM_USER_IOCTL( version, (drm_version_t *)data, sizeof(version) );
795
796 #define DRM_COPY( name, value )                                         \
797         len = strlen( value );                                          \
798         if ( len > name##_len ) len = name##_len;                       \
799         name##_len = strlen( value );                                   \
800         if ( len && name ) {                                            \
801                 if ( DRM_COPY_TO_USER( name, value, len ) )             \
802                         return DRM_ERR(EFAULT);                         \
803         }
804
805         version.version_major = DRIVER_MAJOR;
806         version.version_minor = DRIVER_MINOR;
807         version.version_patchlevel = DRIVER_PATCHLEVEL;
808
809         DRM_COPY( version.name, DRIVER_NAME );
810         DRM_COPY( version.date, DRIVER_DATE );
811         DRM_COPY( version.desc, DRIVER_DESC );
812
813         DRM_COPY_TO_USER_IOCTL( (drm_version_t *)data, version, sizeof(version) );
814
815         return 0;
816 }
817
818 int DRM(open)(struct dev_open_args *ap)
819 {
820         cdev_t kdev = ap->a_head.a_dev;
821         drm_device_t *dev = NULL;
822         int retcode = 0;
823
824         dev = DRIVER_SOFTC(minor(kdev));
825
826         DRM_DEBUG( "open_count = %d\n", dev->open_count );
827
828         retcode = DRM(open_helper)(kdev, ap->a_oflags, ap->a_devtype,
829                                    curthread, dev);
830
831         if ( !retcode ) {
832                 atomic_inc( &dev->counts[_DRM_STAT_OPENS] );
833                 DRM_SPINLOCK( &dev->count_lock );
834 #if defined(__DragonFly__) || defined(__FreeBSD__)
835                 device_busy(dev->device);
836 #endif
837                 if ( !dev->open_count++ )
838                         retcode = DRM(setup)( dev );
839                 DRM_SPINUNLOCK( &dev->count_lock );
840         }
841
842         return retcode;
843 }
844
845 int DRM(close)(struct dev_close_args *ap)
846 {
847         cdev_t kdev = ap->a_head.a_dev;
848         drm_file_t *priv;
849         DRM_DEVICE;
850         int retcode = 0;
851         DRMFILE __unused filp = (void *)(DRM_CURRENTPID);
852         
853         DRM_DEBUG( "open_count = %d\n", dev->open_count );
854         priv = DRM(find_file_by_proc)(dev, curthread);
855         if (!priv) {
856                 DRM_DEBUG("can't find authenticator\n");
857                 return EINVAL;
858         }
859
860         DRIVER_PRERELEASE();
861
862         /* ========================================================
863          * Begin inline drm_release
864          */
865
866 #if defined(__DragonFly__) || defined(__FreeBSD__)
867         DRM_DEBUG( "pid = %d, device = 0x%lx, open_count = %d\n",
868                    DRM_CURRENTPID, (long)dev->device, dev->open_count );
869 #elif defined(__NetBSD__)
870         DRM_DEBUG( "pid = %d, device = 0x%lx, open_count = %d\n",
871                    DRM_CURRENTPID, (long)&dev->device, dev->open_count);
872 #endif
873
874         if (dev->lock.hw_lock && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)
875             && dev->lock.filp == (void *)DRM_CURRENTPID) {
876                 DRM_DEBUG("Process %d dead, freeing lock for context %d\n",
877                           DRM_CURRENTPID,
878                           _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
879 #if HAVE_DRIVER_RELEASE
880                 DRIVER_RELEASE();
881 #endif
882                 DRM(lock_free)(dev,
883                               &dev->lock.hw_lock->lock,
884                               _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
885                 
886                                 /* FIXME: may require heavy-handed reset of
887                                    hardware at this point, possibly
888                                    processed via a callback to the X
889                                    server. */
890         }
891 #if __HAVE_RELEASE
892         else if ( dev->lock.hw_lock ) {
893                 /* The lock is required to reclaim buffers */
894                 for (;;) {
895                         if ( !dev->lock.hw_lock ) {
896                                 /* Device has been unregistered */
897                                 retcode = DRM_ERR(EINTR);
898                                 break;
899                         }
900                         if ( DRM(lock_take)( &dev->lock.hw_lock->lock,
901                                              DRM_KERNEL_CONTEXT ) ) {
902                                 dev->lock.pid       = DRM_CURRENTPID;
903                                 dev->lock.lock_time = jiffies;
904                                 atomic_inc( &dev->counts[_DRM_STAT_LOCKS] );
905                                 break;  /* Got lock */
906                         }
907                                 /* Contention */
908 #if 0
909                         atomic_inc( &dev->total_sleeps );
910 #endif
911                         retcode = tsleep((void *)&dev->lock.lock_queue,
912                                         PCATCH, "drmlk2", 0);
913                         if (retcode)
914                                 break;
915                 }
916                 if( !retcode ) {
917                         DRIVER_RELEASE();
918                         DRM(lock_free)( dev, &dev->lock.hw_lock->lock,
919                                         DRM_KERNEL_CONTEXT );
920                 }
921         }
922 #elif __HAVE_DMA
923         DRM(reclaim_buffers)( dev, (void *)priv->pid );
924 #endif
925
926 #if defined (__FreeBSD__) && (__FreeBSD_version >= 500000)
927         funsetown(&dev->buf_sigio);
928 #elif defined(__DragonFly__) || defined(__FreeBSD__)
929         funsetown(dev->buf_sigio);
930 #elif defined(__NetBSD__)
931         dev->buf_pgid = 0;
932 #endif /* __NetBSD__ */
933
934         DRM_LOCK;
935         priv = DRM(find_file_by_proc)(dev, curthread);
936         if (priv) {
937                 priv->refs--;
938                 if (!priv->refs) {
939                         TAILQ_REMOVE(&dev->files, priv, link);
940                         DRM(free)( priv, sizeof(*priv), DRM_MEM_FILES );
941                 }
942         }
943         DRM_UNLOCK;
944
945
946         /* ========================================================
947          * End inline drm_release
948          */
949
950         atomic_inc( &dev->counts[_DRM_STAT_CLOSES] );
951         DRM_SPINLOCK( &dev->count_lock );
952 #if defined(__DragonFly__) || defined(__FreeBSD__)
953         device_unbusy(dev->device);
954 #endif
955         if ( !--dev->open_count ) {
956                 DRM_SPINUNLOCK( &dev->count_lock );
957                 return DRM(takedown)( dev );
958         }
959         DRM_SPINUNLOCK( &dev->count_lock );
960         
961         return retcode;
962 }
963
964 /* DRM(ioctl) is called whenever a process performs an ioctl on /dev/drm.
965  */
966 int DRM(ioctl)(struct dev_ioctl_args *ap)
967 {
968         cdev_t kdev = ap->a_head.a_dev;
969         DRM_DEVICE;
970         int retcode = 0;
971         drm_ioctl_desc_t *ioctl;
972         int (*func)(DRM_IOCTL_ARGS);
973         int nr = DRM_IOCTL_NR(ap->a_cmd);
974         DRM_PRIV;
975
976         atomic_inc( &dev->counts[_DRM_STAT_IOCTLS] );
977         ++priv->ioctl_count;
978
979 #if defined(__DragonFly__) || defined(__FreeBSD__)
980         DRM_DEBUG( "pid=%d, cmd=0x%02lx, nr=0x%02x, dev 0x%lx, auth=%d\n",
981                  DRM_CURRENTPID, ap->a_cmd, nr, (long)dev->device, priv->authenticated );
982 #elif defined(__NetBSD__)
983         DRM_DEBUG( "pid=%d, cmd=0x%02lx, nr=0x%02x, dev 0x%lx, auth=%d\n",
984                  DRM_CURRENTPID, ap->a_cmd, nr, (long)&dev->device, priv->authenticated );
985 #endif
986
987         switch (ap->a_cmd) {
988         case FIOASYNC:
989                 dev->flags |= FASYNC;
990                 return 0;
991
992 #if defined(__DragonFly__) || defined(__FreeBSD__)
993         case FIOSETOWN:
994                 return fsetown(*(int *)ap->a_data, &dev->buf_sigio);
995
996         case FIOGETOWN:
997 #if defined(__FreeBSD__) && (__FreeBSD_version >= 500000)
998                 *(int *) ap->a_data = fgetown(&dev->buf_sigio);
999 #else
1000                 *(int *) ap->a_data = fgetown(dev->buf_sigio);
1001 #endif
1002                 return 0;
1003 #endif /* __FreeBSD__ */
1004 #ifdef __NetBSD__
1005         case TIOCSPGRP:
1006                 dev->buf_pgid = *(int *)ap->a_data;
1007                 return 0;
1008
1009         case TIOCGPGRP:
1010                 *(int *)ap->a_data = dev->buf_pgid;
1011                 return 0;
1012 #endif /* __NetBSD__ */
1013         }
1014
1015         if ( nr >= DRIVER_IOCTL_COUNT ) {
1016                 retcode = EINVAL;
1017         } else {
1018                 ioctl = &DRM(ioctls)[nr];
1019                 func = ioctl->func;
1020
1021                 if ( !func ) {
1022                         DRM_DEBUG( "no function\n" );
1023                         retcode = EINVAL;
1024                 } else if ( ( ioctl->root_only && suser_cred(ap->a_cred, 0) ) 
1025                          || ( ioctl->auth_needed && !priv->authenticated ) ) {
1026                         retcode = EACCES;
1027                 } else {
1028                         retcode = func(kdev, ap->a_cmd, ap->a_data, ap->a_fflag, curthread, (void *)DRM_CURRENTPID);
1029                 }
1030         }
1031
1032         return DRM_ERR(retcode);
1033 }
1034
1035 int DRM(lock)( DRM_IOCTL_ARGS )
1036 {
1037         DRM_DEVICE;
1038         drm_lock_t lock;
1039         int ret = 0;
1040
1041         DRM_COPY_FROM_USER_IOCTL( lock, (drm_lock_t *)data, sizeof(lock) );
1042
1043         if ( lock.context == DRM_KERNEL_CONTEXT ) {
1044                 DRM_ERROR( "Process %d using kernel context %d\n",
1045                            DRM_CURRENTPID, lock.context );
1046                 return DRM_ERR(EINVAL);
1047         }
1048
1049         DRM_DEBUG( "%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
1050                    lock.context, DRM_CURRENTPID,
1051                    dev->lock.hw_lock->lock, lock.flags );
1052
1053 #if __HAVE_DMA_QUEUE
1054         if ( lock.context < 0 )
1055                 return DRM_ERR(EINVAL);
1056 #endif
1057
1058         if ( !ret ) {
1059                 for (;;) {
1060                         if ( !dev->lock.hw_lock ) {
1061                                 /* Device has been unregistered */
1062                                 ret = EINTR;
1063                                 break;
1064                         }
1065                         if ( DRM(lock_take)( &dev->lock.hw_lock->lock,
1066                                              lock.context ) ) {
1067                                 dev->lock.filp = (void *)DRM_CURRENTPID;
1068                                 dev->lock.lock_time = jiffies;
1069                                 atomic_inc( &dev->counts[_DRM_STAT_LOCKS] );
1070                                 break;  /* Got lock */
1071                         }
1072
1073                                 /* Contention */
1074                         ret = tsleep((void *)&dev->lock.lock_queue,
1075                                         PCATCH, "drmlk2", 0);
1076                         if (ret)
1077                                 break;
1078                 }
1079         }
1080
1081         if ( !ret ) {
1082                 /* FIXME: Add signal blocking here */
1083
1084 #if __HAVE_DMA_QUIESCENT
1085                 if ( lock.flags & _DRM_LOCK_QUIESCENT ) {
1086                         DRIVER_DMA_QUIESCENT();
1087                 }
1088 #endif
1089         }
1090
1091         DRM_DEBUG( "%d %s\n", lock.context, ret ? "interrupted" : "has lock" );
1092
1093         return DRM_ERR(ret);
1094 }
1095
1096
1097 int DRM(unlock)( DRM_IOCTL_ARGS )
1098 {
1099         DRM_DEVICE;
1100         drm_lock_t lock;
1101
1102         DRM_COPY_FROM_USER_IOCTL( lock, (drm_lock_t *)data, sizeof(lock) ) ;
1103
1104         if ( lock.context == DRM_KERNEL_CONTEXT ) {
1105                 DRM_ERROR( "Process %d using kernel context %d\n",
1106                            DRM_CURRENTPID, lock.context );
1107                 return DRM_ERR(EINVAL);
1108         }
1109
1110         atomic_inc( &dev->counts[_DRM_STAT_UNLOCKS] );
1111
1112         DRM(lock_transfer)( dev, &dev->lock.hw_lock->lock,
1113                             DRM_KERNEL_CONTEXT );
1114 #if __HAVE_DMA_SCHEDULE
1115         DRM(dma_schedule)( dev, 1 );
1116 #endif
1117
1118         /* FIXME: Do we ever really need to check this?
1119          */
1120         if ( 1 /* !dev->context_flag */ ) {
1121                 if ( DRM(lock_free)( dev, &dev->lock.hw_lock->lock,
1122                                      DRM_KERNEL_CONTEXT ) ) {
1123                         DRM_ERROR( "\n" );
1124                 }
1125         }
1126
1127         return 0;
1128 }
1129
1130 #if DRM_LINUX
1131
1132 #include <sys/file2.h>
1133 #include <sys/mapped_ioctl.h>
1134 #include <sys/sysproto.h>
1135 #include <emulation/linux/linux_ioctl.h>
1136
1137 MODULE_DEPEND(DRIVER_NAME, linux, 1, 1, 1);
1138
1139 #define LINUX_IOCTL_DRM_MIN             0x6400
1140 #define LINUX_IOCTL_DRM_MAX             0x64ff
1141
1142 static struct ioctl_map_range DRM(ioctl_cmds)[] = {
1143         MAPPED_IOCTL_MAPRANGE(LINUX_IOCTL_DRM_MIN, LINUX_IOCTL_DRM_MAX, LINUX_IOCTL_DRM_MIN,
1144                               LINUX_IOCTL_DRM_MAX, NULL, linux_gen_dirmap),
1145         MAPPED_IOCTL_MAPF(0, 0, NULL)
1146 };
1147
1148 static struct ioctl_map_handler DRM(ioctl_handler) = {
1149         &linux_ioctl_map,
1150         __XSTRING(DRM(linux)),
1151         DRM(ioctl_cmds)
1152 };
1153
1154 SYSINIT(DRM(register), SI_BOOT2_KLD, SI_ORDER_MIDDLE, 
1155     mapped_ioctl_register_handler, &DRM(ioctl_handler));
1156 SYSUNINIT(DRM(unregister), SI_BOOT2_KLD, SI_ORDER_MIDDLE, 
1157     mapped_ioctl_unregister_handler, &DRM(ioctl_handler));
1158
1159 #endif /* DRM_LINUX */