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