bktr_os.c revision 256281
11573Srgrimes/*-
21573Srgrimes * 1. Redistributions of source code must retain the
31573Srgrimes * Copyright (c) 1997 Amancio Hasty, 1999 Roger Hardiman
41573Srgrimes * All rights reserved.
51573Srgrimes *
61573Srgrimes * Redistribution and use in source and binary forms, with or without
71573Srgrimes * modification, are permitted provided that the following conditions
81573Srgrimes * are met:
91573Srgrimes * 1. Redistributions of source code must retain the above copyright
101573Srgrimes *    notice, this list of conditions and the following disclaimer.
111573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
121573Srgrimes *    notice, this list of conditions and the following disclaimer in the
131573Srgrimes *    documentation and/or other materials provided with the distribution.
141573Srgrimes * 3. All advertising materials mentioning features or use of this software
151573Srgrimes *    must display the following acknowledgement:
161573Srgrimes *	This product includes software developed by Amancio Hasty and
171573Srgrimes *      Roger Hardiman
181573Srgrimes * 4. The name of the author may not be used to endorse or promote products
191573Srgrimes *    derived from this software without specific prior written permission.
201573Srgrimes *
211573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
221573Srgrimes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
231573Srgrimes * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
241573Srgrimes * DISCLAIMED.	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
251573Srgrimes * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
261573Srgrimes * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
271573Srgrimes * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
291573Srgrimes * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
301573Srgrimes * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
311573Srgrimes * POSSIBILITY OF SUCH DAMAGE.
321573Srgrimes */
331573Srgrimes
341573Srgrimes#include <sys/cdefs.h>
351573Srgrimes__FBSDID("$FreeBSD: stable/10/sys/dev/bktr/bktr_os.c 254263 2013-08-12 23:30:01Z scottl $");
361573Srgrimes
371573Srgrimes/*
381573Srgrimes * This is part of the Driver for Video Capture Cards (Frame grabbers)
391573Srgrimes * and TV Tuner cards using the Brooktree Bt848, Bt848A, Bt849A, Bt878, Bt879
401573Srgrimes * chipset.
411573Srgrimes * Copyright Roger Hardiman and Amancio Hasty.
421573Srgrimes *
431573Srgrimes * bktr_os : This has all the Operating System dependant code,
441573Srgrimes *             probe/attach and open/close/ioctl/read/mmap
451573Srgrimes *             memory allocation
461573Srgrimes *             PCI bus interfacing
471573Srgrimes */
481573Srgrimes
491573Srgrimes#include "opt_bktr.h"		/* include any kernel config options */
501573Srgrimes
511573Srgrimes#define FIFO_RISC_DISABLED      0
521573Srgrimes#define ALL_INTS_DISABLED       0
531573Srgrimes
541573Srgrimes
551573Srgrimes/*******************/
561573Srgrimes/* *** FreeBSD *** */
571573Srgrimes/*******************/
581573Srgrimes#ifdef __FreeBSD__
591573Srgrimes
601573Srgrimes#include <sys/param.h>
611573Srgrimes#include <sys/systm.h>
621573Srgrimes#include <sys/conf.h>
631573Srgrimes#include <sys/uio.h>
641573Srgrimes#include <sys/kernel.h>
651573Srgrimes#include <sys/module.h>
661573Srgrimes#include <sys/signalvar.h>
671573Srgrimes#include <sys/malloc.h>
681573Srgrimes#include <sys/mman.h>
691573Srgrimes#include <sys/poll.h>
701573Srgrimes#if __FreeBSD_version >= 500014
711573Srgrimes#include <sys/selinfo.h>
721573Srgrimes#else
731573Srgrimes#include <sys/select.h>
741573Srgrimes#endif
751573Srgrimes
761573Srgrimes#include <vm/vm.h>
771573Srgrimes#include <vm/vm_kern.h>
781573Srgrimes#include <vm/pmap.h>
791573Srgrimes#include <vm/vm_extern.h>
801573Srgrimes
811573Srgrimes#include <sys/bus.h>		/* used by smbus and newbus */
821573Srgrimes
831573Srgrimes#include <machine/bus.h>	/* used by bus space and newbus */
841573Srgrimes#include <sys/bus.h>
851573Srgrimes
861573Srgrimes#include <sys/rman.h>		/* used by newbus */
871573Srgrimes#include <machine/resource.h>	/* used by newbus */
881573Srgrimes
891573Srgrimes#if (__FreeBSD_version < 500000)
901573Srgrimes#include <machine/clock.h>              /* for DELAY */
911573Srgrimes#include <pci/pcivar.h>
921573Srgrimes#include <pci/pcireg.h>
931573Srgrimes#else
941573Srgrimes#include <dev/pci/pcivar.h>
951573Srgrimes#include <dev/pci/pcireg.h>
961573Srgrimes#endif
971573Srgrimes
981573Srgrimes#include <sys/sysctl.h>
991573Srgrimesint bt848_card = -1;
1001573Srgrimesint bt848_tuner = -1;
1011573Srgrimesint bt848_reverse_mute = -1;
1021573Srgrimesint bt848_format = -1;
1031573Srgrimesint bt848_slow_msp_audio = -1;
1041573Srgrimes#ifdef BKTR_NEW_MSP34XX_DRIVER
1051573Srgrimesint bt848_stereo_once = 0;	/* no continuous stereo monitoring */
1061573Srgrimesint bt848_amsound = 0;		/* hard-wire AM sound at 6.5 Hz (france),
1071573Srgrimes				   the autoscan seems work well only with FM... */
1081573Srgrimesint bt848_dolby = 0;
1091573Srgrimes#endif
1101573Srgrimes
1111573Srgrimesstatic SYSCTL_NODE(_hw, OID_AUTO, bt848, CTLFLAG_RW, 0, "Bt848 Driver mgmt");
1121573SrgrimesSYSCTL_INT(_hw_bt848, OID_AUTO, card, CTLFLAG_RW, &bt848_card, -1, "");
1131573SrgrimesSYSCTL_INT(_hw_bt848, OID_AUTO, tuner, CTLFLAG_RW, &bt848_tuner, -1, "");
1141573SrgrimesSYSCTL_INT(_hw_bt848, OID_AUTO, reverse_mute, CTLFLAG_RW, &bt848_reverse_mute, -1, "");
1151573SrgrimesSYSCTL_INT(_hw_bt848, OID_AUTO, format, CTLFLAG_RW, &bt848_format, -1, "");
1161573SrgrimesSYSCTL_INT(_hw_bt848, OID_AUTO, slow_msp_audio, CTLFLAG_RW, &bt848_slow_msp_audio, -1, "");
1171573Srgrimes#ifdef BKTR_NEW_MSP34XX_DRIVER
1181573SrgrimesSYSCTL_INT(_hw_bt848, OID_AUTO, stereo_once, CTLFLAG_RW, &bt848_stereo_once, 0, "");
1191573SrgrimesSYSCTL_INT(_hw_bt848, OID_AUTO, amsound, CTLFLAG_RW, &bt848_amsound, 0, "");
1201573SrgrimesSYSCTL_INT(_hw_bt848, OID_AUTO, dolby, CTLFLAG_RW, &bt848_dolby, 0, "");
1211573Srgrimes#endif
1221573Srgrimes
1231573Srgrimes#endif /* end freebsd section */
1241573Srgrimes
1251573Srgrimes
1261573Srgrimes
1271573Srgrimes/****************/
1281573Srgrimes/* *** BSDI *** */
1291573Srgrimes/****************/
1301573Srgrimes#ifdef __bsdi__
1311573Srgrimes#endif /* __bsdi__ */
1321573Srgrimes
1331573Srgrimes
1341573Srgrimes/**************************/
1351573Srgrimes/* *** OpenBSD/NetBSD *** */
1361573Srgrimes/**************************/
1371573Srgrimes#if defined(__NetBSD__) || defined(__OpenBSD__)
1381573Srgrimes
1391573Srgrimes#include <sys/param.h>
1401573Srgrimes#include <sys/systm.h>
1411573Srgrimes#include <sys/conf.h>
1421573Srgrimes#include <sys/uio.h>
1431573Srgrimes#include <sys/kernel.h>
1441573Srgrimes#include <sys/signalvar.h>
1451573Srgrimes#include <sys/mman.h>
1461573Srgrimes#include <sys/poll.h>
1471573Srgrimes#include <sys/select.h>
1481573Srgrimes#include <sys/vnode.h>
1491573Srgrimes
1501573Srgrimes#include <vm/vm.h>
1511573Srgrimes
1521573Srgrimes#include <dev/bktr/ioctl_bt848.h>	/* extensions to ioctl_meteor.h */
1531573Srgrimes
1541573Srgrimes#ifndef __NetBSD__
1551573Srgrimes#include <vm/vm_kern.h>
1561573Srgrimes#include <vm/pmap.h>
1571573Srgrimes#include <vm/vm_extern.h>
1581573Srgrimes#endif
1591573Srgrimes
1601573Srgrimes#include <sys/device.h>
1611573Srgrimes#include <dev/pci/pcivar.h>
1621573Srgrimes#include <dev/pci/pcireg.h>
1631573Srgrimes#include <dev/pci/pcidevs.h>
1641573Srgrimes
1651573Srgrimes#define BKTR_DEBUG
1661573Srgrimes#ifdef BKTR_DEBUG
1671573Srgrimesint bktr_debug = 0;
1681573Srgrimes#define DPR(x)	(bktr_debug ? printf x : 0)
1691573Srgrimes#else
1701573Srgrimes#define DPR(x)
1711573Srgrimes#endif
1721573Srgrimes#endif /* __NetBSD__ || __OpenBSD__ */
1731573Srgrimes
1741573Srgrimes
1751573Srgrimes#ifdef __NetBSD__
1761573Srgrimes#include <dev/ic/bt8xx.h>	/* NetBSD location for .h files */
1771573Srgrimes#include <dev/pci/bktr/bktr_reg.h>
1781573Srgrimes#include <dev/pci/bktr/bktr_tuner.h>
1791573Srgrimes#include <dev/pci/bktr/bktr_card.h>
1801573Srgrimes#include <dev/pci/bktr/bktr_audio.h>
1811573Srgrimes#include <dev/pci/bktr/bktr_core.h>
1821573Srgrimes#include <dev/pci/bktr/bktr_os.h>
1831573Srgrimes#else					/* Traditional location for .h files */
1841573Srgrimes#include <dev/bktr/ioctl_meteor.h>
1851573Srgrimes#include <dev/bktr/ioctl_bt848.h>	/* extensions to ioctl_meteor.h */
1861573Srgrimes#include <dev/bktr/bktr_reg.h>
1871573Srgrimes#include <dev/bktr/bktr_tuner.h>
1881573Srgrimes#include <dev/bktr/bktr_card.h>
1891573Srgrimes#include <dev/bktr/bktr_audio.h>
1901573Srgrimes#include <dev/bktr/bktr_core.h>
1911573Srgrimes#include <dev/bktr/bktr_os.h>
1921573Srgrimes
1931573Srgrimes#if defined(BKTR_USE_FREEBSD_SMBUS)
1941573Srgrimes#include <dev/bktr/bktr_i2c.h>
1951573Srgrimes
1961573Srgrimes#include "iicbb_if.h"
1971573Srgrimes#include "smbus_if.h"
1981573Srgrimes#endif
1991573Srgrimes#endif
2001573Srgrimes
2011573Srgrimes
2021573Srgrimes/****************************/
2031573Srgrimes/* *** FreeBSD 4.x code *** */
2041573Srgrimes/****************************/
2051573Srgrimes
2061573Srgrimesstatic int	bktr_probe( device_t dev );
2071573Srgrimesstatic int	bktr_attach( device_t dev );
2081573Srgrimesstatic int	bktr_detach( device_t dev );
2091573Srgrimesstatic int	bktr_shutdown( device_t dev );
2101573Srgrimesstatic void	bktr_intr(void *arg) { common_bktr_intr(arg); }
2111573Srgrimes
2121573Srgrimesstatic device_method_t bktr_methods[] = {
2131573Srgrimes	/* Device interface */
2141573Srgrimes	DEVMETHOD(device_probe,         bktr_probe),
2151573Srgrimes	DEVMETHOD(device_attach,        bktr_attach),
2161573Srgrimes	DEVMETHOD(device_detach,        bktr_detach),
2171573Srgrimes	DEVMETHOD(device_shutdown,      bktr_shutdown),
2181573Srgrimes
2191573Srgrimes#if defined(BKTR_USE_FREEBSD_SMBUS)
2201573Srgrimes	/* iicbb interface */
2211573Srgrimes	DEVMETHOD(iicbb_callback,	bti2c_iic_callback),
2221573Srgrimes	DEVMETHOD(iicbb_setsda,		bti2c_iic_setsda),
2231573Srgrimes	DEVMETHOD(iicbb_setscl,		bti2c_iic_setscl),
2241573Srgrimes	DEVMETHOD(iicbb_getsda,		bti2c_iic_getsda),
2251573Srgrimes	DEVMETHOD(iicbb_getscl,		bti2c_iic_getscl),
2261573Srgrimes	DEVMETHOD(iicbb_reset,		bti2c_iic_reset),
2271573Srgrimes
2281573Srgrimes	/* smbus interface */
2291573Srgrimes	DEVMETHOD(smbus_callback,	bti2c_smb_callback),
2301573Srgrimes	DEVMETHOD(smbus_writeb,		bti2c_smb_writeb),
2311573Srgrimes	DEVMETHOD(smbus_writew,		bti2c_smb_writew),
2321573Srgrimes	DEVMETHOD(smbus_readb,		bti2c_smb_readb),
2331573Srgrimes#endif
2341573Srgrimes
2351573Srgrimes	{ 0, 0 }
2361573Srgrimes};
2371573Srgrimes
2381573Srgrimesstatic driver_t bktr_driver = {
2391573Srgrimes	"bktr",
2401573Srgrimes	bktr_methods,
2411573Srgrimes	sizeof(struct bktr_softc),
2421573Srgrimes};
2431573Srgrimes
2441573Srgrimesstatic devclass_t bktr_devclass;
2451573Srgrimes
2461573Srgrimesstatic	d_open_t	bktr_open;
2471573Srgrimesstatic	d_close_t	bktr_close;
2481573Srgrimesstatic	d_read_t	bktr_read;
2491573Srgrimesstatic	d_write_t	bktr_write;
2501573Srgrimesstatic	d_ioctl_t	bktr_ioctl;
2511573Srgrimesstatic	d_mmap_t	bktr_mmap;
2521573Srgrimesstatic	d_poll_t	bktr_poll;
2531573Srgrimes
2541573Srgrimesstatic struct cdevsw bktr_cdevsw = {
2551573Srgrimes	.d_version =	D_VERSION,
2561573Srgrimes	.d_flags =	D_NEEDGIANT,
2571573Srgrimes	.d_open =	bktr_open,
2581573Srgrimes	.d_close =	bktr_close,
2591573Srgrimes	.d_read =	bktr_read,
2601573Srgrimes	.d_write =	bktr_write,
2611573Srgrimes	.d_ioctl =	bktr_ioctl,
2621573Srgrimes	.d_poll =	bktr_poll,
2631573Srgrimes	.d_mmap =	bktr_mmap,
2641573Srgrimes	.d_name =	"bktr",
2651573Srgrimes};
2661573Srgrimes
2671573Srgrimes#ifdef BKTR_USE_FREEBSD_SMBUS
2681573Srgrimes#include <dev/iicbus/iiconf.h>
2691573Srgrimes#include <dev/smbus/smbconf.h>
2701573SrgrimesMODULE_DEPEND(bktr, iicbb, IICBB_MINVER, IICBB_MODVER, IICBB_MAXVER);
2711573SrgrimesMODULE_DEPEND(bktr, iicbus, IICBUS_MINVER, IICBUS_MODVER, IICBUS_MAXVER);
2721573SrgrimesMODULE_DEPEND(bktr, smbus, SMBUS_MINVER, SMBUS_MODVER, SMBUS_MAXVER);
2731573Srgrimes#endif
2741573SrgrimesDRIVER_MODULE(bktr, pci, bktr_driver, bktr_devclass, 0, 0);
2751573SrgrimesMODULE_DEPEND(bktr, bktr_mem, 1,1,1);
2761573SrgrimesMODULE_VERSION(bktr, 1);
2771573Srgrimes
2781573Srgrimes
2791573Srgrimes/*
2801573Srgrimes * the boot time probe routine.
2811573Srgrimes */
2821573Srgrimesstatic int
2831573Srgrimesbktr_probe( device_t dev )
2841573Srgrimes{
2851573Srgrimes	unsigned int type = pci_get_devid(dev);
2861573Srgrimes        unsigned int rev  = pci_get_revid(dev);
2871573Srgrimes
2881573Srgrimes	if (PCI_VENDOR(type) == PCI_VENDOR_BROOKTREE)
2891573Srgrimes	{
2901573Srgrimes		switch (PCI_PRODUCT(type)) {
2911573Srgrimes		case PCI_PRODUCT_BROOKTREE_BT848:
2921573Srgrimes			if (rev == 0x12)
2931573Srgrimes				device_set_desc(dev, "BrookTree 848A");
2941573Srgrimes			else
2951573Srgrimes				device_set_desc(dev, "BrookTree 848");
2961573Srgrimes			return BUS_PROBE_DEFAULT;
2971573Srgrimes		case PCI_PRODUCT_BROOKTREE_BT849:
2981573Srgrimes			device_set_desc(dev, "BrookTree 849A");
2991573Srgrimes			return BUS_PROBE_DEFAULT;
3001573Srgrimes		case PCI_PRODUCT_BROOKTREE_BT878:
3011573Srgrimes			device_set_desc(dev, "BrookTree 878");
3021573Srgrimes			return BUS_PROBE_DEFAULT;
3031573Srgrimes		case PCI_PRODUCT_BROOKTREE_BT879:
3041573Srgrimes			device_set_desc(dev, "BrookTree 879");
3051573Srgrimes			return BUS_PROBE_DEFAULT;
3061573Srgrimes		}
3071573Srgrimes	};
3081573Srgrimes
3091573Srgrimes        return ENXIO;
3101573Srgrimes}
3111573Srgrimes
3121573Srgrimes
3131573Srgrimes/*
3141573Srgrimes * the attach routine.
3151573Srgrimes */
3161573Srgrimesstatic int
3171573Srgrimesbktr_attach( device_t dev )
3181573Srgrimes{
3191573Srgrimes	u_long		latency;
3201573Srgrimes	u_long		fun;
3211573Srgrimes	unsigned int	rev;
3221573Srgrimes	unsigned int	unit;
3231573Srgrimes	int		error = 0;
3241573Srgrimes#ifdef BROOKTREE_IRQ
3251573Srgrimes	u_long		old_irq, new_irq;
3261573Srgrimes#endif
3271573Srgrimes
3281573Srgrimes        struct bktr_softc *bktr = device_get_softc(dev);
3291573Srgrimes
3301573Srgrimes	unit = device_get_unit(dev);
3311573Srgrimes
3321573Srgrimes	/* build the device name for bktr_name() */
3331573Srgrimes	snprintf(bktr->bktr_xname, sizeof(bktr->bktr_xname), "bktr%d",unit);
3341573Srgrimes
3351573Srgrimes	/*
3361573Srgrimes	 * Enable bus mastering and Memory Mapped device
3371573Srgrimes	 */
3381573Srgrimes	pci_enable_busmaster(dev);
3391573Srgrimes
3401573Srgrimes	/*
3411573Srgrimes	 * Map control/status registers.
3421573Srgrimes	 */
3431573Srgrimes	bktr->mem_rid = PCIR_BAR(0);
3441573Srgrimes	bktr->res_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
3451573Srgrimes					&bktr->mem_rid, RF_ACTIVE);
3461573Srgrimes
3471573Srgrimes	if (!bktr->res_mem) {
3481573Srgrimes		device_printf(dev, "could not map memory\n");
3491573Srgrimes		error = ENXIO;
3501573Srgrimes		goto fail;
3511573Srgrimes	}
3521573Srgrimes	bktr->memt = rman_get_bustag(bktr->res_mem);
3531573Srgrimes	bktr->memh = rman_get_bushandle(bktr->res_mem);
3541573Srgrimes
3551573Srgrimes
3561573Srgrimes	/*
3571573Srgrimes	 * Disable the brooktree device
3581573Srgrimes	 */
3591573Srgrimes	OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
3601573Srgrimes	OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
3611573Srgrimes
3621573Srgrimes
3631573Srgrimes#ifdef BROOKTREE_IRQ		/* from the configuration file */
3641573Srgrimes	old_irq = pci_conf_read(tag, PCI_INTERRUPT_REG);
3651573Srgrimes	pci_conf_write(tag, PCI_INTERRUPT_REG, BROOKTREE_IRQ);
3661573Srgrimes	new_irq = pci_conf_read(tag, PCI_INTERRUPT_REG);
3671573Srgrimes	printf("bktr%d: attach: irq changed from %d to %d\n",
3681573Srgrimes		unit, (old_irq & 0xff), (new_irq & 0xff));
3691573Srgrimes#endif
3701573Srgrimes
3711573Srgrimes	/*
3721573Srgrimes	 * Allocate our interrupt.
3731573Srgrimes	 */
3741573Srgrimes	bktr->irq_rid = 0;
3751573Srgrimes	bktr->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
3761573Srgrimes				&bktr->irq_rid, RF_SHAREABLE | RF_ACTIVE);
3771573Srgrimes	if (bktr->res_irq == NULL) {
3781573Srgrimes		device_printf(dev, "could not map interrupt\n");
3791573Srgrimes		error = ENXIO;
3801573Srgrimes		goto fail;
3811573Srgrimes	}
3821573Srgrimes
3831573Srgrimes	error = bus_setup_intr(dev, bktr->res_irq, INTR_TYPE_TTY,
3841573Srgrimes                               NULL, bktr_intr, bktr, &bktr->res_ih);
3851573Srgrimes	if (error) {
3861573Srgrimes		device_printf(dev, "could not setup irq\n");
3871573Srgrimes		goto fail;
3881573Srgrimes
3891573Srgrimes	}
3901573Srgrimes
3911573Srgrimes
3921573Srgrimes	/* Update the Device Control Register */
3931573Srgrimes	/* on Bt878 and Bt879 cards           */
3941573Srgrimes	fun = pci_read_config( dev, 0x40, 2);
3951573Srgrimes        fun = fun | 1;	/* Enable writes to the sub-system vendor ID */
3961573Srgrimes
3971573Srgrimes#if defined( BKTR_430_FX_MODE )
3981573Srgrimes	if (bootverbose) printf("Using 430 FX chipset compatibilty mode\n");
3991573Srgrimes        fun = fun | 2;	/* Enable Intel 430 FX compatibility mode */
4001573Srgrimes#endif
4011573Srgrimes
4021573Srgrimes#if defined( BKTR_SIS_VIA_MODE )
4031573Srgrimes	if (bootverbose) printf("Using SiS/VIA chipset compatibilty mode\n");
4041573Srgrimes        fun = fun | 4;	/* Enable SiS/VIA compatibility mode (useful for
4051573Srgrimes                           OPTi chipset motherboards too */
4061573Srgrimes#endif
4071573Srgrimes	pci_write_config(dev, 0x40, fun, 2);
4081573Srgrimes
4091573Srgrimes#if defined(BKTR_USE_FREEBSD_SMBUS)
4101573Srgrimes	if (bt848_i2c_attach(dev))
4111573Srgrimes		printf("bktr%d: i2c_attach: can't attach\n", unit);
4121573Srgrimes#endif
4131573Srgrimes
4141573Srgrimes/*
4151573Srgrimes * PCI latency timer.  32 is a good value for 4 bus mastering slots, if
4161573Srgrimes * you have more than four, then 16 would probably be a better value.
4171573Srgrimes */
4181573Srgrimes#ifndef BROOKTREE_DEF_LATENCY_VALUE
4191573Srgrimes#define BROOKTREE_DEF_LATENCY_VALUE	10
4201573Srgrimes#endif
4211573Srgrimes	latency = pci_read_config(dev, PCI_LATENCY_TIMER, 4);
4221573Srgrimes	latency = (latency >> 8) & 0xff;
4231573Srgrimes	if ( bootverbose ) {
4241573Srgrimes		if (latency)
4251573Srgrimes			printf("brooktree%d: PCI bus latency is", unit);
4261573Srgrimes		else
4271573Srgrimes			printf("brooktree%d: PCI bus latency was 0 changing to",
4281573Srgrimes				unit);
4291573Srgrimes	}
4301573Srgrimes	if ( !latency ) {
4311573Srgrimes		latency = BROOKTREE_DEF_LATENCY_VALUE;
4321573Srgrimes		pci_write_config(dev, PCI_LATENCY_TIMER, latency<<8, 4);
4331573Srgrimes	}
4341573Srgrimes	if ( bootverbose ) {
4351573Srgrimes		printf(" %d.\n", (int) latency);
4361573Srgrimes	}
4371573Srgrimes
4381573Srgrimes	/* read the pci device id and revision id */
4391573Srgrimes	fun = pci_get_devid(dev);
4401573Srgrimes        rev = pci_get_revid(dev);
4411573Srgrimes
4421573Srgrimes	/* call the common attach code */
4431573Srgrimes	common_bktr_attach( bktr, unit, fun, rev );
4441573Srgrimes
4451573Srgrimes	/* make the device entries */
4461573Srgrimes	bktr->bktrdev = make_dev(&bktr_cdevsw, unit,
4471573Srgrimes				0, 0, 0444, "bktr%d",  unit);
4481573Srgrimes	bktr->tunerdev= make_dev(&bktr_cdevsw, unit+16,
4491573Srgrimes				0, 0, 0444, "tuner%d", unit);
4501573Srgrimes	bktr->vbidev  = make_dev(&bktr_cdevsw, unit+32,
4511573Srgrimes				0, 0, 0444, "vbi%d"  , unit);
4521573Srgrimes
4531573Srgrimes
4541573Srgrimes	/* if this is unit 0 (/dev/bktr0, /dev/tuner0, /dev/vbi0) then make */
4551573Srgrimes	/* alias entries to /dev/bktr /dev/tuner and /dev/vbi */
4561573Srgrimes#if (__FreeBSD_version >=500000)
4571573Srgrimes	if (unit == 0) {
4581573Srgrimes		bktr->bktrdev_alias = make_dev_alias(bktr->bktrdev,  "bktr");
4591573Srgrimes		bktr->tunerdev_alias= make_dev_alias(bktr->tunerdev, "tuner");
4601573Srgrimes		bktr->vbidev_alias  = make_dev_alias(bktr->vbidev,   "vbi");
4611573Srgrimes	}
4621573Srgrimes#endif
4631573Srgrimes
4641573Srgrimes	return 0;
4651573Srgrimes
4661573Srgrimesfail:
4671573Srgrimes	if (bktr->res_irq)
4681573Srgrimes		bus_release_resource(dev, SYS_RES_IRQ, bktr->irq_rid, bktr->res_irq);
4691573Srgrimes	if (bktr->res_mem)
4701573Srgrimes		bus_release_resource(dev, SYS_RES_MEMORY, bktr->mem_rid, bktr->res_mem);
4711573Srgrimes	return error;
4721573Srgrimes
4731573Srgrimes}
4741573Srgrimes
4751573Srgrimes/*
4761573Srgrimes * the detach routine.
4771573Srgrimes */
4781573Srgrimesstatic int
4791573Srgrimesbktr_detach( device_t dev )
4801573Srgrimes{
4811573Srgrimes	struct bktr_softc *bktr = device_get_softc(dev);
4821573Srgrimes
4831573Srgrimes#ifdef BKTR_NEW_MSP34XX_DRIVER
4841573Srgrimes	/* Disable the soundchip and kernel thread */
4851573Srgrimes	if (bktr->msp3400c_info != NULL)
4861573Srgrimes		msp_detach(bktr);
4871573Srgrimes#endif
4881573Srgrimes
4891573Srgrimes	/* Disable the brooktree device */
4901573Srgrimes	OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
4911573Srgrimes	OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
4921573Srgrimes
4931573Srgrimes#if defined(BKTR_USE_FREEBSD_SMBUS)
4941573Srgrimes	if (bt848_i2c_detach(dev))
4951573Srgrimes		printf("bktr%d: i2c_attach: can't attach\n",
4961573Srgrimes		     device_get_unit(dev));
4971573Srgrimes#endif
4981573Srgrimes#ifdef USE_VBIMUTEX
4991573Srgrimes        mtx_destroy(&bktr->vbimutex);
5001573Srgrimes#endif
5011573Srgrimes
5021573Srgrimes	/* Note: We do not free memory for RISC programs, grab buffer, vbi buffers */
5031573Srgrimes	/* The memory is retained by the bktr_mem module so we can unload and */
5041573Srgrimes	/* then reload the main bktr driver module */
5051573Srgrimes
5061573Srgrimes	/* Unregister the /dev/bktrN, tunerN and vbiN devices,
5071573Srgrimes	 * the aliases for unit 0 are automatically destroyed */
5081573Srgrimes	destroy_dev(bktr->vbidev);
5091573Srgrimes	destroy_dev(bktr->tunerdev);
5101573Srgrimes	destroy_dev(bktr->bktrdev);
5111573Srgrimes
5121573Srgrimes	/*
5131573Srgrimes	 * Deallocate resources.
5141573Srgrimes	 */
5151573Srgrimes	bus_teardown_intr(dev, bktr->res_irq, bktr->res_ih);
5161573Srgrimes	bus_release_resource(dev, SYS_RES_IRQ, bktr->irq_rid, bktr->res_irq);
5171573Srgrimes	bus_release_resource(dev, SYS_RES_MEMORY, bktr->mem_rid, bktr->res_mem);
5181573Srgrimes
5191573Srgrimes	return 0;
5201573Srgrimes}
5211573Srgrimes
5221573Srgrimes/*
5231573Srgrimes * the shutdown routine.
5241573Srgrimes */
5251573Srgrimesstatic int
5261573Srgrimesbktr_shutdown( device_t dev )
5271573Srgrimes{
5281573Srgrimes	struct bktr_softc *bktr = device_get_softc(dev);
5291573Srgrimes
5301573Srgrimes	/* Disable the brooktree device */
5311573Srgrimes	OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
5321573Srgrimes	OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
5331573Srgrimes
5341573Srgrimes	return 0;
5351573Srgrimes}
5361573Srgrimes
5371573Srgrimes
5381573Srgrimes/*
5391573Srgrimes * Special Memory Allocation
5401573Srgrimes */
5411573Srgrimesvm_offset_t
5421573Srgrimesget_bktr_mem( int unit, unsigned size )
5431573Srgrimes{
5441573Srgrimes	vm_offset_t	addr = 0;
5451573Srgrimes
5461573Srgrimes	addr = (vm_offset_t)contigmalloc(size, M_DEVBUF, M_NOWAIT, 0,
5471573Srgrimes	    0xffffffff, 1<<24, 0);
5481573Srgrimes	if (addr == 0)
5491573Srgrimes		addr = (vm_offset_t)contigmalloc(size, M_DEVBUF, M_NOWAIT, 0,
5501573Srgrimes		    0xffffffff, PAGE_SIZE, 0);
5511573Srgrimes	if (addr == 0) {
5521573Srgrimes		printf("bktr%d: Unable to allocate %d bytes of memory.\n",
5531573Srgrimes			unit, size);
5541573Srgrimes	}
5551573Srgrimes
5561573Srgrimes	return( addr );
5571573Srgrimes}
5581573Srgrimes
5591573Srgrimes
5601573Srgrimes/*---------------------------------------------------------
5611573Srgrimes**
5621573Srgrimes**	BrookTree 848 character device driver routines
5631573Srgrimes**
5641573Srgrimes**---------------------------------------------------------
5651573Srgrimes*/
5661573Srgrimes
5671573Srgrimes#define VIDEO_DEV	0x00
5681573Srgrimes#define TUNER_DEV	0x01
5691573Srgrimes#define VBI_DEV		0x02
5701573Srgrimes
5711573Srgrimes#define UNIT(x)		((x) & 0x0f)
5721573Srgrimes#define FUNCTION(x)	(x >> 4)
5731573Srgrimes
5741573Srgrimes/*
5751573Srgrimes *
5761573Srgrimes */
5771573Srgrimesstatic int
5781573Srgrimesbktr_open( struct cdev *dev, int flags, int fmt, struct thread *td )
5791573Srgrimes{
5801573Srgrimes	bktr_ptr_t	bktr;
5811573Srgrimes	int		unit;
5821573Srgrimes	int		result;
5831573Srgrimes
5841573Srgrimes	unit = UNIT( dev2unit(dev) );
5851573Srgrimes
5861573Srgrimes	/* Get the device data */
5871573Srgrimes	bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
5881573Srgrimes	if (bktr == NULL) {
5891573Srgrimes		/* the device is no longer valid/functioning */
5901573Srgrimes		return (ENXIO);
5911573Srgrimes	}
5921573Srgrimes
5931573Srgrimes	if (!(bktr->flags & METEOR_INITALIZED)) /* device not found */
5941573Srgrimes		return( ENXIO );
5951573Srgrimes
5961573Srgrimes	/* Record that the device is now busy */
5971573Srgrimes	device_busy(devclass_get_device(bktr_devclass, unit));
5981573Srgrimes
5991573Srgrimes
6001573Srgrimes	if (bt848_card != -1) {
6011573Srgrimes	  if ((bt848_card >> 8   == unit ) &&
6021573Srgrimes	     ( (bt848_card & 0xff) < Bt848_MAX_CARD )) {
6031573Srgrimes	    if ( bktr->bt848_card != (bt848_card & 0xff) ) {
6041573Srgrimes	      bktr->bt848_card = (bt848_card & 0xff);
6051573Srgrimes	      probeCard(bktr, FALSE, unit);
6061573Srgrimes	    }
6071573Srgrimes	  }
6081573Srgrimes	}
6091573Srgrimes
6101573Srgrimes	if (bt848_tuner != -1) {
6111573Srgrimes	  if ((bt848_tuner >> 8   == unit ) &&
6121573Srgrimes	     ( (bt848_tuner & 0xff) < Bt848_MAX_TUNER )) {
6131573Srgrimes	    if ( bktr->bt848_tuner != (bt848_tuner & 0xff) ) {
6141573Srgrimes	      bktr->bt848_tuner = (bt848_tuner & 0xff);
6151573Srgrimes	      probeCard(bktr, FALSE, unit);
6161573Srgrimes	    }
6171573Srgrimes	  }
6181573Srgrimes	}
6191573Srgrimes
6201573Srgrimes	if (bt848_reverse_mute != -1) {
6211573Srgrimes	  if ((bt848_reverse_mute >> 8)   == unit ) {
6221573Srgrimes	    bktr->reverse_mute = bt848_reverse_mute & 0xff;
6231573Srgrimes	  }
6241573Srgrimes	}
6251573Srgrimes
6261573Srgrimes	if (bt848_slow_msp_audio != -1) {
6271573Srgrimes	  if ((bt848_slow_msp_audio >> 8) == unit ) {
6281573Srgrimes	      bktr->slow_msp_audio = (bt848_slow_msp_audio & 0xff);
6291573Srgrimes	  }
6301573Srgrimes	}
6311573Srgrimes
6321573Srgrimes#ifdef BKTR_NEW_MSP34XX_DRIVER
6331573Srgrimes	if (bt848_stereo_once != 0) {
6341573Srgrimes	  if ((bt848_stereo_once >> 8) == unit ) {
6351573Srgrimes	      bktr->stereo_once = (bt848_stereo_once & 0xff);
6361573Srgrimes	  }
6371573Srgrimes	}
6381573Srgrimes
6391573Srgrimes	if (bt848_amsound != -1) {
6401573Srgrimes	  if ((bt848_amsound >> 8) == unit ) {
6411573Srgrimes	      bktr->amsound = (bt848_amsound & 0xff);
6421573Srgrimes	  }
6431573Srgrimes	}
6441573Srgrimes
6451573Srgrimes	if (bt848_dolby != -1) {
6461573Srgrimes	  if ((bt848_dolby >> 8) == unit ) {
6471573Srgrimes	      bktr->dolby = (bt848_dolby & 0xff);
6481573Srgrimes	  }
6491573Srgrimes	}
6501573Srgrimes#endif
6511573Srgrimes
6521573Srgrimes	switch ( FUNCTION( dev2unit(dev) ) ) {
6531573Srgrimes	case VIDEO_DEV:
6541573Srgrimes		result = video_open( bktr );
6551573Srgrimes		break;
6561573Srgrimes	case TUNER_DEV:
6571573Srgrimes		result = tuner_open( bktr );
6581573Srgrimes		break;
6591573Srgrimes	case VBI_DEV:
6601573Srgrimes		result = vbi_open( bktr );
6611573Srgrimes		break;
6621573Srgrimes	default:
6631573Srgrimes		result = ENXIO;
6641573Srgrimes		break;
6651573Srgrimes	}
6661573Srgrimes
6671573Srgrimes	/* If there was an error opening the device, undo the busy status */
6681573Srgrimes	if (result != 0)
6691573Srgrimes		device_unbusy(devclass_get_device(bktr_devclass, unit));
6701573Srgrimes	return( result );
6711573Srgrimes}
6721573Srgrimes
6731573Srgrimes
6741573Srgrimes/*
6751573Srgrimes *
6761573Srgrimes */
6771573Srgrimesstatic int
6781573Srgrimesbktr_close( struct cdev *dev, int flags, int fmt, struct thread *td )
6791573Srgrimes{
6801573Srgrimes	bktr_ptr_t	bktr;
6811573Srgrimes	int		unit;
6821573Srgrimes	int		result;
6831573Srgrimes
6841573Srgrimes	unit = UNIT( dev2unit(dev) );
6851573Srgrimes
6861573Srgrimes	/* Get the device data */
6871573Srgrimes	bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
6881573Srgrimes	if (bktr == NULL) {
6891573Srgrimes		/* the device is no longer valid/functioning */
6901573Srgrimes		return (ENXIO);
6918870Srgrimes	}
6921573Srgrimes
6931573Srgrimes	switch ( FUNCTION( dev2unit(dev) ) ) {
6941573Srgrimes	case VIDEO_DEV:
6951573Srgrimes		result = video_close( bktr );
6961573Srgrimes		break;
6971573Srgrimes	case TUNER_DEV:
6981573Srgrimes		result = tuner_close( bktr );
6991573Srgrimes		break;
7001573Srgrimes	case VBI_DEV:
7011573Srgrimes		result = vbi_close( bktr );
7021573Srgrimes		break;
7031573Srgrimes	default:
7041573Srgrimes		return (ENXIO);
7051573Srgrimes		break;
7061573Srgrimes	}
7071573Srgrimes
7081573Srgrimes	device_unbusy(devclass_get_device(bktr_devclass, unit));
7091573Srgrimes	return( result );
7101573Srgrimes}
7111573Srgrimes
7121573Srgrimes
7131573Srgrimes/*
7141573Srgrimes *
7151573Srgrimes */
7161573Srgrimesstatic int
7171573Srgrimesbktr_read( struct cdev *dev, struct uio *uio, int ioflag )
7181573Srgrimes{
7191573Srgrimes	bktr_ptr_t	bktr;
7201573Srgrimes	int		unit;
7211573Srgrimes
7221573Srgrimes	unit = UNIT(dev2unit(dev));
7231573Srgrimes
7241573Srgrimes	/* Get the device data */
7251573Srgrimes	bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
7261573Srgrimes	if (bktr == NULL) {
7271573Srgrimes		/* the device is no longer valid/functioning */
7281573Srgrimes		return (ENXIO);
7291573Srgrimes	}
7301573Srgrimes
7311573Srgrimes	switch ( FUNCTION( dev2unit(dev) ) ) {
7321573Srgrimes	case VIDEO_DEV:
7331573Srgrimes		return( video_read( bktr, unit, dev, uio ) );
7341573Srgrimes	case VBI_DEV:
7351573Srgrimes		return( vbi_read( bktr, uio, ioflag ) );
7361573Srgrimes	}
7371573Srgrimes        return( ENXIO );
7381573Srgrimes}
7391573Srgrimes
7401573Srgrimes
7411573Srgrimes/*
7421573Srgrimes *
7431573Srgrimes */
7441573Srgrimesstatic int
7451573Srgrimesbktr_write( struct cdev *dev, struct uio *uio, int ioflag )
7461573Srgrimes{
7471573Srgrimes	return( EINVAL ); /* XXX or ENXIO ? */
7481573Srgrimes}
7491573Srgrimes
7501573Srgrimes
7511573Srgrimes/*
7521573Srgrimes *
7531573Srgrimes */
7541573Srgrimesstatic int
7551573Srgrimesbktr_ioctl( struct cdev *dev, ioctl_cmd_t cmd, caddr_t arg, int flag, struct thread *td )
7561573Srgrimes{
7571573Srgrimes	bktr_ptr_t	bktr;
7581573Srgrimes	int		unit;
7591573Srgrimes
7601573Srgrimes	unit = UNIT(dev2unit(dev));
7611573Srgrimes
7621573Srgrimes	/* Get the device data */
7631573Srgrimes	bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
7641573Srgrimes	if (bktr == NULL) {
7651573Srgrimes		/* the device is no longer valid/functioning */
7661573Srgrimes		return (ENXIO);
7671573Srgrimes	}
7681573Srgrimes
7691573Srgrimes#ifdef BKTR_GPIO_ACCESS
7701573Srgrimes	if (bktr->bigbuf == 0 && cmd != BT848_GPIO_GET_EN &&
7711573Srgrimes	    cmd != BT848_GPIO_SET_EN && cmd != BT848_GPIO_GET_DATA &&
7721573Srgrimes	    cmd != BT848_GPIO_SET_DATA)	/* no frame buffer allocated (ioctl failed) */
7731573Srgrimes		return( ENOMEM );
7741573Srgrimes#else
7751573Srgrimes	if (bktr->bigbuf == 0)	/* no frame buffer allocated (ioctl failed) */
7761573Srgrimes		return( ENOMEM );
7771573Srgrimes#endif
7781573Srgrimes
7791573Srgrimes	switch ( FUNCTION( dev2unit(dev) ) ) {
7801573Srgrimes	case VIDEO_DEV:
7811573Srgrimes		return( video_ioctl( bktr, unit, cmd, arg, td ) );
7821573Srgrimes	case TUNER_DEV:
7831573Srgrimes		return( tuner_ioctl( bktr, unit, cmd, arg, td ) );
7841573Srgrimes	}
7851573Srgrimes
7861573Srgrimes	return( ENXIO );
7871573Srgrimes}
7881573Srgrimes
7891573Srgrimes
7901573Srgrimes/*
7911573Srgrimes *
7921573Srgrimes */
7931573Srgrimesstatic int
7941573Srgrimesbktr_mmap( struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr,
7951573Srgrimes    int nprot, vm_memattr_t *memattr )
7961573Srgrimes{
7971573Srgrimes	int		unit;
7981573Srgrimes	bktr_ptr_t	bktr;
7991573Srgrimes
8001573Srgrimes	unit = UNIT(dev2unit(dev));
8011573Srgrimes
8021573Srgrimes	if (FUNCTION(dev2unit(dev)) > 0)	/* only allow mmap on /dev/bktr[n] */
8031573Srgrimes		return( -1 );
8041573Srgrimes
8051573Srgrimes	/* Get the device data */
8061573Srgrimes	bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
8071573Srgrimes	if (bktr == NULL) {
8081573Srgrimes		/* the device is no longer valid/functioning */
8091573Srgrimes		return (ENXIO);
8101573Srgrimes	}
8111573Srgrimes
8121573Srgrimes	if (nprot & PROT_EXEC)
8131573Srgrimes		return( -1 );
8141573Srgrimes
8151573Srgrimes	if (offset < 0)
8161573Srgrimes		return( -1 );
8171573Srgrimes
8181573Srgrimes	if (offset >= bktr->alloc_pages * PAGE_SIZE)
8191573Srgrimes		return( -1 );
8201573Srgrimes
8211573Srgrimes	*paddr = vtophys(bktr->bigbuf) + offset;
8221573Srgrimes	return( 0 );
8231573Srgrimes}
8241573Srgrimes
8251573Srgrimesstatic int
8261573Srgrimesbktr_poll( struct cdev *dev, int events, struct thread *td)
8271573Srgrimes{
8281573Srgrimes	int		unit;
8291573Srgrimes	bktr_ptr_t	bktr;
8301573Srgrimes	int revents = 0;
8311573Srgrimes	DECLARE_INTR_MASK(s);
8321573Srgrimes
8331573Srgrimes	unit = UNIT(dev2unit(dev));
8341573Srgrimes
8351573Srgrimes	/* Get the device data */
8361573Srgrimes	bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
8371573Srgrimes	if (bktr == NULL) {
8381573Srgrimes		/* the device is no longer valid/functioning */
8391573Srgrimes		return (ENXIO);
8401573Srgrimes	}
8411573Srgrimes
8421573Srgrimes	LOCK_VBI(bktr);
8431573Srgrimes	DISABLE_INTR(s);
8441573Srgrimes
8451573Srgrimes	if (events & (POLLIN | POLLRDNORM)) {
8461573Srgrimes
8471573Srgrimes		switch ( FUNCTION( dev2unit(dev) ) ) {
8481573Srgrimes		case VBI_DEV:
8491573Srgrimes			if(bktr->vbisize == 0)
8501573Srgrimes				selrecord(td, &bktr->vbi_select);
8511573Srgrimes			else
8521573Srgrimes				revents |= events & (POLLIN | POLLRDNORM);
8531573Srgrimes			break;
8541573Srgrimes		}
8551573Srgrimes	}
8561573Srgrimes
8571573Srgrimes	ENABLE_INTR(s);
8581573Srgrimes	UNLOCK_VBI(bktr);
8591573Srgrimes
8601573Srgrimes	return (revents);
8611573Srgrimes}
8621573Srgrimes
8631573Srgrimes/*****************/
8641573Srgrimes/* *** BSDI  *** */
8651573Srgrimes/*****************/
8661573Srgrimes
8671573Srgrimes#if defined(__bsdi__)
8681573Srgrimes#endif		/* __bsdi__ BSDI specific kernel interface routines */
8691573Srgrimes
8701573Srgrimes
8711573Srgrimes/*****************************/
8721573Srgrimes/* *** OpenBSD / NetBSD  *** */
8731573Srgrimes/*****************************/
8741573Srgrimes#if defined(__NetBSD__) || defined(__OpenBSD__)
8751573Srgrimes
8761573Srgrimes#define IPL_VIDEO       IPL_BIO         /* XXX */
8771573Srgrimes
8781573Srgrimesstatic	int		bktr_intr(void *arg) { return common_bktr_intr(arg); }
8791573Srgrimes
8801573Srgrimes#define bktr_open       bktropen
8811573Srgrimes#define bktr_close      bktrclose
8821573Srgrimes#define bktr_read       bktrread
8831573Srgrimes#define bktr_write      bktrwrite
8841573Srgrimes#define bktr_ioctl      bktrioctl
8851573Srgrimes#define bktr_mmap       bktrmmap
8861573Srgrimes
8871573Srgrimesvm_offset_t vm_page_alloc_contig(vm_offset_t, vm_offset_t,
8881573Srgrimes                                 vm_offset_t, vm_offset_t);
8891573Srgrimes
8901573Srgrimes#if defined(__OpenBSD__)
8911573Srgrimesstatic int      bktr_probe(struct device *, void *, void *);
8921573Srgrimes#else
8931573Srgrimesstatic int      bktr_probe(struct device *, struct cfdata *, void *);
8941573Srgrimes#endif
8951573Srgrimesstatic void     bktr_attach(struct device *, struct device *, void *);
8961573Srgrimes
8971573Srgrimesstruct cfattach bktr_ca = {
8981573Srgrimes        sizeof(struct bktr_softc), bktr_probe, bktr_attach
8991573Srgrimes};
9001573Srgrimes
9011573Srgrimes#if defined(__NetBSD__)
9021573Srgrimesextern struct cfdriver bktr_cd;
9031573Srgrimes#else
9041573Srgrimesstruct cfdriver bktr_cd = {
9051573Srgrimes        NULL, "bktr", DV_DULL
9061573Srgrimes};
9071573Srgrimes#endif
9081573Srgrimes
9091573Srgrimesint
9101573Srgrimesbktr_probe(parent, match, aux)
9111573Srgrimes	struct device *parent;
9121573Srgrimes#if defined(__OpenBSD__)
9131573Srgrimes        void *match;
9141573Srgrimes#else
9151573Srgrimes        struct cfdata *match;
9161573Srgrimes#endif
9171573Srgrimes        void *aux;
9181573Srgrimes{
9191573Srgrimes        struct pci_attach_args *pa = aux;
9201573Srgrimes
9211573Srgrimes        if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_BROOKTREE &&
9221573Srgrimes            (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROOKTREE_BT848 ||
9231573Srgrimes             PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROOKTREE_BT849 ||
9241573Srgrimes             PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROOKTREE_BT878 ||
9251573Srgrimes             PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROOKTREE_BT879))
9261573Srgrimes                return 1;
9271573Srgrimes
9281573Srgrimes        return 0;
9291573Srgrimes}
9301573Srgrimes
9311573Srgrimes
9321573Srgrimes/*
9331573Srgrimes * the attach routine.
9341573Srgrimes */
9351573Srgrimesstatic void
9361573Srgrimesbktr_attach(struct device *parent, struct device *self, void *aux)
9371573Srgrimes{
9381573Srgrimes	bktr_ptr_t	bktr;
9391573Srgrimes	u_long		latency;
9401573Srgrimes	u_long		fun;
9411573Srgrimes	unsigned int	rev;
9421573Srgrimes
9431573Srgrimes#if defined(__OpenBSD__)
9441573Srgrimes	struct pci_attach_args *pa = aux;
945	pci_chipset_tag_t pc = pa->pa_pc;
946
947	pci_intr_handle_t ih;
948	const char *intrstr;
949	int retval;
950	int unit;
951
952	bktr = (bktr_ptr_t)self;
953	unit = bktr->bktr_dev.dv_unit;
954
955	bktr->pc = pa->pa_pc;
956	bktr->tag = pa->pa_tag;
957        bktr->dmat = pa->pa_dmat;
958
959	/*
960	 * map memory
961	 */
962	bktr->memt = pa->pa_memt;
963	retval = pci_mem_find(pc, pa->pa_tag, PCI_MAPREG_START,
964			      &bktr->phys_base, &bktr->obmemsz, NULL);
965	if (!retval)
966		retval = bus_space_map(pa->pa_memt, bktr->phys_base,
967				       bktr->obmemsz, 0, &bktr->memh);
968	if (retval) {
969		printf(": couldn't map memory\n");
970		return;
971	}
972
973
974	/*
975	 * map interrupt
976	 */
977	if (pci_intr_map(pa->pa_pc, pa->pa_intrtag, pa->pa_intrpin,
978			 pa->pa_intrline, &ih)) {
979		printf(": couldn't map interrupt\n");
980		return;
981	}
982	intrstr = pci_intr_string(pa->pa_pc, ih);
983
984	bktr->ih = pci_intr_establish(pa->pa_pc, ih, IPL_VIDEO,
985				      bktr_intr, bktr, bktr->bktr_dev.dv_xname);
986	if (bktr->ih == NULL) {
987		printf(": couldn't establish interrupt");
988		if (intrstr != NULL)
989			printf(" at %s", intrstr);
990		printf("\n");
991		return;
992	}
993
994	if (intrstr != NULL)
995		printf(": %s\n", intrstr);
996#endif /* __OpenBSD__ */
997
998#if defined(__NetBSD__)
999	struct pci_attach_args *pa = aux;
1000	pci_intr_handle_t ih;
1001	const char *intrstr;
1002	int retval;
1003	int unit;
1004
1005	bktr = (bktr_ptr_t)self;
1006	unit = bktr->bktr_dev.dv_unit;
1007        bktr->dmat = pa->pa_dmat;
1008
1009	printf("\n");
1010
1011	/*
1012	 * map memory
1013	 */
1014	retval = pci_mapreg_map(pa, PCI_MAPREG_START,
1015				PCI_MAPREG_TYPE_MEM
1016				| PCI_MAPREG_MEM_TYPE_32BIT, 0,
1017				&bktr->memt, &bktr->memh, NULL,
1018				&bktr->obmemsz);
1019	DPR(("pci_mapreg_map: memt %x, memh %x, size %x\n",
1020	     bktr->memt, (u_int)bktr->memh, (u_int)bktr->obmemsz));
1021	if (retval) {
1022		printf("%s: couldn't map memory\n", bktr_name(bktr));
1023		return;
1024	}
1025
1026	/*
1027	 * Disable the brooktree device
1028	 */
1029	OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
1030	OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
1031
1032	/*
1033	 * map interrupt
1034	 */
1035	if (pci_intr_map(pa->pa_pc, pa->pa_intrtag, pa->pa_intrpin,
1036			 pa->pa_intrline, &ih)) {
1037		printf("%s: couldn't map interrupt\n",
1038		       bktr_name(bktr));
1039		return;
1040	}
1041	intrstr = pci_intr_string(pa->pa_pc, ih);
1042	bktr->ih = pci_intr_establish(pa->pa_pc, ih, IPL_VIDEO,
1043				      bktr_intr, bktr);
1044	if (bktr->ih == NULL) {
1045		printf("%s: couldn't establish interrupt",
1046		       bktr_name(bktr));
1047		if (intrstr != NULL)
1048			printf(" at %s", intrstr);
1049		printf("\n");
1050		return;
1051	}
1052	if (intrstr != NULL)
1053		printf("%s: interrupting at %s\n", bktr_name(bktr),
1054		       intrstr);
1055#endif /* __NetBSD__ */
1056
1057/*
1058 * PCI latency timer.  32 is a good value for 4 bus mastering slots, if
1059 * you have more than four, then 16 would probably be a better value.
1060 */
1061#ifndef BROOKTREE_DEF_LATENCY_VALUE
1062#define BROOKTREE_DEF_LATENCY_VALUE	10
1063#endif
1064	latency = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_LATENCY_TIMER);
1065	latency = (latency >> 8) & 0xff;
1066
1067	if (!latency) {
1068		if (bootverbose) {
1069			printf("%s: PCI bus latency was 0 changing to %d",
1070			       bktr_name(bktr), BROOKTREE_DEF_LATENCY_VALUE);
1071		}
1072		latency = BROOKTREE_DEF_LATENCY_VALUE;
1073		pci_conf_write(pa->pa_pc, pa->pa_tag,
1074			       PCI_LATENCY_TIMER, latency<<8);
1075	}
1076
1077
1078	/* Enabled Bus Master
1079	   XXX: check if all old DMA is stopped first (e.g. after warm
1080	   boot) */
1081	fun = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
1082	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
1083		       fun | PCI_COMMAND_MASTER_ENABLE);
1084
1085	/* read the pci id and determine the card type */
1086	fun = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ID_REG);
1087        rev = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_CLASS_REG) & 0x000000ff;
1088
1089	common_bktr_attach(bktr, unit, fun, rev);
1090}
1091
1092
1093/*
1094 * Special Memory Allocation
1095 */
1096vm_offset_t
1097get_bktr_mem(bktr, dmapp, size)
1098        bktr_ptr_t bktr;
1099        bus_dmamap_t *dmapp;
1100        unsigned int size;
1101{
1102        bus_dma_tag_t dmat = bktr->dmat;
1103        bus_dma_segment_t seg;
1104        bus_size_t align;
1105        int rseg;
1106        caddr_t kva;
1107
1108        /*
1109         * Allocate a DMA area
1110         */
1111        align = 1 << 24;
1112        if (bus_dmamem_alloc(dmat, size, align, 0, &seg, 1,
1113                             &rseg, BUS_DMA_NOWAIT)) {
1114                align = PAGE_SIZE;
1115                if (bus_dmamem_alloc(dmat, size, align, 0, &seg, 1,
1116                                     &rseg, BUS_DMA_NOWAIT)) {
1117                        printf("%s: Unable to dmamem_alloc of %d bytes\n",
1118			       bktr_name(bktr), size);
1119                        return 0;
1120                }
1121        }
1122        if (bus_dmamem_map(dmat, &seg, rseg, size,
1123                           &kva, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) {
1124                printf("%s: Unable to dmamem_map of %d bytes\n",
1125                        bktr_name(bktr), size);
1126                bus_dmamem_free(dmat, &seg, rseg);
1127                return 0;
1128        }
1129#ifdef __OpenBSD__
1130        bktr->dm_mapsize = size;
1131#endif
1132        /*
1133         * Create and locd the DMA map for the DMA area
1134         */
1135        if (bus_dmamap_create(dmat, size, 1, size, 0, BUS_DMA_NOWAIT, dmapp)) {
1136                printf("%s: Unable to dmamap_create of %d bytes\n",
1137                        bktr_name(bktr), size);
1138                bus_dmamem_unmap(dmat, kva, size);
1139                bus_dmamem_free(dmat, &seg, rseg);
1140                return 0;
1141        }
1142        if (bus_dmamap_load(dmat, *dmapp, kva, size, NULL, BUS_DMA_NOWAIT)) {
1143                printf("%s: Unable to dmamap_load of %d bytes\n",
1144                        bktr_name(bktr), size);
1145                bus_dmamem_unmap(dmat, kva, size);
1146                bus_dmamem_free(dmat, &seg, rseg);
1147                bus_dmamap_destroy(dmat, *dmapp);
1148                return 0;
1149        }
1150        return (vm_offset_t)kva;
1151}
1152
1153void
1154free_bktr_mem(bktr, dmap, kva)
1155        bktr_ptr_t bktr;
1156        bus_dmamap_t dmap;
1157        vm_offset_t kva;
1158{
1159        bus_dma_tag_t dmat = bktr->dmat;
1160
1161#ifdef __NetBSD__
1162        bus_dmamem_unmap(dmat, (caddr_t)kva, dmap->dm_mapsize);
1163#else
1164        bus_dmamem_unmap(dmat, (caddr_t)kva, bktr->dm_mapsize);
1165#endif
1166        bus_dmamem_free(dmat, dmap->dm_segs, 1);
1167        bus_dmamap_destroy(dmat, dmap);
1168}
1169
1170
1171/*---------------------------------------------------------
1172**
1173**	BrookTree 848 character device driver routines
1174**
1175**---------------------------------------------------------
1176*/
1177
1178
1179#define VIDEO_DEV	0x00
1180#define TUNER_DEV	0x01
1181#define VBI_DEV		0x02
1182
1183#define UNIT(x)         (dev2unit((x) & 0x0f))
1184#define FUNCTION(x)     (dev2unit((x >> 4) & 0x0f))
1185
1186/*
1187 *
1188 */
1189int
1190bktr_open(dev_t dev, int flags, int fmt, struct thread *td)
1191{
1192	bktr_ptr_t	bktr;
1193	int		unit;
1194
1195	unit = UNIT(dev);
1196
1197	/* unit out of range */
1198	if ((unit > bktr_cd.cd_ndevs) || (bktr_cd.cd_devs[unit] == NULL))
1199		return(ENXIO);
1200
1201	bktr = bktr_cd.cd_devs[unit];
1202
1203	if (!(bktr->flags & METEOR_INITALIZED)) /* device not found */
1204		return(ENXIO);
1205
1206	switch (FUNCTION(dev)) {
1207	case VIDEO_DEV:
1208		return(video_open(bktr));
1209	case TUNER_DEV:
1210		return(tuner_open(bktr));
1211	case VBI_DEV:
1212		return(vbi_open(bktr));
1213	}
1214
1215	return(ENXIO);
1216}
1217
1218
1219/*
1220 *
1221 */
1222int
1223bktr_close(dev_t dev, int flags, int fmt, struct thread *td)
1224{
1225	bktr_ptr_t	bktr;
1226	int		unit;
1227
1228	unit = UNIT(dev);
1229
1230	bktr = bktr_cd.cd_devs[unit];
1231
1232	switch (FUNCTION(dev)) {
1233	case VIDEO_DEV:
1234		return(video_close(bktr));
1235	case TUNER_DEV:
1236		return(tuner_close(bktr));
1237	case VBI_DEV:
1238		return(vbi_close(bktr));
1239	}
1240
1241	return(ENXIO);
1242}
1243
1244/*
1245 *
1246 */
1247int
1248bktr_read(dev_t dev, struct uio *uio, int ioflag)
1249{
1250	bktr_ptr_t	bktr;
1251	int		unit;
1252
1253	unit = UNIT(dev);
1254
1255	bktr = bktr_cd.cd_devs[unit];
1256
1257	switch (FUNCTION(dev)) {
1258	case VIDEO_DEV:
1259		return(video_read(bktr, unit, dev, uio));
1260	case VBI_DEV:
1261		return(vbi_read(bktr, uio, ioflag));
1262	}
1263
1264        return(ENXIO);
1265}
1266
1267
1268/*
1269 *
1270 */
1271int
1272bktr_write(dev_t dev, struct uio *uio, int ioflag)
1273{
1274	/* operation not supported */
1275	return(EOPNOTSUPP);
1276}
1277
1278/*
1279 *
1280 */
1281int
1282bktr_ioctl(dev_t dev, ioctl_cmd_t cmd, caddr_t arg, int flag, struct thread *td)
1283{
1284	bktr_ptr_t	bktr;
1285	int		unit;
1286
1287	unit = UNIT(dev);
1288
1289	bktr = bktr_cd.cd_devs[unit];
1290
1291	if (bktr->bigbuf == 0)	/* no frame buffer allocated (ioctl failed) */
1292		return(ENOMEM);
1293
1294	switch (FUNCTION(dev)) {
1295	case VIDEO_DEV:
1296		return(video_ioctl(bktr, unit, cmd, arg, pr));
1297	case TUNER_DEV:
1298		return(tuner_ioctl(bktr, unit, cmd, arg, pr));
1299	}
1300
1301	return(ENXIO);
1302}
1303
1304/*
1305 *
1306 */
1307paddr_t
1308bktr_mmap(dev_t dev, off_t offset, int nprot)
1309{
1310	int		unit;
1311	bktr_ptr_t	bktr;
1312
1313	unit = UNIT(dev);
1314
1315	if (FUNCTION(dev) > 0)	/* only allow mmap on /dev/bktr[n] */
1316		return(-1);
1317
1318	bktr = bktr_cd.cd_devs[unit];
1319
1320	if ((vaddr_t)offset < 0)
1321		return(-1);
1322
1323	if ((vaddr_t)offset >= bktr->alloc_pages * PAGE_SIZE)
1324		return(-1);
1325
1326#ifdef __NetBSD__
1327	return (bus_dmamem_mmap(bktr->dmat, bktr->dm_mem->dm_segs, 1,
1328				(vaddr_t)offset, nprot, BUS_DMA_WAITOK));
1329#else
1330	return(i386_btop(vtophys(bktr->bigbuf) + offset));
1331#endif
1332}
1333
1334#endif /* __NetBSD__ || __OpenBSD__ */
1335