bktr_os.c revision 104094
1/* $FreeBSD: head/sys/dev/bktr/bktr_os.c 104094 2002-09-28 17:15:38Z phk $ */
2
3/*
4 * This is part of the Driver for Video Capture Cards (Frame grabbers)
5 * and TV Tuner cards using the Brooktree Bt848, Bt848A, Bt849A, Bt878, Bt879
6 * chipset.
7 * Copyright Roger Hardiman and Amancio Hasty.
8 *
9 * bktr_os : This has all the Operating System dependant code,
10 *             probe/attach and open/close/ioctl/read/mmap
11 *             memory allocation
12 *             PCI bus interfacing
13 *
14 *
15 */
16
17/*
18 * 1. Redistributions of source code must retain the
19 * Copyright (c) 1997 Amancio Hasty, 1999 Roger Hardiman
20 * All rights reserved.
21 *
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions
24 * are met:
25 * 1. Redistributions of source code must retain the above copyright
26 *    notice, this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright
28 *    notice, this list of conditions and the following disclaimer in the
29 *    documentation and/or other materials provided with the distribution.
30 * 3. All advertising materials mentioning features or use of this software
31 *    must display the following acknowledgement:
32 *	This product includes software developed by Amancio Hasty and
33 *      Roger Hardiman
34 * 4. The name of the author may not be used to endorse or promote products
35 *    derived from this software without specific prior written permission.
36 *
37 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
38 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
39 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40 * DISCLAIMED.	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
41 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
42 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
45 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
46 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
47 * POSSIBILITY OF SUCH DAMAGE.
48 */
49
50
51#include "opt_bktr.h"		/* include any kernel config options */
52
53#define FIFO_RISC_DISABLED      0
54#define ALL_INTS_DISABLED       0
55
56
57/*******************/
58/* *** FreeBSD *** */
59/*******************/
60#ifdef __FreeBSD__
61
62#include <sys/param.h>
63#include <sys/systm.h>
64#include <sys/conf.h>
65#include <sys/uio.h>
66#include <sys/kernel.h>
67#include <sys/signalvar.h>
68#include <sys/mman.h>
69#include <sys/poll.h>
70#if __FreeBSD_version >= 500014
71#include <sys/selinfo.h>
72#else
73#include <sys/select.h>
74#endif
75#include <sys/vnode.h>
76
77#include <vm/vm.h>
78#include <vm/vm_kern.h>
79#include <vm/pmap.h>
80#include <vm/vm_extern.h>
81
82#if (__FreeBSD_version >=400000)
83#include <sys/bus.h>		/* used by smbus and newbus */
84#endif
85
86#if (__FreeBSD_version >=300000)
87#include <machine/bus_memio.h>	/* used by bus space */
88#include <machine/bus.h>	/* used by bus space and newbus */
89#include <sys/bus.h>
90#endif
91
92#if (__FreeBSD_version >=400000)
93#include <sys/rman.h>		/* used by newbus */
94#include <machine/resource.h>	/* used by newbus */
95#endif
96
97#if (__FreeBSD_version < 500000)
98#include <machine/clock.h>              /* for DELAY */
99#endif
100
101#include <pci/pcivar.h>
102#include <pci/pcireg.h>
103
104#include <sys/sysctl.h>
105int bt848_card = -1;
106int bt848_tuner = -1;
107int bt848_reverse_mute = -1;
108int bt848_format = -1;
109int bt848_slow_msp_audio = -1;
110
111SYSCTL_NODE(_hw, OID_AUTO, bt848, CTLFLAG_RW, 0, "Bt848 Driver mgmt");
112SYSCTL_INT(_hw_bt848, OID_AUTO, card, CTLFLAG_RW, &bt848_card, -1, "");
113SYSCTL_INT(_hw_bt848, OID_AUTO, tuner, CTLFLAG_RW, &bt848_tuner, -1, "");
114SYSCTL_INT(_hw_bt848, OID_AUTO, reverse_mute, CTLFLAG_RW, &bt848_reverse_mute, -1, "");
115SYSCTL_INT(_hw_bt848, OID_AUTO, format, CTLFLAG_RW, &bt848_format, -1, "");
116SYSCTL_INT(_hw_bt848, OID_AUTO, slow_msp_audio, CTLFLAG_RW, &bt848_slow_msp_audio, -1, "");
117
118#endif /* end freebsd section */
119
120
121
122/****************/
123/* *** BSDI *** */
124/****************/
125#ifdef __bsdi__
126#endif /* __bsdi__ */
127
128
129/**************************/
130/* *** OpenBSD/NetBSD *** */
131/**************************/
132#if defined(__NetBSD__) || defined(__OpenBSD__)
133
134#include <sys/param.h>
135#include <sys/systm.h>
136#include <sys/conf.h>
137#include <sys/uio.h>
138#include <sys/kernel.h>
139#include <sys/signalvar.h>
140#include <sys/mman.h>
141#include <sys/poll.h>
142#include <sys/select.h>
143#include <sys/vnode.h>
144
145#include <vm/vm.h>
146
147#ifndef __NetBSD__
148#include <vm/vm_kern.h>
149#include <vm/pmap.h>
150#include <vm/vm_extern.h>
151#endif
152
153#include <sys/device.h>
154#include <dev/pci/pcivar.h>
155#include <dev/pci/pcireg.h>
156#include <dev/pci/pcidevs.h>
157
158#define BKTR_DEBUG
159#ifdef BKTR_DEBUG
160int bktr_debug = 0;
161#define DPR(x)	(bktr_debug ? printf x : 0)
162#else
163#define DPR(x)
164#endif
165#endif /* __NetBSD__ || __OpenBSD__ */
166
167
168#ifdef __NetBSD__
169#include <dev/ic/bt8xx.h>	/* NetBSD location for .h files */
170#include <dev/pci/bktr/bktr_reg.h>
171#include <dev/pci/bktr/bktr_tuner.h>
172#include <dev/pci/bktr/bktr_card.h>
173#include <dev/pci/bktr/bktr_audio.h>
174#include <dev/pci/bktr/bktr_core.h>
175#include <dev/pci/bktr/bktr_os.h>
176#else					/* Traditional location for .h files */
177#include <machine/ioctl_meteor.h>
178#include <machine/ioctl_bt848.h>	/* extensions to ioctl_meteor.h */
179#include <dev/bktr/bktr_reg.h>
180#include <dev/bktr/bktr_tuner.h>
181#include <dev/bktr/bktr_card.h>
182#include <dev/bktr/bktr_audio.h>
183#include <dev/bktr/bktr_core.h>
184#include <dev/bktr/bktr_os.h>
185
186#if defined(BKTR_USE_FREEBSD_SMBUS)
187#include <dev/bktr/bktr_i2c.h>
188
189#include "iicbb_if.h"
190#include "smbus_if.h"
191#endif
192#endif
193
194
195/****************************/
196/* *** FreeBSD 4.x code *** */
197/****************************/
198#if (__FreeBSD_version >= 400000)
199
200static int	bktr_probe( device_t dev );
201static int	bktr_attach( device_t dev );
202static int	bktr_detach( device_t dev );
203static int	bktr_shutdown( device_t dev );
204static void	bktr_intr(void *arg) { common_bktr_intr(arg); }
205
206static device_method_t bktr_methods[] = {
207	/* Device interface */
208	DEVMETHOD(device_probe,         bktr_probe),
209	DEVMETHOD(device_attach,        bktr_attach),
210	DEVMETHOD(device_detach,        bktr_detach),
211	DEVMETHOD(device_shutdown,      bktr_shutdown),
212
213#if defined(BKTR_USE_FREEBSD_SMBUS)
214	/* iicbb interface */
215	DEVMETHOD(iicbb_callback,	bti2c_iic_callback),
216	DEVMETHOD(iicbb_setsda,		bti2c_iic_setsda),
217	DEVMETHOD(iicbb_setscl,		bti2c_iic_setscl),
218	DEVMETHOD(iicbb_getsda,		bti2c_iic_getsda),
219	DEVMETHOD(iicbb_getscl,		bti2c_iic_getscl),
220	DEVMETHOD(iicbb_reset,		bti2c_iic_reset),
221
222	/* smbus interface */
223	DEVMETHOD(smbus_callback,	bti2c_smb_callback),
224	DEVMETHOD(smbus_writeb,		bti2c_smb_writeb),
225	DEVMETHOD(smbus_writew,		bti2c_smb_writew),
226	DEVMETHOD(smbus_readb,		bti2c_smb_readb),
227#endif
228
229	{ 0, 0 }
230};
231
232static driver_t bktr_driver = {
233	"bktr",
234	bktr_methods,
235	sizeof(struct bktr_softc),
236};
237
238static devclass_t bktr_devclass;
239
240static	d_open_t	bktr_open;
241static	d_close_t	bktr_close;
242static	d_read_t	bktr_read;
243static	d_write_t	bktr_write;
244static	d_ioctl_t	bktr_ioctl;
245static	d_mmap_t	bktr_mmap;
246static	d_poll_t	bktr_poll;
247
248#define CDEV_MAJOR 92
249static struct cdevsw bktr_cdevsw = {
250	/* open */	bktr_open,
251	/* close */	bktr_close,
252	/* read */	bktr_read,
253	/* write */	bktr_write,
254	/* ioctl */	bktr_ioctl,
255	/* poll */	bktr_poll,
256	/* mmap */	bktr_mmap,
257	/* strategy */	nostrategy,
258	/* name */	"bktr",
259	/* maj */	CDEV_MAJOR,
260	/* dump */	nodump,
261	/* psize */	nopsize,
262	/* flags */	0,
263};
264
265DRIVER_MODULE(bktr, pci, bktr_driver, bktr_devclass, 0, 0);
266#if (__FreeBSD_version > 410000)
267MODULE_DEPEND(bktr, bktr_mem, 1,1,1);
268MODULE_VERSION(bktr, 1);
269#endif
270
271
272/*
273 * the boot time probe routine.
274 */
275static int
276bktr_probe( device_t dev )
277{
278	unsigned int type = pci_get_devid(dev);
279        unsigned int rev  = pci_get_revid(dev);
280
281	if (PCI_VENDOR(type) == PCI_VENDOR_BROOKTREE)
282	{
283		switch (PCI_PRODUCT(type)) {
284		case PCI_PRODUCT_BROOKTREE_BT848:
285			if (rev == 0x12)
286				device_set_desc(dev, "BrookTree 848A");
287			else
288				device_set_desc(dev, "BrookTree 848");
289			return 0;
290		case PCI_PRODUCT_BROOKTREE_BT849:
291			device_set_desc(dev, "BrookTree 849A");
292			return 0;
293		case PCI_PRODUCT_BROOKTREE_BT878:
294			device_set_desc(dev, "BrookTree 878");
295			return 0;
296		case PCI_PRODUCT_BROOKTREE_BT879:
297			device_set_desc(dev, "BrookTree 879");
298			return 0;
299		}
300	};
301
302        return ENXIO;
303}
304
305
306/*
307 * the attach routine.
308 */
309static int
310bktr_attach( device_t dev )
311{
312	u_long		latency;
313	u_long		fun;
314	u_long		val;
315	unsigned int	rev;
316	unsigned int	unit;
317	int		error = 0;
318#ifdef BROOKTREE_IRQ
319	u_long		old_irq, new_irq;
320#endif
321
322        struct bktr_softc *bktr = device_get_softc(dev);
323
324	unit = device_get_unit(dev);
325
326	/* build the device name for bktr_name() */
327	snprintf(bktr->bktr_xname, sizeof(bktr->bktr_xname), "bktr%d",unit);
328
329	/*
330	 * Enable bus mastering and Memory Mapped device
331	 */
332	val = pci_read_config(dev, PCIR_COMMAND, 4);
333	val |= (PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
334	pci_write_config(dev, PCIR_COMMAND, val, 4);
335
336	/*
337	 * Map control/status registers.
338	 */
339	bktr->mem_rid = PCIR_MAPS;
340	bktr->res_mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &bktr->mem_rid,
341					0, ~0, 1, RF_ACTIVE);
342
343
344	if (!bktr->res_mem) {
345		device_printf(dev, "could not map memory\n");
346		error = ENXIO;
347		goto fail;
348	}
349	bktr->memt = rman_get_bustag(bktr->res_mem);
350	bktr->memh = rman_get_bushandle(bktr->res_mem);
351
352
353	/*
354	 * Disable the brooktree device
355	 */
356	OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
357	OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
358
359
360#ifdef BROOKTREE_IRQ		/* from the configuration file */
361	old_irq = pci_conf_read(tag, PCI_INTERRUPT_REG);
362	pci_conf_write(tag, PCI_INTERRUPT_REG, BROOKTREE_IRQ);
363	new_irq = pci_conf_read(tag, PCI_INTERRUPT_REG);
364	printf("bktr%d: attach: irq changed from %d to %d\n",
365		unit, (old_irq & 0xff), (new_irq & 0xff));
366#endif
367
368	/*
369	 * Allocate our interrupt.
370	 */
371	bktr->irq_rid = 0;
372	bktr->res_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &bktr->irq_rid,
373				0, ~0, 1, RF_SHAREABLE | RF_ACTIVE);
374	if (bktr->res_irq == NULL) {
375		device_printf(dev, "could not map interrupt\n");
376		error = ENXIO;
377		goto fail;
378	}
379
380	error = bus_setup_intr(dev, bktr->res_irq, INTR_TYPE_TTY,
381                               bktr_intr, bktr, &bktr->res_ih);
382	if (error) {
383		device_printf(dev, "could not setup irq\n");
384		goto fail;
385
386	}
387
388
389	/* Update the Device Control Register */
390	/* on Bt878 and Bt879 cards           */
391	fun = pci_read_config( dev, 0x40, 2);
392        fun = fun | 1;	/* Enable writes to the sub-system vendor ID */
393
394#if defined( BKTR_430_FX_MODE )
395	if (bootverbose) printf("Using 430 FX chipset compatibilty mode\n");
396        fun = fun | 2;	/* Enable Intel 430 FX compatibility mode */
397#endif
398
399#if defined( BKTR_SIS_VIA_MODE )
400	if (bootverbose) printf("Using SiS/VIA chipset compatibilty mode\n");
401        fun = fun | 4;	/* Enable SiS/VIA compatibility mode (usefull for
402                           OPTi chipset motherboards too */
403#endif
404	pci_write_config(dev, 0x40, fun, 2);
405
406#if defined(BKTR_USE_FREEBSD_SMBUS)
407	if (bt848_i2c_attach(dev))
408		printf("bktr%d: i2c_attach: can't attach\n", unit);
409#endif
410
411/*
412 * PCI latency timer.  32 is a good value for 4 bus mastering slots, if
413 * you have more than four, then 16 would probably be a better value.
414 */
415#ifndef BROOKTREE_DEF_LATENCY_VALUE
416#define BROOKTREE_DEF_LATENCY_VALUE	10
417#endif
418	latency = pci_read_config(dev, PCI_LATENCY_TIMER, 4);
419	latency = (latency >> 8) & 0xff;
420	if ( bootverbose ) {
421		if (latency)
422			printf("brooktree%d: PCI bus latency is", unit);
423		else
424			printf("brooktree%d: PCI bus latency was 0 changing to",
425				unit);
426	}
427	if ( !latency ) {
428		latency = BROOKTREE_DEF_LATENCY_VALUE;
429		pci_write_config(dev, PCI_LATENCY_TIMER, latency<<8, 4);
430	}
431	if ( bootverbose ) {
432		printf(" %d.\n", (int) latency);
433	}
434
435	/* read the pci device id and revision id */
436	fun = pci_get_devid(dev);
437        rev = pci_get_revid(dev);
438
439	/* call the common attach code */
440	common_bktr_attach( bktr, unit, fun, rev );
441
442	/* make the device entries */
443	bktr->bktrdev = make_dev(&bktr_cdevsw, unit,
444				0, 0, 0444, "bktr%d",  unit);
445	bktr->tunerdev= make_dev(&bktr_cdevsw, unit+16,
446				0, 0, 0444, "tuner%d", unit);
447	bktr->vbidev  = make_dev(&bktr_cdevsw, unit+32,
448				0, 0, 0444, "vbi%d"  , unit);
449
450
451	/* if this is unit 0 (/dev/bktr0, /dev/tuner0, /dev/vbi0) then make */
452	/* alias entries to /dev/bktr /dev/tuner and /dev/vbi */
453#if (__FreeBSD_version >=500000)
454	if (unit == 0) {
455		bktr->bktrdev_alias = make_dev_alias(bktr->bktrdev,  "bktr");
456		bktr->tunerdev_alias= make_dev_alias(bktr->tunerdev, "tuner");
457		bktr->vbidev_alias  = make_dev_alias(bktr->vbidev,   "vbi");
458	}
459#endif
460
461	return 0;
462
463fail:
464	if (bktr->res_irq)
465		bus_release_resource(dev, SYS_RES_IRQ, bktr->irq_rid, bktr->res_irq);
466	if (bktr->res_mem)
467		bus_release_resource(dev, SYS_RES_IRQ, bktr->mem_rid, bktr->res_mem);
468	return error;
469
470}
471
472/*
473 * the detach routine.
474 */
475static int
476bktr_detach( device_t dev )
477{
478	unsigned int	unit;
479
480	struct bktr_softc *bktr = device_get_softc(dev);
481
482	unit = device_get_unit(dev);
483
484	/* Disable the brooktree device */
485	OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
486	OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
487
488#if defined(BKTR_USE_FREEBSD_SMBUS)
489	if (bt848_i2c_detach(dev))
490		printf("bktr%d: i2c_attach: can't attach\n", unit);
491#endif
492
493	/* Note: We do not free memory for RISC programs, grab buffer, vbi buffers */
494	/* The memory is retained by the bktr_mem module so we can unload and */
495	/* then reload the main bktr driver module */
496
497	/* Unregister the /dev/bktrN, tunerN and vbiN devices */
498	destroy_dev(bktr->vbidev);
499	destroy_dev(bktr->tunerdev);
500	destroy_dev(bktr->bktrdev);
501
502	/* If this is unit 0, then destroy the alias entries too */
503#if (__FreeBSD_version >=500000)
504	if (unit == 0) {
505	    destroy_dev(bktr->vbidev_alias);
506	    destroy_dev(bktr->tunerdev_alias);
507	    destroy_dev(bktr->bktrdev_alias);
508	}
509#endif
510
511	/*
512	 * Deallocate resources.
513	 */
514	bus_teardown_intr(dev, bktr->res_irq, bktr->res_ih);
515	bus_release_resource(dev, SYS_RES_IRQ, bktr->irq_rid, bktr->res_irq);
516	bus_release_resource(dev, SYS_RES_MEMORY, bktr->mem_rid, bktr->res_mem);
517
518	return 0;
519}
520
521/*
522 * the shutdown routine.
523 */
524static int
525bktr_shutdown( device_t dev )
526{
527	struct bktr_softc *bktr = device_get_softc(dev);
528
529	/* Disable the brooktree device */
530	OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
531	OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
532
533	return 0;
534}
535
536
537/*
538 * Special Memory Allocation
539 */
540vm_offset_t
541get_bktr_mem( int unit, unsigned size )
542{
543	vm_offset_t	addr = 0;
544
545	addr = vm_page_alloc_contig(size, 0, 0xffffffff, 1<<24);
546	if (addr == 0)
547		addr = vm_page_alloc_contig(size, 0, 0xffffffff, PAGE_SIZE);
548	if (addr == 0) {
549		printf("bktr%d: Unable to allocate %d bytes of memory.\n",
550			unit, size);
551	}
552
553	return( addr );
554}
555
556
557/*---------------------------------------------------------
558**
559**	BrookTree 848 character device driver routines
560**
561**---------------------------------------------------------
562*/
563
564#define VIDEO_DEV	0x00
565#define TUNER_DEV	0x01
566#define VBI_DEV		0x02
567
568#define UNIT(x)		((x) & 0x0f)
569#define FUNCTION(x)	(x >> 4)
570
571/*
572 *
573 */
574static int
575bktr_open( dev_t dev, int flags, int fmt, struct thread *td )
576{
577	bktr_ptr_t	bktr;
578	int		unit;
579	int		result;
580
581	unit = UNIT( minor(dev) );
582
583	/* Get the device data */
584	bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
585	if (bktr == NULL) {
586		/* the device is no longer valid/functioning */
587		return (ENXIO);
588	}
589
590	if (!(bktr->flags & METEOR_INITALIZED)) /* device not found */
591		return( ENXIO );
592
593	/* Record that the device is now busy */
594	device_busy(devclass_get_device(bktr_devclass, unit));
595
596
597	if (bt848_card != -1) {
598	  if ((bt848_card >> 8   == unit ) &&
599	     ( (bt848_card & 0xff) < Bt848_MAX_CARD )) {
600	    if ( bktr->bt848_card != (bt848_card & 0xff) ) {
601	      bktr->bt848_card = (bt848_card & 0xff);
602	      probeCard(bktr, FALSE, unit);
603	    }
604	  }
605	}
606
607	if (bt848_tuner != -1) {
608	  if ((bt848_tuner >> 8   == unit ) &&
609	     ( (bt848_tuner & 0xff) < Bt848_MAX_TUNER )) {
610	    if ( bktr->bt848_tuner != (bt848_tuner & 0xff) ) {
611	      bktr->bt848_tuner = (bt848_tuner & 0xff);
612	      probeCard(bktr, FALSE, unit);
613	    }
614	  }
615	}
616
617	if (bt848_reverse_mute != -1) {
618	  if ((bt848_reverse_mute >> 8)   == unit ) {
619	    bktr->reverse_mute = bt848_reverse_mute & 0xff;
620	  }
621	}
622
623	if (bt848_slow_msp_audio != -1) {
624	  if ((bt848_slow_msp_audio >> 8) == unit ) {
625	      bktr->slow_msp_audio = (bt848_slow_msp_audio & 0xff);
626	  }
627	}
628
629	switch ( FUNCTION( minor(dev) ) ) {
630	case VIDEO_DEV:
631		result = video_open( bktr );
632		break;
633	case TUNER_DEV:
634		result = tuner_open( bktr );
635		break;
636	case VBI_DEV:
637		result = vbi_open( bktr );
638		break;
639	default:
640		result = ENXIO;
641		break;
642	}
643
644	/* If there was an error opening the device, undo the busy status */
645	if (result != 0)
646		device_unbusy(devclass_get_device(bktr_devclass, unit));
647	return( result );
648}
649
650
651/*
652 *
653 */
654static int
655bktr_close( dev_t dev, int flags, int fmt, struct thread *td )
656{
657	bktr_ptr_t	bktr;
658	int		unit;
659	int		result;
660
661	unit = UNIT( minor(dev) );
662
663	/* Get the device data */
664	bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
665	if (bktr == NULL) {
666		/* the device is no longer valid/functioning */
667		return (ENXIO);
668	}
669
670	switch ( FUNCTION( minor(dev) ) ) {
671	case VIDEO_DEV:
672		result = video_close( bktr );
673		break;
674	case TUNER_DEV:
675		result = tuner_close( bktr );
676		break;
677	case VBI_DEV:
678		result = vbi_close( bktr );
679		break;
680	default:
681		return (ENXIO);
682		break;
683	}
684
685	device_unbusy(devclass_get_device(bktr_devclass, unit));
686	return( result );
687}
688
689
690/*
691 *
692 */
693static int
694bktr_read( dev_t dev, struct uio *uio, int ioflag )
695{
696	bktr_ptr_t	bktr;
697	int		unit;
698
699	unit = UNIT(minor(dev));
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	switch ( FUNCTION( minor(dev) ) ) {
709	case VIDEO_DEV:
710		return( video_read( bktr, unit, dev, uio ) );
711	case VBI_DEV:
712		return( vbi_read( bktr, uio, ioflag ) );
713	}
714        return( ENXIO );
715}
716
717
718/*
719 *
720 */
721static int
722bktr_write( dev_t dev, struct uio *uio, int ioflag )
723{
724	return( EINVAL ); /* XXX or ENXIO ? */
725}
726
727
728/*
729 *
730 */
731static int
732bktr_ioctl( dev_t dev, ioctl_cmd_t cmd, caddr_t arg, int flag, struct thread *td )
733{
734	bktr_ptr_t	bktr;
735	int		unit;
736
737	unit = UNIT(minor(dev));
738
739	/* Get the device data */
740	bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
741	if (bktr == NULL) {
742		/* the device is no longer valid/functioning */
743		return (ENXIO);
744	}
745
746	if (bktr->bigbuf == 0)	/* no frame buffer allocated (ioctl failed) */
747		return( ENOMEM );
748
749	switch ( FUNCTION( minor(dev) ) ) {
750	case VIDEO_DEV:
751		return( video_ioctl( bktr, unit, cmd, arg, td ) );
752	case TUNER_DEV:
753		return( tuner_ioctl( bktr, unit, cmd, arg, td ) );
754	}
755
756	return( ENXIO );
757}
758
759
760/*
761 *
762 */
763static int
764bktr_mmap( dev_t dev, vm_offset_t offset, int nprot )
765{
766	int		unit;
767	bktr_ptr_t	bktr;
768
769	unit = UNIT(minor(dev));
770
771	if (FUNCTION(minor(dev)) > 0)	/* only allow mmap on /dev/bktr[n] */
772		return( -1 );
773
774	/* Get the device data */
775	bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
776	if (bktr == NULL) {
777		/* the device is no longer valid/functioning */
778		return (ENXIO);
779	}
780
781	if (nprot & PROT_EXEC)
782		return( -1 );
783
784	if (offset < 0)
785		return( -1 );
786
787	if (offset >= bktr->alloc_pages * PAGE_SIZE)
788		return( -1 );
789
790	return( atop(vtophys(bktr->bigbuf) + offset) );
791}
792
793static int
794bktr_poll( dev_t dev, int events, struct thread *td)
795{
796	int		unit;
797	bktr_ptr_t	bktr;
798	int revents = 0;
799	DECLARE_INTR_MASK(s);
800
801	unit = UNIT(minor(dev));
802
803	/* Get the device data */
804	bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
805	if (bktr == NULL) {
806		/* the device is no longer valid/functioning */
807		return (ENXIO);
808	}
809
810	DISABLE_INTR(s);
811
812	if (events & (POLLIN | POLLRDNORM)) {
813
814		switch ( FUNCTION( minor(dev) ) ) {
815		case VBI_DEV:
816			if(bktr->vbisize == 0)
817				selrecord(td, &bktr->vbi_select);
818			else
819				revents |= events & (POLLIN | POLLRDNORM);
820			break;
821		}
822	}
823
824	ENABLE_INTR(s);
825
826	return (revents);
827}
828
829#endif		/* FreeBSD 4.x specific kernel interface routines */
830
831/*****************/
832/* *** BSDI  *** */
833/*****************/
834
835#if defined(__bsdi__)
836#endif		/* __bsdi__ BSDI specific kernel interface routines */
837
838
839/*****************************/
840/* *** OpenBSD / NetBSD  *** */
841/*****************************/
842#if defined(__NetBSD__) || defined(__OpenBSD__)
843
844#define IPL_VIDEO       IPL_BIO         /* XXX */
845
846static	int		bktr_intr(void *arg) { return common_bktr_intr(arg); }
847
848#define bktr_open       bktropen
849#define bktr_close      bktrclose
850#define bktr_read       bktrread
851#define bktr_write      bktrwrite
852#define bktr_ioctl      bktrioctl
853#define bktr_mmap       bktrmmap
854
855vm_offset_t vm_page_alloc_contig(vm_offset_t, vm_offset_t,
856                                 vm_offset_t, vm_offset_t);
857
858#if defined(__OpenBSD__)
859static int      bktr_probe(struct device *, void *, void *);
860#else
861static int      bktr_probe(struct device *, struct cfdata *, void *);
862#endif
863static void     bktr_attach(struct device *, struct device *, void *);
864
865struct cfattach bktr_ca = {
866        sizeof(struct bktr_softc), bktr_probe, bktr_attach
867};
868
869#if defined(__NetBSD__)
870extern struct cfdriver bktr_cd;
871#else
872struct cfdriver bktr_cd = {
873        NULL, "bktr", DV_DULL
874};
875#endif
876
877int
878bktr_probe(parent, match, aux)
879	struct device *parent;
880#if defined(__OpenBSD__)
881        void *match;
882#else
883        struct cfdata *match;
884#endif
885        void *aux;
886{
887        struct pci_attach_args *pa = aux;
888
889        if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_BROOKTREE &&
890            (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROOKTREE_BT848 ||
891             PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROOKTREE_BT849 ||
892             PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROOKTREE_BT878 ||
893             PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROOKTREE_BT879))
894                return 1;
895
896        return 0;
897}
898
899
900/*
901 * the attach routine.
902 */
903static void
904bktr_attach(struct device *parent, struct device *self, void *aux)
905{
906	bktr_ptr_t	bktr;
907	u_long		latency;
908	u_long		fun;
909	unsigned int	rev;
910
911#if defined(__OpenBSD__)
912	struct pci_attach_args *pa = aux;
913	pci_chipset_tag_t pc = pa->pa_pc;
914
915	pci_intr_handle_t ih;
916	const char *intrstr;
917	int retval;
918	int unit;
919
920	bktr = (bktr_ptr_t)self;
921	unit = bktr->bktr_dev.dv_unit;
922
923	bktr->pc = pa->pa_pc;
924	bktr->tag = pa->pa_tag;
925        bktr->dmat = pa->pa_dmat;
926
927	/*
928	 * map memory
929	 */
930	bktr->memt = pa->pa_memt;
931	retval = pci_mem_find(pc, pa->pa_tag, PCI_MAPREG_START,
932			      &bktr->phys_base, &bktr->obmemsz, NULL);
933	if (!retval)
934		retval = bus_space_map(pa->pa_memt, bktr->phys_base,
935				       bktr->obmemsz, 0, &bktr->memh);
936	if (retval) {
937		printf(": couldn't map memory\n");
938		return;
939	}
940
941
942	/*
943	 * map interrupt
944	 */
945	if (pci_intr_map(pa->pa_pc, pa->pa_intrtag, pa->pa_intrpin,
946			 pa->pa_intrline, &ih)) {
947		printf(": couldn't map interrupt\n");
948		return;
949	}
950	intrstr = pci_intr_string(pa->pa_pc, ih);
951
952	bktr->ih = pci_intr_establish(pa->pa_pc, ih, IPL_VIDEO,
953				      bktr_intr, bktr, bktr->bktr_dev.dv_xname);
954	if (bktr->ih == NULL) {
955		printf(": couldn't establish interrupt");
956		if (intrstr != NULL)
957			printf(" at %s", intrstr);
958		printf("\n");
959		return;
960	}
961
962	if (intrstr != NULL)
963		printf(": %s\n", intrstr);
964#endif /* __OpenBSD__ */
965
966#if defined(__NetBSD__)
967	struct pci_attach_args *pa = aux;
968	pci_intr_handle_t ih;
969	const char *intrstr;
970	int retval;
971	int unit;
972
973	bktr = (bktr_ptr_t)self;
974	unit = bktr->bktr_dev.dv_unit;
975        bktr->dmat = pa->pa_dmat;
976
977	printf("\n");
978
979	/*
980	 * map memory
981	 */
982	retval = pci_mapreg_map(pa, PCI_MAPREG_START,
983				PCI_MAPREG_TYPE_MEM
984				| PCI_MAPREG_MEM_TYPE_32BIT, 0,
985				&bktr->memt, &bktr->memh, NULL,
986				&bktr->obmemsz);
987	DPR(("pci_mapreg_map: memt %x, memh %x, size %x\n",
988	     bktr->memt, (u_int)bktr->memh, (u_int)bktr->obmemsz));
989	if (retval) {
990		printf("%s: couldn't map memory\n", bktr_name(bktr));
991		return;
992	}
993
994	/*
995	 * Disable the brooktree device
996	 */
997	OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
998	OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
999
1000	/*
1001	 * map interrupt
1002	 */
1003	if (pci_intr_map(pa->pa_pc, pa->pa_intrtag, pa->pa_intrpin,
1004			 pa->pa_intrline, &ih)) {
1005		printf("%s: couldn't map interrupt\n",
1006		       bktr_name(bktr));
1007		return;
1008	}
1009	intrstr = pci_intr_string(pa->pa_pc, ih);
1010	bktr->ih = pci_intr_establish(pa->pa_pc, ih, IPL_VIDEO,
1011				      bktr_intr, bktr);
1012	if (bktr->ih == NULL) {
1013		printf("%s: couldn't establish interrupt",
1014		       bktr_name(bktr));
1015		if (intrstr != NULL)
1016			printf(" at %s", intrstr);
1017		printf("\n");
1018		return;
1019	}
1020	if (intrstr != NULL)
1021		printf("%s: interrupting at %s\n", bktr_name(bktr),
1022		       intrstr);
1023#endif /* __NetBSD__ */
1024
1025/*
1026 * PCI latency timer.  32 is a good value for 4 bus mastering slots, if
1027 * you have more than four, then 16 would probably be a better value.
1028 */
1029#ifndef BROOKTREE_DEF_LATENCY_VALUE
1030#define BROOKTREE_DEF_LATENCY_VALUE	10
1031#endif
1032	latency = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_LATENCY_TIMER);
1033	latency = (latency >> 8) & 0xff;
1034
1035	if (!latency) {
1036		if (bootverbose) {
1037			printf("%s: PCI bus latency was 0 changing to %d",
1038			       bktr_name(bktr), BROOKTREE_DEF_LATENCY_VALUE);
1039		}
1040		latency = BROOKTREE_DEF_LATENCY_VALUE;
1041		pci_conf_write(pa->pa_pc, pa->pa_tag,
1042			       PCI_LATENCY_TIMER, latency<<8);
1043	}
1044
1045
1046	/* Enabled Bus Master
1047	   XXX: check if all old DMA is stopped first (e.g. after warm
1048	   boot) */
1049	fun = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
1050	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
1051		       fun | PCI_COMMAND_MASTER_ENABLE);
1052
1053	/* read the pci id and determine the card type */
1054	fun = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ID_REG);
1055        rev = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_CLASS_REG) & 0x000000ff;
1056
1057	common_bktr_attach(bktr, unit, fun, rev);
1058}
1059
1060
1061/*
1062 * Special Memory Allocation
1063 */
1064vm_offset_t
1065get_bktr_mem(bktr, dmapp, size)
1066        bktr_ptr_t bktr;
1067        bus_dmamap_t *dmapp;
1068        unsigned int size;
1069{
1070        bus_dma_tag_t dmat = bktr->dmat;
1071        bus_dma_segment_t seg;
1072        bus_size_t align;
1073        int rseg;
1074        caddr_t kva;
1075
1076        /*
1077         * Allocate a DMA area
1078         */
1079        align = 1 << 24;
1080        if (bus_dmamem_alloc(dmat, size, align, 0, &seg, 1,
1081                             &rseg, BUS_DMA_NOWAIT)) {
1082                align = PAGE_SIZE;
1083                if (bus_dmamem_alloc(dmat, size, align, 0, &seg, 1,
1084                                     &rseg, BUS_DMA_NOWAIT)) {
1085                        printf("%s: Unable to dmamem_alloc of %d bytes\n",
1086			       bktr_name(bktr), size);
1087                        return 0;
1088                }
1089        }
1090        if (bus_dmamem_map(dmat, &seg, rseg, size,
1091                           &kva, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) {
1092                printf("%s: Unable to dmamem_map of %d bytes\n",
1093                        bktr_name(bktr), size);
1094                bus_dmamem_free(dmat, &seg, rseg);
1095                return 0;
1096        }
1097#ifdef __OpenBSD__
1098        bktr->dm_mapsize = size;
1099#endif
1100        /*
1101         * Create and locd the DMA map for the DMA area
1102         */
1103        if (bus_dmamap_create(dmat, size, 1, size, 0, BUS_DMA_NOWAIT, dmapp)) {
1104                printf("%s: Unable to dmamap_create of %d bytes\n",
1105                        bktr_name(bktr), size);
1106                bus_dmamem_unmap(dmat, kva, size);
1107                bus_dmamem_free(dmat, &seg, rseg);
1108                return 0;
1109        }
1110        if (bus_dmamap_load(dmat, *dmapp, kva, size, NULL, BUS_DMA_NOWAIT)) {
1111                printf("%s: Unable to dmamap_load of %d bytes\n",
1112                        bktr_name(bktr), size);
1113                bus_dmamem_unmap(dmat, kva, size);
1114                bus_dmamem_free(dmat, &seg, rseg);
1115                bus_dmamap_destroy(dmat, *dmapp);
1116                return 0;
1117        }
1118        return (vm_offset_t)kva;
1119}
1120
1121void
1122free_bktr_mem(bktr, dmap, kva)
1123        bktr_ptr_t bktr;
1124        bus_dmamap_t dmap;
1125        vm_offset_t kva;
1126{
1127        bus_dma_tag_t dmat = bktr->dmat;
1128
1129#ifdef __NetBSD__
1130        bus_dmamem_unmap(dmat, (caddr_t)kva, dmap->dm_mapsize);
1131#else
1132        bus_dmamem_unmap(dmat, (caddr_t)kva, bktr->dm_mapsize);
1133#endif
1134        bus_dmamem_free(dmat, dmap->dm_segs, 1);
1135        bus_dmamap_destroy(dmat, dmap);
1136}
1137
1138
1139/*---------------------------------------------------------
1140**
1141**	BrookTree 848 character device driver routines
1142**
1143**---------------------------------------------------------
1144*/
1145
1146
1147#define VIDEO_DEV	0x00
1148#define TUNER_DEV	0x01
1149#define VBI_DEV		0x02
1150
1151#define UNIT(x)         (minor((x) & 0x0f))
1152#define FUNCTION(x)     (minor((x >> 4) & 0x0f))
1153
1154/*
1155 *
1156 */
1157int
1158bktr_open(dev_t dev, int flags, int fmt, struct thread *td)
1159{
1160	bktr_ptr_t	bktr;
1161	int		unit;
1162
1163	unit = UNIT(dev);
1164
1165	/* unit out of range */
1166	if ((unit > bktr_cd.cd_ndevs) || (bktr_cd.cd_devs[unit] == NULL))
1167		return(ENXIO);
1168
1169	bktr = bktr_cd.cd_devs[unit];
1170
1171	if (!(bktr->flags & METEOR_INITALIZED)) /* device not found */
1172		return(ENXIO);
1173
1174	switch (FUNCTION(dev)) {
1175	case VIDEO_DEV:
1176		return(video_open(bktr));
1177	case TUNER_DEV:
1178		return(tuner_open(bktr));
1179	case VBI_DEV:
1180		return(vbi_open(bktr));
1181	}
1182
1183	return(ENXIO);
1184}
1185
1186
1187/*
1188 *
1189 */
1190int
1191bktr_close(dev_t dev, int flags, int fmt, struct thread *td)
1192{
1193	bktr_ptr_t	bktr;
1194	int		unit;
1195
1196	unit = UNIT(dev);
1197
1198	bktr = bktr_cd.cd_devs[unit];
1199
1200	switch (FUNCTION(dev)) {
1201	case VIDEO_DEV:
1202		return(video_close(bktr));
1203	case TUNER_DEV:
1204		return(tuner_close(bktr));
1205	case VBI_DEV:
1206		return(vbi_close(bktr));
1207	}
1208
1209	return(ENXIO);
1210}
1211
1212/*
1213 *
1214 */
1215int
1216bktr_read(dev_t dev, struct uio *uio, int ioflag)
1217{
1218	bktr_ptr_t	bktr;
1219	int		unit;
1220
1221	unit = UNIT(dev);
1222
1223	bktr = bktr_cd.cd_devs[unit];
1224
1225	switch (FUNCTION(dev)) {
1226	case VIDEO_DEV:
1227		return(video_read(bktr, unit, dev, uio));
1228	case VBI_DEV:
1229		return(vbi_read(bktr, uio, ioflag));
1230	}
1231
1232        return(ENXIO);
1233}
1234
1235
1236/*
1237 *
1238 */
1239int
1240bktr_write(dev_t dev, struct uio *uio, int ioflag)
1241{
1242	/* operation not supported */
1243	return(EOPNOTSUPP);
1244}
1245
1246/*
1247 *
1248 */
1249int
1250bktr_ioctl(dev_t dev, ioctl_cmd_t cmd, caddr_t arg, int flag, struct thread *td)
1251{
1252	bktr_ptr_t	bktr;
1253	int		unit;
1254
1255	unit = UNIT(dev);
1256
1257	bktr = bktr_cd.cd_devs[unit];
1258
1259	if (bktr->bigbuf == 0)	/* no frame buffer allocated (ioctl failed) */
1260		return(ENOMEM);
1261
1262	switch (FUNCTION(dev)) {
1263	case VIDEO_DEV:
1264		return(video_ioctl(bktr, unit, cmd, arg, pr));
1265	case TUNER_DEV:
1266		return(tuner_ioctl(bktr, unit, cmd, arg, pr));
1267	}
1268
1269	return(ENXIO);
1270}
1271
1272/*
1273 *
1274 */
1275paddr_t
1276bktr_mmap(dev_t dev, off_t offset, int nprot)
1277{
1278	int		unit;
1279	bktr_ptr_t	bktr;
1280
1281	unit = UNIT(dev);
1282
1283	if (FUNCTION(dev) > 0)	/* only allow mmap on /dev/bktr[n] */
1284		return(-1);
1285
1286	bktr = bktr_cd.cd_devs[unit];
1287
1288	if ((vaddr_t)offset < 0)
1289		return(-1);
1290
1291	if ((vaddr_t)offset >= bktr->alloc_pages * PAGE_SIZE)
1292		return(-1);
1293
1294#ifdef __NetBSD__
1295	return (bus_dmamem_mmap(bktr->dmat, bktr->dm_mem->dm_segs, 1,
1296				(vaddr_t)offset, nprot, BUS_DMA_WAITOK));
1297#else
1298	return(i386_btop(vtophys(bktr->bigbuf) + offset));
1299#endif
1300}
1301
1302#endif /* __NetBSD__ || __OpenBSD__ */
1303