bktr_os.c revision 123291
16059Samurai/*-
26059Samurai * 1. Redistributions of source code must retain the
36059Samurai * Copyright (c) 1997 Amancio Hasty, 1999 Roger Hardiman
46059Samurai * All rights reserved.
56059Samurai *
66059Samurai * Redistribution and use in source and binary forms, with or without
76059Samurai * modification, are permitted provided that the following conditions
86059Samurai * are met:
96059Samurai * 1. Redistributions of source code must retain the above copyright
106059Samurai *    notice, this list of conditions and the following disclaimer.
116059Samurai * 2. Redistributions in binary form must reproduce the above copyright
126059Samurai *    notice, this list of conditions and the following disclaimer in the
136059Samurai *    documentation and/or other materials provided with the distribution.
146059Samurai * 3. All advertising materials mentioning features or use of this software
156059Samurai *    must display the following acknowledgement:
166059Samurai *	This product includes software developed by Amancio Hasty and
176059Samurai *      Roger Hardiman
186059Samurai * 4. The name of the author may not be used to endorse or promote products
198857Srgrimes *    derived from this software without specific prior written permission.
2031598Sbrian *
218857Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
226059Samurai * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2330715Sbrian * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2430715Sbrian * DISCLAIMED.	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
2526031Sbrian * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2630715Sbrian * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2726031Sbrian * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2830715Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
2926031Sbrian * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
3030715Sbrian * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3130715Sbrian * POSSIBILITY OF SUCH DAMAGE.
3231343Sbrian */
3326031Sbrian
3431343Sbrian#include <sys/cdefs.h>
3530715Sbrian__FBSDID("$FreeBSD: head/sys/dev/bktr/bktr_os.c 123291 2003-12-08 07:59:18Z obrien $");
3630715Sbrian
3726516Sbrian/*
3830715Sbrian * This is part of the Driver for Video Capture Cards (Frame grabbers)
3930715Sbrian * and TV Tuner cards using the Brooktree Bt848, Bt848A, Bt849A, Bt878, Bt879
4030715Sbrian * chipset.
4130715Sbrian * Copyright Roger Hardiman and Amancio Hasty.
4230715Sbrian *
4330715Sbrian * bktr_os : This has all the Operating System dependant code,
4430715Sbrian *             probe/attach and open/close/ioctl/read/mmap
4530715Sbrian *             memory allocation
4630715Sbrian *             PCI bus interfacing
4730715Sbrian */
4831343Sbrian
4930715Sbrian#include "opt_bktr.h"		/* include any kernel config options */
5030715Sbrian
5130715Sbrian#define FIFO_RISC_DISABLED      0
5230715Sbrian#define ALL_INTS_DISABLED       0
536059Samurai
546059Samurai
556059Samurai/*******************/
566059Samurai/* *** FreeBSD *** */
576059Samurai/*******************/
5813389Sphk#ifdef __FreeBSD__
5931343Sbrian
6026031Sbrian#include <sys/param.h>
6131343Sbrian#include <sys/systm.h>
626059Samurai#include <sys/conf.h>
6326142Sbrian#include <sys/uio.h>
646059Samurai#include <sys/kernel.h>
6525630Sbrian#include <sys/signalvar.h>
6625630Sbrian#include <sys/mman.h>
676059Samurai#include <sys/poll.h>
6826940Sbrian#if __FreeBSD_version >= 500014
6930715Sbrian#include <sys/selinfo.h>
7030715Sbrian#else
7130715Sbrian#include <sys/select.h>
7230733Sbrian#endif
7330715Sbrian#include <sys/vnode.h>
7431080Sbrian
756059Samurai#include <vm/vm.h>
766059Samurai#include <vm/vm_kern.h>
776059Samurai#include <vm/pmap.h>
7831343Sbrian#include <vm/vm_extern.h>
7931343Sbrian
8031343Sbrian#if (__FreeBSD_version >=400000)
8131343Sbrian#include <sys/bus.h>		/* used by smbus and newbus */
8231343Sbrian#endif
8331343Sbrian
8431343Sbrian#if (__FreeBSD_version >=300000)
8531343Sbrian#include <machine/bus_memio.h>	/* used by bus space */
8631343Sbrian#include <machine/bus.h>	/* used by bus space and newbus */
8731343Sbrian#include <sys/bus.h>
8831343Sbrian#endif
8931343Sbrian
9031343Sbrian#if (__FreeBSD_version >=400000)
9131343Sbrian#include <sys/rman.h>		/* used by newbus */
9231343Sbrian#include <machine/resource.h>	/* used by newbus */
9331343Sbrian#endif
9431343Sbrian
956059Samurai#if (__FreeBSD_version < 500000)
966059Samurai#include <machine/clock.h>              /* for DELAY */
9731343Sbrian#include <pci/pcivar.h>
986059Samurai#include <pci/pcireg.h>
9928679Sbrian#else
10031372Sbrian#include <dev/pci/pcivar.h>
1016059Samurai#include <dev/pci/pcireg.h>
10226516Sbrian#endif
10326516Sbrian
10426516Sbrian#include <sys/sysctl.h>
10531343Sbrianint bt848_card = -1;
10631343Sbrianint bt848_tuner = -1;
10731372Sbrianint bt848_reverse_mute = -1;
10831372Sbrianint bt848_format = -1;
10928679Sbrianint bt848_slow_msp_audio = -1;
11028679Sbrian#ifdef BKTR_NEW_MSP34XX_DRIVER
1116059Samuraiint bt848_stereo_once = 0;	/* no continuous stereo monitoring */
11226516Sbrianint bt848_amsound = 0;		/* hard-wire AM sound at 6.5 Hz (france),
1136059Samurai				   the autoscan seems work well only with FM... */
11431372Sbrianint bt848_dolby = 0;
11531372Sbrian#endif
11631372Sbrian
11731372SbrianSYSCTL_NODE(_hw, OID_AUTO, bt848, CTLFLAG_RW, 0, "Bt848 Driver mgmt");
11831372SbrianSYSCTL_INT(_hw_bt848, OID_AUTO, card, CTLFLAG_RW, &bt848_card, -1, "");
11931372SbrianSYSCTL_INT(_hw_bt848, OID_AUTO, tuner, CTLFLAG_RW, &bt848_tuner, -1, "");
12031372SbrianSYSCTL_INT(_hw_bt848, OID_AUTO, reverse_mute, CTLFLAG_RW, &bt848_reverse_mute, -1, "");
12131372SbrianSYSCTL_INT(_hw_bt848, OID_AUTO, format, CTLFLAG_RW, &bt848_format, -1, "");
12231372SbrianSYSCTL_INT(_hw_bt848, OID_AUTO, slow_msp_audio, CTLFLAG_RW, &bt848_slow_msp_audio, -1, "");
12331372Sbrian#ifdef BKTR_NEW_MSP34XX_DRIVER
1246059SamuraiSYSCTL_INT(_hw_bt848, OID_AUTO, stereo_once, CTLFLAG_RW, &bt848_stereo_once, 0, "");
12531343SbrianSYSCTL_INT(_hw_bt848, OID_AUTO, amsound, CTLFLAG_RW, &bt848_amsound, 0, "");
1266764SamuraiSYSCTL_INT(_hw_bt848, OID_AUTO, dolby, CTLFLAG_RW, &bt848_dolby, 0, "");
12731372Sbrian#endif
12831372Sbrian
12931372Sbrian#endif /* end freebsd section */
13031372Sbrian
1316059Samurai
13231372Sbrian
13326516Sbrian/****************/
13426516Sbrian/* *** BSDI *** */
13526516Sbrian/****************/
1366059Samurai#ifdef __bsdi__
1376059Samurai#endif /* __bsdi__ */
1386059Samurai
13930913Sbrian
1406059Samurai/**************************/
14131343Sbrian/* *** OpenBSD/NetBSD *** */
1426059Samurai/**************************/
14320120Snate#if defined(__NetBSD__) || defined(__OpenBSD__)
14420120Snate
14525908Sbrian#include <sys/param.h>
14625908Sbrian#include <sys/systm.h>
14720120Snate#include <sys/conf.h>
14810528Samurai#include <sys/uio.h>
1496059Samurai#include <sys/kernel.h>
15010528Samurai#include <sys/signalvar.h>
1516059Samurai#include <sys/mman.h>
15210528Samurai#include <sys/poll.h>
1536059Samurai#include <sys/select.h>
15430913Sbrian#include <sys/vnode.h>
15526516Sbrian
15626516Sbrian#include <vm/vm.h>
1576059Samurai
15826516Sbrian#ifndef __NetBSD__
1596059Samurai#include <vm/vm_kern.h>
1606059Samurai#include <vm/pmap.h>
1616059Samurai#include <vm/vm_extern.h>
16231343Sbrian#endif
1636059Samurai
16411336Samurai#include <sys/device.h>
16526858Sbrian#include <dev/pci/pcivar.h>
16611336Samurai#include <dev/pci/pcireg.h>
1676059Samurai#include <dev/pci/pcidevs.h>
16826516Sbrian
16926516Sbrian#define BKTR_DEBUG
17026516Sbrian#ifdef BKTR_DEBUG
1716059Samuraiint bktr_debug = 0;
17226516Sbrian#define DPR(x)	(bktr_debug ? printf x : 0)
17331343Sbrian#else
17431140Sbrian#define DPR(x)
17531121Sbrian#endif
17611336Samurai#endif /* __NetBSD__ || __OpenBSD__ */
17711336Samurai
17826516Sbrian
17926516Sbrian#ifdef __NetBSD__
18031034Sbrian#include <dev/ic/bt8xx.h>	/* NetBSD location for .h files */
18126516Sbrian#include <dev/pci/bktr/bktr_reg.h>
18228679Sbrian#include <dev/pci/bktr/bktr_tuner.h>
18311336Samurai#include <dev/pci/bktr/bktr_card.h>
18411336Samurai#include <dev/pci/bktr/bktr_audio.h>
18526858Sbrian#include <dev/pci/bktr/bktr_core.h>
18630697Sbrian#include <dev/pci/bktr/bktr_os.h>
18731343Sbrian#else					/* Traditional location for .h files */
18811336Samurai#include <dev/bktr/ioctl_meteor.h>
18911336Samurai#include <dev/bktr/ioctl_bt848.h>	/* extensions to ioctl_meteor.h */
19026858Sbrian#include <dev/bktr/bktr_reg.h>
19126858Sbrian#include <dev/bktr/bktr_tuner.h>
19211336Samurai#include <dev/bktr/bktr_card.h>
19326516Sbrian#include <dev/bktr/bktr_audio.h>
19426516Sbrian#include <dev/bktr/bktr_core.h>
1956059Samurai#include <dev/bktr/bktr_os.h>
1966059Samurai
19710528Samurai#if defined(BKTR_USE_FREEBSD_SMBUS)
19831343Sbrian#include <dev/bktr/bktr_i2c.h>
19928536Sbrian
20031343Sbrian#include "iicbb_if.h"
20131343Sbrian#include "smbus_if.h"
20228536Sbrian#endif
20331141Sbrian#endif
20431141Sbrian
20531343Sbrian
20628536Sbrian/****************************/
20731141Sbrian/* *** FreeBSD 4.x code *** */
20831141Sbrian/****************************/
20928536Sbrian#if (__FreeBSD_version >= 400000)
21028536Sbrian
21128536Sbrianstatic int	bktr_probe( device_t dev );
21228536Sbrianstatic int	bktr_attach( device_t dev );
21331343Sbrianstatic int	bktr_detach( device_t dev );
21410528Samuraistatic int	bktr_shutdown( device_t dev );
21510528Samuraistatic void	bktr_intr(void *arg) { common_bktr_intr(arg); }
21610528Samurai
21726516Sbrianstatic device_method_t bktr_methods[] = {
21831343Sbrian	/* Device interface */
21931343Sbrian	DEVMETHOD(device_probe,         bktr_probe),
22020813Sjkh	DEVMETHOD(device_attach,        bktr_attach),
22118856Ssos	DEVMETHOD(device_detach,        bktr_detach),
22226911Sbrian	DEVMETHOD(device_shutdown,      bktr_shutdown),
22326516Sbrian
22426516Sbrian#if defined(BKTR_USE_FREEBSD_SMBUS)
22526516Sbrian	/* iicbb interface */
22610528Samurai	DEVMETHOD(iicbb_callback,	bti2c_iic_callback),
22726911Sbrian	DEVMETHOD(iicbb_setsda,		bti2c_iic_setsda),
22826911Sbrian	DEVMETHOD(iicbb_setscl,		bti2c_iic_setscl),
22928679Sbrian	DEVMETHOD(iicbb_getsda,		bti2c_iic_getsda),
23026911Sbrian	DEVMETHOD(iicbb_getscl,		bti2c_iic_getscl),
23128679Sbrian	DEVMETHOD(iicbb_reset,		bti2c_iic_reset),
23228679Sbrian
23326911Sbrian	/* smbus interface */
23431121Sbrian	DEVMETHOD(smbus_callback,	bti2c_smb_callback),
23528679Sbrian	DEVMETHOD(smbus_writeb,		bti2c_smb_writeb),
23626516Sbrian	DEVMETHOD(smbus_writew,		bti2c_smb_writew),
23726516Sbrian	DEVMETHOD(smbus_readb,		bti2c_smb_readb),
23826516Sbrian#endif
23926516Sbrian
24031343Sbrian	{ 0, 0 }
24128381Sbrian};
24231121Sbrian
24331121Sbrianstatic driver_t bktr_driver = {
24431121Sbrian	"bktr",
24531121Sbrian	bktr_methods,
24631121Sbrian	sizeof(struct bktr_softc),
24731121Sbrian};
24828381Sbrian
24928381Sbrianstatic devclass_t bktr_devclass;
25028381Sbrian
25128679Sbrianstatic	d_open_t	bktr_open;
25228381Sbrianstatic	d_close_t	bktr_close;
25328381Sbrianstatic	d_read_t	bktr_read;
25428679Sbrianstatic	d_write_t	bktr_write;
25526516Sbrianstatic	d_ioctl_t	bktr_ioctl;
25626516Sbrianstatic	d_mmap_t	bktr_mmap;
25728679Sbrianstatic	d_poll_t	bktr_poll;
25828679Sbrian
25918531Sbde#define CDEV_MAJOR 92
26028679Sbrianstatic struct cdevsw bktr_cdevsw = {
26128679Sbrian	.d_open =	bktr_open,
26228679Sbrian	.d_close =	bktr_close,
26328679Sbrian	.d_read =	bktr_read,
26428679Sbrian	.d_write =	bktr_write,
26528679Sbrian	.d_ioctl =	bktr_ioctl,
26628679Sbrian	.d_poll =	bktr_poll,
26728679Sbrian	.d_mmap =	bktr_mmap,
26826516Sbrian	.d_name =	"bktr",
26928679Sbrian	.d_maj =	CDEV_MAJOR,
27028679Sbrian};
27128679Sbrian
27228679SbrianDRIVER_MODULE(bktr, pci, bktr_driver, bktr_devclass, 0, 0);
27328679Sbrian#if (__FreeBSD_version > 410000)
27428679SbrianMODULE_DEPEND(bktr, bktr_mem, 1,1,1);
27528679SbrianMODULE_VERSION(bktr, 1);
27628679Sbrian#endif
27726516Sbrian
27828679Sbrian
27931343Sbrian/*
28026516Sbrian * the boot time probe routine.
28128679Sbrian */
28231061Sbrianstatic int
28331343Sbrianbktr_probe( device_t dev )
28428679Sbrian{
28531343Sbrian	unsigned int type = pci_get_devid(dev);
28631343Sbrian        unsigned int rev  = pci_get_revid(dev);
28731343Sbrian
28831343Sbrian	if (PCI_VENDOR(type) == PCI_VENDOR_BROOKTREE)
28931343Sbrian	{
29031343Sbrian		switch (PCI_PRODUCT(type)) {
29131343Sbrian		case PCI_PRODUCT_BROOKTREE_BT848:
29231343Sbrian			if (rev == 0x12)
29331343Sbrian				device_set_desc(dev, "BrookTree 848A");
29431343Sbrian			else
29531343Sbrian				device_set_desc(dev, "BrookTree 848");
29631343Sbrian			return 0;
29728679Sbrian		case PCI_PRODUCT_BROOKTREE_BT849:
29828679Sbrian			device_set_desc(dev, "BrookTree 849A");
29910528Samurai			return 0;
30028679Sbrian		case PCI_PRODUCT_BROOKTREE_BT878:
30128679Sbrian			device_set_desc(dev, "BrookTree 878");
30228974Sbrian			return 0;
30328679Sbrian		case PCI_PRODUCT_BROOKTREE_BT879:
30428679Sbrian			device_set_desc(dev, "BrookTree 879");
30531125Sbrian			return 0;
30631343Sbrian		}
30731343Sbrian	};
30830316Sbrian
30930316Sbrian        return ENXIO;
31030316Sbrian}
31131343Sbrian
31230316Sbrian
31320813Sjkh/*
31431343Sbrian * the attach routine.
31528679Sbrian */
31610528Samuraistatic int
31728679Sbrianbktr_attach( device_t dev )
31826516Sbrian{
31910528Samurai	u_long		latency;
32010528Samurai	u_long		fun;
32128679Sbrian	u_long		val;
32231343Sbrian	unsigned int	rev;
32310528Samurai	unsigned int	unit;
32420813Sjkh	int		error = 0;
32510528Samurai#ifdef BROOKTREE_IRQ
32620813Sjkh	u_long		old_irq, new_irq;
32728679Sbrian#endif
32810528Samurai
32910528Samurai        struct bktr_softc *bktr = device_get_softc(dev);
33031343Sbrian
33131343Sbrian	unit = device_get_unit(dev);
33231343Sbrian
33331343Sbrian	/* build the device name for bktr_name() */
33431343Sbrian	snprintf(bktr->bktr_xname, sizeof(bktr->bktr_xname), "bktr%d",unit);
33531343Sbrian
33631343Sbrian	/*
33731343Sbrian	 * Enable bus mastering and Memory Mapped device
33831343Sbrian	 */
33931343Sbrian	val = pci_read_config(dev, PCIR_COMMAND, 4);
34031343Sbrian	val |= (PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
34131343Sbrian	pci_write_config(dev, PCIR_COMMAND, val, 4);
34231343Sbrian
34331343Sbrian	/*
34430715Sbrian	 * Map control/status registers.
34528679Sbrian	 */
34628679Sbrian	bktr->mem_rid = PCIR_BAR(0);
34728679Sbrian	bktr->res_mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &bktr->mem_rid,
34828679Sbrian					0, ~0, 1, RF_ACTIVE);
34931121Sbrian
35031121Sbrian
35128679Sbrian	if (!bktr->res_mem) {
35231372Sbrian		device_printf(dev, "could not map memory\n");
35328679Sbrian		error = ENXIO;
35428679Sbrian		goto fail;
35528679Sbrian	}
35628679Sbrian	bktr->memt = rman_get_bustag(bktr->res_mem);
35728679Sbrian	bktr->memh = rman_get_bushandle(bktr->res_mem);
35828679Sbrian
35928679Sbrian
36028679Sbrian	/*
36128679Sbrian	 * Disable the brooktree device
36228679Sbrian	 */
36328679Sbrian	OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
36428679Sbrian	OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
36528679Sbrian
36628679Sbrian
36728679Sbrian#ifdef BROOKTREE_IRQ		/* from the configuration file */
36829083Sbrian	old_irq = pci_conf_read(tag, PCI_INTERRUPT_REG);
36928679Sbrian	pci_conf_write(tag, PCI_INTERRUPT_REG, BROOKTREE_IRQ);
37028679Sbrian	new_irq = pci_conf_read(tag, PCI_INTERRUPT_REG);
37128679Sbrian	printf("bktr%d: attach: irq changed from %d to %d\n",
37228679Sbrian		unit, (old_irq & 0xff), (new_irq & 0xff));
37328679Sbrian#endif
37428679Sbrian
37528679Sbrian	/*
37628679Sbrian	 * Allocate our interrupt.
37728679Sbrian	 */
37831372Sbrian	bktr->irq_rid = 0;
37928679Sbrian	bktr->res_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &bktr->irq_rid,
38031372Sbrian				0, ~0, 1, RF_SHAREABLE | RF_ACTIVE);
38131343Sbrian	if (bktr->res_irq == NULL) {
38228679Sbrian		device_printf(dev, "could not map interrupt\n");
38328679Sbrian		error = ENXIO;
38431343Sbrian		goto fail;
38528679Sbrian	}
38628679Sbrian
38728679Sbrian	error = bus_setup_intr(dev, bktr->res_irq, INTR_TYPE_TTY,
38831343Sbrian                               bktr_intr, bktr, &bktr->res_ih);
38928679Sbrian	if (error) {
39028679Sbrian		device_printf(dev, "could not setup irq\n");
39128679Sbrian		goto fail;
3926059Samurai
3936059Samurai	}
39428536Sbrian
39531343Sbrian
39628536Sbrian	/* Update the Device Control Register */
39728536Sbrian	/* on Bt878 and Bt879 cards           */
39828536Sbrian	fun = pci_read_config( dev, 0x40, 2);
39928536Sbrian        fun = fun | 1;	/* Enable writes to the sub-system vendor ID */
40028536Sbrian
40128536Sbrian#if defined( BKTR_430_FX_MODE )
40228536Sbrian	if (bootverbose) printf("Using 430 FX chipset compatibilty mode\n");
40328679Sbrian        fun = fun | 2;	/* Enable Intel 430 FX compatibility mode */
40431343Sbrian#endif
4056059Samurai
4066059Samurai#if defined( BKTR_SIS_VIA_MODE )
4076059Samurai	if (bootverbose) printf("Using SiS/VIA chipset compatibilty mode\n");
40826516Sbrian        fun = fun | 4;	/* Enable SiS/VIA compatibility mode (usefull for
40926516Sbrian                           OPTi chipset motherboards too */
41030913Sbrian#endif
41130913Sbrian	pci_write_config(dev, 0x40, fun, 2);
41230913Sbrian
41330913Sbrian#if defined(BKTR_USE_FREEBSD_SMBUS)
41426516Sbrian	if (bt848_i2c_attach(dev))
41530913Sbrian		printf("bktr%d: i2c_attach: can't attach\n", unit);
41630913Sbrian#endif
41730913Sbrian
41830913Sbrian/*
41930913Sbrian * PCI latency timer.  32 is a good value for 4 bus mastering slots, if
42030913Sbrian * you have more than four, then 16 would probably be a better value.
42126516Sbrian */
42226516Sbrian#ifndef BROOKTREE_DEF_LATENCY_VALUE
42326516Sbrian#define BROOKTREE_DEF_LATENCY_VALUE	10
4246059Samurai#endif
4256059Samurai	latency = pci_read_config(dev, PCI_LATENCY_TIMER, 4);
42628679Sbrian	latency = (latency >> 8) & 0xff;
42731343Sbrian	if ( bootverbose ) {
4286059Samurai		if (latency)
4296059Samurai			printf("brooktree%d: PCI bus latency is", unit);
4306059Samurai		else
43126516Sbrian			printf("brooktree%d: PCI bus latency was 0 changing to",
43226516Sbrian				unit);
4336059Samurai	}
43426516Sbrian	if ( !latency ) {
43526516Sbrian		latency = BROOKTREE_DEF_LATENCY_VALUE;
43628679Sbrian		pci_write_config(dev, PCI_LATENCY_TIMER, latency<<8, 4);
43728679Sbrian	}
43828679Sbrian	if ( bootverbose ) {
43926516Sbrian		printf(" %d.\n", (int) latency);
4406059Samurai	}
44131077Sbrian
4426059Samurai	/* read the pci device id and revision id */
4436059Samurai	fun = pci_get_devid(dev);
44428679Sbrian        rev = pci_get_revid(dev);
44531343Sbrian
4466059Samurai	/* call the common attach code */
44731077Sbrian	common_bktr_attach( bktr, unit, fun, rev );
44831077Sbrian
44931077Sbrian	/* make the device entries */
45031077Sbrian	bktr->bktrdev = make_dev(&bktr_cdevsw, unit,
45131077Sbrian				0, 0, 0444, "bktr%d",  unit);
4526059Samurai	bktr->tunerdev= make_dev(&bktr_cdevsw, unit+16,
4536059Samurai				0, 0, 0444, "tuner%d", unit);
45428679Sbrian	bktr->vbidev  = make_dev(&bktr_cdevsw, unit+32,
45531343Sbrian				0, 0, 0444, "vbi%d"  , unit);
45628327Sbrian
45728327Sbrian
45828327Sbrian	/* if this is unit 0 (/dev/bktr0, /dev/tuner0, /dev/vbi0) then make */
45928461Sbrian	/* alias entries to /dev/bktr /dev/tuner and /dev/vbi */
46028461Sbrian#if (__FreeBSD_version >=500000)
46128461Sbrian	if (unit == 0) {
46228461Sbrian		bktr->bktrdev_alias = make_dev_alias(bktr->bktrdev,  "bktr");
46328327Sbrian		bktr->tunerdev_alias= make_dev_alias(bktr->tunerdev, "tuner");
46428461Sbrian		bktr->vbidev_alias  = make_dev_alias(bktr->vbidev,   "vbi");
46528461Sbrian	}
46628461Sbrian#endif
46728461Sbrian
46828461Sbrian	return 0;
46928461Sbrian
47028461Sbrianfail:
47128461Sbrian	if (bktr->res_irq)
47228461Sbrian		bus_release_resource(dev, SYS_RES_IRQ, bktr->irq_rid, bktr->res_irq);
47328461Sbrian	if (bktr->res_mem)
47428461Sbrian		bus_release_resource(dev, SYS_RES_IRQ, bktr->mem_rid, bktr->res_mem);
47528461Sbrian	return error;
47628461Sbrian
47728461Sbrian}
47828461Sbrian
47928461Sbrian/*
48031077Sbrian * the detach routine.
48128327Sbrian */
48228327Sbrianstatic int
48328679Sbrianbktr_detach( device_t dev )
48431343Sbrian{
4856059Samurai	struct bktr_softc *bktr = device_get_softc(dev);
48626516Sbrian
48726516Sbrian#ifdef BKTR_NEW_MSP34XX_DRIVER
48826516Sbrian	/* Disable the soundchip and kernel thread */
48926516Sbrian	if (bktr->msp3400c_info != NULL)
49029840Sbrian		msp_detach(bktr);
49129840Sbrian#endif
49229840Sbrian
49331077Sbrian	/* Disable the brooktree device */
4946059Samurai	OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
4956059Samurai	OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
49628679Sbrian
49731343Sbrian#if defined(BKTR_USE_FREEBSD_SMBUS)
4986059Samurai	if (bt848_i2c_detach(dev))
49931077Sbrian		printf("bktr%d: i2c_attach: can't attach\n",
50031077Sbrian		     device_get_unit(dev));
50131077Sbrian#endif
5026059Samurai#ifdef USE_VBIMUTEX
5036059Samurai        mtx_destroy(&bktr->vbimutex);
50428679Sbrian#endif
50531343Sbrian
50626326Sbrian	/* Note: We do not free memory for RISC programs, grab buffer, vbi buffers */
50731077Sbrian	/* The memory is retained by the bktr_mem module so we can unload and */
50831077Sbrian	/* then reload the main bktr driver module */
50931077Sbrian
51026326Sbrian	/* Unregister the /dev/bktrN, tunerN and vbiN devices,
51126326Sbrian	 * the aliases for unit 0 are automatically destroyed */
51228679Sbrian	destroy_dev(bktr->vbidev);
51331343Sbrian	destroy_dev(bktr->tunerdev);
51426326Sbrian	destroy_dev(bktr->bktrdev);
51531077Sbrian
51631077Sbrian	/*
51731077Sbrian	 * Deallocate resources.
51831077Sbrian	 */
51931077Sbrian	bus_teardown_intr(dev, bktr->res_irq, bktr->res_ih);
52031077Sbrian	bus_release_resource(dev, SYS_RES_IRQ, bktr->irq_rid, bktr->res_irq);
52126326Sbrian	bus_release_resource(dev, SYS_RES_MEMORY, bktr->mem_rid, bktr->res_mem);
52226326Sbrian
52328679Sbrian	return 0;
52431343Sbrian}
52525067Sbrian
52631077Sbrian/*
52731077Sbrian * the shutdown routine.
52831077Sbrian */
52931077Sbrianstatic int
53025067Sbrianbktr_shutdown( device_t dev )
53125067Sbrian{
53228679Sbrian	struct bktr_softc *bktr = device_get_softc(dev);
53331343Sbrian
53411336Samurai	/* Disable the brooktree device */
53526516Sbrian	OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
53626516Sbrian	OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
53726516Sbrian
53811336Samurai	return 0;
53911336Samurai}
54026516Sbrian
54128679Sbrian
54226516Sbrian/*
54311336Samurai * Special Memory Allocation
54411336Samurai */
54526516Sbrianvm_offset_t
54624939Sbrianget_bktr_mem( int unit, unsigned size )
54724939Sbrian{
54826516Sbrian	vm_offset_t	addr = 0;
54928679Sbrian
55026516Sbrian	addr = vm_page_alloc_contig(size, 0, 0xffffffff, 1<<24);
55124939Sbrian	if (addr == 0)
55224939Sbrian		addr = vm_page_alloc_contig(size, 0, 0xffffffff, PAGE_SIZE);
55311336Samurai	if (addr == 0) {
55428679Sbrian		printf("bktr%d: Unable to allocate %d bytes of memory.\n",
55511336Samurai			unit, size);
55626516Sbrian	}
55711336Samurai
55831077Sbrian	return( addr );
55911336Samurai}
56011336Samurai
56126516Sbrian
56228679Sbrian/*---------------------------------------------------------
56331343Sbrian**
56418752Sjkh**	BrookTree 848 character device driver routines
56531077Sbrian**
56631077Sbrian**---------------------------------------------------------
56731077Sbrian*/
56831077Sbrian
56931077Sbrian#define VIDEO_DEV	0x00
57031077Sbrian#define TUNER_DEV	0x01
57131077Sbrian#define VBI_DEV		0x02
57231077Sbrian
57318752Sjkh#define UNIT(x)		((x) & 0x0f)
57428679Sbrian#define FUNCTION(x)	(x >> 4)
57526516Sbrian
57618752Sjkh/*
57730715Sbrian *
57828679Sbrian */
57931372Sbrianstatic int
58028679Sbrianbktr_open( dev_t dev, int flags, int fmt, struct thread *td )
58131372Sbrian{
58228679Sbrian	bktr_ptr_t	bktr;
58328679Sbrian	int		unit;
58428679Sbrian	int		result;
58531372Sbrian
58628679Sbrian	unit = UNIT( minor(dev) );
58728679Sbrian
58828679Sbrian	/* Get the device data */
58928679Sbrian	bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
59028679Sbrian	if (bktr == NULL) {
59131372Sbrian		/* the device is no longer valid/functioning */
59228679Sbrian		return (ENXIO);
59328679Sbrian	}
59428679Sbrian
59528679Sbrian	if (!(bktr->flags & METEOR_INITALIZED)) /* device not found */
59628679Sbrian		return( ENXIO );
59728679Sbrian
59828679Sbrian	/* Record that the device is now busy */
59931372Sbrian	device_busy(devclass_get_device(bktr_devclass, unit));
60028679Sbrian
60131372Sbrian
60228679Sbrian	if (bt848_card != -1) {
60328679Sbrian	  if ((bt848_card >> 8   == unit ) &&
60428679Sbrian	     ( (bt848_card & 0xff) < Bt848_MAX_CARD )) {
60528679Sbrian	    if ( bktr->bt848_card != (bt848_card & 0xff) ) {
60628679Sbrian	      bktr->bt848_card = (bt848_card & 0xff);
60728679Sbrian	      probeCard(bktr, FALSE, unit);
60828679Sbrian	    }
60928679Sbrian	  }
61028679Sbrian	}
61128679Sbrian
61228679Sbrian	if (bt848_tuner != -1) {
61328679Sbrian	  if ((bt848_tuner >> 8   == unit ) &&
61428679Sbrian	     ( (bt848_tuner & 0xff) < Bt848_MAX_TUNER )) {
61531372Sbrian	    if ( bktr->bt848_tuner != (bt848_tuner & 0xff) ) {
61628679Sbrian	      bktr->bt848_tuner = (bt848_tuner & 0xff);
61731372Sbrian	      probeCard(bktr, FALSE, unit);
61828679Sbrian	    }
61928679Sbrian	  }
62028679Sbrian	}
62131372Sbrian
62228679Sbrian	if (bt848_reverse_mute != -1) {
62331372Sbrian	  if ((bt848_reverse_mute >> 8)   == unit ) {
62426516Sbrian	    bktr->reverse_mute = bt848_reverse_mute & 0xff;
62528679Sbrian	  }
62628679Sbrian	}
62726516Sbrian
62828679Sbrian	if (bt848_slow_msp_audio != -1) {
62928679Sbrian	  if ((bt848_slow_msp_audio >> 8) == unit ) {
63028679Sbrian	      bktr->slow_msp_audio = (bt848_slow_msp_audio & 0xff);
63131343Sbrian	  }
63228679Sbrian	}
6336059Samurai
6346059Samurai#ifdef BKTR_NEW_MSP34XX_DRIVER
63530715Sbrian	if (bt848_stereo_once != 0) {
63631343Sbrian	  if ((bt848_stereo_once >> 8) == unit ) {
6376059Samurai	      bktr->stereo_once = (bt848_stereo_once & 0xff);
63826516Sbrian	  }
63926516Sbrian	}
64028679Sbrian
6416059Samurai	if (bt848_amsound != -1) {
64226516Sbrian	  if ((bt848_amsound >> 8) == unit ) {
64326516Sbrian	      bktr->amsound = (bt848_amsound & 0xff);
64426516Sbrian	  }
6456059Samurai	}
64625566Sbrian
64726516Sbrian	if (bt848_dolby != -1) {
64828679Sbrian	  if ((bt848_dolby >> 8) == unit ) {
64928679Sbrian	      bktr->dolby = (bt848_dolby & 0xff);
65026516Sbrian	  }
6516059Samurai	}
6526059Samurai#endif
65328679Sbrian
65426516Sbrian	switch ( FUNCTION( minor(dev) ) ) {
65528679Sbrian	case VIDEO_DEV:
65628679Sbrian		result = video_open( bktr );
65726516Sbrian		break;
6586059Samurai	case TUNER_DEV:
6596059Samurai		result = tuner_open( bktr );
6606059Samurai		break;
6616059Samurai	case VBI_DEV:
6626059Samurai		result = vbi_open( bktr );
6636059Samurai		break;
66426516Sbrian	default:
6656059Samurai		result = ENXIO;
6666059Samurai		break;
66730715Sbrian	}
66831343Sbrian
6696059Samurai	/* If there was an error opening the device, undo the busy status */
67028679Sbrian	if (result != 0)
6716059Samurai		device_unbusy(devclass_get_device(bktr_devclass, unit));
6726059Samurai	return( result );
67331343Sbrian}
6746059Samurai
67531343Sbrian
6766059Samurai/*
67726516Sbrian *
67831343Sbrian */
67931372Sbrianstatic int
68031343Sbrianbktr_close( dev_t dev, int flags, int fmt, struct thread *td )
68131343Sbrian{
68231343Sbrian	bktr_ptr_t	bktr;
68331343Sbrian	int		unit;
68431343Sbrian	int		result;
68526516Sbrian
68626516Sbrian	unit = UNIT( minor(dev) );
68726516Sbrian
68826516Sbrian	/* Get the device data */
68928679Sbrian	bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
69026516Sbrian	if (bktr == NULL) {
69126516Sbrian		/* the device is no longer valid/functioning */
69226516Sbrian		return (ENXIO);
6936059Samurai	}
6946059Samurai
69518885Sjkh	switch ( FUNCTION( minor(dev) ) ) {
69618885Sjkh	case VIDEO_DEV:
6976059Samurai		result = video_close( bktr );
69818885Sjkh		break;
6996059Samurai	case TUNER_DEV:
70031343Sbrian		result = tuner_close( bktr );
7016735Samurai		break;
70231121Sbrian	case VBI_DEV:
7036059Samurai		result = vbi_close( bktr );
7046735Samurai		break;
70518885Sjkh	default:
70626516Sbrian		return (ENXIO);
70718885Sjkh		break;
70818885Sjkh	}
7096735Samurai
71028679Sbrian	device_unbusy(devclass_get_device(bktr_devclass, unit));
7116735Samurai	return( result );
7126735Samurai}
7136735Samurai
7146059Samurai
7156735Samurai/*
7166059Samurai *
7176735Samurai */
71826516Sbrianstatic int
71926516Sbrianbktr_read( dev_t dev, struct uio *uio, int ioflag )
7206059Samurai{
7216059Samurai	bktr_ptr_t	bktr;
7226059Samurai	int		unit;
72331121Sbrian
7246059Samurai	unit = UNIT(minor(dev));
72531343Sbrian
7266059Samurai	/* Get the device data */
7276059Samurai	bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
7286059Samurai	if (bktr == NULL) {
7296059Samurai		/* the device is no longer valid/functioning */
7306059Samurai		return (ENXIO);
7316059Samurai	}
73231121Sbrian
73331121Sbrian	switch ( FUNCTION( minor(dev) ) ) {
73431121Sbrian	case VIDEO_DEV:
73531121Sbrian		return( video_read( bktr, unit, dev, uio ) );
73631121Sbrian	case VBI_DEV:
7376059Samurai		return( vbi_read( bktr, uio, ioflag ) );
73831121Sbrian	}
73931343Sbrian        return( ENXIO );
74031121Sbrian}
74131156Sbrian
74231156Sbrian
74331156Sbrian/*
74431156Sbrian *
74531156Sbrian */
74631156Sbrianstatic int
74731156Sbrianbktr_write( dev_t dev, struct uio *uio, int ioflag )
74831156Sbrian{
74931156Sbrian	return( EINVAL ); /* XXX or ENXIO ? */
75031156Sbrian}
75131156Sbrian
75231156Sbrian
75331156Sbrian/*
75431156Sbrian *
75531156Sbrian */
75631156Sbrianstatic int
75731156Sbrianbktr_ioctl( dev_t dev, ioctl_cmd_t cmd, caddr_t arg, int flag, struct thread *td )
75831156Sbrian{
75931156Sbrian	bktr_ptr_t	bktr;
76031121Sbrian	int		unit;
76131156Sbrian
7626059Samurai	unit = UNIT(minor(dev));
7636059Samurai
76431121Sbrian	/* Get the device data */
76531156Sbrian	bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
76631121Sbrian	if (bktr == NULL) {
76731121Sbrian		/* the device is no longer valid/functioning */
76831121Sbrian		return (ENXIO);
76931121Sbrian	}
77031121Sbrian
77131343Sbrian	if (bktr->bigbuf == 0)	/* no frame buffer allocated (ioctl failed) */
77231121Sbrian		return( ENOMEM );
77331121Sbrian
7746059Samurai	switch ( FUNCTION( minor(dev) ) ) {
77531343Sbrian	case VIDEO_DEV:
7766059Samurai		return( video_ioctl( bktr, unit, cmd, arg, td ) );
77731343Sbrian	case TUNER_DEV:
77831343Sbrian		return( tuner_ioctl( bktr, unit, cmd, arg, td ) );
77926516Sbrian	}
78031343Sbrian
7816059Samurai	return( ENXIO );
78226516Sbrian}
78326516Sbrian
78426516Sbrian
7856059Samurai/*
7866059Samurai *
7876059Samurai */
78831343Sbrianstatic int
7896059Samuraibktr_mmap( dev_t dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot )
7906059Samurai{
79126516Sbrian	int		unit;
79226516Sbrian	bktr_ptr_t	bktr;
79326516Sbrian
7946059Samurai	unit = UNIT(minor(dev));
79530913Sbrian
79628679Sbrian	if (FUNCTION(minor(dev)) > 0)	/* only allow mmap on /dev/bktr[n] */
79731034Sbrian		return( -1 );
79826516Sbrian
79926516Sbrian	/* Get the device data */
80028679Sbrian	bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
8016059Samurai	if (bktr == NULL) {
80226516Sbrian		/* the device is no longer valid/functioning */
80326516Sbrian		return (ENXIO);
80426516Sbrian	}
80526516Sbrian
8066059Samurai	if (nprot & PROT_EXEC)
80728679Sbrian		return( -1 );
8086059Samurai
8096059Samurai	if (offset < 0)
8106059Samurai		return( -1 );
81131343Sbrian
8126059Samurai	if (offset >= bktr->alloc_pages * PAGE_SIZE)
81331203Sbrian		return( -1 );
81431203Sbrian
81531203Sbrian	*paddr = vtophys(bktr->bigbuf) + offset;
81631203Sbrian	return( 0 );
81731343Sbrian}
81831203Sbrian
81931121Sbrianstatic int
82026516Sbrianbktr_poll( dev_t dev, int events, struct thread *td)
82126516Sbrian{
8226059Samurai	int		unit;
8236059Samurai	bktr_ptr_t	bktr;
8246059Samurai	int revents = 0;
82531343Sbrian	DECLARE_INTR_MASK(s);
8266059Samurai
82726098Sbrian	unit = UNIT(minor(dev));
8286059Samurai
82926516Sbrian	/* Get the device data */
8306059Samurai	bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
8316059Samurai	if (bktr == NULL) {
8326059Samurai		/* the device is no longer valid/functioning */
83331343Sbrian		return (ENXIO);
8346059Samurai	}
8356059Samurai
83626516Sbrian	LOCK_VBI(bktr);
8376059Samurai	DISABLE_INTR(s);
8386059Samurai
83925067Sbrian	if (events & (POLLIN | POLLRDNORM)) {
84031343Sbrian
8416059Samurai		switch ( FUNCTION( minor(dev) ) ) {
8426059Samurai		case VBI_DEV:
8436059Samurai			if(bktr->vbisize == 0)
84431343Sbrian				selrecord(td, &bktr->vbi_select);
84531343Sbrian			else
8466735Samurai				revents |= events & (POLLIN | POLLRDNORM);
84726516Sbrian			break;
8486735Samurai		}
84931343Sbrian	}
8506735Samurai
8516735Samurai	ENABLE_INTR(s);
85226516Sbrian	UNLOCK_VBI(bktr);
8536059Samurai
85431343Sbrian	return (revents);
8556059Samurai}
85626516Sbrian
8576059Samurai#endif		/* FreeBSD 4.x specific kernel interface routines */
8586059Samurai
85925067Sbrian/*****************/
86031343Sbrian/* *** BSDI  *** */
86111336Samurai/*****************/
86231343Sbrian
86331343Sbrian#if defined(__bsdi__)
86431343Sbrian#endif		/* __bsdi__ BSDI specific kernel interface routines */
86526516Sbrian
86626516Sbrian
86726516Sbrian/*****************************/
86825067Sbrian/* *** OpenBSD / NetBSD  *** */
86925067Sbrian/*****************************/
87025067Sbrian#if defined(__NetBSD__) || defined(__OpenBSD__)
87131343Sbrian
87225067Sbrian#define IPL_VIDEO       IPL_BIO         /* XXX */
87311336Samurai
87411336Samuraistatic	int		bktr_intr(void *arg) { return common_bktr_intr(arg); }
87524939Sbrian
87611336Samurai#define bktr_open       bktropen
87731343Sbrian#define bktr_close      bktrclose
87831343Sbrian#define bktr_read       bktrread
87931343Sbrian#define bktr_write      bktrwrite
88011336Samurai#define bktr_ioctl      bktrioctl
88130715Sbrian#define bktr_mmap       bktrmmap
88226516Sbrian
88331343Sbrianvm_offset_t vm_page_alloc_contig(vm_offset_t, vm_offset_t,
88411336Samurai                                 vm_offset_t, vm_offset_t);
88526516Sbrian
88611336Samurai#if defined(__OpenBSD__)
88711336Samuraistatic int      bktr_probe(struct device *, void *, void *);
88826516Sbrian#else
88928679Sbrianstatic int      bktr_probe(struct device *, struct cfdata *, void *);
89011336Samurai#endif
89111336Samuraistatic void     bktr_attach(struct device *, struct device *, void *);
89224939Sbrian
89331343Sbrianstruct cfattach bktr_ca = {
89424939Sbrian        sizeof(struct bktr_softc), bktr_probe, bktr_attach
89524939Sbrian};
89628679Sbrian
89730715Sbrian#if defined(__NetBSD__)
89828679Sbrianextern struct cfdriver bktr_cd;
89928679Sbrian#else
90028679Sbrianstruct cfdriver bktr_cd = {
90128679Sbrian        NULL, "bktr", DV_DULL
90228679Sbrian};
90328679Sbrian#endif
90426516Sbrian
90528679Sbrianint
90624939Sbrianbktr_probe(parent, match, aux)
90728679Sbrian	struct device *parent;
90828679Sbrian#if defined(__OpenBSD__)
90924939Sbrian        void *match;
91031343Sbrian#else
91131343Sbrian        struct cfdata *match;
91211336Samurai#endif
91311336Samurai        void *aux;
91426516Sbrian{
91526516Sbrian        struct pci_attach_args *pa = aux;
91626516Sbrian
91726516Sbrian        if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_BROOKTREE &&
91811336Samurai            (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROOKTREE_BT848 ||
91911336Samurai             PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROOKTREE_BT849 ||
92026516Sbrian             PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROOKTREE_BT878 ||
92111336Samurai             PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROOKTREE_BT879))
92226516Sbrian                return 1;
92311336Samurai
92411336Samurai        return 0;
92525067Sbrian}
92631343Sbrian
92728327Sbrian
92828461Sbrian/*
92928461Sbrian * the attach routine.
93028461Sbrian */
93131343Sbrianstatic void
93231343Sbrianbktr_attach(struct device *parent, struct device *self, void *aux)
93331343Sbrian{
93431343Sbrian	bktr_ptr_t	bktr;
93531343Sbrian	u_long		latency;
93631343Sbrian	u_long		fun;
93731343Sbrian	unsigned int	rev;
93828461Sbrian
93928461Sbrian#if defined(__OpenBSD__)
94028327Sbrian	struct pci_attach_args *pa = aux;
94128327Sbrian	pci_chipset_tag_t pc = pa->pa_pc;
94228327Sbrian
94328327Sbrian	pci_intr_handle_t ih;
94428327Sbrian	const char *intrstr;
94531081Sbrian	int retval;
94631081Sbrian	int unit;
94731081Sbrian
94828327Sbrian	bktr = (bktr_ptr_t)self;
94931343Sbrian	unit = bktr->bktr_dev.dv_unit;
95026940Sbrian
95126940Sbrian	bktr->pc = pa->pa_pc;
95226940Sbrian	bktr->tag = pa->pa_tag;
95331343Sbrian        bktr->dmat = pa->pa_dmat;
95431081Sbrian
95531081Sbrian	/*
95631081Sbrian	 * map memory
95731343Sbrian	 */
95831343Sbrian	bktr->memt = pa->pa_memt;
95931343Sbrian	retval = pci_mem_find(pc, pa->pa_tag, PCI_MAPREG_START,
96031081Sbrian			      &bktr->phys_base, &bktr->obmemsz, NULL);
96131343Sbrian	if (!retval)
96231081Sbrian		retval = bus_space_map(pa->pa_memt, bktr->phys_base,
96331343Sbrian				       bktr->obmemsz, 0, &bktr->memh);
96431081Sbrian	if (retval) {
96531081Sbrian		printf(": couldn't map memory\n");
96631343Sbrian		return;
96731343Sbrian	}
96831343Sbrian
96931081Sbrian
97031081Sbrian	/*
97131081Sbrian	 * map interrupt
97231081Sbrian	 */
97331081Sbrian	if (pci_intr_map(pa->pa_pc, pa->pa_intrtag, pa->pa_intrpin,
97431081Sbrian			 pa->pa_intrline, &ih)) {
97531081Sbrian		printf(": couldn't map interrupt\n");
97631081Sbrian		return;
97731081Sbrian	}
97831081Sbrian	intrstr = pci_intr_string(pa->pa_pc, ih);
97931081Sbrian
98031081Sbrian	bktr->ih = pci_intr_establish(pa->pa_pc, ih, IPL_VIDEO,
98131081Sbrian				      bktr_intr, bktr, bktr->bktr_dev.dv_xname);
98231081Sbrian	if (bktr->ih == NULL) {
98331081Sbrian		printf(": couldn't establish interrupt");
98431081Sbrian		if (intrstr != NULL)
98531081Sbrian			printf(" at %s", intrstr);
98631081Sbrian		printf("\n");
98731081Sbrian		return;
98831081Sbrian	}
98926940Sbrian
99031081Sbrian	if (intrstr != NULL)
99131081Sbrian		printf(": %s\n", intrstr);
99226940Sbrian#endif /* __OpenBSD__ */
99331081Sbrian
99431081Sbrian#if defined(__NetBSD__)
99528679Sbrian	struct pci_attach_args *pa = aux;
99631081Sbrian	pci_intr_handle_t ih;
99728679Sbrian	const char *intrstr;
99828679Sbrian	int retval;
99931081Sbrian	int unit;
100031081Sbrian
100131081Sbrian	bktr = (bktr_ptr_t)self;
100231081Sbrian	unit = bktr->bktr_dev.dv_unit;
100331081Sbrian        bktr->dmat = pa->pa_dmat;
100431081Sbrian
100531081Sbrian	printf("\n");
100627346Sbrian
100731081Sbrian	/*
100828679Sbrian	 * map memory
100931081Sbrian	 */
101031081Sbrian	retval = pci_mapreg_map(pa, PCI_MAPREG_START,
101128679Sbrian				PCI_MAPREG_TYPE_MEM
101231081Sbrian				| PCI_MAPREG_MEM_TYPE_32BIT, 0,
101331081Sbrian				&bktr->memt, &bktr->memh, NULL,
101431081Sbrian				&bktr->obmemsz);
101531081Sbrian	DPR(("pci_mapreg_map: memt %x, memh %x, size %x\n",
101631081Sbrian	     bktr->memt, (u_int)bktr->memh, (u_int)bktr->obmemsz));
101731081Sbrian	if (retval) {
101828679Sbrian		printf("%s: couldn't map memory\n", bktr_name(bktr));
101931081Sbrian		return;
102027346Sbrian	}
102131081Sbrian
102231081Sbrian	/*
102327346Sbrian	 * Disable the brooktree device
102431081Sbrian	 */
102526940Sbrian	OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
102626940Sbrian	OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
102726940Sbrian
102826940Sbrian	/*
102926940Sbrian	 * map interrupt
103031343Sbrian	 */
10316059Samurai	if (pci_intr_map(pa->pa_pc, pa->pa_intrtag, pa->pa_intrpin,
103231343Sbrian			 pa->pa_intrline, &ih)) {
10336059Samurai		printf("%s: couldn't map interrupt\n",
10346059Samurai		       bktr_name(bktr));
10356059Samurai		return;
103631343Sbrian	}
10376059Samurai	intrstr = pci_intr_string(pa->pa_pc, ih);
103826516Sbrian	bktr->ih = pci_intr_establish(pa->pa_pc, ih, IPL_VIDEO,
103926516Sbrian				      bktr_intr, bktr);
104031343Sbrian	if (bktr->ih == NULL) {
104131343Sbrian		printf("%s: couldn't establish interrupt",
104230913Sbrian		       bktr_name(bktr));
104330913Sbrian		if (intrstr != NULL)
10446059Samurai			printf(" at %s", intrstr);
104531343Sbrian		printf("\n");
104631343Sbrian		return;
104726516Sbrian	}
104831288Sbrian	if (intrstr != NULL)
104930913Sbrian		printf("%s: interrupting at %s\n", bktr_name(bktr),
105030913Sbrian		       intrstr);
105130913Sbrian#endif /* __NetBSD__ */
105230913Sbrian
105330913Sbrian/*
105430913Sbrian * PCI latency timer.  32 is a good value for 4 bus mastering slots, if
105530913Sbrian * you have more than four, then 16 would probably be a better value.
105630913Sbrian */
105730913Sbrian#ifndef BROOKTREE_DEF_LATENCY_VALUE
105830913Sbrian#define BROOKTREE_DEF_LATENCY_VALUE	10
105930913Sbrian#endif
106026516Sbrian	latency = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_LATENCY_TIMER);
106131343Sbrian	latency = (latency >> 8) & 0xff;
106226516Sbrian
106331343Sbrian	if (!latency) {
106426516Sbrian		if (bootverbose) {
106531343Sbrian			printf("%s: PCI bus latency was 0 changing to %d",
106628679Sbrian			       bktr_name(bktr), BROOKTREE_DEF_LATENCY_VALUE);
106730913Sbrian		}
106828679Sbrian		latency = BROOKTREE_DEF_LATENCY_VALUE;
106930913Sbrian		pci_conf_write(pa->pa_pc, pa->pa_tag,
10706059Samurai			       PCI_LATENCY_TIMER, latency<<8);
10716059Samurai	}
107226516Sbrian
107331343Sbrian
107426516Sbrian	/* Enabled Bus Master
10756059Samurai	   XXX: check if all old DMA is stopped first (e.g. after warm
107626516Sbrian	   boot) */
10776059Samurai	fun = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
107826516Sbrian	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
10796059Samurai		       fun | PCI_COMMAND_MASTER_ENABLE);
10806059Samurai
10816059Samurai	/* read the pci id and determine the card type */
108231343Sbrian	fun = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ID_REG);
10836059Samurai        rev = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_CLASS_REG) & 0x000000ff;
10846059Samurai
108531343Sbrian	common_bktr_attach(bktr, unit, fun, rev);
108631343Sbrian}
10876059Samurai
10886059Samurai
10896059Samurai/*
109031343Sbrian * Special Memory Allocation
10916059Samurai */
10926059Samuraivm_offset_t
10936059Samuraiget_bktr_mem(bktr, dmapp, size)
109428679Sbrian        bktr_ptr_t bktr;
10956059Samurai        bus_dmamap_t *dmapp;
10966059Samurai        unsigned int size;
109726516Sbrian{
10986059Samurai        bus_dma_tag_t dmat = bktr->dmat;
10996059Samurai        bus_dma_segment_t seg;
11006059Samurai        bus_size_t align;
110131343Sbrian        int rseg;
11026059Samurai        caddr_t kva;
110326326Sbrian
110431343Sbrian        /*
11056059Samurai         * Allocate a DMA area
110631343Sbrian         */
110731343Sbrian        align = 1 << 24;
110826326Sbrian        if (bus_dmamem_alloc(dmat, size, align, 0, &seg, 1,
110926516Sbrian                             &rseg, BUS_DMA_NOWAIT)) {
11106059Samurai                align = PAGE_SIZE;
111126516Sbrian                if (bus_dmamem_alloc(dmat, size, align, 0, &seg, 1,
111226516Sbrian                                     &rseg, BUS_DMA_NOWAIT)) {
11136059Samurai                        printf("%s: Unable to dmamem_alloc of %d bytes\n",
111426516Sbrian			       bktr_name(bktr), size);
111526516Sbrian                        return 0;
111626516Sbrian                }
111726516Sbrian        }
111826516Sbrian        if (bus_dmamem_map(dmat, &seg, rseg, size,
11196059Samurai                           &kva, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) {
11206059Samurai                printf("%s: Unable to dmamem_map of %d bytes\n",
11216059Samurai                        bktr_name(bktr), size);
112231343Sbrian                bus_dmamem_free(dmat, &seg, rseg);
112326326Sbrian                return 0;
112426326Sbrian        }
112531343Sbrian#ifdef __OpenBSD__
112626326Sbrian        bktr->dm_mapsize = size;
112731343Sbrian#endif
112831343Sbrian        /*
112926516Sbrian         * Create and locd the DMA map for the DMA area
113026326Sbrian         */
113126516Sbrian        if (bus_dmamap_create(dmat, size, 1, size, 0, BUS_DMA_NOWAIT, dmapp)) {
113226516Sbrian                printf("%s: Unable to dmamap_create of %d bytes\n",
113326516Sbrian                        bktr_name(bktr), size);
113426326Sbrian                bus_dmamem_unmap(dmat, kva, size);
113526516Sbrian                bus_dmamem_free(dmat, &seg, rseg);
113626516Sbrian                return 0;
113726326Sbrian        }
113826516Sbrian        if (bus_dmamap_load(dmat, *dmapp, kva, size, NULL, BUS_DMA_NOWAIT)) {
113926516Sbrian                printf("%s: Unable to dmamap_load of %d bytes\n",
114026516Sbrian                        bktr_name(bktr), size);
114126516Sbrian                bus_dmamem_unmap(dmat, kva, size);
114226516Sbrian                bus_dmamem_free(dmat, &seg, rseg);
114326326Sbrian                bus_dmamap_destroy(dmat, *dmapp);
114426326Sbrian                return 0;
114526326Sbrian        }
114631343Sbrian        return (vm_offset_t)kva;
11476059Samurai}
114831343Sbrian
114931343Sbrianvoid
115028679Sbrianfree_bktr_mem(bktr, dmap, kva)
115131343Sbrian        bktr_ptr_t bktr;
115231343Sbrian        bus_dmamap_t dmap;
11536735Samurai        vm_offset_t kva;
11546735Samurai{
115531343Sbrian        bus_dma_tag_t dmat = bktr->dmat;
115631343Sbrian
11576735Samurai#ifdef __NetBSD__
11586735Samurai        bus_dmamem_unmap(dmat, (caddr_t)kva, dmap->dm_mapsize);
11596735Samurai#else
11606735Samurai        bus_dmamem_unmap(dmat, (caddr_t)kva, bktr->dm_mapsize);
116126516Sbrian#endif
11626059Samurai        bus_dmamem_free(dmat, dmap->dm_segs, 1);
116326516Sbrian        bus_dmamap_destroy(dmat, dmap);
11646059Samurai}
11656059Samurai
116630715Sbrian
116731343Sbrian/*---------------------------------------------------------
11686059Samurai**
11696059Samurai**	BrookTree 848 character device driver routines
11706059Samurai**
11716059Samurai**---------------------------------------------------------
11726059Samurai*/
11736059Samurai
117430715Sbrian
11756059Samurai#define VIDEO_DEV	0x00
11766059Samurai#define TUNER_DEV	0x01
117728679Sbrian#define VBI_DEV		0x02
11786059Samurai
11796059Samurai#define UNIT(x)         (minor((x) & 0x0f))
11806059Samurai#define FUNCTION(x)     (minor((x >> 4) & 0x0f))
118131343Sbrian
11826059Samurai/*
118328394Sbrian *
11846059Samurai */
118531343Sbrianint
118628679Sbrianbktr_open(dev_t dev, int flags, int fmt, struct thread *td)
118726516Sbrian{
118828394Sbrian	bktr_ptr_t	bktr;
118928394Sbrian	int		unit;
119028394Sbrian
119131343Sbrian	unit = UNIT(dev);
119231343Sbrian
119328679Sbrian	/* unit out of range */
119428679Sbrian	if ((unit > bktr_cd.cd_ndevs) || (bktr_cd.cd_devs[unit] == NULL))
119528679Sbrian		return(ENXIO);
119628679Sbrian
119731343Sbrian	bktr = bktr_cd.cd_devs[unit];
119831343Sbrian
119925630Sbrian	if (!(bktr->flags & METEOR_INITALIZED)) /* device not found */
120025630Sbrian		return(ENXIO);
120125630Sbrian
120228679Sbrian	switch (FUNCTION(dev)) {
120331343Sbrian	case VIDEO_DEV:
120431343Sbrian		return(video_open(bktr));
120531343Sbrian	case TUNER_DEV:
120631343Sbrian		return(tuner_open(bktr));
120728679Sbrian	case VBI_DEV:
12089440Samurai		return(vbi_open(bktr));
12096059Samurai	}
12106059Samurai
12116059Samurai	return(ENXIO);
121228394Sbrian}
12136059Samurai
12146059Samurai
12156059Samurai/*
12166059Samurai *
12176059Samurai */
12186059Samuraiint
12196059Samuraibktr_close(dev_t dev, int flags, int fmt, struct thread *td)
12206059Samurai{
12216059Samurai	bktr_ptr_t	bktr;
12226059Samurai	int		unit;
12236059Samurai
122428537Sbrian	unit = UNIT(dev);
122528537Sbrian
122628537Sbrian	bktr = bktr_cd.cd_devs[unit];
122731121Sbrian
122831121Sbrian	switch (FUNCTION(dev)) {
122931121Sbrian	case VIDEO_DEV:
123031121Sbrian		return(video_close(bktr));
123126516Sbrian	case TUNER_DEV:
12326059Samurai		return(tuner_close(bktr));
12336059Samurai	case VBI_DEV:
123426516Sbrian		return(vbi_close(bktr));
12356059Samurai	}
123630715Sbrian
123728679Sbrian	return(ENXIO);
123828679Sbrian}
123928679Sbrian
124031343Sbrian/*
124118752Sjkh *
124218752Sjkh */
124318752Sjkhint
124418752Sjkhbktr_read(dev_t dev, struct uio *uio, int ioflag)
124518752Sjkh{
124618752Sjkh	bktr_ptr_t	bktr;
124728679Sbrian	int		unit;
124818752Sjkh
124928679Sbrian	unit = UNIT(dev);
125018752Sjkh
125118752Sjkh	bktr = bktr_cd.cd_devs[unit];
125218752Sjkh
125318752Sjkh	switch (FUNCTION(dev)) {
125418752Sjkh	case VIDEO_DEV:
125528679Sbrian		return(video_read(bktr, unit, dev, uio));
125628679Sbrian	case VBI_DEV:
125728679Sbrian		return(vbi_read(bktr, uio, ioflag));
125828679Sbrian	}
125928679Sbrian
126028679Sbrian        return(ENXIO);
126118752Sjkh}
126218752Sjkh
126318752Sjkh
126418752Sjkh/*
126531343Sbrian *
126618752Sjkh */
126731343Sbrianint
126826516Sbrianbktr_write(dev_t dev, struct uio *uio, int ioflag)
126918752Sjkh{
127018752Sjkh	/* operation not supported */
127118752Sjkh	return(EOPNOTSUPP);
127231343Sbrian}
127318752Sjkh
127431343Sbrian/*
127526516Sbrian *
127618752Sjkh */
127718752Sjkhint
127828679Sbrianbktr_ioctl(dev_t dev, ioctl_cmd_t cmd, caddr_t arg, int flag, struct thread *td)
127918752Sjkh{
128029696Sbrian	bktr_ptr_t	bktr;
128131343Sbrian	int		unit;
12826059Samurai
12836059Samurai	unit = UNIT(dev);
128431343Sbrian
128531343Sbrian	bktr = bktr_cd.cd_devs[unit];
12866059Samurai
128731343Sbrian	if (bktr->bigbuf == 0)	/* no frame buffer allocated (ioctl failed) */
128831343Sbrian		return(ENOMEM);
128926551Sbrian
129031343Sbrian	switch (FUNCTION(dev)) {
129126551Sbrian	case VIDEO_DEV:
129226551Sbrian		return(video_ioctl(bktr, unit, cmd, arg, pr));
129328679Sbrian	case TUNER_DEV:
129431343Sbrian		return(tuner_ioctl(bktr, unit, cmd, arg, pr));
129528679Sbrian	}
129628679Sbrian
129728679Sbrian	return(ENXIO);
129831343Sbrian}
129928679Sbrian
130028679Sbrian/*
130128679Sbrian *
130231343Sbrian */
130328679Sbrianpaddr_t
130428679Sbrianbktr_mmap(dev_t dev, off_t offset, int nprot)
130528679Sbrian{
130631343Sbrian	int		unit;
130728679Sbrian	bktr_ptr_t	bktr;
130828679Sbrian
130928679Sbrian	unit = UNIT(dev);
131029696Sbrian
131129696Sbrian	if (FUNCTION(dev) > 0)	/* only allow mmap on /dev/bktr[n] */
131231343Sbrian		return(-1);
131329696Sbrian
131431343Sbrian	bktr = bktr_cd.cd_devs[unit];
131529696Sbrian
131630715Sbrian	if ((vaddr_t)offset < 0)
131729696Sbrian		return(-1);
131829696Sbrian
131928679Sbrian	if ((vaddr_t)offset >= bktr->alloc_pages * PAGE_SIZE)
132028679Sbrian		return(-1);
132131343Sbrian
132228679Sbrian#ifdef __NetBSD__
132328679Sbrian	return (bus_dmamem_mmap(bktr->dmat, bktr->dm_mem->dm_segs, 1,
132428679Sbrian				(vaddr_t)offset, nprot, BUS_DMA_WAITOK));
132531343Sbrian#else
132628679Sbrian	return(i386_btop(vtophys(bktr->bigbuf) + offset));
132728679Sbrian#endif
132828679Sbrian}
132931082Sbrian
133028679Sbrian#endif /* __NetBSD__ || __OpenBSD__ */
133128679Sbrian