30e27d9623
found only many tv-cards. We currently use more ore less evil hacks (slow_msp_audio sysctl) to configure the various variants of these chips in order to have stereo autodetection work. Nevertheless, this doesn't always work even though it _should_, according to the specs. This is, for example, the case for some popular Hauppauge models sold sold in Germany. However, the Linux driver always worked for me and others. Looking at the sourcecode you will find that the linux-driver uses a very much enhanced approach to program the various msp34xx chipset variants, which is also found in the specs for these chips. This is a port of the Linux MSP34xx code, written by Gerd Knorr <kraxel@bytesex.org>, who agreed to re-release his code under a BSD license for this port. A new config option "BKTR_NEW_MSP34XX_DRIVER" is added, which is required to enable the new driver. Otherwise the old code is used. The msp34xx.c file is diff-reduced to the linux-driver to make later modifications easier, thus it doesn't follow style(9) in most cases. Approved by: roger (committing this, no time to test/review), keichii (code review)
1326 lines
31 KiB
C
1326 lines
31 KiB
C
/* $FreeBSD$ */
|
|
|
|
/*
|
|
* This is part of the Driver for Video Capture Cards (Frame grabbers)
|
|
* and TV Tuner cards using the Brooktree Bt848, Bt848A, Bt849A, Bt878, Bt879
|
|
* chipset.
|
|
* Copyright Roger Hardiman and Amancio Hasty.
|
|
*
|
|
* bktr_os : This has all the Operating System dependant code,
|
|
* probe/attach and open/close/ioctl/read/mmap
|
|
* memory allocation
|
|
* PCI bus interfacing
|
|
*
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* 1. Redistributions of source code must retain the
|
|
* Copyright (c) 1997 Amancio Hasty, 1999 Roger Hardiman
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by Amancio Hasty and
|
|
* Roger Hardiman
|
|
* 4. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
|
|
#include "opt_bktr.h" /* include any kernel config options */
|
|
|
|
#define FIFO_RISC_DISABLED 0
|
|
#define ALL_INTS_DISABLED 0
|
|
|
|
|
|
/*******************/
|
|
/* *** FreeBSD *** */
|
|
/*******************/
|
|
#ifdef __FreeBSD__
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/conf.h>
|
|
#include <sys/uio.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/signalvar.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/poll.h>
|
|
#if __FreeBSD_version >= 500014
|
|
#include <sys/selinfo.h>
|
|
#else
|
|
#include <sys/select.h>
|
|
#endif
|
|
#include <sys/vnode.h>
|
|
|
|
#include <vm/vm.h>
|
|
#include <vm/vm_kern.h>
|
|
#include <vm/pmap.h>
|
|
#include <vm/vm_extern.h>
|
|
|
|
#if (__FreeBSD_version >=400000)
|
|
#include <sys/bus.h> /* used by smbus and newbus */
|
|
#endif
|
|
|
|
#if (__FreeBSD_version >=300000)
|
|
#include <machine/bus_memio.h> /* used by bus space */
|
|
#include <machine/bus.h> /* used by bus space and newbus */
|
|
#include <sys/bus.h>
|
|
#endif
|
|
|
|
#if (__FreeBSD_version >=400000)
|
|
#include <sys/rman.h> /* used by newbus */
|
|
#include <machine/resource.h> /* used by newbus */
|
|
#endif
|
|
|
|
#if (__FreeBSD_version < 500000)
|
|
#include <machine/clock.h> /* for DELAY */
|
|
#endif
|
|
|
|
#include <pci/pcivar.h>
|
|
#include <pci/pcireg.h>
|
|
|
|
#include <sys/sysctl.h>
|
|
int bt848_card = -1;
|
|
int bt848_tuner = -1;
|
|
int bt848_reverse_mute = -1;
|
|
int bt848_format = -1;
|
|
int bt848_slow_msp_audio = -1;
|
|
#ifdef BKTR_NEW_MSP34XX_DRIVER
|
|
int bt848_stereo_once = 0; /* no continuous stereo monitoring */
|
|
int bt848_amsound = 0; /* hard-wire AM sound at 6.5 Hz (france),
|
|
the autoscan seems work well only with FM... */
|
|
int bt848_dolby = 0;
|
|
#endif
|
|
|
|
SYSCTL_NODE(_hw, OID_AUTO, bt848, CTLFLAG_RW, 0, "Bt848 Driver mgmt");
|
|
SYSCTL_INT(_hw_bt848, OID_AUTO, card, CTLFLAG_RW, &bt848_card, -1, "");
|
|
SYSCTL_INT(_hw_bt848, OID_AUTO, tuner, CTLFLAG_RW, &bt848_tuner, -1, "");
|
|
SYSCTL_INT(_hw_bt848, OID_AUTO, reverse_mute, CTLFLAG_RW, &bt848_reverse_mute, -1, "");
|
|
SYSCTL_INT(_hw_bt848, OID_AUTO, format, CTLFLAG_RW, &bt848_format, -1, "");
|
|
SYSCTL_INT(_hw_bt848, OID_AUTO, slow_msp_audio, CTLFLAG_RW, &bt848_slow_msp_audio, -1, "");
|
|
#ifdef BKTR_NEW_MSP34XX_DRIVER
|
|
SYSCTL_INT(_hw_bt848, OID_AUTO, stereo_once, CTLFLAG_RW, &bt848_stereo_once, 0, "");
|
|
SYSCTL_INT(_hw_bt848, OID_AUTO, amsound, CTLFLAG_RW, &bt848_amsound, 0, "");
|
|
SYSCTL_INT(_hw_bt848, OID_AUTO, dolby, CTLFLAG_RW, &bt848_dolby, 0, "");
|
|
#endif
|
|
|
|
#endif /* end freebsd section */
|
|
|
|
|
|
|
|
/****************/
|
|
/* *** BSDI *** */
|
|
/****************/
|
|
#ifdef __bsdi__
|
|
#endif /* __bsdi__ */
|
|
|
|
|
|
/**************************/
|
|
/* *** OpenBSD/NetBSD *** */
|
|
/**************************/
|
|
#if defined(__NetBSD__) || defined(__OpenBSD__)
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/conf.h>
|
|
#include <sys/uio.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/signalvar.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/poll.h>
|
|
#include <sys/select.h>
|
|
#include <sys/vnode.h>
|
|
|
|
#include <vm/vm.h>
|
|
|
|
#ifndef __NetBSD__
|
|
#include <vm/vm_kern.h>
|
|
#include <vm/pmap.h>
|
|
#include <vm/vm_extern.h>
|
|
#endif
|
|
|
|
#include <sys/device.h>
|
|
#include <dev/pci/pcivar.h>
|
|
#include <dev/pci/pcireg.h>
|
|
#include <dev/pci/pcidevs.h>
|
|
|
|
#define BKTR_DEBUG
|
|
#ifdef BKTR_DEBUG
|
|
int bktr_debug = 0;
|
|
#define DPR(x) (bktr_debug ? printf x : 0)
|
|
#else
|
|
#define DPR(x)
|
|
#endif
|
|
#endif /* __NetBSD__ || __OpenBSD__ */
|
|
|
|
|
|
#ifdef __NetBSD__
|
|
#include <dev/ic/bt8xx.h> /* NetBSD location for .h files */
|
|
#include <dev/pci/bktr/bktr_reg.h>
|
|
#include <dev/pci/bktr/bktr_tuner.h>
|
|
#include <dev/pci/bktr/bktr_card.h>
|
|
#include <dev/pci/bktr/bktr_audio.h>
|
|
#include <dev/pci/bktr/bktr_core.h>
|
|
#include <dev/pci/bktr/bktr_os.h>
|
|
#else /* Traditional location for .h files */
|
|
#include <machine/ioctl_meteor.h>
|
|
#include <machine/ioctl_bt848.h> /* extensions to ioctl_meteor.h */
|
|
#include <dev/bktr/bktr_reg.h>
|
|
#include <dev/bktr/bktr_tuner.h>
|
|
#include <dev/bktr/bktr_card.h>
|
|
#include <dev/bktr/bktr_audio.h>
|
|
#include <dev/bktr/bktr_core.h>
|
|
#include <dev/bktr/bktr_os.h>
|
|
|
|
#if defined(BKTR_USE_FREEBSD_SMBUS)
|
|
#include <dev/bktr/bktr_i2c.h>
|
|
|
|
#include "iicbb_if.h"
|
|
#include "smbus_if.h"
|
|
#endif
|
|
#endif
|
|
|
|
|
|
/****************************/
|
|
/* *** FreeBSD 4.x code *** */
|
|
/****************************/
|
|
#if (__FreeBSD_version >= 400000)
|
|
|
|
static int bktr_probe( device_t dev );
|
|
static int bktr_attach( device_t dev );
|
|
static int bktr_detach( device_t dev );
|
|
static int bktr_shutdown( device_t dev );
|
|
static void bktr_intr(void *arg) { common_bktr_intr(arg); }
|
|
|
|
static device_method_t bktr_methods[] = {
|
|
/* Device interface */
|
|
DEVMETHOD(device_probe, bktr_probe),
|
|
DEVMETHOD(device_attach, bktr_attach),
|
|
DEVMETHOD(device_detach, bktr_detach),
|
|
DEVMETHOD(device_shutdown, bktr_shutdown),
|
|
|
|
#if defined(BKTR_USE_FREEBSD_SMBUS)
|
|
/* iicbb interface */
|
|
DEVMETHOD(iicbb_callback, bti2c_iic_callback),
|
|
DEVMETHOD(iicbb_setsda, bti2c_iic_setsda),
|
|
DEVMETHOD(iicbb_setscl, bti2c_iic_setscl),
|
|
DEVMETHOD(iicbb_getsda, bti2c_iic_getsda),
|
|
DEVMETHOD(iicbb_getscl, bti2c_iic_getscl),
|
|
DEVMETHOD(iicbb_reset, bti2c_iic_reset),
|
|
|
|
/* smbus interface */
|
|
DEVMETHOD(smbus_callback, bti2c_smb_callback),
|
|
DEVMETHOD(smbus_writeb, bti2c_smb_writeb),
|
|
DEVMETHOD(smbus_writew, bti2c_smb_writew),
|
|
DEVMETHOD(smbus_readb, bti2c_smb_readb),
|
|
#endif
|
|
|
|
{ 0, 0 }
|
|
};
|
|
|
|
static driver_t bktr_driver = {
|
|
"bktr",
|
|
bktr_methods,
|
|
sizeof(struct bktr_softc),
|
|
};
|
|
|
|
static devclass_t bktr_devclass;
|
|
|
|
static d_open_t bktr_open;
|
|
static d_close_t bktr_close;
|
|
static d_read_t bktr_read;
|
|
static d_write_t bktr_write;
|
|
static d_ioctl_t bktr_ioctl;
|
|
static d_mmap_t bktr_mmap;
|
|
static d_poll_t bktr_poll;
|
|
|
|
#define CDEV_MAJOR 92
|
|
static struct cdevsw bktr_cdevsw = {
|
|
.d_open = bktr_open,
|
|
.d_close = bktr_close,
|
|
.d_read = bktr_read,
|
|
.d_write = bktr_write,
|
|
.d_ioctl = bktr_ioctl,
|
|
.d_poll = bktr_poll,
|
|
.d_mmap = bktr_mmap,
|
|
.d_name = "bktr",
|
|
.d_maj = CDEV_MAJOR,
|
|
};
|
|
|
|
DRIVER_MODULE(bktr, pci, bktr_driver, bktr_devclass, 0, 0);
|
|
#if (__FreeBSD_version > 410000)
|
|
MODULE_DEPEND(bktr, bktr_mem, 1,1,1);
|
|
MODULE_VERSION(bktr, 1);
|
|
#endif
|
|
|
|
|
|
/*
|
|
* the boot time probe routine.
|
|
*/
|
|
static int
|
|
bktr_probe( device_t dev )
|
|
{
|
|
unsigned int type = pci_get_devid(dev);
|
|
unsigned int rev = pci_get_revid(dev);
|
|
|
|
if (PCI_VENDOR(type) == PCI_VENDOR_BROOKTREE)
|
|
{
|
|
switch (PCI_PRODUCT(type)) {
|
|
case PCI_PRODUCT_BROOKTREE_BT848:
|
|
if (rev == 0x12)
|
|
device_set_desc(dev, "BrookTree 848A");
|
|
else
|
|
device_set_desc(dev, "BrookTree 848");
|
|
return 0;
|
|
case PCI_PRODUCT_BROOKTREE_BT849:
|
|
device_set_desc(dev, "BrookTree 849A");
|
|
return 0;
|
|
case PCI_PRODUCT_BROOKTREE_BT878:
|
|
device_set_desc(dev, "BrookTree 878");
|
|
return 0;
|
|
case PCI_PRODUCT_BROOKTREE_BT879:
|
|
device_set_desc(dev, "BrookTree 879");
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
return ENXIO;
|
|
}
|
|
|
|
|
|
/*
|
|
* the attach routine.
|
|
*/
|
|
static int
|
|
bktr_attach( device_t dev )
|
|
{
|
|
u_long latency;
|
|
u_long fun;
|
|
u_long val;
|
|
unsigned int rev;
|
|
unsigned int unit;
|
|
int error = 0;
|
|
#ifdef BROOKTREE_IRQ
|
|
u_long old_irq, new_irq;
|
|
#endif
|
|
|
|
struct bktr_softc *bktr = device_get_softc(dev);
|
|
|
|
unit = device_get_unit(dev);
|
|
|
|
/* build the device name for bktr_name() */
|
|
snprintf(bktr->bktr_xname, sizeof(bktr->bktr_xname), "bktr%d",unit);
|
|
|
|
/*
|
|
* Enable bus mastering and Memory Mapped device
|
|
*/
|
|
val = pci_read_config(dev, PCIR_COMMAND, 4);
|
|
val |= (PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
|
|
pci_write_config(dev, PCIR_COMMAND, val, 4);
|
|
|
|
/*
|
|
* Map control/status registers.
|
|
*/
|
|
bktr->mem_rid = PCIR_MAPS;
|
|
bktr->res_mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &bktr->mem_rid,
|
|
0, ~0, 1, RF_ACTIVE);
|
|
|
|
|
|
if (!bktr->res_mem) {
|
|
device_printf(dev, "could not map memory\n");
|
|
error = ENXIO;
|
|
goto fail;
|
|
}
|
|
bktr->memt = rman_get_bustag(bktr->res_mem);
|
|
bktr->memh = rman_get_bushandle(bktr->res_mem);
|
|
|
|
|
|
/*
|
|
* Disable the brooktree device
|
|
*/
|
|
OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
|
|
OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
|
|
|
|
|
|
#ifdef BROOKTREE_IRQ /* from the configuration file */
|
|
old_irq = pci_conf_read(tag, PCI_INTERRUPT_REG);
|
|
pci_conf_write(tag, PCI_INTERRUPT_REG, BROOKTREE_IRQ);
|
|
new_irq = pci_conf_read(tag, PCI_INTERRUPT_REG);
|
|
printf("bktr%d: attach: irq changed from %d to %d\n",
|
|
unit, (old_irq & 0xff), (new_irq & 0xff));
|
|
#endif
|
|
|
|
/*
|
|
* Allocate our interrupt.
|
|
*/
|
|
bktr->irq_rid = 0;
|
|
bktr->res_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &bktr->irq_rid,
|
|
0, ~0, 1, RF_SHAREABLE | RF_ACTIVE);
|
|
if (bktr->res_irq == NULL) {
|
|
device_printf(dev, "could not map interrupt\n");
|
|
error = ENXIO;
|
|
goto fail;
|
|
}
|
|
|
|
error = bus_setup_intr(dev, bktr->res_irq, INTR_TYPE_TTY,
|
|
bktr_intr, bktr, &bktr->res_ih);
|
|
if (error) {
|
|
device_printf(dev, "could not setup irq\n");
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
/* Update the Device Control Register */
|
|
/* on Bt878 and Bt879 cards */
|
|
fun = pci_read_config( dev, 0x40, 2);
|
|
fun = fun | 1; /* Enable writes to the sub-system vendor ID */
|
|
|
|
#if defined( BKTR_430_FX_MODE )
|
|
if (bootverbose) printf("Using 430 FX chipset compatibilty mode\n");
|
|
fun = fun | 2; /* Enable Intel 430 FX compatibility mode */
|
|
#endif
|
|
|
|
#if defined( BKTR_SIS_VIA_MODE )
|
|
if (bootverbose) printf("Using SiS/VIA chipset compatibilty mode\n");
|
|
fun = fun | 4; /* Enable SiS/VIA compatibility mode (usefull for
|
|
OPTi chipset motherboards too */
|
|
#endif
|
|
pci_write_config(dev, 0x40, fun, 2);
|
|
|
|
#if defined(BKTR_USE_FREEBSD_SMBUS)
|
|
if (bt848_i2c_attach(dev))
|
|
printf("bktr%d: i2c_attach: can't attach\n", unit);
|
|
#endif
|
|
|
|
/*
|
|
* PCI latency timer. 32 is a good value for 4 bus mastering slots, if
|
|
* you have more than four, then 16 would probably be a better value.
|
|
*/
|
|
#ifndef BROOKTREE_DEF_LATENCY_VALUE
|
|
#define BROOKTREE_DEF_LATENCY_VALUE 10
|
|
#endif
|
|
latency = pci_read_config(dev, PCI_LATENCY_TIMER, 4);
|
|
latency = (latency >> 8) & 0xff;
|
|
if ( bootverbose ) {
|
|
if (latency)
|
|
printf("brooktree%d: PCI bus latency is", unit);
|
|
else
|
|
printf("brooktree%d: PCI bus latency was 0 changing to",
|
|
unit);
|
|
}
|
|
if ( !latency ) {
|
|
latency = BROOKTREE_DEF_LATENCY_VALUE;
|
|
pci_write_config(dev, PCI_LATENCY_TIMER, latency<<8, 4);
|
|
}
|
|
if ( bootverbose ) {
|
|
printf(" %d.\n", (int) latency);
|
|
}
|
|
|
|
/* read the pci device id and revision id */
|
|
fun = pci_get_devid(dev);
|
|
rev = pci_get_revid(dev);
|
|
|
|
/* call the common attach code */
|
|
common_bktr_attach( bktr, unit, fun, rev );
|
|
|
|
/* make the device entries */
|
|
bktr->bktrdev = make_dev(&bktr_cdevsw, unit,
|
|
0, 0, 0444, "bktr%d", unit);
|
|
bktr->tunerdev= make_dev(&bktr_cdevsw, unit+16,
|
|
0, 0, 0444, "tuner%d", unit);
|
|
bktr->vbidev = make_dev(&bktr_cdevsw, unit+32,
|
|
0, 0, 0444, "vbi%d" , unit);
|
|
|
|
|
|
/* if this is unit 0 (/dev/bktr0, /dev/tuner0, /dev/vbi0) then make */
|
|
/* alias entries to /dev/bktr /dev/tuner and /dev/vbi */
|
|
#if (__FreeBSD_version >=500000)
|
|
if (unit == 0) {
|
|
bktr->bktrdev_alias = make_dev_alias(bktr->bktrdev, "bktr");
|
|
bktr->tunerdev_alias= make_dev_alias(bktr->tunerdev, "tuner");
|
|
bktr->vbidev_alias = make_dev_alias(bktr->vbidev, "vbi");
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
fail:
|
|
if (bktr->res_irq)
|
|
bus_release_resource(dev, SYS_RES_IRQ, bktr->irq_rid, bktr->res_irq);
|
|
if (bktr->res_mem)
|
|
bus_release_resource(dev, SYS_RES_IRQ, bktr->mem_rid, bktr->res_mem);
|
|
return error;
|
|
|
|
}
|
|
|
|
/*
|
|
* the detach routine.
|
|
*/
|
|
static int
|
|
bktr_detach( device_t dev )
|
|
{
|
|
struct bktr_softc *bktr = device_get_softc(dev);
|
|
|
|
#ifdef BKTR_NEW_MSP34XX_DRIVER
|
|
/* Disable the soundchip and kernel thread */
|
|
if (bktr->msp3400c_info != NULL)
|
|
msp_detach(bktr);
|
|
#endif
|
|
|
|
/* Disable the brooktree device */
|
|
OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
|
|
OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
|
|
|
|
#if defined(BKTR_USE_FREEBSD_SMBUS)
|
|
if (bt848_i2c_detach(dev))
|
|
printf("bktr%d: i2c_attach: can't attach\n",
|
|
device_get_unit(dev));
|
|
#endif
|
|
|
|
/* Note: We do not free memory for RISC programs, grab buffer, vbi buffers */
|
|
/* The memory is retained by the bktr_mem module so we can unload and */
|
|
/* then reload the main bktr driver module */
|
|
|
|
/* Unregister the /dev/bktrN, tunerN and vbiN devices,
|
|
* the aliases for unit 0 are automatically destroyed */
|
|
destroy_dev(bktr->vbidev);
|
|
destroy_dev(bktr->tunerdev);
|
|
destroy_dev(bktr->bktrdev);
|
|
|
|
/*
|
|
* Deallocate resources.
|
|
*/
|
|
bus_teardown_intr(dev, bktr->res_irq, bktr->res_ih);
|
|
bus_release_resource(dev, SYS_RES_IRQ, bktr->irq_rid, bktr->res_irq);
|
|
bus_release_resource(dev, SYS_RES_MEMORY, bktr->mem_rid, bktr->res_mem);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* the shutdown routine.
|
|
*/
|
|
static int
|
|
bktr_shutdown( device_t dev )
|
|
{
|
|
struct bktr_softc *bktr = device_get_softc(dev);
|
|
|
|
/* Disable the brooktree device */
|
|
OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
|
|
OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Special Memory Allocation
|
|
*/
|
|
vm_offset_t
|
|
get_bktr_mem( int unit, unsigned size )
|
|
{
|
|
vm_offset_t addr = 0;
|
|
|
|
addr = vm_page_alloc_contig(size, 0, 0xffffffff, 1<<24);
|
|
if (addr == 0)
|
|
addr = vm_page_alloc_contig(size, 0, 0xffffffff, PAGE_SIZE);
|
|
if (addr == 0) {
|
|
printf("bktr%d: Unable to allocate %d bytes of memory.\n",
|
|
unit, size);
|
|
}
|
|
|
|
return( addr );
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------
|
|
**
|
|
** BrookTree 848 character device driver routines
|
|
**
|
|
**---------------------------------------------------------
|
|
*/
|
|
|
|
#define VIDEO_DEV 0x00
|
|
#define TUNER_DEV 0x01
|
|
#define VBI_DEV 0x02
|
|
|
|
#define UNIT(x) ((x) & 0x0f)
|
|
#define FUNCTION(x) (x >> 4)
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static int
|
|
bktr_open( dev_t dev, int flags, int fmt, struct thread *td )
|
|
{
|
|
bktr_ptr_t bktr;
|
|
int unit;
|
|
int result;
|
|
|
|
unit = UNIT( minor(dev) );
|
|
|
|
/* Get the device data */
|
|
bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
|
|
if (bktr == NULL) {
|
|
/* the device is no longer valid/functioning */
|
|
return (ENXIO);
|
|
}
|
|
|
|
if (!(bktr->flags & METEOR_INITALIZED)) /* device not found */
|
|
return( ENXIO );
|
|
|
|
/* Record that the device is now busy */
|
|
device_busy(devclass_get_device(bktr_devclass, unit));
|
|
|
|
|
|
if (bt848_card != -1) {
|
|
if ((bt848_card >> 8 == unit ) &&
|
|
( (bt848_card & 0xff) < Bt848_MAX_CARD )) {
|
|
if ( bktr->bt848_card != (bt848_card & 0xff) ) {
|
|
bktr->bt848_card = (bt848_card & 0xff);
|
|
probeCard(bktr, FALSE, unit);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bt848_tuner != -1) {
|
|
if ((bt848_tuner >> 8 == unit ) &&
|
|
( (bt848_tuner & 0xff) < Bt848_MAX_TUNER )) {
|
|
if ( bktr->bt848_tuner != (bt848_tuner & 0xff) ) {
|
|
bktr->bt848_tuner = (bt848_tuner & 0xff);
|
|
probeCard(bktr, FALSE, unit);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bt848_reverse_mute != -1) {
|
|
if ((bt848_reverse_mute >> 8) == unit ) {
|
|
bktr->reverse_mute = bt848_reverse_mute & 0xff;
|
|
}
|
|
}
|
|
|
|
if (bt848_slow_msp_audio != -1) {
|
|
if ((bt848_slow_msp_audio >> 8) == unit ) {
|
|
bktr->slow_msp_audio = (bt848_slow_msp_audio & 0xff);
|
|
}
|
|
}
|
|
|
|
#ifdef BKTR_NEW_MSP34XX_DRIVER
|
|
if (bt848_stereo_once != 0) {
|
|
if ((bt848_stereo_once >> 8) == unit ) {
|
|
bktr->stereo_once = (bt848_stereo_once & 0xff);
|
|
}
|
|
}
|
|
|
|
if (bt848_amsound != -1) {
|
|
if ((bt848_amsound >> 8) == unit ) {
|
|
bktr->amsound = (bt848_amsound & 0xff);
|
|
}
|
|
}
|
|
|
|
if (bt848_dolby != -1) {
|
|
if ((bt848_dolby >> 8) == unit ) {
|
|
bktr->dolby = (bt848_dolby & 0xff);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
switch ( FUNCTION( minor(dev) ) ) {
|
|
case VIDEO_DEV:
|
|
result = video_open( bktr );
|
|
break;
|
|
case TUNER_DEV:
|
|
result = tuner_open( bktr );
|
|
break;
|
|
case VBI_DEV:
|
|
result = vbi_open( bktr );
|
|
break;
|
|
default:
|
|
result = ENXIO;
|
|
break;
|
|
}
|
|
|
|
/* If there was an error opening the device, undo the busy status */
|
|
if (result != 0)
|
|
device_unbusy(devclass_get_device(bktr_devclass, unit));
|
|
return( result );
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static int
|
|
bktr_close( dev_t dev, int flags, int fmt, struct thread *td )
|
|
{
|
|
bktr_ptr_t bktr;
|
|
int unit;
|
|
int result;
|
|
|
|
unit = UNIT( minor(dev) );
|
|
|
|
/* Get the device data */
|
|
bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
|
|
if (bktr == NULL) {
|
|
/* the device is no longer valid/functioning */
|
|
return (ENXIO);
|
|
}
|
|
|
|
switch ( FUNCTION( minor(dev) ) ) {
|
|
case VIDEO_DEV:
|
|
result = video_close( bktr );
|
|
break;
|
|
case TUNER_DEV:
|
|
result = tuner_close( bktr );
|
|
break;
|
|
case VBI_DEV:
|
|
result = vbi_close( bktr );
|
|
break;
|
|
default:
|
|
return (ENXIO);
|
|
break;
|
|
}
|
|
|
|
device_unbusy(devclass_get_device(bktr_devclass, unit));
|
|
return( result );
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static int
|
|
bktr_read( dev_t dev, struct uio *uio, int ioflag )
|
|
{
|
|
bktr_ptr_t bktr;
|
|
int unit;
|
|
|
|
unit = UNIT(minor(dev));
|
|
|
|
/* Get the device data */
|
|
bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
|
|
if (bktr == NULL) {
|
|
/* the device is no longer valid/functioning */
|
|
return (ENXIO);
|
|
}
|
|
|
|
switch ( FUNCTION( minor(dev) ) ) {
|
|
case VIDEO_DEV:
|
|
return( video_read( bktr, unit, dev, uio ) );
|
|
case VBI_DEV:
|
|
return( vbi_read( bktr, uio, ioflag ) );
|
|
}
|
|
return( ENXIO );
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static int
|
|
bktr_write( dev_t dev, struct uio *uio, int ioflag )
|
|
{
|
|
return( EINVAL ); /* XXX or ENXIO ? */
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static int
|
|
bktr_ioctl( dev_t dev, ioctl_cmd_t cmd, caddr_t arg, int flag, struct thread *td )
|
|
{
|
|
bktr_ptr_t bktr;
|
|
int unit;
|
|
|
|
unit = UNIT(minor(dev));
|
|
|
|
/* Get the device data */
|
|
bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
|
|
if (bktr == NULL) {
|
|
/* the device is no longer valid/functioning */
|
|
return (ENXIO);
|
|
}
|
|
|
|
if (bktr->bigbuf == 0) /* no frame buffer allocated (ioctl failed) */
|
|
return( ENOMEM );
|
|
|
|
switch ( FUNCTION( minor(dev) ) ) {
|
|
case VIDEO_DEV:
|
|
return( video_ioctl( bktr, unit, cmd, arg, td ) );
|
|
case TUNER_DEV:
|
|
return( tuner_ioctl( bktr, unit, cmd, arg, td ) );
|
|
}
|
|
|
|
return( ENXIO );
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static int
|
|
bktr_mmap( dev_t dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot )
|
|
{
|
|
int unit;
|
|
bktr_ptr_t bktr;
|
|
|
|
unit = UNIT(minor(dev));
|
|
|
|
if (FUNCTION(minor(dev)) > 0) /* only allow mmap on /dev/bktr[n] */
|
|
return( -1 );
|
|
|
|
/* Get the device data */
|
|
bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
|
|
if (bktr == NULL) {
|
|
/* the device is no longer valid/functioning */
|
|
return (ENXIO);
|
|
}
|
|
|
|
if (nprot & PROT_EXEC)
|
|
return( -1 );
|
|
|
|
if (offset < 0)
|
|
return( -1 );
|
|
|
|
if (offset >= bktr->alloc_pages * PAGE_SIZE)
|
|
return( -1 );
|
|
|
|
*paddr = vtophys(bktr->bigbuf) + offset;
|
|
return( 0 );
|
|
}
|
|
|
|
static int
|
|
bktr_poll( dev_t dev, int events, struct thread *td)
|
|
{
|
|
int unit;
|
|
bktr_ptr_t bktr;
|
|
int revents = 0;
|
|
DECLARE_INTR_MASK(s);
|
|
|
|
unit = UNIT(minor(dev));
|
|
|
|
/* Get the device data */
|
|
bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
|
|
if (bktr == NULL) {
|
|
/* the device is no longer valid/functioning */
|
|
return (ENXIO);
|
|
}
|
|
|
|
DISABLE_INTR(s);
|
|
|
|
if (events & (POLLIN | POLLRDNORM)) {
|
|
|
|
switch ( FUNCTION( minor(dev) ) ) {
|
|
case VBI_DEV:
|
|
if(bktr->vbisize == 0)
|
|
selrecord(td, &bktr->vbi_select);
|
|
else
|
|
revents |= events & (POLLIN | POLLRDNORM);
|
|
break;
|
|
}
|
|
}
|
|
|
|
ENABLE_INTR(s);
|
|
|
|
return (revents);
|
|
}
|
|
|
|
#endif /* FreeBSD 4.x specific kernel interface routines */
|
|
|
|
/*****************/
|
|
/* *** BSDI *** */
|
|
/*****************/
|
|
|
|
#if defined(__bsdi__)
|
|
#endif /* __bsdi__ BSDI specific kernel interface routines */
|
|
|
|
|
|
/*****************************/
|
|
/* *** OpenBSD / NetBSD *** */
|
|
/*****************************/
|
|
#if defined(__NetBSD__) || defined(__OpenBSD__)
|
|
|
|
#define IPL_VIDEO IPL_BIO /* XXX */
|
|
|
|
static int bktr_intr(void *arg) { return common_bktr_intr(arg); }
|
|
|
|
#define bktr_open bktropen
|
|
#define bktr_close bktrclose
|
|
#define bktr_read bktrread
|
|
#define bktr_write bktrwrite
|
|
#define bktr_ioctl bktrioctl
|
|
#define bktr_mmap bktrmmap
|
|
|
|
vm_offset_t vm_page_alloc_contig(vm_offset_t, vm_offset_t,
|
|
vm_offset_t, vm_offset_t);
|
|
|
|
#if defined(__OpenBSD__)
|
|
static int bktr_probe(struct device *, void *, void *);
|
|
#else
|
|
static int bktr_probe(struct device *, struct cfdata *, void *);
|
|
#endif
|
|
static void bktr_attach(struct device *, struct device *, void *);
|
|
|
|
struct cfattach bktr_ca = {
|
|
sizeof(struct bktr_softc), bktr_probe, bktr_attach
|
|
};
|
|
|
|
#if defined(__NetBSD__)
|
|
extern struct cfdriver bktr_cd;
|
|
#else
|
|
struct cfdriver bktr_cd = {
|
|
NULL, "bktr", DV_DULL
|
|
};
|
|
#endif
|
|
|
|
int
|
|
bktr_probe(parent, match, aux)
|
|
struct device *parent;
|
|
#if defined(__OpenBSD__)
|
|
void *match;
|
|
#else
|
|
struct cfdata *match;
|
|
#endif
|
|
void *aux;
|
|
{
|
|
struct pci_attach_args *pa = aux;
|
|
|
|
if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_BROOKTREE &&
|
|
(PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROOKTREE_BT848 ||
|
|
PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROOKTREE_BT849 ||
|
|
PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROOKTREE_BT878 ||
|
|
PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROOKTREE_BT879))
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* the attach routine.
|
|
*/
|
|
static void
|
|
bktr_attach(struct device *parent, struct device *self, void *aux)
|
|
{
|
|
bktr_ptr_t bktr;
|
|
u_long latency;
|
|
u_long fun;
|
|
unsigned int rev;
|
|
|
|
#if defined(__OpenBSD__)
|
|
struct pci_attach_args *pa = aux;
|
|
pci_chipset_tag_t pc = pa->pa_pc;
|
|
|
|
pci_intr_handle_t ih;
|
|
const char *intrstr;
|
|
int retval;
|
|
int unit;
|
|
|
|
bktr = (bktr_ptr_t)self;
|
|
unit = bktr->bktr_dev.dv_unit;
|
|
|
|
bktr->pc = pa->pa_pc;
|
|
bktr->tag = pa->pa_tag;
|
|
bktr->dmat = pa->pa_dmat;
|
|
|
|
/*
|
|
* map memory
|
|
*/
|
|
bktr->memt = pa->pa_memt;
|
|
retval = pci_mem_find(pc, pa->pa_tag, PCI_MAPREG_START,
|
|
&bktr->phys_base, &bktr->obmemsz, NULL);
|
|
if (!retval)
|
|
retval = bus_space_map(pa->pa_memt, bktr->phys_base,
|
|
bktr->obmemsz, 0, &bktr->memh);
|
|
if (retval) {
|
|
printf(": couldn't map memory\n");
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
* map interrupt
|
|
*/
|
|
if (pci_intr_map(pa->pa_pc, pa->pa_intrtag, pa->pa_intrpin,
|
|
pa->pa_intrline, &ih)) {
|
|
printf(": couldn't map interrupt\n");
|
|
return;
|
|
}
|
|
intrstr = pci_intr_string(pa->pa_pc, ih);
|
|
|
|
bktr->ih = pci_intr_establish(pa->pa_pc, ih, IPL_VIDEO,
|
|
bktr_intr, bktr, bktr->bktr_dev.dv_xname);
|
|
if (bktr->ih == NULL) {
|
|
printf(": couldn't establish interrupt");
|
|
if (intrstr != NULL)
|
|
printf(" at %s", intrstr);
|
|
printf("\n");
|
|
return;
|
|
}
|
|
|
|
if (intrstr != NULL)
|
|
printf(": %s\n", intrstr);
|
|
#endif /* __OpenBSD__ */
|
|
|
|
#if defined(__NetBSD__)
|
|
struct pci_attach_args *pa = aux;
|
|
pci_intr_handle_t ih;
|
|
const char *intrstr;
|
|
int retval;
|
|
int unit;
|
|
|
|
bktr = (bktr_ptr_t)self;
|
|
unit = bktr->bktr_dev.dv_unit;
|
|
bktr->dmat = pa->pa_dmat;
|
|
|
|
printf("\n");
|
|
|
|
/*
|
|
* map memory
|
|
*/
|
|
retval = pci_mapreg_map(pa, PCI_MAPREG_START,
|
|
PCI_MAPREG_TYPE_MEM
|
|
| PCI_MAPREG_MEM_TYPE_32BIT, 0,
|
|
&bktr->memt, &bktr->memh, NULL,
|
|
&bktr->obmemsz);
|
|
DPR(("pci_mapreg_map: memt %x, memh %x, size %x\n",
|
|
bktr->memt, (u_int)bktr->memh, (u_int)bktr->obmemsz));
|
|
if (retval) {
|
|
printf("%s: couldn't map memory\n", bktr_name(bktr));
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Disable the brooktree device
|
|
*/
|
|
OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
|
|
OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
|
|
|
|
/*
|
|
* map interrupt
|
|
*/
|
|
if (pci_intr_map(pa->pa_pc, pa->pa_intrtag, pa->pa_intrpin,
|
|
pa->pa_intrline, &ih)) {
|
|
printf("%s: couldn't map interrupt\n",
|
|
bktr_name(bktr));
|
|
return;
|
|
}
|
|
intrstr = pci_intr_string(pa->pa_pc, ih);
|
|
bktr->ih = pci_intr_establish(pa->pa_pc, ih, IPL_VIDEO,
|
|
bktr_intr, bktr);
|
|
if (bktr->ih == NULL) {
|
|
printf("%s: couldn't establish interrupt",
|
|
bktr_name(bktr));
|
|
if (intrstr != NULL)
|
|
printf(" at %s", intrstr);
|
|
printf("\n");
|
|
return;
|
|
}
|
|
if (intrstr != NULL)
|
|
printf("%s: interrupting at %s\n", bktr_name(bktr),
|
|
intrstr);
|
|
#endif /* __NetBSD__ */
|
|
|
|
/*
|
|
* PCI latency timer. 32 is a good value for 4 bus mastering slots, if
|
|
* you have more than four, then 16 would probably be a better value.
|
|
*/
|
|
#ifndef BROOKTREE_DEF_LATENCY_VALUE
|
|
#define BROOKTREE_DEF_LATENCY_VALUE 10
|
|
#endif
|
|
latency = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_LATENCY_TIMER);
|
|
latency = (latency >> 8) & 0xff;
|
|
|
|
if (!latency) {
|
|
if (bootverbose) {
|
|
printf("%s: PCI bus latency was 0 changing to %d",
|
|
bktr_name(bktr), BROOKTREE_DEF_LATENCY_VALUE);
|
|
}
|
|
latency = BROOKTREE_DEF_LATENCY_VALUE;
|
|
pci_conf_write(pa->pa_pc, pa->pa_tag,
|
|
PCI_LATENCY_TIMER, latency<<8);
|
|
}
|
|
|
|
|
|
/* Enabled Bus Master
|
|
XXX: check if all old DMA is stopped first (e.g. after warm
|
|
boot) */
|
|
fun = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
|
|
pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
|
|
fun | PCI_COMMAND_MASTER_ENABLE);
|
|
|
|
/* read the pci id and determine the card type */
|
|
fun = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ID_REG);
|
|
rev = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_CLASS_REG) & 0x000000ff;
|
|
|
|
common_bktr_attach(bktr, unit, fun, rev);
|
|
}
|
|
|
|
|
|
/*
|
|
* Special Memory Allocation
|
|
*/
|
|
vm_offset_t
|
|
get_bktr_mem(bktr, dmapp, size)
|
|
bktr_ptr_t bktr;
|
|
bus_dmamap_t *dmapp;
|
|
unsigned int size;
|
|
{
|
|
bus_dma_tag_t dmat = bktr->dmat;
|
|
bus_dma_segment_t seg;
|
|
bus_size_t align;
|
|
int rseg;
|
|
caddr_t kva;
|
|
|
|
/*
|
|
* Allocate a DMA area
|
|
*/
|
|
align = 1 << 24;
|
|
if (bus_dmamem_alloc(dmat, size, align, 0, &seg, 1,
|
|
&rseg, BUS_DMA_NOWAIT)) {
|
|
align = PAGE_SIZE;
|
|
if (bus_dmamem_alloc(dmat, size, align, 0, &seg, 1,
|
|
&rseg, BUS_DMA_NOWAIT)) {
|
|
printf("%s: Unable to dmamem_alloc of %d bytes\n",
|
|
bktr_name(bktr), size);
|
|
return 0;
|
|
}
|
|
}
|
|
if (bus_dmamem_map(dmat, &seg, rseg, size,
|
|
&kva, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) {
|
|
printf("%s: Unable to dmamem_map of %d bytes\n",
|
|
bktr_name(bktr), size);
|
|
bus_dmamem_free(dmat, &seg, rseg);
|
|
return 0;
|
|
}
|
|
#ifdef __OpenBSD__
|
|
bktr->dm_mapsize = size;
|
|
#endif
|
|
/*
|
|
* Create and locd the DMA map for the DMA area
|
|
*/
|
|
if (bus_dmamap_create(dmat, size, 1, size, 0, BUS_DMA_NOWAIT, dmapp)) {
|
|
printf("%s: Unable to dmamap_create of %d bytes\n",
|
|
bktr_name(bktr), size);
|
|
bus_dmamem_unmap(dmat, kva, size);
|
|
bus_dmamem_free(dmat, &seg, rseg);
|
|
return 0;
|
|
}
|
|
if (bus_dmamap_load(dmat, *dmapp, kva, size, NULL, BUS_DMA_NOWAIT)) {
|
|
printf("%s: Unable to dmamap_load of %d bytes\n",
|
|
bktr_name(bktr), size);
|
|
bus_dmamem_unmap(dmat, kva, size);
|
|
bus_dmamem_free(dmat, &seg, rseg);
|
|
bus_dmamap_destroy(dmat, *dmapp);
|
|
return 0;
|
|
}
|
|
return (vm_offset_t)kva;
|
|
}
|
|
|
|
void
|
|
free_bktr_mem(bktr, dmap, kva)
|
|
bktr_ptr_t bktr;
|
|
bus_dmamap_t dmap;
|
|
vm_offset_t kva;
|
|
{
|
|
bus_dma_tag_t dmat = bktr->dmat;
|
|
|
|
#ifdef __NetBSD__
|
|
bus_dmamem_unmap(dmat, (caddr_t)kva, dmap->dm_mapsize);
|
|
#else
|
|
bus_dmamem_unmap(dmat, (caddr_t)kva, bktr->dm_mapsize);
|
|
#endif
|
|
bus_dmamem_free(dmat, dmap->dm_segs, 1);
|
|
bus_dmamap_destroy(dmat, dmap);
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------
|
|
**
|
|
** BrookTree 848 character device driver routines
|
|
**
|
|
**---------------------------------------------------------
|
|
*/
|
|
|
|
|
|
#define VIDEO_DEV 0x00
|
|
#define TUNER_DEV 0x01
|
|
#define VBI_DEV 0x02
|
|
|
|
#define UNIT(x) (minor((x) & 0x0f))
|
|
#define FUNCTION(x) (minor((x >> 4) & 0x0f))
|
|
|
|
/*
|
|
*
|
|
*/
|
|
int
|
|
bktr_open(dev_t dev, int flags, int fmt, struct thread *td)
|
|
{
|
|
bktr_ptr_t bktr;
|
|
int unit;
|
|
|
|
unit = UNIT(dev);
|
|
|
|
/* unit out of range */
|
|
if ((unit > bktr_cd.cd_ndevs) || (bktr_cd.cd_devs[unit] == NULL))
|
|
return(ENXIO);
|
|
|
|
bktr = bktr_cd.cd_devs[unit];
|
|
|
|
if (!(bktr->flags & METEOR_INITALIZED)) /* device not found */
|
|
return(ENXIO);
|
|
|
|
switch (FUNCTION(dev)) {
|
|
case VIDEO_DEV:
|
|
return(video_open(bktr));
|
|
case TUNER_DEV:
|
|
return(tuner_open(bktr));
|
|
case VBI_DEV:
|
|
return(vbi_open(bktr));
|
|
}
|
|
|
|
return(ENXIO);
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
*/
|
|
int
|
|
bktr_close(dev_t dev, int flags, int fmt, struct thread *td)
|
|
{
|
|
bktr_ptr_t bktr;
|
|
int unit;
|
|
|
|
unit = UNIT(dev);
|
|
|
|
bktr = bktr_cd.cd_devs[unit];
|
|
|
|
switch (FUNCTION(dev)) {
|
|
case VIDEO_DEV:
|
|
return(video_close(bktr));
|
|
case TUNER_DEV:
|
|
return(tuner_close(bktr));
|
|
case VBI_DEV:
|
|
return(vbi_close(bktr));
|
|
}
|
|
|
|
return(ENXIO);
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
int
|
|
bktr_read(dev_t dev, struct uio *uio, int ioflag)
|
|
{
|
|
bktr_ptr_t bktr;
|
|
int unit;
|
|
|
|
unit = UNIT(dev);
|
|
|
|
bktr = bktr_cd.cd_devs[unit];
|
|
|
|
switch (FUNCTION(dev)) {
|
|
case VIDEO_DEV:
|
|
return(video_read(bktr, unit, dev, uio));
|
|
case VBI_DEV:
|
|
return(vbi_read(bktr, uio, ioflag));
|
|
}
|
|
|
|
return(ENXIO);
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
*/
|
|
int
|
|
bktr_write(dev_t dev, struct uio *uio, int ioflag)
|
|
{
|
|
/* operation not supported */
|
|
return(EOPNOTSUPP);
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
int
|
|
bktr_ioctl(dev_t dev, ioctl_cmd_t cmd, caddr_t arg, int flag, struct thread *td)
|
|
{
|
|
bktr_ptr_t bktr;
|
|
int unit;
|
|
|
|
unit = UNIT(dev);
|
|
|
|
bktr = bktr_cd.cd_devs[unit];
|
|
|
|
if (bktr->bigbuf == 0) /* no frame buffer allocated (ioctl failed) */
|
|
return(ENOMEM);
|
|
|
|
switch (FUNCTION(dev)) {
|
|
case VIDEO_DEV:
|
|
return(video_ioctl(bktr, unit, cmd, arg, pr));
|
|
case TUNER_DEV:
|
|
return(tuner_ioctl(bktr, unit, cmd, arg, pr));
|
|
}
|
|
|
|
return(ENXIO);
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
paddr_t
|
|
bktr_mmap(dev_t dev, off_t offset, int nprot)
|
|
{
|
|
int unit;
|
|
bktr_ptr_t bktr;
|
|
|
|
unit = UNIT(dev);
|
|
|
|
if (FUNCTION(dev) > 0) /* only allow mmap on /dev/bktr[n] */
|
|
return(-1);
|
|
|
|
bktr = bktr_cd.cd_devs[unit];
|
|
|
|
if ((vaddr_t)offset < 0)
|
|
return(-1);
|
|
|
|
if ((vaddr_t)offset >= bktr->alloc_pages * PAGE_SIZE)
|
|
return(-1);
|
|
|
|
#ifdef __NetBSD__
|
|
return (bus_dmamem_mmap(bktr->dmat, bktr->dm_mem->dm_segs, 1,
|
|
(vaddr_t)offset, nprot, BUS_DMA_WAITOK));
|
|
#else
|
|
return(i386_btop(vtophys(bktr->bigbuf) + offset));
|
|
#endif
|
|
}
|
|
|
|
#endif /* __NetBSD__ || __OpenBSD__ */
|