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