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