xref: /dragonfly/sys/dev/video/bktr/bktr_os.c (revision 0bb9290e)
1 /*
2  * 1. Redistributions of source code must retain the
3  * Copyright (c) 1997 Amancio Hasty, 1999 Roger Hardiman
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *	This product includes software developed by Amancio Hasty and
17  *      Roger Hardiman
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24  * DISCLAIMED.	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  * $FreeBSD: src/sys/dev/bktr/bktr_os.c,v 1.45 2004/03/17 17:50:28 njl Exp $
34  * $DragonFly: src/sys/dev/video/bktr/bktr_os.c,v 1.14 2006/07/28 02:17:39 dillon Exp $
35  */
36 
37 /*
38  * This is part of the Driver for Video Capture Cards (Frame grabbers)
39  * and TV Tuner cards using the Brooktree Bt848, Bt848A, Bt849A, Bt878, Bt879
40  * chipset.
41  * Copyright Roger Hardiman and Amancio Hasty.
42  *
43  * bktr_os : This has all the Operating System dependant code,
44  *             probe/attach and open/close/ioctl/read/mmap
45  *             memory allocation
46  *             PCI bus interfacing
47  */
48 
49 #include "opt_bktr.h"		/* include any kernel config options */
50 
51 #define FIFO_RISC_DISABLED      0
52 #define ALL_INTS_DISABLED       0
53 
54 #include <sys/param.h>
55 #include <sys/systm.h>
56 #include <sys/conf.h>
57 #include <sys/device.h>
58 #include <sys/uio.h>
59 #include <sys/kernel.h>
60 #include <sys/signalvar.h>
61 #include <sys/malloc.h>
62 #include <sys/mman.h>
63 #include <sys/poll.h>
64 #include <sys/select.h>
65 #include <sys/vnode.h>
66 #include <sys/thread2.h>
67 
68 #include <vm/vm.h>
69 #include <vm/vm_kern.h>
70 #include <vm/pmap.h>
71 #include <vm/vm_extern.h>
72 
73 #include <sys/bus.h>		/* used by smbus and newbus */
74 
75 #include <machine/bus_memio.h>	/* used by bus space */
76 #include <machine/bus.h>	/* used by bus space and newbus */
77 #include <sys/bus.h>
78 
79 #include <sys/rman.h>		/* used by newbus */
80 #include <machine/resource.h>	/* used by newbus */
81 #include <bus/pci/pcivar.h>
82 #include <bus/pci/pcireg.h>
83 #include <bus/pci/pcidevs.h>
84 
85 #include <sys/sysctl.h>
86 int bt848_card = -1;
87 int bt848_tuner = -1;
88 int bt848_reverse_mute = -1;
89 int bt848_format = -1;
90 int bt848_slow_msp_audio = -1;
91 #ifdef BKTR_NEW_MSP34XX_DRIVER
92 int bt848_stereo_once = 0;	/* no continuous stereo monitoring */
93 int bt848_amsound = 0;		/* hard-wire AM sound at 6.5 Hz (france),
94 				   the autoscan seems work well only with FM... */
95 int bt848_dolby = 0;
96 #endif
97 
98 SYSCTL_NODE(_hw, OID_AUTO, bt848, CTLFLAG_RW, 0, "Bt848 Driver mgmt");
99 SYSCTL_INT(_hw_bt848, OID_AUTO, card, CTLFLAG_RW, &bt848_card, -1, "");
100 SYSCTL_INT(_hw_bt848, OID_AUTO, tuner, CTLFLAG_RW, &bt848_tuner, -1, "");
101 SYSCTL_INT(_hw_bt848, OID_AUTO, reverse_mute, CTLFLAG_RW, &bt848_reverse_mute, -1, "");
102 SYSCTL_INT(_hw_bt848, OID_AUTO, format, CTLFLAG_RW, &bt848_format, -1, "");
103 SYSCTL_INT(_hw_bt848, OID_AUTO, slow_msp_audio, CTLFLAG_RW, &bt848_slow_msp_audio, -1, "");
104 #ifdef BKTR_NEW_MSP34XX_DRIVER
105 SYSCTL_INT(_hw_bt848, OID_AUTO, stereo_once, CTLFLAG_RW, &bt848_stereo_once, 0, "");
106 SYSCTL_INT(_hw_bt848, OID_AUTO, amsound, CTLFLAG_RW, &bt848_amsound, 0, "");
107 SYSCTL_INT(_hw_bt848, OID_AUTO, dolby, CTLFLAG_RW, &bt848_dolby, 0, "");
108 #endif
109 
110 #include <dev/video/meteor/ioctl_meteor.h>
111 #include <dev/video/bktr/ioctl_bt848.h>	/* extensions to ioctl_meteor.h */
112 #include <dev/video/bktr/bktr_reg.h>
113 #include <dev/video/bktr/bktr_tuner.h>
114 #include <dev/video/bktr/bktr_card.h>
115 #include <dev/video/bktr/bktr_audio.h>
116 #include <dev/video/bktr/bktr_core.h>
117 #include <dev/video/bktr/bktr_os.h>
118 
119 #if defined(BKTR_USE_FREEBSD_SMBUS)
120 #include <dev/video/bktr/bktr_i2c.h>
121 
122 #include "iicbb_if.h"
123 #include "smbus_if.h"
124 #endif
125 
126 static int	bktr_probe( device_t dev );
127 static int	bktr_attach( device_t dev );
128 static int	bktr_detach( device_t dev );
129 static int	bktr_shutdown( device_t dev );
130 static void	bktr_intr(void *arg) { common_bktr_intr(arg); }
131 
132 static device_method_t bktr_methods[] = {
133 	/* Device interface */
134 	DEVMETHOD(device_probe,         bktr_probe),
135 	DEVMETHOD(device_attach,        bktr_attach),
136 	DEVMETHOD(device_detach,        bktr_detach),
137 	DEVMETHOD(device_shutdown,      bktr_shutdown),
138 
139 #if defined(BKTR_USE_FREEBSD_SMBUS)
140 	/* iicbb interface */
141 	DEVMETHOD(iicbb_callback,	bti2c_iic_callback),
142 	DEVMETHOD(iicbb_setsda,		bti2c_iic_setsda),
143 	DEVMETHOD(iicbb_setscl,		bti2c_iic_setscl),
144 	DEVMETHOD(iicbb_getsda,		bti2c_iic_getsda),
145 	DEVMETHOD(iicbb_getscl,		bti2c_iic_getscl),
146 	DEVMETHOD(iicbb_reset,		bti2c_iic_reset),
147 
148 	/* smbus interface */
149 	DEVMETHOD(smbus_callback,	bti2c_smb_callback),
150 	DEVMETHOD(smbus_writeb,		bti2c_smb_writeb),
151 	DEVMETHOD(smbus_writew,		bti2c_smb_writew),
152 	DEVMETHOD(smbus_readb,		bti2c_smb_readb),
153 #endif
154 
155 	{ 0, 0 }
156 };
157 
158 static driver_t bktr_driver = {
159 	"bktr",
160 	bktr_methods,
161 	sizeof(struct bktr_softc),
162 };
163 
164 static devclass_t bktr_devclass;
165 
166 static	d_open_t	bktr_open;
167 static	d_close_t	bktr_close;
168 static	d_read_t	bktr_read;
169 static	d_write_t	bktr_write;
170 static	d_ioctl_t	bktr_ioctl;
171 static	d_mmap_t	bktr_mmap;
172 static	d_poll_t	bktr_poll;
173 
174 #define CDEV_MAJOR 92
175 static struct dev_ops bktr_ops = {
176 	{ "bktr", CDEV_MAJOR, 0 },
177 	.d_open =	bktr_open,
178 	.d_close =	bktr_close,
179 	.d_read =	bktr_read,
180 	.d_write =	bktr_write,
181 	.d_ioctl =	bktr_ioctl,
182 	.d_poll =	bktr_poll,
183 	.d_mmap =	bktr_mmap,
184 };
185 
186 DRIVER_MODULE(bktr, pci, bktr_driver, bktr_devclass, 0, 0);
187 MODULE_DEPEND(bktr, bktr_mem, 1,1,1);
188 MODULE_VERSION(bktr, 1);
189 
190 /*
191  * the boot time probe routine.
192  */
193 static int
194 bktr_probe( device_t dev )
195 {
196 	unsigned int type = pci_get_devid(dev);
197         unsigned int rev  = pci_get_revid(dev);
198 
199 	if (PCI_VENDOR(type) == PCI_VENDOR_BROOKTREE)
200 	{
201 		switch (PCI_PRODUCT(type)) {
202 		case PCI_PRODUCT_BROOKTREE_BT848:
203 			if (rev == 0x12)
204 				device_set_desc(dev, "BrookTree 848A");
205 			else
206 				device_set_desc(dev, "BrookTree 848");
207 			return 0;
208 		case PCI_PRODUCT_BROOKTREE_BT849:
209 			device_set_desc(dev, "BrookTree 849A");
210 			return 0;
211 		case PCI_PRODUCT_BROOKTREE_BT878:
212 			device_set_desc(dev, "BrookTree 878");
213 			return 0;
214 		case PCI_PRODUCT_BROOKTREE_BT879:
215 			device_set_desc(dev, "BrookTree 879");
216 			return 0;
217 		}
218 	};
219 
220         return ENXIO;
221 }
222 
223 
224 /*
225  * the attach routine.
226  */
227 static int
228 bktr_attach( device_t dev )
229 {
230 	u_long		latency;
231 	u_long		fun;
232 	u_long		val;
233 	unsigned int	rev;
234 	unsigned int	unit;
235 	int		error = 0;
236 #ifdef BROOKTREE_IRQ
237 	u_long		old_irq, new_irq;
238 #endif
239 
240         struct bktr_softc *bktr = device_get_softc(dev);
241 
242 	unit = device_get_unit(dev);
243 
244 	/* build the device name for bktr_name() */
245 	snprintf(bktr->bktr_xname, sizeof(bktr->bktr_xname), "bktr%d",unit);
246 
247 	/*
248 	 * Enable bus mastering and Memory Mapped device
249 	 */
250 	val = pci_read_config(dev, PCIR_COMMAND, 4);
251 	val |= (PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
252 	pci_write_config(dev, PCIR_COMMAND, val, 4);
253 
254 	/*
255 	 * Map control/status registers.
256 	 */
257 	bktr->mem_rid = PCIR_BAR(0);
258 	bktr->res_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
259 					&bktr->mem_rid, RF_ACTIVE);
260 
261 	if (!bktr->res_mem) {
262 		device_printf(dev, "could not map memory\n");
263 		error = ENXIO;
264 		goto fail;
265 	}
266 	bktr->memt = rman_get_bustag(bktr->res_mem);
267 	bktr->memh = rman_get_bushandle(bktr->res_mem);
268 
269 
270 	/*
271 	 * Disable the brooktree device
272 	 */
273 	OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
274 	OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
275 
276 
277 #ifdef BROOKTREE_IRQ		/* from the configuration file */
278 	old_irq = pci_conf_read(tag, PCI_INTERRUPT_REG);
279 	pci_conf_write(tag, PCI_INTERRUPT_REG, BROOKTREE_IRQ);
280 	new_irq = pci_conf_read(tag, PCI_INTERRUPT_REG);
281 	printf("bktr%d: attach: irq changed from %d to %d\n",
282 		unit, (old_irq & 0xff), (new_irq & 0xff));
283 #endif
284 
285 	/*
286 	 * Allocate our interrupt.
287 	 */
288 	bktr->irq_rid = 0;
289 	bktr->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
290 				&bktr->irq_rid, RF_SHAREABLE | RF_ACTIVE);
291 	if (bktr->res_irq == NULL) {
292 		device_printf(dev, "could not map interrupt\n");
293 		error = ENXIO;
294 		goto fail;
295 	}
296 
297 	error = bus_setup_intr(dev, bktr->res_irq, 0,
298                                bktr_intr, bktr, &bktr->res_ih, NULL);
299 	if (error) {
300 		device_printf(dev, "could not setup irq\n");
301 		goto fail;
302 
303 	}
304 
305 
306 	/* Update the Device Control Register */
307 	/* on Bt878 and Bt879 cards           */
308 	fun = pci_read_config( dev, 0x40, 2);
309         fun = fun | 1;	/* Enable writes to the sub-system vendor ID */
310 
311 #if defined( BKTR_430_FX_MODE )
312 	if (bootverbose) printf("Using 430 FX chipset compatibilty mode\n");
313         fun = fun | 2;	/* Enable Intel 430 FX compatibility mode */
314 #endif
315 
316 #if defined( BKTR_SIS_VIA_MODE )
317 	if (bootverbose) printf("Using SiS/VIA chipset compatibilty mode\n");
318         fun = fun | 4;	/* Enable SiS/VIA compatibility mode (usefull for
319                            OPTi chipset motherboards too */
320 #endif
321 	pci_write_config(dev, 0x40, fun, 2);
322 
323 #if defined(BKTR_USE_FREEBSD_SMBUS)
324 	if (bt848_i2c_attach(dev))
325 		printf("bktr%d: i2c_attach: can't attach\n", unit);
326 #endif
327 
328 /*
329  * PCI latency timer.  32 is a good value for 4 bus mastering slots, if
330  * you have more than four, then 16 would probably be a better value.
331  */
332 #ifndef BROOKTREE_DEF_LATENCY_VALUE
333 #define BROOKTREE_DEF_LATENCY_VALUE	10
334 #endif
335 	latency = pci_read_config(dev, PCI_LATENCY_TIMER, 4);
336 	latency = (latency >> 8) & 0xff;
337 	if ( bootverbose ) {
338 		if (latency)
339 			printf("brooktree%d: PCI bus latency is", unit);
340 		else
341 			printf("brooktree%d: PCI bus latency was 0 changing to",
342 				unit);
343 	}
344 	if ( !latency ) {
345 		latency = BROOKTREE_DEF_LATENCY_VALUE;
346 		pci_write_config(dev, PCI_LATENCY_TIMER, latency<<8, 4);
347 	}
348 	if ( bootverbose ) {
349 		printf(" %d.\n", (int) latency);
350 	}
351 
352 	/* read the pci device id and revision id */
353 	fun = pci_get_devid(dev);
354         rev = pci_get_revid(dev);
355 
356 	/* call the common attach code */
357 	common_bktr_attach( bktr, unit, fun, rev );
358 
359 	/* make the device entries */
360 	dev_ops_add(&bktr_ops, 0x0f, unit);
361 	make_dev(&bktr_ops, unit,    0, 0, 0444, "bktr%d",  unit);
362 	make_dev(&bktr_ops, unit+16, 0, 0, 0444, "tuner%d", unit);
363 	make_dev(&bktr_ops, unit+32, 0, 0, 0444, "vbi%d"  , unit);
364 
365 
366 	return 0;
367 
368 fail:
369 	if (bktr->res_irq)
370 		bus_release_resource(dev, SYS_RES_IRQ, bktr->irq_rid, bktr->res_irq);
371 	if (bktr->res_mem)
372 		bus_release_resource(dev, SYS_RES_IRQ, bktr->mem_rid, bktr->res_mem);
373 	return error;
374 
375 }
376 
377 /*
378  * the detach routine.
379  */
380 static int
381 bktr_detach( device_t dev )
382 {
383 	struct bktr_softc *bktr = device_get_softc(dev);
384 
385 #ifdef BKTR_NEW_MSP34XX_DRIVER
386 	/* Disable the soundchip and kernel thread */
387 	if (bktr->msp3400c_info != NULL)
388 		msp_detach(bktr);
389 #endif
390 
391 	/* Disable the brooktree device */
392 	OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
393 	OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
394 
395 #if defined(BKTR_USE_FREEBSD_SMBUS)
396 	if (bt848_i2c_detach(dev))
397 		printf("bktr%d: i2c_attach: can't attach\n",
398 		     device_get_unit(dev));
399 #endif
400 #ifdef USE_VBIMUTEX
401         mtx_destroy(&bktr->vbimutex);
402 #endif
403 
404 	/* Note: We do not free memory for RISC programs, grab buffer, vbi buffers */
405 	/* The memory is retained by the bktr_mem module so we can unload and */
406 	/* then reload the main bktr driver module */
407 
408 	/* removing the ops automatically destroys all related devices */
409 	dev_ops_remove(&bktr_ops, 0x0f, device_get_unit(dev));
410 
411 	/*
412 	 * Deallocate resources.
413 	 */
414 	bus_teardown_intr(dev, bktr->res_irq, bktr->res_ih);
415 	bus_release_resource(dev, SYS_RES_IRQ, bktr->irq_rid, bktr->res_irq);
416 	bus_release_resource(dev, SYS_RES_MEMORY, bktr->mem_rid, bktr->res_mem);
417 
418 	return 0;
419 }
420 
421 /*
422  * the shutdown routine.
423  */
424 static int
425 bktr_shutdown( device_t dev )
426 {
427 	struct bktr_softc *bktr = device_get_softc(dev);
428 
429 	/* Disable the brooktree device */
430 	OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
431 	OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
432 
433 	return 0;
434 }
435 
436 
437 /*
438  * Special Memory Allocation
439  */
440 vm_offset_t
441 get_bktr_mem( int unit, unsigned size )
442 {
443 	vm_offset_t	addr = 0;
444 
445 	addr = (vm_offset_t)contigmalloc(size, M_DEVBUF, M_NOWAIT, 0,
446 	    0xffffffff, 1<<24, 0);
447 	if (addr == 0)
448 		addr = (vm_offset_t)contigmalloc(size, M_DEVBUF, M_NOWAIT, 0,
449 		    0xffffffff, PAGE_SIZE, 0);
450 	if (addr == 0) {
451 		printf("bktr%d: Unable to allocate %d bytes of memory.\n",
452 			unit, size);
453 	}
454 
455 	return( addr );
456 }
457 
458 
459 /*---------------------------------------------------------
460 **
461 **	BrookTree 848 character device driver routines
462 **
463 **---------------------------------------------------------
464 */
465 
466 #define VIDEO_DEV	0x00
467 #define TUNER_DEV	0x01
468 #define VBI_DEV		0x02
469 
470 #define UNIT(x)		((x) & 0x0f)
471 #define FUNCTION(x)	(x >> 4)
472 
473 /*
474  *
475  */
476 static int
477 bktr_open(struct dev_open_args *ap)
478 {
479 	dev_t dev = ap->a_head.a_dev;
480 	bktr_ptr_t	bktr;
481 	int		unit;
482 	int		result;
483 
484 	unit = UNIT( minor(dev) );
485 
486 	/* Get the device data */
487 	bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
488 	if (bktr == NULL) {
489 		/* the device is no longer valid/functioning */
490 		return (ENXIO);
491 	}
492 
493 	if (!(bktr->flags & METEOR_INITALIZED)) /* device not found */
494 		return( ENXIO );
495 
496 	/* Record that the device is now busy */
497 	device_busy(devclass_get_device(bktr_devclass, unit));
498 
499 
500 	if (bt848_card != -1) {
501 	  if ((bt848_card >> 8   == unit ) &&
502 	     ( (bt848_card & 0xff) < Bt848_MAX_CARD )) {
503 	    if ( bktr->bt848_card != (bt848_card & 0xff) ) {
504 	      bktr->bt848_card = (bt848_card & 0xff);
505 	      probeCard(bktr, FALSE, unit);
506 	    }
507 	  }
508 	}
509 
510 	if (bt848_tuner != -1) {
511 	  if ((bt848_tuner >> 8   == unit ) &&
512 	     ( (bt848_tuner & 0xff) < Bt848_MAX_TUNER )) {
513 	    if ( bktr->bt848_tuner != (bt848_tuner & 0xff) ) {
514 	      bktr->bt848_tuner = (bt848_tuner & 0xff);
515 	      probeCard(bktr, FALSE, unit);
516 	    }
517 	  }
518 	}
519 
520 	if (bt848_reverse_mute != -1) {
521 	  if ((bt848_reverse_mute >> 8)   == unit ) {
522 	    bktr->reverse_mute = bt848_reverse_mute & 0xff;
523 	  }
524 	}
525 
526 	if (bt848_slow_msp_audio != -1) {
527 	  if ((bt848_slow_msp_audio >> 8) == unit ) {
528 	      bktr->slow_msp_audio = (bt848_slow_msp_audio & 0xff);
529 	  }
530 	}
531 
532 #ifdef BKTR_NEW_MSP34XX_DRIVER
533 	if (bt848_stereo_once != 0) {
534 	  if ((bt848_stereo_once >> 8) == unit ) {
535 	      bktr->stereo_once = (bt848_stereo_once & 0xff);
536 	  }
537 	}
538 
539 	if (bt848_amsound != -1) {
540 	  if ((bt848_amsound >> 8) == unit ) {
541 	      bktr->amsound = (bt848_amsound & 0xff);
542 	  }
543 	}
544 
545 	if (bt848_dolby != -1) {
546 	  if ((bt848_dolby >> 8) == unit ) {
547 	      bktr->dolby = (bt848_dolby & 0xff);
548 	  }
549 	}
550 #endif
551 
552 	switch ( FUNCTION( minor(dev) ) ) {
553 	case VIDEO_DEV:
554 		result = video_open( bktr );
555 		break;
556 	case TUNER_DEV:
557 		result = tuner_open( bktr );
558 		break;
559 	case VBI_DEV:
560 		result = vbi_open( bktr );
561 		break;
562 	default:
563 		result = ENXIO;
564 		break;
565 	}
566 
567 	/* If there was an error opening the device, undo the busy status */
568 	if (result != 0)
569 		device_unbusy(devclass_get_device(bktr_devclass, unit));
570 	return( result );
571 }
572 
573 
574 /*
575  *
576  */
577 static int
578 bktr_close(struct dev_close_args *ap)
579 {
580 	dev_t dev = ap->a_head.a_dev;
581 	bktr_ptr_t	bktr;
582 	int		unit;
583 	int		result;
584 
585 	unit = UNIT( minor(dev) );
586 
587 	/* Get the device data */
588 	bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
589 	if (bktr == NULL) {
590 		/* the device is no longer valid/functioning */
591 		return (ENXIO);
592 	}
593 
594 	switch ( FUNCTION( minor(dev) ) ) {
595 	case VIDEO_DEV:
596 		result = video_close( bktr );
597 		break;
598 	case TUNER_DEV:
599 		result = tuner_close( bktr );
600 		break;
601 	case VBI_DEV:
602 		result = vbi_close( bktr );
603 		break;
604 	default:
605 		return (ENXIO);
606 		break;
607 	}
608 
609 	device_unbusy(devclass_get_device(bktr_devclass, unit));
610 	return( result );
611 }
612 
613 
614 /*
615  *
616  */
617 static int
618 bktr_read(struct dev_read_args *ap)
619 {
620 	dev_t dev = ap->a_head.a_dev;
621 	bktr_ptr_t	bktr;
622 	int		unit;
623 
624 	unit = UNIT(minor(dev));
625 
626 	/* Get the device data */
627 	bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
628 	if (bktr == NULL) {
629 		/* the device is no longer valid/functioning */
630 		return (ENXIO);
631 	}
632 
633 	switch ( FUNCTION( minor(dev) ) ) {
634 	case VIDEO_DEV:
635 		return( video_read( bktr, unit, dev, ap->a_uio ) );
636 	case VBI_DEV:
637 		return( vbi_read( bktr, ap->a_uio, ap->a_ioflag ) );
638 	}
639         return( ENXIO );
640 }
641 
642 
643 /*
644  *
645  */
646 static int
647 bktr_write(struct dev_write_args *ap)
648 {
649 	return( EINVAL ); /* XXX or ENXIO ? */
650 }
651 
652 
653 /*
654  *
655  */
656 static int
657 bktr_ioctl(struct dev_ioctl_args *ap)
658 {
659 	dev_t dev = ap->a_head.a_dev;
660 	bktr_ptr_t	bktr;
661 	int		unit;
662 
663 	unit = UNIT(minor(dev));
664 
665 	/* Get the device data */
666 	bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
667 	if (bktr == NULL) {
668 		/* the device is no longer valid/functioning */
669 		return (ENXIO);
670 	}
671 
672 	if (bktr->bigbuf == 0)	/* no frame buffer allocated (ioctl failed) */
673 		return( ENOMEM );
674 
675 	switch ( FUNCTION( minor(dev) ) ) {
676 	case VIDEO_DEV:
677 		return( video_ioctl( bktr, unit, ap->a_cmd, ap->a_data, curthread ) );
678 	case TUNER_DEV:
679 		return( tuner_ioctl( bktr, unit, ap->a_cmd, ap->a_data, curthread ) );
680 	}
681 
682 	return( ENXIO );
683 }
684 
685 
686 /*
687  *
688  */
689 static int
690 bktr_mmap(struct dev_mmap_args *ap)
691 {
692 	dev_t dev = ap->a_head.a_dev;
693 	int		unit;
694 	bktr_ptr_t	bktr;
695 
696 	unit = UNIT(minor(dev));
697 
698 	if (FUNCTION(minor(dev)) > 0)	/* only allow mmap on /dev/bktr[n] */
699 		return(EINVAL);
700 
701 	/* Get the device data */
702 	bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
703 	if (bktr == NULL) {
704 		/* the device is no longer valid/functioning */
705 		return (ENXIO);
706 	}
707 
708 	if (ap->a_nprot & PROT_EXEC)
709 		return(EINVAL);
710 
711 	if (ap->a_offset < 0)
712 		return(EINVAL);
713 
714 	if (ap->a_offset >= bktr->alloc_pages * PAGE_SIZE)
715 		return(EINVAL);
716 
717 	ap->a_result = atop(vtophys(bktr->bigbuf) + ap->a_offset);
718 	return(0);
719 }
720 
721 static int
722 bktr_poll(struct dev_poll_args *ap)
723 {
724 	dev_t dev = ap->a_head.a_dev;
725 	int		unit;
726 	bktr_ptr_t	bktr;
727 	int revents = 0;
728 
729 	unit = UNIT(minor(dev));
730 
731 	/* Get the device data */
732 	bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
733 	if (bktr == NULL) {
734 		/* the device is no longer valid/functioning */
735 		return (ENXIO);
736 	}
737 
738 	LOCK_VBI(bktr);
739 	crit_enter();
740 
741 	if (ap->a_events & (POLLIN | POLLRDNORM)) {
742 
743 		switch ( FUNCTION( minor(dev) ) ) {
744 		case VBI_DEV:
745 			if(bktr->vbisize == 0)
746 				selrecord(curthread, &bktr->vbi_select);
747 			else
748 				revents |= ap->a_events & (POLLIN | POLLRDNORM);
749 			break;
750 		}
751 	}
752 
753 	crit_exit();
754 	UNLOCK_VBI(bktr);
755 
756 	ap->a_events = revents;
757 	return (0);
758 }
759