Index: head/share/man/man4/bktr.4 =================================================================== --- head/share/man/man4/bktr.4 (revision 358473) +++ head/share/man/man4/bktr.4 (revision 358474) @@ -1,258 +1,264 @@ .\" .\" $FreeBSD$ .\" -.Dd January 18, 2006 +.Dd February 25, 2020 .Dt BKTR 4 .Os .Sh NAME .Nm bktr .Nd Brooktree Bt848/849/878/879 and Pinnacle PCTV video capture driver .Sh SYNOPSIS .Cd device bktr .Pp .Cd device iicbus .Cd device iicbb .Cd device smbus +.Sh DEPRECATION NOTICE +The +.Nm +driver is not present in +.Fx 13.0 +and later. .Sh DESCRIPTION The .Nm bktr driver provides support for PCI .Em video capture and .Em VBI capture on low cost, high performance boards. The driver is based on the Matrox Meteor driver and uses the same API. The .Nm driver should support most video cards based on the .Em "Brooktree Bt848/849/878/879 Video Capture Chip" . Also supported are most .Em "Pinnacle PCTV" video cards. Furthermore, the driver supports .Em FM Radio if the tuner supports it. .Pp The driver currently supports the following features: .Bd -unfilled -offset indent PCI to PCI dma transfer clipping yuv rgb16 rgb24 rgb32 .Ed .Pp On the supported cards, tuners and other components are interconnected with an I2C bus. The Brooktree848 chips act as a master device on the bus to control them. Therefore, .Xr iicbus 4 , .Xr iicbb 4 and .Xr smbus 4 controller declarations are mandatory to activate .Nm support. .Pp The following kernel parameters may be used to further configure the driver: .Pp .Em options "BROOKTREE_ALLOC_PAGES=xxx" specifies the number of contiguous pages to allocate when successfully probed. The default number of pages allocated by the kernel is 216. This means that there are (216*4096) bytes available for use. .Bd -unfilled .Cd options BROOKTREE_SYSTEM_DEFAULT=BROOKTREE_PAL .Cd options BROOKTREE_SYSTEM_DEFAULT=BROOKTREE_NTSC .Ed One of these options can be used to set the default video format for the driver. This fixed random hangs and lockups with the VideoLogic Captivator PCI card. .Pp The following sysctls may be used to further configure the driver: .Pp .Em sysctl hw.bt848.card=nnnn This can be used to override the card make which was detected at boot time. .Ql nnnn is set to an integer from 1 to 23 taken from the following table: .Pp .Bl -tag -compact -width 30n .It MIRO 1 .It HAUPPAUGE 2 .It STB 3 .It INTEL 4 .It IMS_TURBO 5 .It AVER_MEDIA 6 .It OSPREY 7 .It NEC_PK 8 .It IO_GV 9 .It FLYVIDEO 10 .It ZOLTRIX 11 .It KISS 12 .It VIDEO_HIGHWAY_XTREME 13 .It ASKEY_DYNALINK_MAGIC_TVIEW 14 .It LEADTEK 15 .It TERRATVPLUS 16 .It IO_BCTV3 17 .It AOPEN_VA1000 18 .It PINNACLE_PCTV_RAVE 19 .It PIXELVIEW_PLAYTV_PAK 20 .It TERRATVALUE 21 .It PIXELVIEW_PLAYTV_PRO_REV_4C 22 .It Bt848_MAX 23 .El .Pp .Em sysctl hw.bt848.tuner=nnnn This can be used to override the tuner make which was detected at boot time. .Ql nnnn is set to an integer from 0 to 16 taken from the following table: .Pp .Bl -tag -compact -width 22n .It NO_TUNER 0 .It TEMIC_NTSC 1 .It TEMIC_PAL 2 .It TEMIC_SECAM 3 .It PHILIPS_NTSC 4 .It PHILIPS_PAL 5 .It PHILIPS_SECAM 6 .It TEMIC_PALI 7 .It PHILIPS_PALI 8 .It PHILIPS_FR1236_NTSC 9 /* These have FM Radio support */ .It PHILIPS_FR1216_PAL 10 /* These have FM Radio support */ .It PHILIPS_FR1236_SECAM 11 /* These have FM Radio support */ .It ALPS_TSCH5 12 .It ALPS_TSBH1 13 .It MT2032 14 .It LG_TPI8PSB12P_PAL 15 .It Bt848_MAX 16 .El .Sh HARDWARE The .Nm driver supports video capture cards based on the Brooktree Bt848/849/878/879 chips, as well as Pinnacle PCTV cards, including: .Pp .Bl -bullet -compact .It AOpen VA1000 .It AVerMedia AVerTV Studio .It AVerMedia TF/FM-98 .It ATI TV Wonder VE .It Hauppauge WinCast/TV .It Hauppauge WinTV-Go-FM .It Hauppauge WinTV-pci .It Hauppauge WinTV-radio .It Intel Smart Video Recorder III .It KWORLD PCI TV Tuner .It Miro PC TV .It Pinnacle PCTV Pro .It Pinnacle PCTV Rave .It PixelView PlayTV PAK .It PixelView PlayTV Pro (rev 4C, 9D) .It SIGMA TV II .It STB TV PCI Television Tuner .It Super TV Tuner .It TerraTec TValue .It V-Stream XPERT TV-PVR 878 .It Video Highway XTreme .It VideoLogic Captivator PCI .El .Sh FILES .Bl -tag -width /usr/share/examples/meteor -compact .It Pa /usr/ports/multimedia/fxtv A TV and Camera display program utilizing the bktr driver - requires that .Em The X Window System and .Em The Ports Collection also be installed. .It Pa /usr/ports/audio/xmradio An FM Radio Tuner for cards which have an FM Radio tuner fitted - requires that .Em The X Window System and .Em The Ports Collection also be installed. It also requires .Em Motif or the .Em lesstif port. .El .Sh SEE ALSO .Xr meteor 4 .Sh HISTORY The .Nm driver first appeared in .Fx 2.2 . .Sh AUTHORS .An -nosplit This driver is based on the work of .An Jim Lowe Aq Mt james@miller.cs.uwm.edu , .An Mark Tinguely Aq Mt tinguely@plains.nodak.edu , .An Amancio Hasty Aq Mt hasty@star-gate.com , .An Roger Hardiman Aq Mt roger@FreeBSD.org and a bunch of other people. Support for Pinnacle PCTV Rave cards was added by .An Branko Lankester Aq Mt branko@euro.net . Index: head/sys/dev/bktr/bktr_os.c =================================================================== --- head/sys/dev/bktr/bktr_os.c (revision 358473) +++ head/sys/dev/bktr/bktr_os.c (revision 358474) @@ -1,1347 +1,1348 @@ /*- * SPDX-License-Identifier: BSD-4-Clause * * 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 __FBSDID("$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 dependent code, * probe/attach and open/close/ioctl/read/mmap * memory allocation * PCI bus interfacing */ #include "opt_bktr.h" /* include any kernel config options */ #define FIFO_RISC_DISABLED 0 #define ALL_INTS_DISABLED 0 /*******************/ /* *** FreeBSD *** */ /*******************/ #ifdef __FreeBSD__ #include #include #include #include #include #include #include #include #include #include #if __FreeBSD_version >= 500014 #include #else #include #endif #include #include #include #include #include /* used by smbus and newbus */ #include /* used by bus space and newbus */ #include #include /* used by newbus */ #include /* used by newbus */ #if (__FreeBSD_version < 500000) #include /* for DELAY */ #include #include #else #include #include #endif #include 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 static SYSCTL_NODE(_hw, OID_AUTO, bt848, CTLFLAG_RW | CTLFLAG_MPSAFE, 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 #include #include #include #include #include #include #include #include #include #include #include /* extensions to ioctl_meteor.h */ #ifndef __NetBSD__ #include #include #include #endif #include #include #include #include #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 /* NetBSD location for .h files */ #include #include #include #include #include #include #else /* Traditional location for .h files */ #include #include /* extensions to ioctl_meteor.h */ #include #include #include #include #include #include #if defined(BKTR_USE_FREEBSD_SMBUS) #include #include "iicbb_if.h" #include "smbus_if.h" #endif #endif /****************************/ /* *** FreeBSD 4.x code *** */ /****************************/ 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; static struct cdevsw bktr_cdevsw = { .d_version = D_VERSION, .d_flags = D_NEEDGIANT, .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", }; #ifdef BKTR_USE_FREEBSD_SMBUS #include #include MODULE_DEPEND(bktr, iicbb, IICBB_MINVER, IICBB_MODVER, IICBB_MAXVER); MODULE_DEPEND(bktr, iicbus, IICBUS_MINVER, IICBUS_MODVER, IICBUS_MAXVER); MODULE_DEPEND(bktr, smbus, SMBUS_MINVER, SMBUS_MODVER, SMBUS_MAXVER); #endif DRIVER_MODULE(bktr, pci, bktr_driver, bktr_devclass, 0, 0); MODULE_DEPEND(bktr, bktr_mem, 1,1,1); MODULE_VERSION(bktr, 1); /* * 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 (BKTR_PCI_VENDOR(type) == PCI_VENDOR_BROOKTREE) { switch (BKTR_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 BUS_PROBE_DEFAULT; case PCI_PRODUCT_BROOKTREE_BT849: device_set_desc(dev, "BrookTree 849A"); return BUS_PROBE_DEFAULT; case PCI_PRODUCT_BROOKTREE_BT878: device_set_desc(dev, "BrookTree 878"); return BUS_PROBE_DEFAULT; case PCI_PRODUCT_BROOKTREE_BT879: device_set_desc(dev, "BrookTree 879"); return BUS_PROBE_DEFAULT; } } return ENXIO; } /* * the attach routine. */ static int bktr_attach( device_t dev ) { u_long latency; u_long fun; 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 */ pci_enable_busmaster(dev); /* * Map control/status registers. */ bktr->mem_rid = PCIR_BAR(0); bktr->res_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &bktr->mem_rid, 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_any(dev, SYS_RES_IRQ, &bktr->irq_rid, 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, NULL, 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 compatibility 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 compatibility mode\n"); fun = fun | 4; /* Enable SiS/VIA compatibility mode (useful 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 + gone_in_dev(dev, 13, "bktr driver removed in FreeBSD 13.0\n"); 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_MEMORY, 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 #ifdef USE_VBIMUTEX mtx_destroy(&bktr->vbimutex); #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_offset_t)contigmalloc(size, M_DEVBUF, M_NOWAIT, 0, 0xffffffff, 1<<24, 0); if (addr == 0) addr = (vm_offset_t)contigmalloc(size, M_DEVBUF, M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0); 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( struct cdev *dev, int flags, int fmt, struct thread *td ) { bktr_ptr_t bktr; int unit; int result; unit = UNIT( dev2unit(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( dev2unit(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( struct cdev *dev, int flags, int fmt, struct thread *td ) { bktr_ptr_t bktr; int unit; int result; unit = UNIT( dev2unit(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( dev2unit(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( struct cdev *dev, struct uio *uio, int ioflag ) { bktr_ptr_t bktr; int unit; unit = UNIT(dev2unit(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( dev2unit(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( struct cdev *dev, struct uio *uio, int ioflag ) { return( EINVAL ); /* XXX or ENXIO ? */ } /* * */ static int bktr_ioctl( struct cdev *dev, ioctl_cmd_t cmd, caddr_t arg, int flag, struct thread *td ) { bktr_ptr_t bktr; int unit; unit = UNIT(dev2unit(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); } #ifdef BKTR_GPIO_ACCESS if (bktr->bigbuf == 0 && cmd != BT848_GPIO_GET_EN && cmd != BT848_GPIO_SET_EN && cmd != BT848_GPIO_GET_DATA && cmd != BT848_GPIO_SET_DATA) /* no frame buffer allocated (ioctl failed) */ return( ENOMEM ); #else if (bktr->bigbuf == 0) /* no frame buffer allocated (ioctl failed) */ return( ENOMEM ); #endif switch ( FUNCTION( dev2unit(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( struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot, vm_memattr_t *memattr ) { int unit; bktr_ptr_t bktr; unit = UNIT(dev2unit(dev)); if (FUNCTION(dev2unit(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( struct cdev *dev, int events, struct thread *td) { int unit; bktr_ptr_t bktr; int revents = 0; DECLARE_INTR_MASK(s); unit = UNIT(dev2unit(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); } LOCK_VBI(bktr); DISABLE_INTR(s); if (events & (POLLIN | POLLRDNORM)) { switch ( FUNCTION( dev2unit(dev) ) ) { case VBI_DEV: if(bktr->vbisize == 0) selrecord(td, &bktr->vbi_select); else revents |= events & (POLLIN | POLLRDNORM); break; } } ENABLE_INTR(s); UNLOCK_VBI(bktr); return (revents); } /*****************/ /* *** 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 *); static void bktr_attach(struct device *, struct device *, void *); #else static int bktr_probe(device_t, struct cfdata *, void *); static void bktr_attach(device_t, device_t, void *); #endif 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) #if defined(__OpenBSD__) struct device *parent; void *match; #else device_t parent; struct cfdata *match; #endif void *aux; { struct pci_attach_args *pa = aux; if (BKTR_PCI_VENDOR(pa->pa_id) == PCI_VENDOR_BROOKTREE && (BKTR_PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROOKTREE_BT848 || BKTR_PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROOKTREE_BT849 || BKTR_PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROOKTREE_BT878 || BKTR_PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROOKTREE_BT879)) return 1; return 0; } /* * the attach routine. */ static void bktr_attach(parent, self, aux) #if defined(__OpenBSD__) struct device *parent; struct device *self; #else device_t parent; device_t self; #endif 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) (dev2unit((x) & 0x0f)) #define FUNCTION(x) (dev2unit((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__ */