Merge from vendor branch BINUTILS:
[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.10 2004/09/18 16:25:54 joerg 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 cdevsw DRM(cdevsw) = {
210         .d_name =       DRIVER_NAME,
211         .d_maj =        CDEV_MAJOR,
212         .d_flags =      D_TTY | D_TRACKCLOSE,
213         .d_port =       NULL,
214         .d_clone =      NULL,
215
216         .old_open =     DRM( open ),
217         .old_close =    DRM( close ),
218         .old_read =     DRM( read ),
219         .old_ioctl =    DRM( ioctl ),
220         .old_poll =     DRM( poll ),
221         .old_mmap =     DRM( mmap )
222 };
223
224 static int DRM(probe)(device_t dev)
225 {
226         const char *s = NULL;
227
228         int pciid=pci_get_devid(dev);
229         int vendor = (pciid & 0x0000ffff);
230         int device = (pciid & 0xffff0000) >> 16;
231         
232         s = DRM(find_description)(vendor, device);
233         if (s) {
234                 device_set_desc(dev, s);
235                 return 0;
236         }
237
238         return ENXIO;
239 }
240
241 static int DRM(attach)(device_t dev)
242 {
243         return DRM(init)(dev);
244 }
245
246 static int DRM(detach)(device_t dev)
247 {
248         DRM(cleanup)(dev);
249         return 0;
250 }
251 static device_method_t DRM(methods)[] = {
252         /* Device interface */
253         DEVMETHOD(device_probe,         DRM( probe)),
254         DEVMETHOD(device_attach,        DRM( attach)),
255         DEVMETHOD(device_detach,        DRM( detach)),
256
257         { 0, 0 }
258 };
259
260 static driver_t DRM(driver) = {
261         "drm",
262         DRM(methods),
263         sizeof(drm_device_t),
264 };
265
266 static devclass_t DRM(devclass);
267
268 #elif defined(__NetBSD__)
269
270 static struct cdevsw DRM(cdevsw) = {
271         DRM(open),
272         DRM(close),
273         DRM(read),
274         nowrite,
275         DRM(ioctl),
276         nostop,
277         notty,
278         DRM(poll),
279         DRM(mmap),
280         nokqfilter,
281         D_TTY
282 };
283
284 int DRM(refcnt) = 0;
285 #if __NetBSD_Version__ >= 106080000
286 MOD_DEV( DRIVER_NAME, DRIVER_NAME, NULL, -1, &DRM(cdevsw), CDEV_MAJOR);
287 #else
288 MOD_DEV( DRIVER_NAME, LM_DT_CHAR, CDEV_MAJOR, &DRM(cdevsw) );
289 #endif
290
291 int DRM(lkmentry)(struct lkm_table *lkmtp, int cmd, int ver);
292 static int DRM(lkmhandle)(struct lkm_table *lkmtp, int cmd);
293
294 int DRM(modprobe)();
295 int DRM(probe)(struct pci_attach_args *pa);
296 void DRM(attach)(struct pci_attach_args *pa, dev_t kdev);
297
298 int DRM(lkmentry)(struct lkm_table *lkmtp, int cmd, int ver) {
299         DISPATCH(lkmtp, cmd, ver, DRM(lkmhandle), DRM(lkmhandle), DRM(lkmhandle));
300 }
301
302 static int DRM(lkmhandle)(struct lkm_table *lkmtp, int cmd)
303 {
304         int j, error = 0;
305 #if defined(__NetBSD__) && (__NetBSD_Version__ > 106080000)
306         struct lkm_dev *args = lkmtp->private.lkm_dev;
307 #endif
308
309         switch(cmd) {
310         case LKM_E_LOAD:
311                 if (lkmexists(lkmtp))
312                         return EEXIST;
313
314                 if(DRM(modprobe)())
315                         return 0;
316
317                 return 1;
318
319         case LKM_E_UNLOAD:
320                 if (DRM(refcnt) > 0)
321                         return (EBUSY);
322                 break;
323         case LKM_E_STAT:
324                 break;
325
326         default:
327                 error = EIO;
328                 break;
329         }
330         
331         return error;
332 }
333
334 int DRM(modprobe)() {
335         struct pci_attach_args pa;
336         int error = 0;
337         if((error = pci_find_device(&pa, DRM(probe))) != 0)
338                 DRM(attach)(&pa, 0);
339
340         return error;
341 }
342
343 int DRM(probe)(struct pci_attach_args *pa)
344 {
345         const char *desc;
346
347         desc = DRM(find_description)(PCI_VENDOR(pa->pa_id), PCI_PRODUCT(pa->pa_id));
348         if (desc != NULL) {
349                 return 1;
350         }
351
352         return 0;
353 }
354
355 void DRM(attach)(struct pci_attach_args *pa, dev_t kdev)
356 {
357         int i;
358         drm_device_t *dev;
359
360         config_makeroom(kdev, &DRM(cd));
361         DRM(cd).cd_devs[(kdev)] = DRM(alloc)(sizeof(drm_device_t),
362             DRM_MEM_DRIVER);
363         dev = DRIVER_SOFTC(kdev);
364
365         memset(dev, 0, sizeof(drm_device_t));
366         memcpy(&dev->pa, pa, sizeof(dev->pa));
367
368         DRM_INFO("%s", DRM(find_description)(PCI_VENDOR(pa->pa_id), PCI_PRODUCT(pa->pa_id)));
369         DRM(init)(dev);
370 }
371
372 int DRM(detach)(struct device *self, int flags)
373 {
374         DRM(cleanup)((drm_device_t *)self);
375         return 0;
376 }
377
378 int DRM(activate)(struct device *self, enum devact act)
379 {
380         switch (act) {
381         case DVACT_ACTIVATE:
382                 return (EOPNOTSUPP);
383                 break;
384
385         case DVACT_DEACTIVATE:
386                 /* FIXME */
387                 break;
388         }
389         return (0);
390 }
391 #endif /* __NetBSD__ */
392
393 const char *DRM(find_description)(int vendor, int device) {
394         const char *s = NULL;
395         int i=0, done=0;
396         
397         while ( !done && (DRM(devicelist)[i].vendor != 0 ) ) {
398                 if ( (DRM(devicelist)[i].vendor == vendor) &&
399                      (DRM(devicelist)[i].device == device) ) {
400                         done=1;
401                         if ( DRM(devicelist)[i].supported )
402                                 s = DRM(devicelist)[i].name;
403                         else
404                                 DRM_INFO("%s not supported\n", DRM(devicelist)[i].name);
405                 }
406                 i++;
407         }
408         return s;
409 }
410
411 static int DRM(setup)( drm_device_t *dev )
412 {
413         int i;
414
415         DRIVER_PRESETUP();
416         dev->buf_use = 0;
417         dev->buf_alloc = 0;
418
419 #if __HAVE_DMA
420         i = DRM(dma_setup)( dev );
421         if ( i < 0 )
422                 return i;
423 #endif
424
425         dev->counters  = 6 + __HAVE_COUNTERS;
426         dev->types[0]  = _DRM_STAT_LOCK;
427         dev->types[1]  = _DRM_STAT_OPENS;
428         dev->types[2]  = _DRM_STAT_CLOSES;
429         dev->types[3]  = _DRM_STAT_IOCTLS;
430         dev->types[4]  = _DRM_STAT_LOCKS;
431         dev->types[5]  = _DRM_STAT_UNLOCKS;
432 #ifdef __HAVE_COUNTER6
433         dev->types[6]  = __HAVE_COUNTER6;
434 #endif
435 #ifdef __HAVE_COUNTER7
436         dev->types[7]  = __HAVE_COUNTER7;
437 #endif
438 #ifdef __HAVE_COUNTER8
439         dev->types[8]  = __HAVE_COUNTER8;
440 #endif
441 #ifdef __HAVE_COUNTER9
442         dev->types[9]  = __HAVE_COUNTER9;
443 #endif
444 #ifdef __HAVE_COUNTER10
445         dev->types[10] = __HAVE_COUNTER10;
446 #endif
447 #ifdef __HAVE_COUNTER11
448         dev->types[11] = __HAVE_COUNTER11;
449 #endif
450 #ifdef __HAVE_COUNTER12
451         dev->types[12] = __HAVE_COUNTER12;
452 #endif
453 #ifdef __HAVE_COUNTER13
454         dev->types[13] = __HAVE_COUNTER13;
455 #endif
456 #ifdef __HAVE_COUNTER14
457         dev->types[14] = __HAVE_COUNTER14;
458 #endif
459 #ifdef __HAVE_COUNTER15
460         dev->types[14] = __HAVE_COUNTER14;
461 #endif
462
463         for ( i = 0 ; i < DRM_ARRAY_SIZE(dev->counts) ; i++ )
464                 atomic_set( &dev->counts[i], 0 );
465
466         for ( i = 0 ; i < DRM_HASH_SIZE ; i++ ) {
467                 dev->magiclist[i].head = NULL;
468                 dev->magiclist[i].tail = NULL;
469         }
470
471         dev->maplist = DRM(alloc)(sizeof(*dev->maplist),
472                                   DRM_MEM_MAPS);
473         if(dev->maplist == NULL) return DRM_ERR(ENOMEM);
474         memset(dev->maplist, 0, sizeof(*dev->maplist));
475         TAILQ_INIT(dev->maplist);
476
477         dev->lock.hw_lock = NULL;
478         dev->lock.lock_queue = 0;
479         dev->irq = 0;
480         dev->context_flag = 0;
481         dev->last_context = 0;
482 #if defined(__FreeBSD__) && __FreeBSD_version >= 500000
483         callout_init( &dev->timer, 1 );
484 #else
485         callout_init( &dev->timer );
486 #endif
487
488 #if defined(__DragonFly__) || defined(__FreeBSD__)
489         dev->buf_sigio = NULL;
490 #elif defined(__NetBSD__)
491         dev->buf_pgid = 0;
492 #endif
493
494         DRM_DEBUG( "\n" );
495
496         DRIVER_POSTSETUP();
497         return 0;
498 }
499
500
501 static int DRM(takedown)( drm_device_t *dev )
502 {
503         drm_magic_entry_t *pt, *next;
504         drm_local_map_t *map;
505         drm_map_list_entry_t *list;
506         int i;
507
508         DRM_DEBUG( "\n" );
509
510         DRIVER_PRETAKEDOWN();
511 #if __HAVE_DMA_IRQ
512         if ( dev->irq ) DRM(irq_uninstall)( dev );
513 #endif
514
515         DRM_LOCK;
516         callout_stop( &dev->timer );
517
518         if ( dev->unique ) {
519                 DRM(free)( dev->unique, strlen( dev->unique ) + 1,
520                            DRM_MEM_DRIVER );
521                 dev->unique = NULL;
522                 dev->unique_len = 0;
523         }
524                                 /* Clear pid list */
525         for ( i = 0 ; i < DRM_HASH_SIZE ; i++ ) {
526                 for ( pt = dev->magiclist[i].head ; pt ; pt = next ) {
527                         next = pt->next;
528                         DRM(free)( pt, sizeof(*pt), DRM_MEM_MAGIC );
529                 }
530                 dev->magiclist[i].head = dev->magiclist[i].tail = NULL;
531         }
532
533 #if __REALLY_HAVE_AGP
534                                 /* Clear AGP information */
535         if ( dev->agp ) {
536                 drm_agp_mem_t *entry;
537                 drm_agp_mem_t *nexte;
538
539                                 /* Remove AGP resources, but leave dev->agp
540                                    intact until drv_cleanup is called. */
541                 for ( entry = dev->agp->memory ; entry ; entry = nexte ) {
542                         nexte = entry->next;
543                         if ( entry->bound ) DRM(unbind_agp)( entry->handle );
544                         DRM(free_agp)( entry->handle, entry->pages );
545                         DRM(free)( entry, sizeof(*entry), DRM_MEM_AGPLISTS );
546                 }
547                 dev->agp->memory = NULL;
548
549                 if ( dev->agp->acquired ) DRM(agp_do_release)();
550
551                 dev->agp->acquired = 0;
552                 dev->agp->enabled  = 0;
553         }
554 #endif
555
556         if( dev->maplist ) {
557                 while ((list=TAILQ_FIRST(dev->maplist))) {
558                         map = list->map;
559                         switch ( map->type ) {
560                         case _DRM_REGISTERS:
561                         case _DRM_FRAME_BUFFER:
562 #if __REALLY_HAVE_MTRR
563                                 if ( map->mtrr >= 0 ) {
564                                         int retcode;
565 #if defined(__DragonFly__) || defined(__FreeBSD__)
566                                         int act;
567                                         struct mem_range_desc mrdesc;
568                                         mrdesc.mr_base = map->offset;
569                                         mrdesc.mr_len = map->size;
570                                         mrdesc.mr_flags = MDF_WRITECOMBINE;
571                                         act = MEMRANGE_SET_UPDATE;
572                                         bcopy(DRIVER_NAME, &mrdesc.mr_owner, strlen(DRIVER_NAME));
573                                         retcode = mem_range_attr_set(&mrdesc, &act);
574                                         map->mtrr=1;
575 #elif defined __NetBSD__
576                                         struct mtrr mtrrmap;
577                                         int one = 1;
578                                         mtrrmap.base = map->offset;
579                                         mtrrmap.len = map->size;
580                                         mtrrmap.type = MTRR_TYPE_WC;
581                                         mtrrmap.flags = 0;
582                                         retcode = mtrr_set( &mtrrmap, &one, 
583                                                 DRM_CURPROC, MTRR_GETSET_KERNEL);
584 #endif
585                                         DRM_DEBUG( "mtrr_del=%d\n", retcode );
586                                 }
587 #endif
588                                 DRM(ioremapfree)( map );
589                                 break;
590                         case _DRM_SHM:
591                                 DRM(free)(map->handle,
592                                                map->size,
593                                                DRM_MEM_SAREA);
594                                 break;
595
596                         case _DRM_AGP:
597                                 /* Do nothing here, because this is all
598                                  * handled in the AGP/GART driver.
599                                  */
600                                 break;
601                        case _DRM_SCATTER_GATHER:
602                                 /* Handle it, but do nothing, if REALLY_HAVE_SG
603                                  * isn't defined.
604                                  */
605 #if __REALLY_HAVE_SG
606                                 if(dev->sg) {
607                                         DRM(sg_cleanup)(dev->sg);
608                                         dev->sg = NULL;
609                                 }
610 #endif
611                                 break;
612                         }
613                         TAILQ_REMOVE(dev->maplist, list, link);
614                         DRM(free)(list, sizeof(*list), DRM_MEM_MAPS);
615                         DRM(free)(map, sizeof(*map), DRM_MEM_MAPS);
616                 }
617                 DRM(free)(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
618                 dev->maplist   = NULL;
619         }
620
621 #if __HAVE_DMA
622         DRM(dma_takedown)( dev );
623 #endif
624         if ( dev->lock.hw_lock ) {
625                 dev->lock.hw_lock = NULL; /* SHM removed */
626                 dev->lock.filp = NULL;
627                 DRM_WAKEUP_INT((void *)&dev->lock.lock_queue);
628         }
629         DRM_UNLOCK;
630
631         return 0;
632 }
633
634 /* linux: drm_init is called via init_module at module load time, or via
635  *        linux/init/main.c (this is not currently supported).
636  * bsd:   drm_init is called via the attach function per device.
637  */
638 static int DRM(init)( device_t nbdev )
639 {
640         int unit;
641 #if defined(__DragonFly__) || defined(__FreeBSD__)
642         drm_device_t *dev;
643 #elif defined(__NetBSD__)
644         drm_device_t *dev = nbdev;
645 #endif
646 #if __HAVE_CTX_BITMAP
647         int retcode;
648 #endif
649         DRM_DEBUG( "\n" );
650         DRIVER_PREINIT();
651
652 #if defined(__DragonFly__) || defined(__FreeBSD__)
653         unit = device_get_unit(nbdev);
654         dev = device_get_softc(nbdev);
655         memset( (void *)dev, 0, sizeof(*dev) );
656         dev->device = nbdev;
657         cdevsw_add(&DRM(cdevsw), -1, unit);
658         dev->devnode = make_dev( &DRM(cdevsw),
659                         unit,
660                         DRM_DEV_UID,
661                         DRM_DEV_GID,
662                         DRM_DEV_MODE,
663                         "dri/card%d", unit );
664         reference_dev(dev->devnode);
665 #elif defined(__NetBSD__)
666         unit = minor(dev->device.dv_unit);
667 #endif
668         DRM_SPININIT(dev->count_lock, "drm device");
669         lockinit(&dev->dev_lock, 0, "drmlk", 0, 0);
670         dev->name = DRIVER_NAME;
671         DRM(mem_init)();
672         DRM(sysctl_init)(dev);
673         TAILQ_INIT(&dev->files);
674
675 #if __REALLY_HAVE_AGP
676         dev->agp = DRM(agp_init)();
677 #if __MUST_HAVE_AGP
678         if ( dev->agp == NULL ) {
679                 DRM_ERROR( "Cannot initialize the agpgart module.\n" );
680                 DRM(sysctl_cleanup)( dev );
681 #if defined(__DragonFly__) || defined(__FreeBSD__)
682                 destroy_dev(dev->devnode);
683 #endif
684                 DRM(takedown)( dev );
685                 return DRM_ERR(ENOMEM);
686         }
687 #endif /* __MUST_HAVE_AGP */
688 #if __REALLY_HAVE_MTRR
689         if (dev->agp) {
690 #if defined(__DragonFly__) || defined(__FreeBSD__)
691                 int retcode = 0, act;
692                 struct mem_range_desc mrdesc;
693                 mrdesc.mr_base = dev->agp->info.ai_aperture_base;
694                 mrdesc.mr_len = dev->agp->info.ai_aperture_size;
695                 mrdesc.mr_flags = MDF_WRITECOMBINE;
696                 act = MEMRANGE_SET_UPDATE;
697                 bcopy(DRIVER_NAME, &mrdesc.mr_owner, strlen(DRIVER_NAME));
698                 retcode = mem_range_attr_set(&mrdesc, &act);
699                 dev->agp->agp_mtrr=1;
700 #elif defined __NetBSD__
701                 struct mtrr mtrrmap;
702                 int one = 1;
703                 mtrrmap.base = dev->agp->info.ai_aperture_base;
704                 mtrrmap.len = dev->agp->info.ai_aperture_size;
705                 mtrrmap.type = MTRR_TYPE_WC;
706                 mtrrmap.flags = MTRR_VALID;
707                 dev->agp->agp_mtrr = mtrr_set( &mtrrmap, &one, NULL, MTRR_GETSET_KERNEL);
708 #endif /* __NetBSD__ */
709         }
710 #endif /* __REALLY_HAVE_MTRR */
711 #endif /* __REALLY_HAVE_AGP */
712
713 #if __HAVE_CTX_BITMAP
714         retcode = DRM(ctxbitmap_init)( dev );
715         if( retcode ) {
716                 DRM_ERROR( "Cannot allocate memory for context bitmap.\n" );
717                 DRM(sysctl_cleanup)( dev );
718 #if defined(__DragonFly__) || defined(__FreeBSD__)
719                 destroy_dev(dev->devnode);
720 #endif
721                 DRM(takedown)( dev );
722                 return retcode;
723         }
724 #endif
725         DRM_INFO( "Initialized %s %d.%d.%d %s on minor %d\n",
726                 DRIVER_NAME,
727                 DRIVER_MAJOR,
728                 DRIVER_MINOR,
729                 DRIVER_PATCHLEVEL,
730                 DRIVER_DATE,
731                 unit );
732
733         DRIVER_POSTINIT();
734
735         return 0;
736 }
737
738 /* linux: drm_cleanup is called via cleanup_module at module unload time.
739  * bsd:   drm_cleanup is called per device at module unload time.
740  * FIXME: NetBSD
741  */
742 static void DRM(cleanup)(device_t nbdev)
743 {
744         drm_device_t *dev;
745 #ifdef __NetBSD__
746 #if __REALLY_HAVE_MTRR
747         struct mtrr mtrrmap;
748         int one = 1;
749 #endif /* __REALLY_HAVE_MTRR */
750         dev = nbdev;
751 #endif /* __NetBSD__ */
752
753         DRM_DEBUG( "\n" );
754
755 #if defined(__DragonFly__) || defined(__FreeBSD__)
756         dev = device_get_softc(nbdev);
757 #endif
758         DRM(sysctl_cleanup)( dev );
759 #if defined(__DragonFly__) || defined(__FreeBSD__)
760         destroy_dev(dev->devnode);
761 #endif
762 #if __HAVE_CTX_BITMAP
763         DRM(ctxbitmap_cleanup)( dev );
764 #endif
765
766 #if __REALLY_HAVE_AGP && __REALLY_HAVE_MTRR
767         if ( dev->agp && dev->agp->agp_mtrr >= 0) {
768 #if defined(__NetBSD__)
769                 mtrrmap.base = dev->agp->info.ai_aperture_base;
770                 mtrrmap.len = dev->agp->info.ai_aperture_size;
771                 mtrrmap.type = 0;
772                 mtrrmap.flags = 0;
773                 mtrr_set( &mtrrmap, &one, NULL, MTRR_GETSET_KERNEL);
774 #endif
775         }
776 #endif
777         cdevsw_remove(&DRM(cdevsw), -1, device_get_unit(nbdev));
778
779         DRM(takedown)( dev );
780
781 #if __REALLY_HAVE_AGP
782         if ( dev->agp ) {
783                 DRM(agp_uninit)();
784                 DRM(free)( dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS );
785                 dev->agp = NULL;
786         }
787 #endif
788         DRIVER_POSTCLEANUP();
789         DRM(mem_uninit)();
790         DRM_SPINUNINIT(dev->count_lock);
791 }
792
793
794 int DRM(version)( DRM_IOCTL_ARGS )
795 {
796         drm_version_t version;
797         int len;
798
799         DRM_COPY_FROM_USER_IOCTL( version, (drm_version_t *)data, sizeof(version) );
800
801 #define DRM_COPY( name, value )                                         \
802         len = strlen( value );                                          \
803         if ( len > name##_len ) len = name##_len;                       \
804         name##_len = strlen( value );                                   \
805         if ( len && name ) {                                            \
806                 if ( DRM_COPY_TO_USER( name, value, len ) )             \
807                         return DRM_ERR(EFAULT);                         \
808         }
809
810         version.version_major = DRIVER_MAJOR;
811         version.version_minor = DRIVER_MINOR;
812         version.version_patchlevel = DRIVER_PATCHLEVEL;
813
814         DRM_COPY( version.name, DRIVER_NAME );
815         DRM_COPY( version.date, DRIVER_DATE );
816         DRM_COPY( version.desc, DRIVER_DESC );
817
818         DRM_COPY_TO_USER_IOCTL( (drm_version_t *)data, version, sizeof(version) );
819
820         return 0;
821 }
822
823 int DRM(open)(dev_t kdev, int flags, int fmt, DRM_STRUCTPROC *p)
824 {
825         drm_device_t *dev = NULL;
826         int retcode = 0;
827
828         dev = DRIVER_SOFTC(minor(kdev));
829
830         DRM_DEBUG( "open_count = %d\n", dev->open_count );
831
832         retcode = DRM(open_helper)(kdev, flags, fmt, p, dev);
833
834         if ( !retcode ) {
835                 atomic_inc( &dev->counts[_DRM_STAT_OPENS] );
836                 DRM_SPINLOCK( &dev->count_lock );
837 #if defined(__DragonFly__) || defined(__FreeBSD__)
838                 device_busy(dev->device);
839 #endif
840                 if ( !dev->open_count++ )
841                         retcode = DRM(setup)( dev );
842                 DRM_SPINUNLOCK( &dev->count_lock );
843         }
844
845         return retcode;
846 }
847
848 int DRM(close)(dev_t kdev, int flags, int fmt, DRM_STRUCTPROC *p)
849 {
850         drm_file_t *priv;
851         DRM_DEVICE;
852         int retcode = 0;
853         DRMFILE __unused filp = (void *)(DRM_CURRENTPID);
854         
855         DRM_DEBUG( "open_count = %d\n", dev->open_count );
856         priv = DRM(find_file_by_proc)(dev, p);
857         if (!priv) {
858                 DRM_DEBUG("can't find authenticator\n");
859                 return EINVAL;
860         }
861
862         DRIVER_PRERELEASE();
863
864         /* ========================================================
865          * Begin inline drm_release
866          */
867
868 #if defined(__DragonFly__) || defined(__FreeBSD__)
869         DRM_DEBUG( "pid = %d, device = 0x%lx, open_count = %d\n",
870                    DRM_CURRENTPID, (long)dev->device, dev->open_count );
871 #elif defined(__NetBSD__)
872         DRM_DEBUG( "pid = %d, device = 0x%lx, open_count = %d\n",
873                    DRM_CURRENTPID, (long)&dev->device, dev->open_count);
874 #endif
875
876         if (dev->lock.hw_lock && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)
877             && dev->lock.filp == (void *)DRM_CURRENTPID) {
878                 DRM_DEBUG("Process %d dead, freeing lock for context %d\n",
879                           DRM_CURRENTPID,
880                           _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
881 #if HAVE_DRIVER_RELEASE
882                 DRIVER_RELEASE();
883 #endif
884                 DRM(lock_free)(dev,
885                               &dev->lock.hw_lock->lock,
886                               _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
887                 
888                                 /* FIXME: may require heavy-handed reset of
889                                    hardware at this point, possibly
890                                    processed via a callback to the X
891                                    server. */
892         }
893 #if __HAVE_RELEASE
894         else if ( dev->lock.hw_lock ) {
895                 /* The lock is required to reclaim buffers */
896                 for (;;) {
897                         if ( !dev->lock.hw_lock ) {
898                                 /* Device has been unregistered */
899                                 retcode = DRM_ERR(EINTR);
900                                 break;
901                         }
902                         if ( DRM(lock_take)( &dev->lock.hw_lock->lock,
903                                              DRM_KERNEL_CONTEXT ) ) {
904                                 dev->lock.pid       = DRM_CURRENTPID;
905                                 dev->lock.lock_time = jiffies;
906                                 atomic_inc( &dev->counts[_DRM_STAT_LOCKS] );
907                                 break;  /* Got lock */
908                         }
909                                 /* Contention */
910 #if 0
911                         atomic_inc( &dev->total_sleeps );
912 #endif
913                         retcode = tsleep((void *)&dev->lock.lock_queue,
914                                         PCATCH, "drmlk2", 0);
915                         if (retcode)
916                                 break;
917                 }
918                 if( !retcode ) {
919                         DRIVER_RELEASE();
920                         DRM(lock_free)( dev, &dev->lock.hw_lock->lock,
921                                         DRM_KERNEL_CONTEXT );
922                 }
923         }
924 #elif __HAVE_DMA
925         DRM(reclaim_buffers)( dev, (void *)priv->pid );
926 #endif
927
928 #if defined (__FreeBSD__) && (__FreeBSD_version >= 500000)
929         funsetown(&dev->buf_sigio);
930 #elif defined(__DragonFly__) || defined(__FreeBSD__)
931         funsetown(dev->buf_sigio);
932 #elif defined(__NetBSD__)
933         dev->buf_pgid = 0;
934 #endif /* __NetBSD__ */
935
936         DRM_LOCK;
937         priv = DRM(find_file_by_proc)(dev, p);
938         if (priv) {
939                 priv->refs--;
940                 if (!priv->refs) {
941                         TAILQ_REMOVE(&dev->files, priv, link);
942                         DRM(free)( priv, sizeof(*priv), DRM_MEM_FILES );
943                 }
944         }
945         DRM_UNLOCK;
946
947
948         /* ========================================================
949          * End inline drm_release
950          */
951
952         atomic_inc( &dev->counts[_DRM_STAT_CLOSES] );
953         DRM_SPINLOCK( &dev->count_lock );
954 #if defined(__DragonFly__) || defined(__FreeBSD__)
955         device_unbusy(dev->device);
956 #endif
957         if ( !--dev->open_count ) {
958                 DRM_SPINUNLOCK( &dev->count_lock );
959                 return DRM(takedown)( dev );
960         }
961         DRM_SPINUNLOCK( &dev->count_lock );
962         
963         return retcode;
964 }
965
966 /* DRM(ioctl) is called whenever a process performs an ioctl on /dev/drm.
967  */
968 int DRM(ioctl)(dev_t kdev, u_long cmd, caddr_t data, int flags, 
969     DRM_STRUCTPROC *p)
970 {
971         DRM_DEVICE;
972         int retcode = 0;
973         drm_ioctl_desc_t *ioctl;
974         int (*func)(DRM_IOCTL_ARGS);
975         int nr = DRM_IOCTL_NR(cmd);
976         DRM_PRIV;
977
978         atomic_inc( &dev->counts[_DRM_STAT_IOCTLS] );
979         ++priv->ioctl_count;
980
981 #if defined(__DragonFly__) || defined(__FreeBSD__)
982         DRM_DEBUG( "pid=%d, cmd=0x%02lx, nr=0x%02x, dev 0x%lx, auth=%d\n",
983                  DRM_CURRENTPID, cmd, nr, (long)dev->device, priv->authenticated );
984 #elif defined(__NetBSD__)
985         DRM_DEBUG( "pid=%d, cmd=0x%02lx, nr=0x%02x, dev 0x%lx, auth=%d\n",
986                  DRM_CURRENTPID, cmd, nr, (long)&dev->device, priv->authenticated );
987 #endif
988
989         switch (cmd) {
990         case FIONBIO:
991                 return 0;
992
993         case FIOASYNC:
994                 dev->flags |= FASYNC;
995                 return 0;
996
997 #if defined(__DragonFly__) || defined(__FreeBSD__)
998         case FIOSETOWN:
999                 return fsetown(*(int *)data, &dev->buf_sigio);
1000
1001         case FIOGETOWN:
1002 #if defined(__FreeBSD__) && (__FreeBSD_version >= 500000)
1003                 *(int *) data = fgetown(&dev->buf_sigio);
1004 #else
1005                 *(int *) data = fgetown(dev->buf_sigio);
1006 #endif
1007                 return 0;
1008 #endif /* __FreeBSD__ */
1009 #ifdef __NetBSD__
1010         case TIOCSPGRP:
1011                 dev->buf_pgid = *(int *)data;
1012                 return 0;
1013
1014         case TIOCGPGRP:
1015                 *(int *)data = dev->buf_pgid;
1016                 return 0;
1017 #endif /* __NetBSD__ */
1018         }
1019
1020         if ( nr >= DRIVER_IOCTL_COUNT ) {
1021                 retcode = EINVAL;
1022         } else {
1023                 ioctl = &DRM(ioctls)[nr];
1024                 func = ioctl->func;
1025
1026                 if ( !func ) {
1027                         DRM_DEBUG( "no function\n" );
1028                         retcode = EINVAL;
1029                 } else if ( ( ioctl->root_only && DRM_SUSER(p) ) 
1030                          || ( ioctl->auth_needed && !priv->authenticated ) ) {
1031                         retcode = EACCES;
1032                 } else {
1033                         retcode = func(kdev, cmd, data, flags, p, (void *)DRM_CURRENTPID);
1034                 }
1035         }
1036
1037         return DRM_ERR(retcode);
1038 }
1039
1040 int DRM(lock)( DRM_IOCTL_ARGS )
1041 {
1042         DRM_DEVICE;
1043         drm_lock_t lock;
1044         int ret = 0;
1045
1046         DRM_COPY_FROM_USER_IOCTL( lock, (drm_lock_t *)data, sizeof(lock) );
1047
1048         if ( lock.context == DRM_KERNEL_CONTEXT ) {
1049                 DRM_ERROR( "Process %d using kernel context %d\n",
1050                            DRM_CURRENTPID, lock.context );
1051                 return DRM_ERR(EINVAL);
1052         }
1053
1054         DRM_DEBUG( "%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
1055                    lock.context, DRM_CURRENTPID,
1056                    dev->lock.hw_lock->lock, lock.flags );
1057
1058 #if __HAVE_DMA_QUEUE
1059         if ( lock.context < 0 )
1060                 return DRM_ERR(EINVAL);
1061 #endif
1062
1063         if ( !ret ) {
1064                 for (;;) {
1065                         if ( !dev->lock.hw_lock ) {
1066                                 /* Device has been unregistered */
1067                                 ret = EINTR;
1068                                 break;
1069                         }
1070                         if ( DRM(lock_take)( &dev->lock.hw_lock->lock,
1071                                              lock.context ) ) {
1072                                 dev->lock.filp = (void *)DRM_CURRENTPID;
1073                                 dev->lock.lock_time = jiffies;
1074                                 atomic_inc( &dev->counts[_DRM_STAT_LOCKS] );
1075                                 break;  /* Got lock */
1076                         }
1077
1078                                 /* Contention */
1079                         ret = tsleep((void *)&dev->lock.lock_queue,
1080                                         PCATCH, "drmlk2", 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/file2.h>
1138 #include <sys/mapped_ioctl.h>
1139 #include <sys/sysproto.h>
1140 #include <emulation/linux/linux_ioctl.h>
1141
1142 MODULE_DEPEND(DRIVER_NAME, linux, 1, 1, 1);
1143
1144 #define LINUX_IOCTL_DRM_MIN             0x6400
1145 #define LINUX_IOCTL_DRM_MAX             0x64ff
1146
1147 static ioctl_map_func DRM(ioctl_dirmap);
1148 static struct ioctl_map_range DRM(ioctl_cmds)[] = {
1149         /* XXX: we should have a BSD #define for the range */
1150         MAPPED_IOCTL_MAPRANGE(LINUX_IOCTL_DRM_MIN, LINUX_IOCTL_DRM_MAX, LINUX_IOCTL_DRM_MIN, DRM(ioctl_dirmap)),
1151         MAPPED_IOCTL_MAPF(0, 0, NULL)
1152 };
1153
1154 static struct ioctl_map_handler DRM(ioctl_handler) = {
1155         &linux_ioctl_map,
1156         __XSTRING(DRM(linux)),
1157         DRM(ioctl_cmds)
1158 };
1159
1160 SYSINIT(DRM(register), SI_SUB_KLD, SI_ORDER_MIDDLE, 
1161     mapped_ioctl_register_handler, &DRM(ioctl_handler));
1162 SYSUNINIT(DRM(unregister), SI_SUB_KLD, SI_ORDER_MIDDLE, 
1163     mapped_ioctl_unregister_handler, &DRM(ioctl_handler));
1164
1165 static int
1166 DRM(ioctl_dirmap)(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct thread *td)
1167 {
1168         return(linux_ioctl_dirmap(fp, cmd + (ocmd - LINUX_IOCTL_DRM_MIN),
1169                                   ocmd, data, td));
1170 }
1171
1172 #endif /* DRM_LINUX */