FreeBSD/Linux Kernel Cross Reference
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: releng/5.0/sys/dev/drm/drm_drv.h 104393 2002-10-03 02:13:00Z truckman $
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_MULTIPLE_DMA_QUEUES
66 #define __HAVE_MULTIPLE_DMA_QUEUES 0
67 #endif
68 #ifndef __HAVE_DMA_SCHEDULE
69 #define __HAVE_DMA_SCHEDULE 0
70 #endif
71 #ifndef __HAVE_DMA_FLUSH
72 #define __HAVE_DMA_FLUSH 0
73 #endif
74 #ifndef __HAVE_DMA_READY
75 #define __HAVE_DMA_READY 0
76 #endif
77 #ifndef __HAVE_DMA_QUIESCENT
78 #define __HAVE_DMA_QUIESCENT 0
79 #endif
80 #ifndef __HAVE_RELEASE
81 #define __HAVE_RELEASE 0
82 #endif
83 #ifndef __HAVE_COUNTERS
84 #define __HAVE_COUNTERS 0
85 #endif
86 #ifndef __HAVE_SG
87 #define __HAVE_SG 0
88 #endif
89 #ifndef __HAVE_KERNEL_CTX_SWITCH
90 #define __HAVE_KERNEL_CTX_SWITCH 0
91 #endif
92 #ifndef PCI_ANY_ID
93 #define PCI_ANY_ID ~0
94 #endif
95
96 #ifndef DRIVER_PREINIT
97 #define DRIVER_PREINIT()
98 #endif
99 #ifndef DRIVER_POSTINIT
100 #define DRIVER_POSTINIT()
101 #endif
102 #ifndef DRIVER_PRERELEASE
103 #define DRIVER_PRERELEASE()
104 #endif
105 #ifndef DRIVER_PRETAKEDOWN
106 #define DRIVER_PRETAKEDOWN()
107 #endif
108 #ifndef DRIVER_POSTCLEANUP
109 #define DRIVER_POSTCLEANUP()
110 #endif
111 #ifndef DRIVER_PRESETUP
112 #define DRIVER_PRESETUP()
113 #endif
114 #ifndef DRIVER_POSTSETUP
115 #define DRIVER_POSTSETUP()
116 #endif
117 #ifndef DRIVER_IOCTLS
118 #define DRIVER_IOCTLS
119 #endif
120 #ifndef DRIVER_FOPS
121 #ifdef __linux__
122 #define DRIVER_FOPS \
123 static struct file_operations DRM(fops) = { \
124 owner: THIS_MODULE, \
125 open: DRM(open), \
126 flush: DRM(flush), \
127 release: DRM(release), \
128 ioctl: DRM(ioctl), \
129 mmap: DRM(mmap), \
130 read: DRM(read), \
131 fasync: DRM(fasync), \
132 poll: DRM(poll), \
133 }
134 #endif /* __linux__ */
135 #ifdef __FreeBSD__
136 #if DRM_LINUX
137 #include <sys/file.h>
138 #include <sys/proc.h>
139 #include <machine/../linux/linux.h>
140 #include <machine/../linux/linux_proto.h>
141 #endif
142 #endif /* __FreeBSD__ */
143 #endif
144
145
146 /*
147 * The default number of instances (minor numbers) to initialize.
148 */
149 #ifndef DRIVER_NUM_CARDS
150 #define DRIVER_NUM_CARDS 1
151 #endif
152
153 #ifdef __FreeBSD__
154 static int DRM(init)(device_t nbdev);
155 static void DRM(cleanup)(device_t nbdev);
156
157 #define CDEV_MAJOR 145
158 #define DRIVER_SOFTC(unit) \
159 ((drm_device_t *) devclass_get_softc(DRM(devclass), unit))
160
161 #if __REALLY_HAVE_AGP
162 MODULE_DEPEND(DRIVER_NAME, agp, 1, 1, 1);
163 #endif
164 #if DRM_LINUX
165 MODULE_DEPEND(DRIVER_NAME, linux, 1, 1, 1);
166 #endif
167 #endif /* __FreeBSD__ */
168
169 static drm_device_t *DRM(device);
170 static int *DRM(minor);
171 static int DRM(numdevs) = 0;
172
173 #ifdef __linux__
174 DRIVER_FOPS;
175 #endif /* __linux__ */
176
177 static drm_ioctl_desc_t DRM(ioctls)[] = {
178 [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { DRM(version), 0, 0 },
179 [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = { DRM(getunique), 0, 0 },
180 [DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = { DRM(getmagic), 0, 0 },
181 [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = { DRM(irq_busid), 0, 1 },
182 [DRM_IOCTL_NR(DRM_IOCTL_GET_MAP)] = { DRM(getmap), 0, 0 },
183 [DRM_IOCTL_NR(DRM_IOCTL_GET_CLIENT)] = { DRM(getclient), 0, 0 },
184 [DRM_IOCTL_NR(DRM_IOCTL_GET_STATS)] = { DRM(getstats), 0, 0 },
185
186 [DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = { DRM(setunique), 1, 1 },
187 [DRM_IOCTL_NR(DRM_IOCTL_BLOCK)] = { DRM(block), 1, 1 },
188 [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)] = { DRM(unblock), 1, 1 },
189 [DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = { DRM(authmagic), 1, 1 },
190
191 [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = { DRM(addmap), 1, 1 },
192 [DRM_IOCTL_NR(DRM_IOCTL_RM_MAP)] = { DRM(rmmap), 1, 0 },
193
194 #if __HAVE_CTX_BITMAP
195 [DRM_IOCTL_NR(DRM_IOCTL_SET_SAREA_CTX)] = { DRM(setsareactx), 1, 1 },
196 [DRM_IOCTL_NR(DRM_IOCTL_GET_SAREA_CTX)] = { DRM(getsareactx), 1, 0 },
197 #endif
198
199 [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { DRM(addctx), 1, 1 },
200 [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { DRM(rmctx), 1, 1 },
201 [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { DRM(modctx), 1, 1 },
202 [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { DRM(getctx), 1, 0 },
203 [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { DRM(switchctx), 1, 1 },
204 [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { DRM(newctx), 1, 1 },
205 [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { DRM(resctx), 1, 0 },
206
207 [DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)] = { DRM(adddraw), 1, 1 },
208 [DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)] = { DRM(rmdraw), 1, 1 },
209
210 [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = { DRM(lock), 1, 0 },
211 [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { DRM(unlock), 1, 0 },
212 [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { DRM(finish), 1, 0 },
213
214 #if __HAVE_DMA
215 [DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)] = { DRM(addbufs), 1, 1 },
216 [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)] = { DRM(markbufs), 1, 1 },
217 [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = { DRM(infobufs), 1, 0 },
218 [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = { DRM(mapbufs), 1, 0 },
219 [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = { DRM(freebufs), 1, 0 },
220
221 /* The DRM_IOCTL_DMA ioctl should be defined by the driver.
222 */
223 #if __HAVE_DMA_IRQ
224 [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = { DRM(control), 1, 1 },
225 #endif
226 #endif
227
228 #if __REALLY_HAVE_AGP
229 [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = { DRM(agp_acquire), 1, 1 },
230 [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = { DRM(agp_release), 1, 1 },
231 [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)] = { DRM(agp_enable), 1, 1 },
232 [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)] = { DRM(agp_info), 1, 0 },
233 [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)] = { DRM(agp_alloc), 1, 1 },
234 [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = { DRM(agp_free), 1, 1 },
235 [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = { DRM(agp_bind), 1, 1 },
236 [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = { DRM(agp_unbind), 1, 1 },
237 #endif
238
239 #if __REALLY_HAVE_SG
240 [DRM_IOCTL_NR(DRM_IOCTL_SG_ALLOC)] = { DRM(sg_alloc), 1, 1 },
241 [DRM_IOCTL_NR(DRM_IOCTL_SG_FREE)] = { DRM(sg_free), 1, 1 },
242 #endif
243
244 DRIVER_IOCTLS
245 };
246
247 #define DRIVER_IOCTL_COUNT DRM_ARRAY_SIZE( DRM(ioctls) )
248
249 #ifdef __linux__
250 #ifdef MODULE
251 static char *drm_opts = NULL;
252 #endif
253
254 MODULE_AUTHOR( DRIVER_AUTHOR );
255 MODULE_DESCRIPTION( DRIVER_DESC );
256 MODULE_PARM( drm_opts, "s" );
257 MODULE_LICENSE("GPL and additional rights");
258 #endif /* __linux__ */
259
260 #ifdef __FreeBSD__
261 static int DRM(probe)(device_t dev)
262 {
263 const char *s = 0;
264
265 int pciid=pci_get_devid(dev);
266 int vendor = (pciid & 0x0000ffff);
267 int device = (pciid & 0xffff0000) >> 16;
268 int i=0, done=0;
269 /*DRM_INFO("Checking PCI vendor=%d, device=%d\n", vendor, device);*/
270 while ( !done && (DRM(devicelist)[i].vendor != 0 ) ) {
271 if ( (DRM(devicelist)[i].vendor == vendor) &&
272 (DRM(devicelist)[i].device == device) ) {
273 done=1;
274 if ( DRM(devicelist)[i].supported )
275 s = DRM(devicelist)[i].name;
276 else
277 DRM_INFO("%s not supported\n", DRM(devicelist)[i].name);
278 }
279 i++;
280 }
281
282 if (s) {
283 device_set_desc(dev, s);
284 return 0;
285 }
286
287 return ENXIO;
288 }
289
290 static int DRM(attach)(device_t dev)
291 {
292 return DRM(init)(dev);
293 }
294
295 static int DRM(detach)(device_t dev)
296 {
297 DRM(cleanup)(dev);
298 return 0;
299 }
300
301 static device_method_t DRM(methods)[] = {
302 /* Device interface */
303 DEVMETHOD(device_probe, DRM( probe)),
304 DEVMETHOD(device_attach, DRM( attach)),
305 DEVMETHOD(device_detach, DRM( detach)),
306
307 { 0, 0 }
308 };
309
310 static driver_t DRM(driver) = {
311 "drm",
312 DRM(methods),
313 sizeof(drm_device_t),
314 };
315
316 static devclass_t DRM( devclass);
317
318 static struct cdevsw DRM( cdevsw) = {
319 /* open */ DRM( open ),
320 /* close */ DRM( close ),
321 /* read */ DRM( read ),
322 /* write */ DRM( write ),
323 /* ioctl */ DRM( ioctl ),
324 /* poll */ DRM( poll ),
325 /* mmap */ DRM( mmap ),
326 /* strategy */ nostrategy,
327 /* name */ DRIVER_NAME,
328 /* maj */ CDEV_MAJOR,
329 /* dump */ nodump,
330 /* psize */ nopsize,
331 /* flags */ D_TTY | D_TRACKCLOSE,
332 #if __FreeBSD_version >= 500000
333 /* kqfilter */ 0
334 #else
335 /* bmaj */ -1
336 #endif
337 };
338 #endif /* __FreeBSD__ */
339
340 static int DRM(setup)( drm_device_t *dev )
341 {
342 int i;
343
344 DRIVER_PRESETUP();
345 atomic_set( &dev->ioctl_count, 0 );
346 atomic_set( &dev->vma_count, 0 );
347 dev->buf_use = 0;
348 atomic_set( &dev->buf_alloc, 0 );
349
350 #if __HAVE_DMA
351 i = DRM(dma_setup)( dev );
352 if ( i < 0 )
353 return i;
354 #endif
355
356 dev->counters = 6 + __HAVE_COUNTERS;
357 dev->types[0] = _DRM_STAT_LOCK;
358 dev->types[1] = _DRM_STAT_OPENS;
359 dev->types[2] = _DRM_STAT_CLOSES;
360 dev->types[3] = _DRM_STAT_IOCTLS;
361 dev->types[4] = _DRM_STAT_LOCKS;
362 dev->types[5] = _DRM_STAT_UNLOCKS;
363 #ifdef __HAVE_COUNTER6
364 dev->types[6] = __HAVE_COUNTER6;
365 #endif
366 #ifdef __HAVE_COUNTER7
367 dev->types[7] = __HAVE_COUNTER7;
368 #endif
369 #ifdef __HAVE_COUNTER8
370 dev->types[8] = __HAVE_COUNTER8;
371 #endif
372 #ifdef __HAVE_COUNTER9
373 dev->types[9] = __HAVE_COUNTER9;
374 #endif
375 #ifdef __HAVE_COUNTER10
376 dev->types[10] = __HAVE_COUNTER10;
377 #endif
378 #ifdef __HAVE_COUNTER11
379 dev->types[11] = __HAVE_COUNTER11;
380 #endif
381 #ifdef __HAVE_COUNTER12
382 dev->types[12] = __HAVE_COUNTER12;
383 #endif
384 #ifdef __HAVE_COUNTER13
385 dev->types[13] = __HAVE_COUNTER13;
386 #endif
387 #ifdef __HAVE_COUNTER14
388 dev->types[14] = __HAVE_COUNTER14;
389 #endif
390 #ifdef __HAVE_COUNTER15
391 dev->types[14] = __HAVE_COUNTER14;
392 #endif
393
394 for ( i = 0 ; i < DRM_ARRAY_SIZE(dev->counts) ; i++ )
395 atomic_set( &dev->counts[i], 0 );
396
397 for ( i = 0 ; i < DRM_HASH_SIZE ; i++ ) {
398 dev->magiclist[i].head = NULL;
399 dev->magiclist[i].tail = NULL;
400 }
401
402 dev->maplist = DRM(alloc)(sizeof(*dev->maplist),
403 DRM_MEM_MAPS);
404 if(dev->maplist == NULL) return DRM_OS_ERR(ENOMEM);
405 memset(dev->maplist, 0, sizeof(*dev->maplist));
406 #ifdef __linux__
407 INIT_LIST_HEAD(&dev->maplist->head);
408 #endif /* __linux__ */
409 #ifdef __FreeBSD__
410 TAILQ_INIT(dev->maplist);
411 #endif /* __FreeBSD__ */
412 dev->map_count = 0;
413
414 dev->vmalist = NULL;
415 dev->lock.hw_lock = NULL;
416 #ifdef __linux__
417 init_waitqueue_head( &dev->lock.lock_queue );
418 #endif /* __linux__ */
419 #ifdef __FreeBSD__
420 dev->lock.lock_queue = 0;
421 #endif /* __FreeBSD__ */
422 dev->queue_count = 0;
423 dev->queue_reserved = 0;
424 dev->queue_slots = 0;
425 dev->queuelist = NULL;
426 dev->irq = 0;
427 dev->context_flag = 0;
428 dev->interrupt_flag = 0;
429 dev->dma_flag = 0;
430 dev->last_context = 0;
431 dev->last_switch = 0;
432 dev->last_checked = 0;
433 #ifdef __linux__
434 init_timer( &dev->timer );
435 init_waitqueue_head( &dev->context_wait );
436 #endif /* __linux__ */
437 #ifdef __FreeBSD__
438 #if __FreeBSD_version >= 500000
439 callout_init( &dev->timer, 1 );
440 #else
441 callout_init( &dev->timer );
442 #endif
443 dev->context_wait = 0;
444 #endif /* __FreeBSD__ */
445
446 dev->ctx_start = 0;
447 dev->lck_start = 0;
448
449 dev->buf_rp = dev->buf;
450 dev->buf_wp = dev->buf;
451 dev->buf_end = dev->buf + DRM_BSZ;
452 #ifdef __linux__
453 dev->buf_async = NULL;
454 init_waitqueue_head( &dev->buf_readers );
455 init_waitqueue_head( &dev->buf_writers );
456 #endif /* __linux__ */
457 #ifdef __FreeBSD__
458 dev->buf_sigio = NULL;
459 dev->buf_readers = 0;
460 dev->buf_writers = 0;
461 dev->buf_selecting = 0;
462 #endif /* __FreeBSD__ */
463
464 DRM_DEBUG( "\n" );
465
466 /* The kernel's context could be created here, but is now created
467 * in drm_dma_enqueue. This is more resource-efficient for
468 * hardware that does not do DMA, but may mean that
469 * drm_select_queue fails between the time the interrupt is
470 * initialized and the time the queues are initialized.
471 */
472 DRIVER_POSTSETUP();
473 return 0;
474 }
475
476
477 static int DRM(takedown)( drm_device_t *dev )
478 {
479 drm_magic_entry_t *pt, *next;
480 drm_map_t *map;
481 #ifdef __linux__
482 drm_map_list_t *r_list;
483 struct list_head *list, *list_next;
484 #endif /* __linux__ */
485 #ifdef __FreeBSD__
486 drm_map_list_entry_t *list;
487 #endif /* __FreeBSD__ */
488 drm_vma_entry_t *vma, *vma_next;
489 int i;
490
491 DRM_DEBUG( "\n" );
492
493 DRIVER_PRETAKEDOWN();
494 #if __HAVE_DMA_IRQ
495 if ( dev->irq ) DRM(irq_uninstall)( dev );
496 #endif
497
498 DRM_OS_LOCK;
499 #ifdef __linux__
500 del_timer( &dev->timer );
501 #endif /* __linux__ */
502 #ifdef __FreeBSD__
503 callout_stop( &dev->timer );
504 #endif /* __FreeBSD__ */
505
506 if ( dev->devname ) {
507 DRM(free)( dev->devname, strlen( dev->devname ) + 1,
508 DRM_MEM_DRIVER );
509 dev->devname = NULL;
510 }
511
512 if ( dev->unique ) {
513 DRM(free)( dev->unique, strlen( dev->unique ) + 1,
514 DRM_MEM_DRIVER );
515 dev->unique = NULL;
516 dev->unique_len = 0;
517 }
518 /* Clear pid list */
519 for ( i = 0 ; i < DRM_HASH_SIZE ; i++ ) {
520 for ( pt = dev->magiclist[i].head ; pt ; pt = next ) {
521 next = pt->next;
522 DRM(free)( pt, sizeof(*pt), DRM_MEM_MAGIC );
523 }
524 dev->magiclist[i].head = dev->magiclist[i].tail = NULL;
525 }
526
527 #if __REALLY_HAVE_AGP
528 /* Clear AGP information */
529 if ( dev->agp ) {
530 drm_agp_mem_t *entry;
531 drm_agp_mem_t *nexte;
532
533 /* Remove AGP resources, but leave dev->agp
534 intact until drv_cleanup is called. */
535 for ( entry = dev->agp->memory ; entry ; entry = nexte ) {
536 nexte = entry->next;
537 #ifdef __linux__
538 if ( entry->bound ) DRM(unbind_agp)( entry->memory );
539 DRM(free_agp)( entry->memory, entry->pages );
540 #endif /* __linux__ */
541 #ifdef __FreeBSD__
542 if ( entry->bound ) DRM(unbind_agp)( entry->handle );
543 DRM(free_agp)( entry->handle, entry->pages );
544 #endif /* __FreeBSD__ */
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 /* Clear vma list (only built for debugging) */
557 if ( dev->vmalist ) {
558 for ( vma = dev->vmalist ; vma ; vma = vma_next ) {
559 vma_next = vma->next;
560 DRM(free)( vma, sizeof(*vma), DRM_MEM_VMAS );
561 }
562 dev->vmalist = NULL;
563 }
564
565 if( dev->maplist ) {
566 #ifdef __linux__
567 for(list = dev->maplist->head.next;
568 list != &dev->maplist->head;
569 list = list_next) {
570 list_next = list->next;
571 r_list = (drm_map_list_t *)list;
572 map = r_list->map;
573 DRM(free)(r_list, sizeof(*r_list), DRM_MEM_MAPS);
574 if(!map) continue;
575 #endif /* __linux__ */
576 #ifdef __FreeBSD__
577 while ((list=TAILQ_FIRST(dev->maplist))) {
578 map = list->map;
579 #endif /* __FreeBSD__ */
580 switch ( map->type ) {
581 case _DRM_REGISTERS:
582 case _DRM_FRAME_BUFFER:
583 #if __REALLY_HAVE_MTRR
584 if ( map->mtrr >= 0 ) {
585 int retcode;
586 retcode = mtrr_del( map->mtrr,
587 map->offset,
588 map->size );
589 DRM_DEBUG( "mtrr_del=%d\n", retcode );
590 }
591 #endif
592 DRM(ioremapfree)( map->handle, map->size );
593 break;
594 case _DRM_SHM:
595 #ifdef __linux__
596 vfree(map->handle);
597 #endif /* __linux__ */
598 #ifdef __FreeBSD__
599 DRM(free_pages)((unsigned long)map->handle,
600 DRM(order)(map->size)
601 - PAGE_SHIFT,
602 DRM_MEM_SAREA);
603 #endif /* __FreeBSD__ */
604 break;
605
606 case _DRM_AGP:
607 /* Do nothing here, because this is all
608 * handled in the AGP/GART driver.
609 */
610 break;
611 case _DRM_SCATTER_GATHER:
612 /* Handle it, but do nothing, if REALLY_HAVE_SG
613 * isn't defined.
614 */
615 #if __REALLY_HAVE_SG
616 if(dev->sg) {
617 DRM(sg_cleanup)(dev->sg);
618 dev->sg = NULL;
619 }
620 #endif
621 break;
622 }
623 #ifdef __FreeBSD__
624 TAILQ_REMOVE(dev->maplist, list, link);
625 DRM(free)(list, sizeof(*list), DRM_MEM_MAPS);
626 #endif /* __FreeBSD__ */
627 DRM(free)(map, sizeof(*map), DRM_MEM_MAPS);
628 }
629 DRM(free)(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
630 dev->maplist = NULL;
631 }
632
633 #if __HAVE_DMA_QUEUE || __HAVE_MULTIPLE_DMA_QUEUES
634 if ( dev->queuelist ) {
635 for ( i = 0 ; i < dev->queue_count ; i++ ) {
636 DRM(waitlist_destroy)( &dev->queuelist[i]->waitlist );
637 if ( dev->queuelist[i] ) {
638 DRM(free)( dev->queuelist[i],
639 sizeof(*dev->queuelist[0]),
640 DRM_MEM_QUEUES );
641 dev->queuelist[i] = NULL;
642 }
643 }
644 DRM(free)( dev->queuelist,
645 dev->queue_slots * sizeof(*dev->queuelist),
646 DRM_MEM_QUEUES );
647 dev->queuelist = NULL;
648 }
649 dev->queue_count = 0;
650 #endif
651
652 #if __HAVE_DMA
653 DRM(dma_takedown)( dev );
654 #endif
655 if ( dev->lock.hw_lock ) {
656 dev->lock.hw_lock = NULL; /* SHM removed */
657 dev->lock.pid = 0;
658 DRM_OS_WAKEUP_INT(&dev->lock.lock_queue);
659 }
660 DRM_OS_UNLOCK;
661
662 return 0;
663 }
664
665 /*
666 * Figure out how many instances to initialize.
667 */
668 static int drm_count_cards(void)
669 {
670 int num = 0;
671 #if defined(DRIVER_CARD_LIST)
672 int i;
673 drm_pci_list_t *l;
674 u16 device, vendor;
675 struct pci_dev *pdev = NULL;
676 #endif
677
678 DRM_DEBUG( "\n" );
679
680 #if defined(DRIVER_COUNT_CARDS)
681 num = DRIVER_COUNT_CARDS();
682 #elif defined(DRIVER_CARD_LIST)
683 for (i = 0, l = DRIVER_CARD_LIST; l[i].vendor != 0; i++) {
684 pdev = NULL;
685 vendor = l[i].vendor;
686 device = l[i].device;
687 if(device == 0xffff) device = PCI_ANY_ID;
688 if(vendor == 0xffff) vendor = PCI_ANY_ID;
689 while ((pdev = pci_find_device(vendor, device, pdev))) {
690 num++; /* FIXME: What about two cards of the same device id? */
691 }
692 }
693 #else
694 num = DRIVER_NUM_CARDS;
695 #endif
696 DRM_DEBUG("numdevs = %d\n", num);
697 return num;
698 }
699
700 /* drm_init is called via init_module at module load time, or via
701 * linux/init/main.c (this is not currently supported).
702 */
703 #ifdef __linux__
704 static int __init drm_init( void )
705 #endif /* __linux__ */
706 #ifdef __FreeBSD__
707 static int DRM(init)( device_t nbdev )
708 #endif /* __FreeBSD__ */
709 {
710
711 drm_device_t *dev;
712 int i;
713 #if __HAVE_CTX_BITMAP
714 int retcode;
715 #endif
716 DRM_DEBUG( "\n" );
717
718 #ifdef MODULE
719 DRM(parse_options)( drm_opts );
720 #endif
721
722 DRM(numdevs) = drm_count_cards();
723 /* Force at least one instance. */
724 if (DRM(numdevs) <= 0)
725 DRM(numdevs) = 1;
726
727 DRM(device) = DRM_OS_MALLOC(sizeof(*DRM(device)) * DRM(numdevs));
728 if (!DRM(device)) {
729 return DRM_OS_ERR(ENOMEM);
730 }
731 DRM(minor) = DRM_OS_MALLOC(sizeof(*(DRM(minor))) * DRM(numdevs));
732 if (!DRM(minor)) {
733 DRM_OS_FREE(DRM(device));
734 return DRM_OS_ERR(ENOMEM);
735 }
736
737 DRIVER_PREINIT();
738
739 #ifdef __linux__
740 DRM(mem_init)();
741 #endif /* __linux__ */
742
743 for (i = 0; i < DRM(numdevs); i++) {
744 #ifdef __linux__
745 dev = &(DRM(device)[i]);
746 #endif /* __linux__ */
747 #ifdef __FreeBSD__
748 int unit = device_get_unit(nbdev);
749 /* FIXME??? - multihead !!! */
750 dev = device_get_softc(nbdev);
751 #endif /* __FreeBSD__ */
752 memset( (void *)dev, 0, sizeof(*dev) );
753 #ifdef __linux__
754 dev->count_lock = SPIN_LOCK_UNLOCKED;
755 sema_init( &dev->struct_sem, 1 );
756 if ((DRM(minor)[i] = DRM(stub_register)(DRIVER_NAME, &DRM(fops),dev)) < 0)
757 return -EPERM;
758 dev->device = MKDEV(DRM_MAJOR, DRM(minor)[i] );
759 dev->name = DRIVER_NAME;
760 #endif /* __linux__ */
761 #ifdef __FreeBSD__
762 DRM(minor)[i]=unit;
763 DRM_OS_SPININIT(dev->count_lock, "drm device");
764 lockinit(&dev->dev_lock, PZERO, "drmlk", 0, 0);
765 dev->device = nbdev;
766 dev->devnode = make_dev( &DRM(cdevsw),
767 unit,
768 DRM_DEV_UID,
769 DRM_DEV_GID,
770 DRM_DEV_MODE,
771 "dri/card%d", unit );
772 dev->name = DRIVER_NAME;
773 DRM(mem_init)();
774 DRM(sysctl_init)(dev);
775 TAILQ_INIT(&dev->files);
776 #endif /* __FreeBSD__ */
777
778 #if __REALLY_HAVE_AGP
779 dev->agp = DRM(agp_init)();
780 #if __MUST_HAVE_AGP
781 if ( dev->agp == NULL ) {
782 DRM_ERROR( "Cannot initialize the agpgart module.\n" );
783 #ifdef __linux__
784 DRM(stub_unregister)(DRM(minor)[i]);
785 #endif /* __linux__ */
786 #ifdef __FreeBSD__
787 DRM(sysctl_cleanup)( dev );
788 destroy_dev(dev->devnode);
789 #endif /* __FreeBSD__ */
790 DRM(takedown)( dev );
791 return DRM_OS_ERR(ENOMEM);
792 }
793 #endif
794 #if __REALLY_HAVE_MTRR
795 if (dev->agp)
796 dev->agp->agp_mtrr = mtrr_add( dev->agp->agp_info.aper_base,
797 dev->agp->agp_info.aper_size*1024*1024,
798 MTRR_TYPE_WRCOMB,
799 1 );
800 #endif
801 #endif
802
803 #if __HAVE_CTX_BITMAP
804 retcode = DRM(ctxbitmap_init)( dev );
805 if( retcode ) {
806 DRM_ERROR( "Cannot allocate memory for context bitmap.\n" );
807 #ifdef __linux__
808 DRM(stub_unregister)(DRM(minor)[i]);
809 #endif /* __linux__ */
810 #ifdef __FreeBSD__
811 DRM(sysctl_cleanup)( dev );
812 destroy_dev(dev->devnode);
813 #endif /* __FreeBSD__ */
814 DRM(takedown)( dev );
815 return retcode;
816 }
817 #endif
818 DRM_INFO( "Initialized %s %d.%d.%d %s on minor %d\n",
819 DRIVER_NAME,
820 DRIVER_MAJOR,
821 DRIVER_MINOR,
822 DRIVER_PATCHLEVEL,
823 DRIVER_DATE,
824 DRM(minor)[i] );
825 }
826
827 DRIVER_POSTINIT();
828
829 return 0;
830 }
831
832 /* drm_cleanup is called via cleanup_module at module unload time.
833 */
834 #ifdef __linux__
835 static void __exit drm_cleanup( void )
836 #endif /* __linux__ */
837 #ifdef __FreeBSD__
838 static void DRM(cleanup)(device_t nbdev)
839 #endif /* __FreeBSD__ */
840 {
841 drm_device_t *dev;
842 int i;
843
844 DRM_DEBUG( "\n" );
845
846 for (i = DRM(numdevs) - 1; i >= 0; i--) {
847 #ifdef __linux__
848 dev = &(DRM(device)[i]);
849 if ( DRM(stub_unregister)(DRM(minor)[i]) ) {
850 DRM_ERROR( "Cannot unload module\n" );
851 } else {
852 DRM_DEBUG("minor %d unregistered\n", DRM(minor)[i]);
853 if (i == 0) {
854 DRM_INFO( "Module unloaded\n" );
855 }
856 }
857 #endif /* __linux__ */
858 #ifdef __FreeBSD__
859 /* FIXME??? - multihead */
860 dev = device_get_softc(nbdev);
861 DRM(sysctl_cleanup)( dev );
862 destroy_dev(dev->devnode);
863 #endif /* __FreeBSD__ */
864 #if __HAVE_CTX_BITMAP
865 DRM(ctxbitmap_cleanup)( dev );
866 #endif
867
868 #if __REALLY_HAVE_AGP && __REALLY_HAVE_MTRR
869 if ( dev->agp && dev->agp->agp_mtrr >= 0) {
870 int retval;
871 retval = mtrr_del( dev->agp->agp_mtrr,
872 dev->agp->agp_info.aper_base,
873 dev->agp->agp_info.aper_size*1024*1024 );
874 DRM_DEBUG( "mtrr_del=%d\n", retval );
875 }
876 #endif
877
878 DRM(takedown)( dev );
879
880 #if __REALLY_HAVE_AGP
881 if ( dev->agp ) {
882 DRM(agp_uninit)();
883 DRM(free)( dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS );
884 dev->agp = NULL;
885 }
886 #endif
887 }
888 DRIVER_POSTCLEANUP();
889 DRM_OS_FREE(DRM(minor));
890 DRM_OS_FREE(DRM(device));
891 DRM(numdevs) = 0;
892 }
893
894 #ifdef __linux__
895 module_init( drm_init );
896 module_exit( drm_cleanup );
897 #endif /* __linux__ */
898
899 int DRM(version)( DRM_OS_IOCTL )
900 {
901 drm_version_t version;
902 int len;
903
904 DRM_OS_KRNFROMUSR( version, (drm_version_t *)data, sizeof(version) );
905
906 #define DRM_COPY( name, value ) \
907 len = strlen( value ); \
908 if ( len > name##_len ) len = name##_len; \
909 name##_len = strlen( value ); \
910 if ( len && name ) { \
911 if ( DRM_OS_COPYTOUSR( name, value, len ) ) \
912 return DRM_OS_ERR(EFAULT); \
913 }
914
915 version.version_major = DRIVER_MAJOR;
916 version.version_minor = DRIVER_MINOR;
917 version.version_patchlevel = DRIVER_PATCHLEVEL;
918
919 DRM_COPY( version.name, DRIVER_NAME );
920 DRM_COPY( version.date, DRIVER_DATE );
921 DRM_COPY( version.desc, DRIVER_DESC );
922
923 DRM_OS_KRNTOUSR( (drm_version_t *)data, version, sizeof(version) );
924
925 return 0;
926 }
927
928 #ifdef __linux__
929 int DRM(open)( struct inode *inode, struct file *filp )
930 #endif /* __linux__ */
931 #ifdef __FreeBSD__
932 int DRM( open)(dev_t kdev, int flags, int fmt, DRM_OS_STRUCTPROC *p)
933 #endif /* __FreeBSD__ */
934 {
935 drm_device_t *dev = NULL;
936 int retcode = 0;
937 int i;
938
939 for (i = 0; i < DRM(numdevs); i++) {
940 #ifdef __linux__
941 if (MINOR(inode->i_rdev) == DRM(minor)[i]) {
942 dev = &(DRM(device)[i]);
943 break;
944 }
945 #endif /* __linux__ */
946 #ifdef __FreeBSD__
947 /* FIXME ??? - multihead */
948 dev = DRIVER_SOFTC(minor(kdev));
949 #endif /* __FreeBSD__ */
950 }
951 if (!dev) {
952 return DRM_OS_ERR(ENODEV);
953 }
954
955 DRM_DEBUG( "open_count = %d\n", dev->open_count );
956
957 #ifdef __linux__
958 retcode = DRM(open_helper)( inode, filp, dev );
959 #endif /* __linux__ */
960 #ifdef __FreeBSD__
961 device_busy(dev->device);
962 retcode = DRM(open_helper)(kdev, flags, fmt, p, dev);
963 #endif /* __FreeBSD__ */
964
965 if ( !retcode ) {
966 atomic_inc( &dev->counts[_DRM_STAT_OPENS] );
967 DRM_OS_SPINLOCK( &dev->count_lock );
968 if ( !dev->open_count++ ) {
969 DRM_OS_SPINUNLOCK( &dev->count_lock );
970 return DRM(setup)( dev );
971 }
972 DRM_OS_SPINUNLOCK( &dev->count_lock );
973 }
974 #ifdef __FreeBSD__
975 device_unbusy(dev->device);
976 #endif /* __FreeBSD__ */
977
978 return retcode;
979 }
980
981 #ifdef __linux__
982 int DRM(release)( struct inode *inode, struct file *filp )
983 {
984 drm_file_t *priv = filp->private_data;
985 drm_device_t *dev;
986 #endif /* __linux__ */
987 #ifdef __FreeBSD__
988 int DRM( close)(dev_t kdev, int flags, int fmt, DRM_OS_STRUCTPROC *p)
989 {
990 drm_file_t *priv;
991 drm_device_t *dev = kdev->si_drv1;
992 #endif /* __FreeBSD__ */
993 int retcode = 0;
994
995 #ifdef __linux__
996 lock_kernel();
997 dev = priv->dev;
998 #endif /* __linux__ */
999 DRM_DEBUG( "open_count = %d\n", dev->open_count );
1000 #ifdef __FreeBSD__
1001 priv = DRM(find_file_by_proc)(dev, p);
1002 if (!priv) {
1003 DRM_DEBUG("can't find authenticator\n");
1004 return EINVAL;
1005 }
1006 #endif /* __FreeBSD__ */
1007
1008 DRIVER_PRERELEASE();
1009
1010 /* ========================================================
1011 * Begin inline drm_release
1012 */
1013
1014 DRM_DEBUG( "pid = %d, device = 0x%lx, open_count = %d\n",
1015 DRM_OS_CURRENTPID, (long)dev->device, dev->open_count );
1016
1017 if (dev->lock.hw_lock && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)
1018 && dev->lock.pid == DRM_OS_CURRENTPID) {
1019 DRM_DEBUG("Process %d dead, freeing lock for context %d\n",
1020 DRM_OS_CURRENTPID,
1021 _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
1022 #if HAVE_DRIVER_RELEASE
1023 DRIVER_RELEASE();
1024 #endif
1025 DRM(lock_free)(dev,
1026 &dev->lock.hw_lock->lock,
1027 _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
1028
1029 /* FIXME: may require heavy-handed reset of
1030 hardware at this point, possibly
1031 processed via a callback to the X
1032 server. */
1033 }
1034 #if __HAVE_RELEASE
1035 else if ( dev->lock.hw_lock ) {
1036 /* The lock is required to reclaim buffers */
1037 #ifdef __linux__
1038 DECLARE_WAITQUEUE( entry, current );
1039 add_wait_queue( &dev->lock.lock_queue, &entry );
1040 #endif /* __linux__ */
1041 for (;;) {
1042 #ifdef __linux__
1043 current->state = TASK_INTERRUPTIBLE;
1044 #endif /* __linux__ */
1045 if ( !dev->lock.hw_lock ) {
1046 /* Device has been unregistered */
1047 retcode = DRM_OS_ERR(EINTR);
1048 break;
1049 }
1050 if ( DRM(lock_take)( &dev->lock.hw_lock->lock,
1051 DRM_KERNEL_CONTEXT ) ) {
1052 #ifdef __linux__
1053 dev->lock.pid = priv->pid;
1054 #endif /* __linux__ */
1055 #ifdef __FreeBSD__
1056 dev->lock.pid = p->p_pid;
1057 #endif /* __FreeBSD__ */
1058 dev->lock.lock_time = jiffies;
1059 atomic_inc( &dev->counts[_DRM_STAT_LOCKS] );
1060 break; /* Got lock */
1061 }
1062 /* Contention */
1063 #if 0
1064 atomic_inc( &dev->total_sleeps );
1065 #endif
1066 #ifdef __linux__
1067 schedule();
1068 if ( signal_pending( current ) ) {
1069 retcode = DRM_OS_ERR(ERESTARTSYS);
1070 break;
1071 }
1072 #endif /* __linux__ */
1073 #ifdef __FreeBSD__
1074 retcode = tsleep(&dev->lock.lock_queue,
1075 PZERO|PCATCH,
1076 "drmlk2",
1077 0);
1078 if (retcode)
1079 break;
1080 #endif /* __FreeBSD__ */
1081 }
1082 #ifdef __linux__
1083 current->state = TASK_RUNNING;
1084 remove_wait_queue( &dev->lock.lock_queue, &entry );
1085 #endif /* __linux__ */
1086 if( !retcode ) {
1087 DRIVER_RELEASE();
1088 DRM(lock_free)( dev, &dev->lock.hw_lock->lock,
1089 DRM_KERNEL_CONTEXT );
1090 }
1091 }
1092 #elif __HAVE_DMA
1093 DRM(reclaim_buffers)( dev, priv->pid );
1094 #endif
1095
1096 #ifdef __linux__
1097 DRM(fasync)( -1, filp, 0 );
1098 #endif /* __linux__ */
1099 #ifdef __FreeBSD__
1100 funsetown(&dev->buf_sigio);
1101 #endif /* __FreeBSD__ */
1102
1103 DRM_OS_LOCK;
1104 #ifdef __linux__
1105 if ( priv->remove_auth_on_close == 1 ) {
1106 drm_file_t *temp = dev->file_first;
1107 while ( temp ) {
1108 temp->authenticated = 0;
1109 temp = temp->next;
1110 }
1111 }
1112 if ( priv->prev ) {
1113 priv->prev->next = priv->next;
1114 } else {
1115 dev->file_first = priv->next;
1116 }
1117 if ( priv->next ) {
1118 priv->next->prev = priv->prev;
1119 } else {
1120 dev->file_last = priv->prev;
1121 }
1122 #endif /* __linux__ */
1123 #ifdef __FreeBSD__
1124 priv = DRM(find_file_by_proc)(dev, p);
1125 if (priv) {
1126 priv->refs--;
1127 if (!priv->refs) {
1128 TAILQ_REMOVE(&dev->files, priv, link);
1129 }
1130 }
1131 #endif /* __FreeBSD__ */
1132 DRM_OS_UNLOCK;
1133
1134 DRM(free)( priv, sizeof(*priv), DRM_MEM_FILES );
1135
1136 /* ========================================================
1137 * End inline drm_release
1138 */
1139
1140 atomic_inc( &dev->counts[_DRM_STAT_CLOSES] );
1141 DRM_OS_SPINLOCK( &dev->count_lock );
1142 if ( !--dev->open_count ) {
1143 if ( atomic_read( &dev->ioctl_count ) || dev->blocked ) {
1144 DRM_ERROR( "Device busy: %ld %d\n",
1145 (unsigned long)atomic_read( &dev->ioctl_count ),
1146 dev->blocked );
1147 DRM_OS_SPINUNLOCK( &dev->count_lock );
1148 #ifdef __linux__
1149 unlock_kernel();
1150 #endif /* __linux__ */
1151 return DRM_OS_ERR(EBUSY);
1152 }
1153 DRM_OS_SPINUNLOCK( &dev->count_lock );
1154 #ifdef __linux__
1155 unlock_kernel();
1156 #endif /* __linux__ */
1157 #ifdef __FreeBSD__
1158 device_unbusy(dev->device);
1159 #endif /* __FreeBSD__ */
1160 return DRM(takedown)( dev );
1161 }
1162 DRM_OS_SPINUNLOCK( &dev->count_lock );
1163
1164 #ifdef __linux__
1165 unlock_kernel();
1166 #endif /* __linux__ */
1167
1168 return retcode;
1169 }
1170
1171 /* DRM(ioctl) is called whenever a process performs an ioctl on /dev/drm.
1172 */
1173 int DRM(ioctl)( DRM_OS_IOCTL )
1174 {
1175 DRM_OS_DEVICE;
1176 int retcode = 0;
1177 drm_ioctl_desc_t *ioctl;
1178 drm_ioctl_t *func;
1179 int nr = DRM_IOCTL_NR(cmd);
1180 DRM_OS_PRIV;
1181
1182 atomic_inc( &dev->ioctl_count );
1183 atomic_inc( &dev->counts[_DRM_STAT_IOCTLS] );
1184 ++priv->ioctl_count;
1185
1186 DRM_DEBUG( "pid=%d, cmd=0x%02lx, nr=0x%02x, dev 0x%lx, auth=%d\n",
1187 DRM_OS_CURRENTPID, cmd, nr, (long)dev->device, priv->authenticated );
1188
1189 #ifdef __FreeBSD__
1190 switch (cmd) {
1191 case FIONBIO:
1192 atomic_dec(&dev->ioctl_count);
1193 return 0;
1194
1195 case FIOASYNC:
1196 atomic_dec(&dev->ioctl_count);
1197 dev->flags |= FASYNC;
1198 return 0;
1199
1200 case FIOSETOWN:
1201 atomic_dec(&dev->ioctl_count);
1202 return fsetown(*(int *)data, &dev->buf_sigio);
1203
1204 case FIOGETOWN:
1205 atomic_dec(&dev->ioctl_count);
1206 *(int *) data = fgetown(&dev->buf_sigio);
1207 return 0;
1208 }
1209 #endif /* __FreeBSD__ */
1210
1211 if ( nr >= DRIVER_IOCTL_COUNT ) {
1212 retcode = DRM_OS_ERR(EINVAL);
1213 } else {
1214 ioctl = &DRM(ioctls)[nr];
1215 func = ioctl->func;
1216
1217 if ( !func ) {
1218 DRM_DEBUG( "no function\n" );
1219 retcode = DRM_OS_ERR(EINVAL);
1220 } else if ( ( ioctl->root_only && DRM_OS_CHECKSUSER )
1221 || ( ioctl->auth_needed && !priv->authenticated ) ) {
1222 retcode = DRM_OS_ERR(EACCES);
1223 } else {
1224 retcode = func( IOCTL_ARGS_PASS );
1225 }
1226 }
1227
1228 atomic_dec( &dev->ioctl_count );
1229 return retcode;
1230 }
1231
1232 int DRM(lock)( DRM_OS_IOCTL )
1233 {
1234 DRM_OS_DEVICE;
1235 #ifdef __linux__
1236 DECLARE_WAITQUEUE( entry, current );
1237 #endif /* __linux__ */
1238 drm_lock_t lock;
1239 int ret = 0;
1240 #if __HAVE_MULTIPLE_DMA_QUEUES
1241 drm_queue_t *q;
1242 #endif
1243 #if __HAVE_DMA_HISTOGRAM
1244 cycles_t start;
1245
1246 dev->lck_start = start = get_cycles();
1247 #endif
1248
1249 DRM_OS_KRNFROMUSR( lock, (drm_lock_t *)data, sizeof(lock) );
1250
1251 if ( lock.context == DRM_KERNEL_CONTEXT ) {
1252 DRM_ERROR( "Process %d using kernel context %d\n",
1253 DRM_OS_CURRENTPID, lock.context );
1254 return DRM_OS_ERR(EINVAL);
1255 }
1256
1257 DRM_DEBUG( "%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
1258 lock.context, DRM_OS_CURRENTPID,
1259 dev->lock.hw_lock->lock, lock.flags );
1260
1261 #if __HAVE_DMA_QUEUE
1262 if ( lock.context < 0 )
1263 return DRM_OS_ERR(EINVAL);
1264 #elif __HAVE_MULTIPLE_DMA_QUEUES
1265 if ( lock.context < 0 || lock.context >= dev->queue_count )
1266 return DRM_OS_ERR(EINVAL);
1267 q = dev->queuelist[lock.context];
1268 #endif
1269
1270 #if __HAVE_DMA_FLUSH
1271 ret = DRM(flush_block_and_flush)( dev, lock.context, lock.flags );
1272 #endif
1273 if ( !ret ) {
1274 #ifdef __linux__
1275 add_wait_queue( &dev->lock.lock_queue, &entry );
1276 #endif /* __linux__ */
1277 for (;;) {
1278 #ifdef __linux__
1279 current->state = TASK_INTERRUPTIBLE;
1280 #endif /* __linux__ */
1281 if ( !dev->lock.hw_lock ) {
1282 /* Device has been unregistered */
1283 ret = DRM_OS_ERR(EINTR);
1284 break;
1285 }
1286 if ( DRM(lock_take)( &dev->lock.hw_lock->lock,
1287 lock.context ) ) {
1288 dev->lock.pid = DRM_OS_CURRENTPID;
1289 dev->lock.lock_time = jiffies;
1290 atomic_inc( &dev->counts[_DRM_STAT_LOCKS] );
1291 break; /* Got lock */
1292 }
1293
1294 /* Contention */
1295 #ifdef __linux__
1296 schedule();
1297 if ( signal_pending( current ) ) {
1298 ret = DRM_OS_ERR(ERESTARTSYS);
1299 break;
1300 }
1301 #endif /* __linux__ */
1302 #ifdef __FreeBSD__
1303 ret = tsleep(&dev->lock.lock_queue,
1304 PZERO|PCATCH,
1305 "drmlk2",
1306 0);
1307 if (ret)
1308 break;
1309 #endif /* __FreeBSD__ */
1310 }
1311 #ifdef __linux__
1312 current->state = TASK_RUNNING;
1313 remove_wait_queue( &dev->lock.lock_queue, &entry );
1314 #endif /* __linux__ */
1315 }
1316
1317 #if __HAVE_DMA_FLUSH
1318 DRM(flush_unblock)( dev, lock.context, lock.flags ); /* cleanup phase */
1319 #endif
1320
1321 if ( !ret ) {
1322 #ifdef __linux__
1323 sigemptyset( &dev->sigmask );
1324 sigaddset( &dev->sigmask, SIGSTOP );
1325 sigaddset( &dev->sigmask, SIGTSTP );
1326 sigaddset( &dev->sigmask, SIGTTIN );
1327 sigaddset( &dev->sigmask, SIGTTOU );
1328 dev->sigdata.context = lock.context;
1329 dev->sigdata.lock = dev->lock.hw_lock;
1330 block_all_signals( DRM(notifier),
1331 &dev->sigdata, &dev->sigmask );
1332 #endif /* __linux__ */
1333
1334 #if __HAVE_DMA_READY
1335 if ( lock.flags & _DRM_LOCK_READY ) {
1336 DRIVER_DMA_READY();
1337 }
1338 #endif
1339 #if __HAVE_DMA_QUIESCENT
1340 if ( lock.flags & _DRM_LOCK_QUIESCENT ) {
1341 DRIVER_DMA_QUIESCENT();
1342 }
1343 #endif
1344 #if __HAVE_KERNEL_CTX_SWITCH
1345 if ( dev->last_context != lock.context ) {
1346 DRM(context_switch)(dev, dev->last_context,
1347 lock.context);
1348 }
1349 #endif
1350 }
1351
1352 DRM_DEBUG( "%d %s\n", lock.context, ret ? "interrupted" : "has lock" );
1353
1354 #if __HAVE_DMA_HISTOGRAM
1355 atomic_inc(&dev->histo.lacq[DRM(histogram_slot)(get_cycles()-start)]);
1356 #endif
1357
1358 return ret;
1359 }
1360
1361
1362 int DRM(unlock)( DRM_OS_IOCTL )
1363 {
1364 DRM_OS_DEVICE;
1365 drm_lock_t lock;
1366
1367 DRM_OS_KRNFROMUSR( lock, (drm_lock_t *)data, sizeof(lock) ) ;
1368
1369 if ( lock.context == DRM_KERNEL_CONTEXT ) {
1370 DRM_ERROR( "Process %d using kernel context %d\n",
1371 DRM_OS_CURRENTPID, lock.context );
1372 return DRM_OS_ERR(EINVAL);
1373 }
1374
1375 atomic_inc( &dev->counts[_DRM_STAT_UNLOCKS] );
1376
1377 #if __HAVE_KERNEL_CTX_SWITCH
1378 /* We no longer really hold it, but if we are the next
1379 * agent to request it then we should just be able to
1380 * take it immediately and not eat the ioctl.
1381 */
1382 dev->lock.pid = 0;
1383 {
1384 __volatile__ unsigned int *plock = &dev->lock.hw_lock->lock;
1385 unsigned int old, new, prev, ctx;
1386
1387 ctx = lock.context;
1388 do {
1389 old = *plock;
1390 new = ctx;
1391 prev = cmpxchg(plock, old, new);
1392 } while (prev != old);
1393 }
1394 wake_up_interruptible(&dev->lock.lock_queue);
1395 #else
1396 DRM(lock_transfer)( dev, &dev->lock.hw_lock->lock,
1397 DRM_KERNEL_CONTEXT );
1398 #if __HAVE_DMA_SCHEDULE
1399 DRM(dma_schedule)( dev, 1 );
1400 #endif
1401
1402 /* FIXME: Do we ever really need to check this???
1403 */
1404 if ( 1 /* !dev->context_flag */ ) {
1405 if ( DRM(lock_free)( dev, &dev->lock.hw_lock->lock,
1406 DRM_KERNEL_CONTEXT ) ) {
1407 DRM_ERROR( "\n" );
1408 }
1409 }
1410 #endif /* !__HAVE_KERNEL_CTX_SWITCH */
1411
1412 #ifdef __linux__
1413 unblock_all_signals();
1414 #endif /* __linux__ */
1415 return 0;
1416 }
1417
1418 #if DRM_LINUX
1419 #define LINUX_IOCTL_DRM_MIN 0x6400
1420 #define LINUX_IOCTL_DRM_MAX 0x64ff
1421
1422 static linux_ioctl_function_t DRM( linux_ioctl);
1423 static struct linux_ioctl_handler DRM( handler) = {DRM( linux_ioctl), LINUX_IOCTL_DRM_MIN, LINUX_IOCTL_DRM_MAX};
1424 SYSINIT (DRM( register), SI_SUB_KLD, SI_ORDER_MIDDLE, linux_ioctl_register_handler, &DRM( handler));
1425 SYSUNINIT(DRM( unregister), SI_SUB_KLD, SI_ORDER_MIDDLE, linux_ioctl_unregister_handler, &DRM( handler));
1426
1427 #define LINUX_IOC_VOID IOC_VOID
1428 #define LINUX_IOC_IN IOC_OUT /* Linux has the values the other way around */
1429 #define LINUX_IOC_OUT IOC_IN
1430
1431 /*
1432 * Linux emulation IOCTL
1433 */
1434 static int
1435 DRM(linux_ioctl)(DRM_OS_STRUCTPROC *p, struct linux_ioctl_args* args)
1436 {
1437 u_long cmd = args->cmd;
1438 #define STK_PARAMS 128
1439 union {
1440 char stkbuf[STK_PARAMS];
1441 long align;
1442 } ubuf;
1443 caddr_t data=NULL, memp=NULL;
1444 u_int size = IOCPARM_LEN(cmd);
1445 int error;
1446 #if (__FreeBSD_version >= 500000)
1447 struct file *fp;
1448 #else
1449 struct file *fp = p->p_fd->fd_ofiles[args->fd];
1450 #endif
1451 if ( size > STK_PARAMS ) {
1452 if ( size > IOCPARM_MAX )
1453 return EINVAL;
1454 memp = malloc( (u_long)size, DRM(M_DRM), M_WAITOK );
1455 data = memp;
1456 } else {
1457 data = ubuf.stkbuf;
1458 }
1459
1460 if ( cmd & LINUX_IOC_IN ) {
1461 if ( size ) {
1462 error = copyin( (caddr_t)args->arg, data, (u_int)size );
1463 if (error) {
1464 if ( memp )
1465 free( data, DRM(M_DRM) );
1466 return error;
1467 }
1468 } else {
1469 data = (caddr_t)args->arg;
1470 }
1471 } else if ( (cmd & LINUX_IOC_OUT) && size ) {
1472 /*
1473 * Zero the buffer so the user always
1474 * gets back something deterministic.
1475 */
1476 bzero( data, size );
1477 } else if ( cmd & LINUX_IOC_VOID ) {
1478 *(caddr_t *)data = (caddr_t)args->arg;
1479 }
1480
1481 #if (__FreeBSD_version >= 500000)
1482 if ( (error = fget( p, args->fd, &fp )) != 0 ) {
1483 if ( memp )
1484 free( memp, DRM(M_DRM) );
1485 return (error);
1486 }
1487 error = fo_ioctl( fp, cmd, data, p->td_ucred, p );
1488 fdrop( fp, p );
1489 #else
1490 error = fo_ioctl( fp, cmd, data, p );
1491 #endif
1492 if ( error == 0 && (cmd & LINUX_IOC_OUT) && size )
1493 error = copyout( data, (caddr_t)args->arg, (u_int)size );
1494 if ( memp )
1495 free( memp, DRM(M_DRM) );
1496 return error;
1497 }
1498 #endif /* DRM_LINUX */
Cache object: 8b6d1040fb4a1c9bb25c1cb7e3924150
|