bktr_os.c revision 119418
1233294Sstas/*-
2102644Snectar * 1. Redistributions of source code must retain the
355682Smarkm * Copyright (c) 1997 Amancio Hasty, 1999 Roger Hardiman
4142403Snectar * All rights reserved.
5233294Sstas *
6233294Sstas * Redistribution and use in source and binary forms, with or without
755682Smarkm * modification, are permitted provided that the following conditions
855682Smarkm * are met:
955682Smarkm * 1. Redistributions of source code must retain the above copyright
1055682Smarkm *    notice, this list of conditions and the following disclaimer.
1155682Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1255682Smarkm *    notice, this list of conditions and the following disclaimer in the
1355682Smarkm *    documentation and/or other materials provided with the distribution.
1455682Smarkm * 3. All advertising materials mentioning features or use of this software
1555682Smarkm *    must display the following acknowledgement:
1690926Snectar *	This product includes software developed by Amancio Hasty and
1790926Snectar *      Roger Hardiman
18233294Sstas * 4. The name of the author may not be used to endorse or promote products
1990926Snectar *    derived from this software without specific prior written permission.
20233294Sstas *
2190926Snectar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22233294Sstas * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2355682Smarkm * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2455682Smarkm * DISCLAIMED.	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
2555682Smarkm * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26233294Sstas * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2755682Smarkm * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29102644Snectar * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30102644Snectar * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31102644Snectar * POSSIBILITY OF SUCH DAMAGE.
32127808Snectar */
3390926Snectar
34127808Snectar#include <sys/cdefs.h>
3555682Smarkm__FBSDID("$FreeBSD: head/sys/dev/bktr/bktr_os.c 119418 2003-08-24 17:55:58Z obrien $");
3655682Smarkm
3755682Smarkm/*
3855682Smarkm * This is part of the Driver for Video Capture Cards (Frame grabbers)
3955682Smarkm * and TV Tuner cards using the Brooktree Bt848, Bt848A, Bt849A, Bt878, Bt879
4055682Smarkm * chipset.
41178825Sdfr * Copyright Roger Hardiman and Amancio Hasty.
4255682Smarkm *
43142403Snectar * bktr_os : This has all the Operating System dependant code,
44142403Snectar *             probe/attach and open/close/ioctl/read/mmap
45178825Sdfr *             memory allocation
46142403Snectar *             PCI bus interfacing
47142403Snectar */
48142403Snectar
49142403Snectar#include "opt_bktr.h"		/* include any kernel config options */
50233294Sstas
51142403Snectar#define FIFO_RISC_DISABLED      0
52142403Snectar#define ALL_INTS_DISABLED       0
53142403Snectar
54142403Snectar
55142403Snectar/*******************/
56142403Snectar/* *** FreeBSD *** */
57142403Snectar/*******************/
58142403Snectar#ifdef __FreeBSD__
59142403Snectar
60142403Snectar#include <sys/param.h>
61142403Snectar#include <sys/systm.h>
62142403Snectar#include <sys/conf.h>
63142403Snectar#include <sys/uio.h>
64142403Snectar#include <sys/kernel.h>
65233294Sstas#include <sys/signalvar.h>
66142403Snectar#include <sys/mman.h>
67142403Snectar#include <sys/poll.h>
68142403Snectar#if __FreeBSD_version >= 500014
69142403Snectar#include <sys/selinfo.h>
70178825Sdfr#else
71142403Snectar#include <sys/select.h>
72142403Snectar#endif
73142403Snectar#include <sys/vnode.h>
74142403Snectar
75142403Snectar#include <vm/vm.h>
76142403Snectar#include <vm/vm_kern.h>
77142403Snectar#include <vm/pmap.h>
78142403Snectar#include <vm/vm_extern.h>
79233294Sstas
80233294Sstas#if (__FreeBSD_version >=400000)
81233294Sstas#include <sys/bus.h>		/* used by smbus and newbus */
82233294Sstas#endif
83233294Sstas
84233294Sstas#if (__FreeBSD_version >=300000)
85178825Sdfr#include <machine/bus_memio.h>	/* used by bus space */
86178825Sdfr#include <machine/bus.h>	/* used by bus space and newbus */
87178825Sdfr#include <sys/bus.h>
88178825Sdfr#endif
89178825Sdfr
90178825Sdfr#if (__FreeBSD_version >=400000)
91178825Sdfr#include <sys/rman.h>		/* used by newbus */
92233294Sstas#include <machine/resource.h>	/* used by newbus */
93142403Snectar#endif
94142403Snectar
95178825Sdfr#if (__FreeBSD_version < 500000)
96142403Snectar#include <machine/clock.h>              /* for DELAY */
97142403Snectar#include <pci/pcivar.h>
98233294Sstas#include <pci/pcireg.h>
99142403Snectar#else
100142403Snectar#include <dev/pci/pcivar.h>
101178825Sdfr#include <dev/pci/pcireg.h>
102233294Sstas#endif
103233294Sstas
104233294Sstas#include <sys/sysctl.h>
105178825Sdfrint bt848_card = -1;
106178825Sdfrint bt848_tuner = -1;
107142403Snectarint bt848_reverse_mute = -1;
108142403Snectarint bt848_format = -1;
109142403Snectarint bt848_slow_msp_audio = -1;
110142403Snectar#ifdef BKTR_NEW_MSP34XX_DRIVER
111142403Snectarint bt848_stereo_once = 0;	/* no continuous stereo monitoring */
112142403Snectarint bt848_amsound = 0;		/* hard-wire AM sound at 6.5 Hz (france),
113142403Snectar				   the autoscan seems work well only with FM... */
114233294Sstasint bt848_dolby = 0;
115233294Sstas#endif
116233294Sstas
117142403SnectarSYSCTL_NODE(_hw, OID_AUTO, bt848, CTLFLAG_RW, 0, "Bt848 Driver mgmt");
118142403SnectarSYSCTL_INT(_hw_bt848, OID_AUTO, card, CTLFLAG_RW, &bt848_card, -1, "");
119178825SdfrSYSCTL_INT(_hw_bt848, OID_AUTO, tuner, CTLFLAG_RW, &bt848_tuner, -1, "");
120178825SdfrSYSCTL_INT(_hw_bt848, OID_AUTO, reverse_mute, CTLFLAG_RW, &bt848_reverse_mute, -1, "");
121178825SdfrSYSCTL_INT(_hw_bt848, OID_AUTO, format, CTLFLAG_RW, &bt848_format, -1, "");
122142403SnectarSYSCTL_INT(_hw_bt848, OID_AUTO, slow_msp_audio, CTLFLAG_RW, &bt848_slow_msp_audio, -1, "");
123178825Sdfr#ifdef BKTR_NEW_MSP34XX_DRIVER
124178825SdfrSYSCTL_INT(_hw_bt848, OID_AUTO, stereo_once, CTLFLAG_RW, &bt848_stereo_once, 0, "");
125178825SdfrSYSCTL_INT(_hw_bt848, OID_AUTO, amsound, CTLFLAG_RW, &bt848_amsound, 0, "");
126178825SdfrSYSCTL_INT(_hw_bt848, OID_AUTO, dolby, CTLFLAG_RW, &bt848_dolby, 0, "");
127178825Sdfr#endif
128233294Sstas
129233294Sstas#endif /* end freebsd section */
130233294Sstas
131233294Sstas
132233294Sstas
133233294Sstas/****************/
134233294Sstas/* *** BSDI *** */
135233294Sstas/****************/
136233294Sstas#ifdef __bsdi__
137233294Sstas#endif /* __bsdi__ */
138233294Sstas
139233294Sstas
140233294Sstas/**************************/
141233294Sstas/* *** OpenBSD/NetBSD *** */
142233294Sstas/**************************/
143233294Sstas#if defined(__NetBSD__) || defined(__OpenBSD__)
144233294Sstas
145233294Sstas#include <sys/param.h>
146233294Sstas#include <sys/systm.h>
147233294Sstas#include <sys/conf.h>
148233294Sstas#include <sys/uio.h>
149142403Snectar#include <sys/kernel.h>
150142403Snectar#include <sys/signalvar.h>
151142403Snectar#include <sys/mman.h>
152142403Snectar#include <sys/poll.h>
153142403Snectar#include <sys/select.h>
154127808Snectar#include <sys/vnode.h>
15555682Smarkm
15672445Sassar#include <vm/vm.h>
157127808Snectar
158233294Sstas#ifndef __NetBSD__
159233294Sstas#include <vm/vm_kern.h>
160127808Snectar#include <vm/pmap.h>
161127808Snectar#include <vm/vm_extern.h>
162127808Snectar#endif
16355682Smarkm
16455682Smarkm#include <sys/device.h>
165233294Sstas#include <dev/pci/pcivar.h>
166233294Sstas#include <dev/pci/pcireg.h>
16755682Smarkm#include <dev/pci/pcidevs.h>
16855682Smarkm
16955682Smarkm#define BKTR_DEBUG
170233294Sstas#ifdef BKTR_DEBUG
171127808Snectarint bktr_debug = 0;
17290926Snectar#define DPR(x)	(bktr_debug ? printf x : 0)
17372445Sassar#else
174127808Snectar#define DPR(x)
175127808Snectar#endif
176233294Sstas#endif /* __NetBSD__ || __OpenBSD__ */
17755682Smarkm
178127808Snectar
179233294Sstas#ifdef __NetBSD__
18090926Snectar#include <dev/ic/bt8xx.h>	/* NetBSD location for .h files */
181178825Sdfr#include <dev/pci/bktr/bktr_reg.h>
182178825Sdfr#include <dev/pci/bktr/bktr_tuner.h>
18372445Sassar#include <dev/pci/bktr/bktr_card.h>
184233294Sstas#include <dev/pci/bktr/bktr_audio.h>
185233294Sstas#include <dev/pci/bktr/bktr_core.h>
186233294Sstas#include <dev/pci/bktr/bktr_os.h>
187127808Snectar#else					/* Traditional location for .h files */
188127808Snectar#include <machine/ioctl_meteor.h>
189127808Snectar#include <machine/ioctl_bt848.h>	/* extensions to ioctl_meteor.h */
190127808Snectar#include <dev/bktr/bktr_reg.h>
191127808Snectar#include <dev/bktr/bktr_tuner.h>
192233294Sstas#include <dev/bktr/bktr_card.h>
193178825Sdfr#include <dev/bktr/bktr_audio.h>
19455682Smarkm#include <dev/bktr/bktr_core.h>
19572445Sassar#include <dev/bktr/bktr_os.h>
196178825Sdfr
197127808Snectar#if defined(BKTR_USE_FREEBSD_SMBUS)
198127808Snectar#include <dev/bktr/bktr_i2c.h>
199233294Sstas
200233294Sstas#include "iicbb_if.h"
201127808Snectar#include "smbus_if.h"
202127808Snectar#endif
203233294Sstas#endif
204178825Sdfr
205127808Snectar
206127808Snectar/****************************/
207127808Snectar/* *** FreeBSD 4.x code *** */
20890926Snectar/****************************/
209233294Sstas#if (__FreeBSD_version >= 400000)
210127808Snectar
211178825Sdfrstatic int	bktr_probe( device_t dev );
21255682Smarkmstatic int	bktr_attach( device_t dev );
213102644Snectarstatic int	bktr_detach( device_t dev );
214102644Snectarstatic int	bktr_shutdown( device_t dev );
215178825Sdfrstatic void	bktr_intr(void *arg) { common_bktr_intr(arg); }
216127808Snectar
217127808Snectarstatic device_method_t bktr_methods[] = {
21855682Smarkm	/* Device interface */
21955682Smarkm	DEVMETHOD(device_probe,         bktr_probe),
22090926Snectar	DEVMETHOD(device_attach,        bktr_attach),
221127808Snectar	DEVMETHOD(device_detach,        bktr_detach),
222127808Snectar	DEVMETHOD(device_shutdown,      bktr_shutdown),
223127808Snectar
224127808Snectar#if defined(BKTR_USE_FREEBSD_SMBUS)
225127808Snectar	/* iicbb interface */
22690926Snectar	DEVMETHOD(iicbb_callback,	bti2c_iic_callback),
22790926Snectar	DEVMETHOD(iicbb_setsda,		bti2c_iic_setsda),
22890926Snectar	DEVMETHOD(iicbb_setscl,		bti2c_iic_setscl),
229127808Snectar	DEVMETHOD(iicbb_getsda,		bti2c_iic_getsda),
230127808Snectar	DEVMETHOD(iicbb_getscl,		bti2c_iic_getscl),
231127808Snectar	DEVMETHOD(iicbb_reset,		bti2c_iic_reset),
232127808Snectar
233233294Sstas	/* smbus interface */
234127808Snectar	DEVMETHOD(smbus_callback,	bti2c_smb_callback),
235127808Snectar	DEVMETHOD(smbus_writeb,		bti2c_smb_writeb),
236233294Sstas	DEVMETHOD(smbus_writew,		bti2c_smb_writew),
237178825Sdfr	DEVMETHOD(smbus_readb,		bti2c_smb_readb),
238127808Snectar#endif
239127808Snectar
240127808Snectar	{ 0, 0 }
241127808Snectar};
242127808Snectar
243127808Snectarstatic driver_t bktr_driver = {
244127808Snectar	"bktr",
245127808Snectar	bktr_methods,
246178825Sdfr	sizeof(struct bktr_softc),
247178825Sdfr};
248178825Sdfr
249178825Sdfrstatic devclass_t bktr_devclass;
250127808Snectar
251127808Snectarstatic	d_open_t	bktr_open;
25255682Smarkmstatic	d_close_t	bktr_close;
253127808Snectarstatic	d_read_t	bktr_read;
254233294Sstasstatic	d_write_t	bktr_write;
255233294Sstasstatic	d_ioctl_t	bktr_ioctl;
256127808Snectarstatic	d_mmap_t	bktr_mmap;
257127808Snectarstatic	d_poll_t	bktr_poll;
258127808Snectar
259127808Snectar#define CDEV_MAJOR 92
260127808Snectarstatic struct cdevsw bktr_cdevsw = {
26155682Smarkm	.d_open =	bktr_open,
262127808Snectar	.d_close =	bktr_close,
263127808Snectar	.d_read =	bktr_read,
264178825Sdfr	.d_write =	bktr_write,
265127808Snectar	.d_ioctl =	bktr_ioctl,
266127808Snectar	.d_poll =	bktr_poll,
26755682Smarkm	.d_mmap =	bktr_mmap,
26855682Smarkm	.d_name =	"bktr",
269127808Snectar	.d_maj =	CDEV_MAJOR,
270127808Snectar};
271233294Sstas
272127808SnectarDRIVER_MODULE(bktr, pci, bktr_driver, bktr_devclass, 0, 0);
273127808Snectar#if (__FreeBSD_version > 410000)
274233294SstasMODULE_DEPEND(bktr, bktr_mem, 1,1,1);
27555682SmarkmMODULE_VERSION(bktr, 1);
27655682Smarkm#endif
277120945Snectar
278127808Snectar
279233294Sstas/*
280178825Sdfr * the boot time probe routine.
281233294Sstas */
282233294Sstasstatic int
283233294Sstasbktr_probe( device_t dev )
28455682Smarkm{
285233294Sstas	unsigned int type = pci_get_devid(dev);
286127808Snectar        unsigned int rev  = pci_get_revid(dev);
287233294Sstas
288233294Sstas	if (PCI_VENDOR(type) == PCI_VENDOR_BROOKTREE)
28955682Smarkm	{
290127808Snectar		switch (PCI_PRODUCT(type)) {
291127808Snectar		case PCI_PRODUCT_BROOKTREE_BT848:
292127808Snectar			if (rev == 0x12)
293127808Snectar				device_set_desc(dev, "BrookTree 848A");
294233294Sstas			else
295127808Snectar				device_set_desc(dev, "BrookTree 848");
296127808Snectar			return 0;
297233294Sstas		case PCI_PRODUCT_BROOKTREE_BT849:
298233294Sstas			device_set_desc(dev, "BrookTree 849A");
299233294Sstas			return 0;
300233294Sstas		case PCI_PRODUCT_BROOKTREE_BT878:
30155682Smarkm			device_set_desc(dev, "BrookTree 878");
302233294Sstas			return 0;
303127808Snectar		case PCI_PRODUCT_BROOKTREE_BT879:
304127808Snectar			device_set_desc(dev, "BrookTree 879");
305233294Sstas			return 0;
306233294Sstas		}
307102644Snectar	};
30855682Smarkm
309178825Sdfr        return ENXIO;
31055682Smarkm}
31155682Smarkm
31255682Smarkm
313178825Sdfr/*
31490926Snectar * the attach routine.
31590926Snectar */
31690926Snectarstatic int
31790926Snectarbktr_attach( device_t dev )
31855682Smarkm{
319178825Sdfr	u_long		latency;
320178825Sdfr	u_long		fun;
321178825Sdfr	u_long		val;
322178825Sdfr	unsigned int	rev;
323178825Sdfr	unsigned int	unit;
324233294Sstas	int		error = 0;
325127808Snectar#ifdef BROOKTREE_IRQ
326233294Sstas	u_long		old_irq, new_irq;
327233294Sstas#endif
328127808Snectar
329233294Sstas        struct bktr_softc *bktr = device_get_softc(dev);
330178825Sdfr
331178825Sdfr	unit = device_get_unit(dev);
332127808Snectar
333127808Snectar	/* build the device name for bktr_name() */
334127808Snectar	snprintf(bktr->bktr_xname, sizeof(bktr->bktr_xname), "bktr%d",unit);
335127808Snectar
336127808Snectar	/*
337127808Snectar	 * Enable bus mastering and Memory Mapped device
338178825Sdfr	 */
339127808Snectar	val = pci_read_config(dev, PCIR_COMMAND, 4);
340178825Sdfr	val |= (PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
341178825Sdfr	pci_write_config(dev, PCIR_COMMAND, val, 4);
342102644Snectar
343102644Snectar	/*
344102644Snectar	 * Map control/status registers.
345178825Sdfr	 */
346127808Snectar	bktr->mem_rid = PCIR_MAPS;
347127808Snectar	bktr->res_mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &bktr->mem_rid,
348127808Snectar					0, ~0, 1, RF_ACTIVE);
349127808Snectar
350127808Snectar
351127808Snectar	if (!bktr->res_mem) {
352178825Sdfr		device_printf(dev, "could not map memory\n");
353127808Snectar		error = ENXIO;
354127808Snectar		goto fail;
35572445Sassar	}
356127808Snectar	bktr->memt = rman_get_bustag(bktr->res_mem);
357127808Snectar	bktr->memh = rman_get_bushandle(bktr->res_mem);
358178825Sdfr
359127808Snectar
360127808Snectar	/*
361142403Snectar	 * Disable the brooktree device
362127808Snectar	 */
363178825Sdfr	OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
364127808Snectar	OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
365127808Snectar
366178825Sdfr
367127808Snectar#ifdef BROOKTREE_IRQ		/* from the configuration file */
368127808Snectar	old_irq = pci_conf_read(tag, PCI_INTERRUPT_REG);
369178825Sdfr	pci_conf_write(tag, PCI_INTERRUPT_REG, BROOKTREE_IRQ);
370233294Sstas	new_irq = pci_conf_read(tag, PCI_INTERRUPT_REG);
371127808Snectar	printf("bktr%d: attach: irq changed from %d to %d\n",
372127808Snectar		unit, (old_irq & 0xff), (new_irq & 0xff));
373233294Sstas#endif
374178825Sdfr
375178825Sdfr	/*
376233294Sstas	 * Allocate our interrupt.
377233294Sstas	 */
378233294Sstas	bktr->irq_rid = 0;
379102644Snectar	bktr->res_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &bktr->irq_rid,
38090926Snectar				0, ~0, 1, RF_SHAREABLE | RF_ACTIVE);
38172445Sassar	if (bktr->res_irq == NULL) {
38255682Smarkm		device_printf(dev, "could not map interrupt\n");
383233294Sstas		error = ENXIO;
38455682Smarkm		goto fail;
38555682Smarkm	}
38655682Smarkm
38755682Smarkm	error = bus_setup_intr(dev, bktr->res_irq, INTR_TYPE_TTY,
38855682Smarkm                               bktr_intr, bktr, &bktr->res_ih);
38955682Smarkm	if (error) {
390233294Sstas		device_printf(dev, "could not setup irq\n");
39155682Smarkm		goto fail;
392120945Snectar
39390926Snectar	}
39472445Sassar
39555682Smarkm
39690926Snectar	/* Update the Device Control Register */
397233294Sstas	/* on Bt878 and Bt879 cards           */
39890926Snectar	fun = pci_read_config( dev, 0x40, 2);
39955682Smarkm        fun = fun | 1;	/* Enable writes to the sub-system vendor ID */
400178825Sdfr
40190926Snectar#if defined( BKTR_430_FX_MODE )
40290926Snectar	if (bootverbose) printf("Using 430 FX chipset compatibilty mode\n");
40390926Snectar        fun = fun | 2;	/* Enable Intel 430 FX compatibility mode */
404233294Sstas#endif
40590926Snectar
40690926Snectar#if defined( BKTR_SIS_VIA_MODE )
407178825Sdfr	if (bootverbose) printf("Using SiS/VIA chipset compatibilty mode\n");
40890926Snectar        fun = fun | 4;	/* Enable SiS/VIA compatibility mode (usefull for
40990926Snectar                           OPTi chipset motherboards too */
41090926Snectar#endif
41190926Snectar	pci_write_config(dev, 0x40, fun, 2);
41255682Smarkm
413178825Sdfr#if defined(BKTR_USE_FREEBSD_SMBUS)
414178825Sdfr	if (bt848_i2c_attach(dev))
415178825Sdfr		printf("bktr%d: i2c_attach: can't attach\n", unit);
416178825Sdfr#endif
41772445Sassar
41872445Sassar/*
41972445Sassar * PCI latency timer.  32 is a good value for 4 bus mastering slots, if
420178825Sdfr * you have more than four, then 16 would probably be a better value.
42172445Sassar */
42272445Sassar#ifndef BROOKTREE_DEF_LATENCY_VALUE
42372445Sassar#define BROOKTREE_DEF_LATENCY_VALUE	10
42472445Sassar#endif
42555682Smarkm	latency = pci_read_config(dev, PCI_LATENCY_TIMER, 4);
426233294Sstas	latency = (latency >> 8) & 0xff;
42790926Snectar	if ( bootverbose ) {
42855682Smarkm		if (latency)
42955682Smarkm			printf("brooktree%d: PCI bus latency is", unit);
430233294Sstas		else
431142403Snectar			printf("brooktree%d: PCI bus latency was 0 changing to",
432142403Snectar				unit);
433142403Snectar	}
434142403Snectar	if ( !latency ) {
435233294Sstas		latency = BROOKTREE_DEF_LATENCY_VALUE;
436233294Sstas		pci_write_config(dev, PCI_LATENCY_TIMER, latency<<8, 4);
437142403Snectar	}
438142403Snectar	if ( bootverbose ) {
439142403Snectar		printf(" %d.\n", (int) latency);
440233294Sstas	}
441233294Sstas
442233294Sstas	/* read the pci device id and revision id */
443142403Snectar	fun = pci_get_devid(dev);
444142403Snectar        rev = pci_get_revid(dev);
445142403Snectar
446142403Snectar	/* call the common attach code */
447142403Snectar	common_bktr_attach( bktr, unit, fun, rev );
448142403Snectar
449142403Snectar	/* make the device entries */
450142403Snectar	bktr->bktrdev = make_dev(&bktr_cdevsw, unit,
451142403Snectar				0, 0, 0444, "bktr%d",  unit);
452142403Snectar	bktr->tunerdev= make_dev(&bktr_cdevsw, unit+16,
453142403Snectar				0, 0, 0444, "tuner%d", unit);
454142403Snectar	bktr->vbidev  = make_dev(&bktr_cdevsw, unit+32,
455142403Snectar				0, 0, 0444, "vbi%d"  , unit);
456142403Snectar
457142403Snectar
458142403Snectar	/* if this is unit 0 (/dev/bktr0, /dev/tuner0, /dev/vbi0) then make */
459142403Snectar	/* alias entries to /dev/bktr /dev/tuner and /dev/vbi */
460233294Sstas#if (__FreeBSD_version >=500000)
46155682Smarkm	if (unit == 0) {
46255682Smarkm		bktr->bktrdev_alias = make_dev_alias(bktr->bktrdev,  "bktr");
463178825Sdfr		bktr->tunerdev_alias= make_dev_alias(bktr->tunerdev, "tuner");
464233294Sstas		bktr->vbidev_alias  = make_dev_alias(bktr->vbidev,   "vbi");
465233294Sstas	}
466233294Sstas#endif
467233294Sstas
468233294Sstas	return 0;
469233294Sstas
470233294Sstasfail:
471233294Sstas	if (bktr->res_irq)
472233294Sstas		bus_release_resource(dev, SYS_RES_IRQ, bktr->irq_rid, bktr->res_irq);
473233294Sstas	if (bktr->res_mem)
474233294Sstas		bus_release_resource(dev, SYS_RES_IRQ, bktr->mem_rid, bktr->res_mem);
475233294Sstas	return error;
476233294Sstas
477233294Sstas}
478233294Sstas
479233294Sstas/*
480233294Sstas * the detach routine.
481233294Sstas */
482233294Sstasstatic int
483233294Sstasbktr_detach( device_t dev )
484233294Sstas{
48555682Smarkm	struct bktr_softc *bktr = device_get_softc(dev);
48655682Smarkm
48755682Smarkm#ifdef BKTR_NEW_MSP34XX_DRIVER
488233294Sstas	/* Disable the soundchip and kernel thread */
489233294Sstas	if (bktr->msp3400c_info != NULL)
490233294Sstas		msp_detach(bktr);
491233294Sstas#endif
492233294Sstas
493233294Sstas	/* Disable the brooktree device */
494233294Sstas	OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
49555682Smarkm	OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
49690926Snectar
497233294Sstas#if defined(BKTR_USE_FREEBSD_SMBUS)
498233294Sstas	if (bt848_i2c_detach(dev))
499233294Sstas		printf("bktr%d: i2c_attach: can't attach\n",
500233294Sstas		     device_get_unit(dev));
501233294Sstas#endif
502233294Sstas
503233294Sstas	/* Note: We do not free memory for RISC programs, grab buffer, vbi buffers */
50490926Snectar	/* The memory is retained by the bktr_mem module so we can unload and */
50590926Snectar	/* then reload the main bktr driver module */
506178825Sdfr
50790926Snectar	/* Unregister the /dev/bktrN, tunerN and vbiN devices,
50855682Smarkm	 * the aliases for unit 0 are automatically destroyed */
509142403Snectar	destroy_dev(bktr->vbidev);
51055682Smarkm	destroy_dev(bktr->tunerdev);
51155682Smarkm	destroy_dev(bktr->bktrdev);
51255682Smarkm
51355682Smarkm	/*
514233294Sstas	 * Deallocate resources.
515233294Sstas	 */
516233294Sstas	bus_teardown_intr(dev, bktr->res_irq, bktr->res_ih);
517233294Sstas	bus_release_resource(dev, SYS_RES_IRQ, bktr->irq_rid, bktr->res_irq);
518233294Sstas	bus_release_resource(dev, SYS_RES_MEMORY, bktr->mem_rid, bktr->res_mem);
519233294Sstas
520233294Sstas	return 0;
521233294Sstas}
522233294Sstas
523233294Sstas/*
524233294Sstas * the shutdown routine.
525233294Sstas */
52690926Snectarstatic int
527233294Sstasbktr_shutdown( device_t dev )
528233294Sstas{
529233294Sstas	struct bktr_softc *bktr = device_get_softc(dev);
530233294Sstas
531233294Sstas	/* Disable the brooktree device */
53255682Smarkm	OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
53372445Sassar	OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
534233294Sstas
535233294Sstas	return 0;
536233294Sstas}
537233294Sstas
538233294Sstas
53990926Snectar/*
54072445Sassar * Special Memory Allocation
541233294Sstas */
542233294Sstasvm_offset_t
543233294Sstasget_bktr_mem( int unit, unsigned size )
544233294Sstas{
545233294Sstas	vm_offset_t	addr = 0;
546102644Snectar
547102644Snectar	addr = vm_page_alloc_contig(size, 0, 0xffffffff, 1<<24);
548102644Snectar	if (addr == 0)
549102644Snectar		addr = vm_page_alloc_contig(size, 0, 0xffffffff, PAGE_SIZE);
550102644Snectar	if (addr == 0) {
551102644Snectar		printf("bktr%d: Unable to allocate %d bytes of memory.\n",
552233294Sstas			unit, size);
55390926Snectar	}
554178825Sdfr
555233294Sstas	return( addr );
556233294Sstas}
557233294Sstas
558233294Sstas
559233294Sstas/*---------------------------------------------------------
560233294Sstas**
561233294Sstas**	BrookTree 848 character device driver routines
562233294Sstas**
563233294Sstas**---------------------------------------------------------
564233294Sstas*/
565233294Sstas
566233294Sstas#define VIDEO_DEV	0x00
567233294Sstas#define TUNER_DEV	0x01
568233294Sstas#define VBI_DEV		0x02
569233294Sstas
570233294Sstas#define UNIT(x)		((x) & 0x0f)
57155682Smarkm#define FUNCTION(x)	(x >> 4)
572233294Sstas
573233294Sstas/*
574233294Sstas *
575233294Sstas */
576233294Sstasstatic int
577233294Sstasbktr_open( dev_t dev, int flags, int fmt, struct thread *td )
578233294Sstas{
57955682Smarkm	bktr_ptr_t	bktr;
58090926Snectar	int		unit;
581233294Sstas	int		result;
582233294Sstas
583233294Sstas	unit = UNIT( minor(dev) );
584233294Sstas
585233294Sstas	/* Get the device data */
586233294Sstas	bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
587233294Sstas	if (bktr == NULL) {
588233294Sstas		/* the device is no longer valid/functioning */
589233294Sstas		return (ENXIO);
59055682Smarkm	}
59172445Sassar
592102644Snectar	if (!(bktr->flags & METEOR_INITALIZED)) /* device not found */
59372445Sassar		return( ENXIO );
59472445Sassar
59572445Sassar	/* Record that the device is now busy */
596233294Sstas	device_busy(devclass_get_device(bktr_devclass, unit));
597233294Sstas
598102644Snectar
599142403Snectar	if (bt848_card != -1) {
60055682Smarkm	  if ((bt848_card >> 8   == unit ) &&
60172445Sassar	     ( (bt848_card & 0xff) < Bt848_MAX_CARD )) {
60272445Sassar	    if ( bktr->bt848_card != (bt848_card & 0xff) ) {
603233294Sstas	      bktr->bt848_card = (bt848_card & 0xff);
60455682Smarkm	      probeCard(bktr, FALSE, unit);
605102644Snectar	    }
60672445Sassar	  }
60772445Sassar	}
60872445Sassar
609233294Sstas	if (bt848_tuner != -1) {
610233294Sstas	  if ((bt848_tuner >> 8   == unit ) &&
611233294Sstas	     ( (bt848_tuner & 0xff) < Bt848_MAX_TUNER )) {
612233294Sstas	    if ( bktr->bt848_tuner != (bt848_tuner & 0xff) ) {
613178825Sdfr	      bktr->bt848_tuner = (bt848_tuner & 0xff);
614233294Sstas	      probeCard(bktr, FALSE, unit);
615233294Sstas	    }
616233294Sstas	  }
617233294Sstas	}
618233294Sstas
619233294Sstas	if (bt848_reverse_mute != -1) {
620233294Sstas	  if ((bt848_reverse_mute >> 8)   == unit ) {
621178825Sdfr	    bktr->reverse_mute = bt848_reverse_mute & 0xff;
622127808Snectar	  }
623127808Snectar	}
624127808Snectar
625127808Snectar	if (bt848_slow_msp_audio != -1) {
626127808Snectar	  if ((bt848_slow_msp_audio >> 8) == unit ) {
627127808Snectar	      bktr->slow_msp_audio = (bt848_slow_msp_audio & 0xff);
628127808Snectar	  }
629233294Sstas	}
630233294Sstas
631233294Sstas#ifdef BKTR_NEW_MSP34XX_DRIVER
632127808Snectar	if (bt848_stereo_once != 0) {
633233294Sstas	  if ((bt848_stereo_once >> 8) == unit ) {
634127808Snectar	      bktr->stereo_once = (bt848_stereo_once & 0xff);
63578527Sassar	  }
636102644Snectar	}
637233294Sstas
638233294Sstas	if (bt848_amsound != -1) {
63978527Sassar	  if ((bt848_amsound >> 8) == unit ) {
64055682Smarkm	      bktr->amsound = (bt848_amsound & 0xff);
641127808Snectar	  }
64255682Smarkm	}
64355682Smarkm
644233294Sstas	if (bt848_dolby != -1) {
645233294Sstas	  if ((bt848_dolby >> 8) == unit ) {
646233294Sstas	      bktr->dolby = (bt848_dolby & 0xff);
647233294Sstas	  }
648233294Sstas	}
649233294Sstas#endif
650233294Sstas
651233294Sstas	switch ( FUNCTION( minor(dev) ) ) {
652233294Sstas	case VIDEO_DEV:
653233294Sstas		result = video_open( bktr );
654233294Sstas		break;
655233294Sstas	case TUNER_DEV:
656233294Sstas		result = tuner_open( bktr );
657178825Sdfr		break;
658178825Sdfr	case VBI_DEV:
659178825Sdfr		result = vbi_open( bktr );
660178825Sdfr		break;
661178825Sdfr	default:
662178825Sdfr		result = ENXIO;
663178825Sdfr		break;
664178825Sdfr	}
665178825Sdfr
666178825Sdfr	/* If there was an error opening the device, undo the busy status */
667178825Sdfr	if (result != 0)
668178825Sdfr		device_unbusy(devclass_get_device(bktr_devclass, unit));
669102644Snectar	return( result );
67055682Smarkm}
671178825Sdfr
672233294Sstas
673233294Sstas/*
674233294Sstas *
675102644Snectar */
676233294Sstasstatic int
677233294Sstasbktr_close( dev_t dev, int flags, int fmt, struct thread *td )
678102644Snectar{
679233294Sstas	bktr_ptr_t	bktr;
68055682Smarkm	int		unit;
681233294Sstas	int		result;
682233294Sstas
68372445Sassar	unit = UNIT( minor(dev) );
68455682Smarkm
68555682Smarkm	/* Get the device data */
68690926Snectar	bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
687127808Snectar	if (bktr == NULL) {
68890926Snectar		/* the device is no longer valid/functioning */
68955682Smarkm		return (ENXIO);
69055682Smarkm	}
69155682Smarkm
69290926Snectar	switch ( FUNCTION( minor(dev) ) ) {
69390926Snectar	case VIDEO_DEV:
694142403Snectar		result = video_close( bktr );
695178825Sdfr		break;
696142403Snectar	case TUNER_DEV:
69790926Snectar		result = tuner_close( bktr );
69855682Smarkm		break;
69955682Smarkm	case VBI_DEV:
70090926Snectar		result = vbi_close( bktr );
70155682Smarkm		break;
70255682Smarkm	default:
70355682Smarkm		return (ENXIO);
70490926Snectar		break;
70590926Snectar	}
70655682Smarkm
70790926Snectar	device_unbusy(devclass_get_device(bktr_devclass, unit));
708127808Snectar	return( result );
70990926Snectar}
71090926Snectar
71155682Smarkm
71255682Smarkm/*
71355682Smarkm *
714178825Sdfr */
71555682Smarkmstatic int
71655682Smarkmbktr_read( dev_t dev, struct uio *uio, int ioflag )
717178825Sdfr{
718233294Sstas	bktr_ptr_t	bktr;
71955682Smarkm	int		unit;
72055682Smarkm
72190926Snectar	unit = UNIT(minor(dev));
72290926Snectar
72390926Snectar	/* Get the device data */
72455682Smarkm	bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
725142403Snectar	if (bktr == NULL) {
726142403Snectar		/* the device is no longer valid/functioning */
72755682Smarkm		return (ENXIO);
72890926Snectar	}
729233294Sstas
730127808Snectar	switch ( FUNCTION( minor(dev) ) ) {
73190926Snectar	case VIDEO_DEV:
732178825Sdfr		return( video_read( bktr, unit, dev, uio ) );
73355682Smarkm	case VBI_DEV:
73490926Snectar		return( vbi_read( bktr, uio, ioflag ) );
73555682Smarkm	}
73690926Snectar        return( ENXIO );
73755682Smarkm}
738142403Snectar
739142403Snectar
740233294Sstas/*
741233294Sstas *
74290926Snectar */
74355682Smarkmstatic int
74490926Snectarbktr_write( dev_t dev, struct uio *uio, int ioflag )
74590926Snectar{
746120945Snectar	return( EINVAL ); /* XXX or ENXIO ? */
747120945Snectar}
748120945Snectar
749178825Sdfr
750178825Sdfr/*
751233294Sstas *
752233294Sstas */
75390926Snectarstatic int
75490926Snectarbktr_ioctl( dev_t dev, ioctl_cmd_t cmd, caddr_t arg, int flag, struct thread *td )
75590926Snectar{
756178825Sdfr	bktr_ptr_t	bktr;
757178825Sdfr	int		unit;
758233294Sstas
759233294Sstas	unit = UNIT(minor(dev));
76090926Snectar
76190926Snectar	/* Get the device data */
762233294Sstas	bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
763233294Sstas	if (bktr == NULL) {
76490926Snectar		/* the device is no longer valid/functioning */
76590926Snectar		return (ENXIO);
766178825Sdfr	}
767178825Sdfr
768233294Sstas	if (bktr->bigbuf == 0)	/* no frame buffer allocated (ioctl failed) */
769233294Sstas		return( ENOMEM );
770178825Sdfr
771178825Sdfr	switch ( FUNCTION( minor(dev) ) ) {
772233294Sstas	case VIDEO_DEV:
773233294Sstas		return( video_ioctl( bktr, unit, cmd, arg, td ) );
77490926Snectar	case TUNER_DEV:
77590926Snectar		return( tuner_ioctl( bktr, unit, cmd, arg, td ) );
77655682Smarkm	}
777233294Sstas
778127808Snectar	return( ENXIO );
77990926Snectar}
78055682Smarkm
78190926Snectar
78255682Smarkm/*
78390926Snectar *
78490926Snectar */
78590926Snectarstatic int
786127808Snectarbktr_mmap( dev_t dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot )
787127808Snectar{
788127808Snectar	int		unit;
789127808Snectar	bktr_ptr_t	bktr;
790127808Snectar
791127808Snectar	unit = UNIT(minor(dev));
792127808Snectar
793127808Snectar	if (FUNCTION(minor(dev)) > 0)	/* only allow mmap on /dev/bktr[n] */
794178825Sdfr		return( -1 );
795178825Sdfr
796178825Sdfr	/* Get the device data */
79790926Snectar	bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
79890926Snectar	if (bktr == NULL) {
799233294Sstas		/* the device is no longer valid/functioning */
800233294Sstas		return (ENXIO);
801178825Sdfr	}
802127808Snectar
803127808Snectar	if (nprot & PROT_EXEC)
804178825Sdfr		return( -1 );
805142403Snectar
806142403Snectar	if (offset < 0)
807178825Sdfr		return( -1 );
808178825Sdfr
809178825Sdfr	if (offset >= bktr->alloc_pages * PAGE_SIZE)
810178825Sdfr		return( -1 );
811178825Sdfr
812178825Sdfr	*paddr = vtophys(bktr->bigbuf) + offset;
813178825Sdfr	return( 0 );
814178825Sdfr}
815178825Sdfr
816178825Sdfrstatic int
81790926Snectarbktr_poll( dev_t dev, int events, struct thread *td)
81890926Snectar{
81955682Smarkm	int		unit;
82055682Smarkm	bktr_ptr_t	bktr;
82155682Smarkm	int revents = 0;
82255682Smarkm	DECLARE_INTR_MASK(s);
82355682Smarkm
82472445Sassar	unit = UNIT(minor(dev));
82572445Sassar
82672445Sassar	/* Get the device data */
82772445Sassar	bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
82855682Smarkm	if (bktr == NULL) {
82955682Smarkm		/* the device is no longer valid/functioning */
83055682Smarkm		return (ENXIO);
831178825Sdfr	}
832178825Sdfr
83355682Smarkm	DISABLE_INTR(s);
83455682Smarkm
83555682Smarkm	if (events & (POLLIN | POLLRDNORM)) {
83655682Smarkm
83755682Smarkm		switch ( FUNCTION( minor(dev) ) ) {
83855682Smarkm		case VBI_DEV:
83972445Sassar			if(bktr->vbisize == 0)
84072445Sassar				selrecord(td, &bktr->vbi_select);
84155682Smarkm			else
842178825Sdfr				revents |= events & (POLLIN | POLLRDNORM);
843178825Sdfr			break;
844178825Sdfr		}
845178825Sdfr	}
846178825Sdfr
847178825Sdfr	ENABLE_INTR(s);
848178825Sdfr
849178825Sdfr	return (revents);
850178825Sdfr}
851178825Sdfr
852178825Sdfr#endif		/* FreeBSD 4.x specific kernel interface routines */
85355682Smarkm
85455682Smarkm/*****************/
85555682Smarkm/* *** BSDI  *** */
856102644Snectar/*****************/
857102644Snectar
858178825Sdfr#if defined(__bsdi__)
859178825Sdfr#endif		/* __bsdi__ BSDI specific kernel interface routines */
860102644Snectar
861102644Snectar
862102644Snectar/*****************************/
863102644Snectar/* *** OpenBSD / NetBSD  *** */
864102644Snectar/*****************************/
865102644Snectar#if defined(__NetBSD__) || defined(__OpenBSD__)
866178825Sdfr
867102644Snectar#define IPL_VIDEO       IPL_BIO         /* XXX */
868102644Snectar
869102644Snectarstatic	int		bktr_intr(void *arg) { return common_bktr_intr(arg); }
870102644Snectar
871102644Snectar#define bktr_open       bktropen
872102644Snectar#define bktr_close      bktrclose
873102644Snectar#define bktr_read       bktrread
874102644Snectar#define bktr_write      bktrwrite
875102644Snectar#define bktr_ioctl      bktrioctl
876102644Snectar#define bktr_mmap       bktrmmap
877102644Snectar
878102644Snectarvm_offset_t vm_page_alloc_contig(vm_offset_t, vm_offset_t,
879102644Snectar                                 vm_offset_t, vm_offset_t);
880102644Snectar
881102644Snectar#if defined(__OpenBSD__)
882178825Sdfrstatic int      bktr_probe(struct device *, void *, void *);
883102644Snectar#else
884102644Snectarstatic int      bktr_probe(struct device *, struct cfdata *, void *);
885102644Snectar#endif
886102644Snectarstatic void     bktr_attach(struct device *, struct device *, void *);
887233294Sstas
888233294Sstasstruct cfattach bktr_ca = {
889233294Sstas        sizeof(struct bktr_softc), bktr_probe, bktr_attach
89055682Smarkm};
89155682Smarkm
89255682Smarkm#if defined(__NetBSD__)
89355682Smarkmextern struct cfdriver bktr_cd;
89455682Smarkm#else
89555682Smarkmstruct cfdriver bktr_cd = {
89655682Smarkm        NULL, "bktr", DV_DULL
89755682Smarkm};
89855682Smarkm#endif
89955682Smarkm
90055682Smarkmint
90155682Smarkmbktr_probe(parent, match, aux)
90255682Smarkm	struct device *parent;
90355682Smarkm#if defined(__OpenBSD__)
90455682Smarkm        void *match;
90555682Smarkm#else
90655682Smarkm        struct cfdata *match;
90755682Smarkm#endif
90855682Smarkm        void *aux;
90955682Smarkm{
91055682Smarkm        struct pci_attach_args *pa = aux;
91155682Smarkm
91255682Smarkm        if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_BROOKTREE &&
91355682Smarkm            (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROOKTREE_BT848 ||
91455682Smarkm             PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROOKTREE_BT849 ||
91555682Smarkm             PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROOKTREE_BT878 ||
91655682Smarkm             PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROOKTREE_BT879))
91755682Smarkm                return 1;
91855682Smarkm
91955682Smarkm        return 0;
92055682Smarkm}
92155682Smarkm
92255682Smarkm
92355682Smarkm/*
92455682Smarkm * the attach routine.
92555682Smarkm */
92655682Smarkmstatic void
92755682Smarkmbktr_attach(struct device *parent, struct device *self, void *aux)
92855682Smarkm{
92955682Smarkm	bktr_ptr_t	bktr;
93055682Smarkm	u_long		latency;
93155682Smarkm	u_long		fun;
93255682Smarkm	unsigned int	rev;
93355682Smarkm
93455682Smarkm#if defined(__OpenBSD__)
93555682Smarkm	struct pci_attach_args *pa = aux;
93655682Smarkm	pci_chipset_tag_t pc = pa->pa_pc;
93755682Smarkm
93855682Smarkm	pci_intr_handle_t ih;
93955682Smarkm	const char *intrstr;
94055682Smarkm	int retval;
94155682Smarkm	int unit;
94255682Smarkm
94355682Smarkm	bktr = (bktr_ptr_t)self;
94455682Smarkm	unit = bktr->bktr_dev.dv_unit;
94555682Smarkm
94655682Smarkm	bktr->pc = pa->pa_pc;
94755682Smarkm	bktr->tag = pa->pa_tag;
94855682Smarkm        bktr->dmat = pa->pa_dmat;
94955682Smarkm
95055682Smarkm	/*
95155682Smarkm	 * map memory
95255682Smarkm	 */
95355682Smarkm	bktr->memt = pa->pa_memt;
95472445Sassar	retval = pci_mem_find(pc, pa->pa_tag, PCI_MAPREG_START,
955178825Sdfr			      &bktr->phys_base, &bktr->obmemsz, NULL);
95655682Smarkm	if (!retval)
957178825Sdfr		retval = bus_space_map(pa->pa_memt, bktr->phys_base,
958178825Sdfr				       bktr->obmemsz, 0, &bktr->memh);
959178825Sdfr	if (retval) {
960120945Snectar		printf(": couldn't map memory\n");
961178825Sdfr		return;
96255682Smarkm	}
96355682Smarkm
96455682Smarkm
96555682Smarkm	/*
96655682Smarkm	 * map interrupt
967178825Sdfr	 */
968178825Sdfr	if (pci_intr_map(pa->pa_pc, pa->pa_intrtag, pa->pa_intrpin,
969178825Sdfr			 pa->pa_intrline, &ih)) {
970178825Sdfr		printf(": couldn't map interrupt\n");
971178825Sdfr		return;
972178825Sdfr	}
973178825Sdfr	intrstr = pci_intr_string(pa->pa_pc, ih);
974178825Sdfr
975233294Sstas	bktr->ih = pci_intr_establish(pa->pa_pc, ih, IPL_VIDEO,
976178825Sdfr				      bktr_intr, bktr, bktr->bktr_dev.dv_xname);
977178825Sdfr	if (bktr->ih == NULL) {
978178825Sdfr		printf(": couldn't establish interrupt");
979178825Sdfr		if (intrstr != NULL)
980178825Sdfr			printf(" at %s", intrstr);
981178825Sdfr		printf("\n");
982178825Sdfr		return;
983178825Sdfr	}
984178825Sdfr
985178825Sdfr	if (intrstr != NULL)
986178825Sdfr		printf(": %s\n", intrstr);
987178825Sdfr#endif /* __OpenBSD__ */
988178825Sdfr
989178825Sdfr#if defined(__NetBSD__)
990178825Sdfr	struct pci_attach_args *pa = aux;
991178825Sdfr	pci_intr_handle_t ih;
992178825Sdfr	const char *intrstr;
993233294Sstas	int retval;
99455682Smarkm	int unit;
99555682Smarkm
99655682Smarkm	bktr = (bktr_ptr_t)self;
997	unit = bktr->bktr_dev.dv_unit;
998        bktr->dmat = pa->pa_dmat;
999
1000	printf("\n");
1001
1002	/*
1003	 * map memory
1004	 */
1005	retval = pci_mapreg_map(pa, PCI_MAPREG_START,
1006				PCI_MAPREG_TYPE_MEM
1007				| PCI_MAPREG_MEM_TYPE_32BIT, 0,
1008				&bktr->memt, &bktr->memh, NULL,
1009				&bktr->obmemsz);
1010	DPR(("pci_mapreg_map: memt %x, memh %x, size %x\n",
1011	     bktr->memt, (u_int)bktr->memh, (u_int)bktr->obmemsz));
1012	if (retval) {
1013		printf("%s: couldn't map memory\n", bktr_name(bktr));
1014		return;
1015	}
1016
1017	/*
1018	 * Disable the brooktree device
1019	 */
1020	OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
1021	OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
1022
1023	/*
1024	 * map interrupt
1025	 */
1026	if (pci_intr_map(pa->pa_pc, pa->pa_intrtag, pa->pa_intrpin,
1027			 pa->pa_intrline, &ih)) {
1028		printf("%s: couldn't map interrupt\n",
1029		       bktr_name(bktr));
1030		return;
1031	}
1032	intrstr = pci_intr_string(pa->pa_pc, ih);
1033	bktr->ih = pci_intr_establish(pa->pa_pc, ih, IPL_VIDEO,
1034				      bktr_intr, bktr);
1035	if (bktr->ih == NULL) {
1036		printf("%s: couldn't establish interrupt",
1037		       bktr_name(bktr));
1038		if (intrstr != NULL)
1039			printf(" at %s", intrstr);
1040		printf("\n");
1041		return;
1042	}
1043	if (intrstr != NULL)
1044		printf("%s: interrupting at %s\n", bktr_name(bktr),
1045		       intrstr);
1046#endif /* __NetBSD__ */
1047
1048/*
1049 * PCI latency timer.  32 is a good value for 4 bus mastering slots, if
1050 * you have more than four, then 16 would probably be a better value.
1051 */
1052#ifndef BROOKTREE_DEF_LATENCY_VALUE
1053#define BROOKTREE_DEF_LATENCY_VALUE	10
1054#endif
1055	latency = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_LATENCY_TIMER);
1056	latency = (latency >> 8) & 0xff;
1057
1058	if (!latency) {
1059		if (bootverbose) {
1060			printf("%s: PCI bus latency was 0 changing to %d",
1061			       bktr_name(bktr), BROOKTREE_DEF_LATENCY_VALUE);
1062		}
1063		latency = BROOKTREE_DEF_LATENCY_VALUE;
1064		pci_conf_write(pa->pa_pc, pa->pa_tag,
1065			       PCI_LATENCY_TIMER, latency<<8);
1066	}
1067
1068
1069	/* Enabled Bus Master
1070	   XXX: check if all old DMA is stopped first (e.g. after warm
1071	   boot) */
1072	fun = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
1073	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
1074		       fun | PCI_COMMAND_MASTER_ENABLE);
1075
1076	/* read the pci id and determine the card type */
1077	fun = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ID_REG);
1078        rev = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_CLASS_REG) & 0x000000ff;
1079
1080	common_bktr_attach(bktr, unit, fun, rev);
1081}
1082
1083
1084/*
1085 * Special Memory Allocation
1086 */
1087vm_offset_t
1088get_bktr_mem(bktr, dmapp, size)
1089        bktr_ptr_t bktr;
1090        bus_dmamap_t *dmapp;
1091        unsigned int size;
1092{
1093        bus_dma_tag_t dmat = bktr->dmat;
1094        bus_dma_segment_t seg;
1095        bus_size_t align;
1096        int rseg;
1097        caddr_t kva;
1098
1099        /*
1100         * Allocate a DMA area
1101         */
1102        align = 1 << 24;
1103        if (bus_dmamem_alloc(dmat, size, align, 0, &seg, 1,
1104                             &rseg, BUS_DMA_NOWAIT)) {
1105                align = PAGE_SIZE;
1106                if (bus_dmamem_alloc(dmat, size, align, 0, &seg, 1,
1107                                     &rseg, BUS_DMA_NOWAIT)) {
1108                        printf("%s: Unable to dmamem_alloc of %d bytes\n",
1109			       bktr_name(bktr), size);
1110                        return 0;
1111                }
1112        }
1113        if (bus_dmamem_map(dmat, &seg, rseg, size,
1114                           &kva, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) {
1115                printf("%s: Unable to dmamem_map of %d bytes\n",
1116                        bktr_name(bktr), size);
1117                bus_dmamem_free(dmat, &seg, rseg);
1118                return 0;
1119        }
1120#ifdef __OpenBSD__
1121        bktr->dm_mapsize = size;
1122#endif
1123        /*
1124         * Create and locd the DMA map for the DMA area
1125         */
1126        if (bus_dmamap_create(dmat, size, 1, size, 0, BUS_DMA_NOWAIT, dmapp)) {
1127                printf("%s: Unable to dmamap_create of %d bytes\n",
1128                        bktr_name(bktr), size);
1129                bus_dmamem_unmap(dmat, kva, size);
1130                bus_dmamem_free(dmat, &seg, rseg);
1131                return 0;
1132        }
1133        if (bus_dmamap_load(dmat, *dmapp, kva, size, NULL, BUS_DMA_NOWAIT)) {
1134                printf("%s: Unable to dmamap_load of %d bytes\n",
1135                        bktr_name(bktr), size);
1136                bus_dmamem_unmap(dmat, kva, size);
1137                bus_dmamem_free(dmat, &seg, rseg);
1138                bus_dmamap_destroy(dmat, *dmapp);
1139                return 0;
1140        }
1141        return (vm_offset_t)kva;
1142}
1143
1144void
1145free_bktr_mem(bktr, dmap, kva)
1146        bktr_ptr_t bktr;
1147        bus_dmamap_t dmap;
1148        vm_offset_t kva;
1149{
1150        bus_dma_tag_t dmat = bktr->dmat;
1151
1152#ifdef __NetBSD__
1153        bus_dmamem_unmap(dmat, (caddr_t)kva, dmap->dm_mapsize);
1154#else
1155        bus_dmamem_unmap(dmat, (caddr_t)kva, bktr->dm_mapsize);
1156#endif
1157        bus_dmamem_free(dmat, dmap->dm_segs, 1);
1158        bus_dmamap_destroy(dmat, dmap);
1159}
1160
1161
1162/*---------------------------------------------------------
1163**
1164**	BrookTree 848 character device driver routines
1165**
1166**---------------------------------------------------------
1167*/
1168
1169
1170#define VIDEO_DEV	0x00
1171#define TUNER_DEV	0x01
1172#define VBI_DEV		0x02
1173
1174#define UNIT(x)         (minor((x) & 0x0f))
1175#define FUNCTION(x)     (minor((x >> 4) & 0x0f))
1176
1177/*
1178 *
1179 */
1180int
1181bktr_open(dev_t dev, int flags, int fmt, struct thread *td)
1182{
1183	bktr_ptr_t	bktr;
1184	int		unit;
1185
1186	unit = UNIT(dev);
1187
1188	/* unit out of range */
1189	if ((unit > bktr_cd.cd_ndevs) || (bktr_cd.cd_devs[unit] == NULL))
1190		return(ENXIO);
1191
1192	bktr = bktr_cd.cd_devs[unit];
1193
1194	if (!(bktr->flags & METEOR_INITALIZED)) /* device not found */
1195		return(ENXIO);
1196
1197	switch (FUNCTION(dev)) {
1198	case VIDEO_DEV:
1199		return(video_open(bktr));
1200	case TUNER_DEV:
1201		return(tuner_open(bktr));
1202	case VBI_DEV:
1203		return(vbi_open(bktr));
1204	}
1205
1206	return(ENXIO);
1207}
1208
1209
1210/*
1211 *
1212 */
1213int
1214bktr_close(dev_t dev, int flags, int fmt, struct thread *td)
1215{
1216	bktr_ptr_t	bktr;
1217	int		unit;
1218
1219	unit = UNIT(dev);
1220
1221	bktr = bktr_cd.cd_devs[unit];
1222
1223	switch (FUNCTION(dev)) {
1224	case VIDEO_DEV:
1225		return(video_close(bktr));
1226	case TUNER_DEV:
1227		return(tuner_close(bktr));
1228	case VBI_DEV:
1229		return(vbi_close(bktr));
1230	}
1231
1232	return(ENXIO);
1233}
1234
1235/*
1236 *
1237 */
1238int
1239bktr_read(dev_t dev, struct uio *uio, int ioflag)
1240{
1241	bktr_ptr_t	bktr;
1242	int		unit;
1243
1244	unit = UNIT(dev);
1245
1246	bktr = bktr_cd.cd_devs[unit];
1247
1248	switch (FUNCTION(dev)) {
1249	case VIDEO_DEV:
1250		return(video_read(bktr, unit, dev, uio));
1251	case VBI_DEV:
1252		return(vbi_read(bktr, uio, ioflag));
1253	}
1254
1255        return(ENXIO);
1256}
1257
1258
1259/*
1260 *
1261 */
1262int
1263bktr_write(dev_t dev, struct uio *uio, int ioflag)
1264{
1265	/* operation not supported */
1266	return(EOPNOTSUPP);
1267}
1268
1269/*
1270 *
1271 */
1272int
1273bktr_ioctl(dev_t dev, ioctl_cmd_t cmd, caddr_t arg, int flag, struct thread *td)
1274{
1275	bktr_ptr_t	bktr;
1276	int		unit;
1277
1278	unit = UNIT(dev);
1279
1280	bktr = bktr_cd.cd_devs[unit];
1281
1282	if (bktr->bigbuf == 0)	/* no frame buffer allocated (ioctl failed) */
1283		return(ENOMEM);
1284
1285	switch (FUNCTION(dev)) {
1286	case VIDEO_DEV:
1287		return(video_ioctl(bktr, unit, cmd, arg, pr));
1288	case TUNER_DEV:
1289		return(tuner_ioctl(bktr, unit, cmd, arg, pr));
1290	}
1291
1292	return(ENXIO);
1293}
1294
1295/*
1296 *
1297 */
1298paddr_t
1299bktr_mmap(dev_t dev, off_t offset, int nprot)
1300{
1301	int		unit;
1302	bktr_ptr_t	bktr;
1303
1304	unit = UNIT(dev);
1305
1306	if (FUNCTION(dev) > 0)	/* only allow mmap on /dev/bktr[n] */
1307		return(-1);
1308
1309	bktr = bktr_cd.cd_devs[unit];
1310
1311	if ((vaddr_t)offset < 0)
1312		return(-1);
1313
1314	if ((vaddr_t)offset >= bktr->alloc_pages * PAGE_SIZE)
1315		return(-1);
1316
1317#ifdef __NetBSD__
1318	return (bus_dmamem_mmap(bktr->dmat, bktr->dm_mem->dm_segs, 1,
1319				(vaddr_t)offset, nprot, BUS_DMA_WAITOK));
1320#else
1321	return(i386_btop(vtophys(bktr->bigbuf) + offset));
1322#endif
1323}
1324
1325#endif /* __NetBSD__ || __OpenBSD__ */
1326