Index: head/sys/dev/bktr/bktr_core.c =================================================================== --- head/sys/dev/bktr/bktr_core.c (revision 123087) +++ head/sys/dev/bktr/bktr_core.c (revision 123088) @@ -1,4282 +1,4320 @@ /*- * 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. */ /*- * 1. Redistributions of source code must retain the * Copyright (c) 1995 Mark Tinguely and Jim Lowe * 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 Mark Tinguely and Jim Lowe * 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_core : This deals with the Bt848/849/878/879 PCI Frame Grabber, * Handles all the open, close, ioctl and read userland calls. * Sets the Bt848 registers and generates RISC pograms. * Controls the i2c bus and GPIO interface. * Contains the interface to the kernel. * (eg probe/attach and open/close/ioctl) */ /* The Brooktree BT848 Driver driver is based upon Mark Tinguely and Jim Lowe's driver for the Matrox Meteor PCI card . The Philips SAA 7116 and SAA 7196 are very different chipsets than the BT848. The original copyright notice by Mark and Jim is included mostly to honor their fantastic work in the Matrox Meteor driver! */ #include "opt_bktr.h" /* Include any kernel config options */ #if ( \ (defined(__FreeBSD__)) \ || (defined(__bsdi__)) \ || (defined(__OpenBSD__)) \ || (defined(__NetBSD__)) \ ) /*******************/ /* *** FreeBSD *** */ /*******************/ #ifdef __FreeBSD__ #include #include #include #include #include #include #include #include #include #include #include #include #if (__FreeBSD_version >=400000) || (NSMBUS > 0) #include /* used by smbus and newbus */ #endif #if (__FreeBSD_version < 500000) #include /* for DELAY */ #define PROC_LOCK(p) #define PROC_UNLOCK(p) #include #else #include #endif #if (__FreeBSD_version >=300000) #include /* for bus space */ #include #include #endif #include #include /* extensions to ioctl_meteor.h */ #include #include #include #include #include #include #if defined(BKTR_FREEBSD_MODULE) #include #endif #if defined(BKTR_USE_FREEBSD_SMBUS) #include #include #include #include "smbus_if.h" #include "iicbus_if.h" #endif const char * bktr_name(bktr_ptr_t bktr) { return bktr->bktr_xname; } #endif /* __FreeBSD__ */ /****************/ /* *** BSDI *** */ /****************/ #ifdef __bsdi__ #define PROC_LOCK(p) #define PROC_UNLOCK(p) #endif /* __bsdi__ */ /**************************/ /* *** OpenBSD/NetBSD *** */ /**************************/ #if defined(__NetBSD__) || defined(__OpenBSD__) #include #include #include #include #include #ifdef __NetBSD__ #include #else #include #include #include #include #endif #include /* uintptr_t */ #include #include #include #include #include #include #include static int bt848_format = -1; const char * bktr_name(bktr_ptr_t bktr) { return (bktr->bktr_dev.dv_xname); } #define PROC_LOCK(p) #define PROC_UNLOCK(p) #endif /* __NetBSD__ || __OpenBSD__ */ typedef u_char bool_t; #define BKTRPRI (PZERO+8)|PCATCH #define VBIPRI (PZERO-4)|PCATCH /* * memory allocated for DMA programs */ #define DMA_PROG_ALLOC (8 * PAGE_SIZE) /* When to split a dma transfer , the bt848 has timing as well as dma transfer size limitations so that we have to split dma transfers into two dma requests */ #define DMA_BT848_SPLIT 319*2 /* * Allocate enough memory for: * 768x576 RGB 16 or YUV (16 storage bits/pixel) = 884736 = 216 pages * * You may override this using the options "BROOKTREE_ALLOC_PAGES=value" * in your kernel configuration file. */ #ifndef BROOKTREE_ALLOC_PAGES #define BROOKTREE_ALLOC_PAGES 217*4 #endif #define BROOKTREE_ALLOC (BROOKTREE_ALLOC_PAGES * PAGE_SIZE) /* Definitions for VBI capture. * There are 16 VBI lines in a PAL video field (32 in a frame), * and we take 2044 samples from each line (placed in a 2048 byte buffer * for alignment). * VBI lines are held in a circular buffer before being read by a * user program from /dev/vbi. */ #define MAX_VBI_LINES 16 /* Maximum for all vidoe formats */ #define VBI_LINE_SIZE 2048 /* Store upto 2048 bytes per line */ #define VBI_BUFFER_ITEMS 20 /* Number of frames we buffer */ #define VBI_DATA_SIZE (VBI_LINE_SIZE * MAX_VBI_LINES * 2) #define VBI_BUFFER_SIZE (VBI_DATA_SIZE * VBI_BUFFER_ITEMS) /* Defines for fields */ #define ODD_F 0x01 #define EVEN_F 0x02 /* * Parameters describing size of transmitted image. */ static struct format_params format_params[] = { /* # define BT848_IFORM_F_AUTO (0x0) - don't matter. */ { 525, 26, 480, 910, 135, 754, 640, 780, 30, 0x68, 0x5d, BT848_IFORM_X_AUTO, 12, 1600 }, /* # define BT848_IFORM_F_NTSCM (0x1) */ { 525, 26, 480, 910, 135, 754, 640, 780, 30, 0x68, 0x5d, BT848_IFORM_X_XT0, 12, 1600 }, /* # define BT848_IFORM_F_NTSCJ (0x2) */ { 525, 22, 480, 910, 135, 754, 640, 780, 30, 0x68, 0x5d, BT848_IFORM_X_XT0, 12, 1600 }, /* # define BT848_IFORM_F_PALBDGHI (0x3) */ { 625, 32, 576, 1135, 186, 924, 768, 944, 25, 0x7f, 0x72, BT848_IFORM_X_XT1, 16, 2044 }, /* # define BT848_IFORM_F_PALM (0x4) */ { 525, 22, 480, 910, 135, 754, 640, 780, 30, 0x68, 0x5d, BT848_IFORM_X_XT0, 12, 1600 }, /* # define BT848_IFORM_F_PALN (0x5) */ { 625, 32, 576, 1135, 186, 924, 768, 944, 25, 0x7f, 0x72, BT848_IFORM_X_XT1, 16, 2044 }, /* # define BT848_IFORM_F_SECAM (0x6) */ { 625, 32, 576, 1135, 186, 924, 768, 944, 25, 0x7f, 0xa0, BT848_IFORM_X_XT1, 16, 2044 }, /* # define BT848_IFORM_F_RSVD (0x7) - ???? */ { 625, 32, 576, 1135, 186, 924, 768, 944, 25, 0x7f, 0x72, BT848_IFORM_X_XT0, 16, 2044 }, }; /* * Table of supported Pixel Formats */ static struct meteor_pixfmt_internal { struct meteor_pixfmt public; u_int color_fmt; } pixfmt_table[] = { { { 0, METEOR_PIXTYPE_RGB, 2, { 0x7c00, 0x03e0, 0x001f }, 0,0 }, 0x33 }, { { 0, METEOR_PIXTYPE_RGB, 2, { 0x7c00, 0x03e0, 0x001f }, 1,0 }, 0x33 }, { { 0, METEOR_PIXTYPE_RGB, 2, { 0xf800, 0x07e0, 0x001f }, 0,0 }, 0x22 }, { { 0, METEOR_PIXTYPE_RGB, 2, { 0xf800, 0x07e0, 0x001f }, 1,0 }, 0x22 }, { { 0, METEOR_PIXTYPE_RGB, 3, { 0xff0000,0x00ff00,0x0000ff }, 1,0 }, 0x11 }, { { 0, METEOR_PIXTYPE_RGB, 4, { 0xff0000,0x00ff00,0x0000ff }, 0,0 }, 0x00 }, { { 0, METEOR_PIXTYPE_RGB, 4, { 0xff0000,0x00ff00,0x0000ff }, 0,1 }, 0x00 }, { { 0, METEOR_PIXTYPE_RGB, 4, { 0xff0000,0x00ff00,0x0000ff }, 1,0 }, 0x00 }, { { 0, METEOR_PIXTYPE_RGB, 4, { 0xff0000,0x00ff00,0x0000ff }, 1,1 }, 0x00 }, { { 0, METEOR_PIXTYPE_YUV, 2, { 0xff0000,0x00ff00,0x0000ff }, 1,1 }, 0x88 }, { { 0, METEOR_PIXTYPE_YUV_PACKED, 2, { 0xff0000,0x00ff00,0x0000ff }, 0,1 }, 0x44 }, { { 0, METEOR_PIXTYPE_YUV_12, 2, { 0xff0000,0x00ff00,0x0000ff }, 1,1 }, 0x88 }, }; #define PIXFMT_TABLE_SIZE ( sizeof(pixfmt_table) / sizeof(pixfmt_table[0]) ) /* * Table of Meteor-supported Pixel Formats (for SETGEO compatibility) */ /* FIXME: Also add YUV_422 and YUV_PACKED as well */ static struct { u_long meteor_format; struct meteor_pixfmt public; } meteor_pixfmt_table[] = { { METEOR_GEO_YUV_12, { 0, METEOR_PIXTYPE_YUV_12, 2, { 0xff0000,0x00ff00,0x0000ff }, 1,1 } }, /* FIXME: Should byte swap flag be on for this one; negative in drvr? */ { METEOR_GEO_YUV_422, { 0, METEOR_PIXTYPE_YUV, 2, { 0xff0000,0x00ff00,0x0000ff }, 1,1 } }, { METEOR_GEO_YUV_PACKED, { 0, METEOR_PIXTYPE_YUV_PACKED, 2, { 0xff0000,0x00ff00,0x0000ff }, 0,1 } }, { METEOR_GEO_RGB16, { 0, METEOR_PIXTYPE_RGB, 2, { 0x7c00, 0x03e0, 0x001f }, 0, 0 } }, { METEOR_GEO_RGB24, { 0, METEOR_PIXTYPE_RGB, 4, { 0xff0000, 0x00ff00, 0x0000ff }, 0, 0 } }, }; #define METEOR_PIXFMT_TABLE_SIZE ( sizeof(meteor_pixfmt_table) / \ sizeof(meteor_pixfmt_table[0]) ) #define BSWAP (BT848_COLOR_CTL_BSWAP_ODD | BT848_COLOR_CTL_BSWAP_EVEN) #define WSWAP (BT848_COLOR_CTL_WSWAP_ODD | BT848_COLOR_CTL_WSWAP_EVEN) /* sync detect threshold */ #if 0 #define SYNC_LEVEL (BT848_ADC_RESERVED | \ BT848_ADC_CRUSH) /* threshold ~125 mV */ #else #define SYNC_LEVEL (BT848_ADC_RESERVED | \ BT848_ADC_SYNC_T) /* threshold ~75 mV */ #endif /* debug utility for holding previous INT_STAT contents */ #define STATUS_SUM static u_long status_sum = 0; /* * defines to make certain bit-fiddles understandable */ #define FIFO_ENABLED BT848_DMA_CTL_FIFO_EN #define RISC_ENABLED BT848_DMA_CTL_RISC_EN #define FIFO_RISC_ENABLED (BT848_DMA_CTL_FIFO_EN | BT848_DMA_CTL_RISC_EN) #define FIFO_RISC_DISABLED 0 #define ALL_INTS_DISABLED 0 #define ALL_INTS_CLEARED 0xffffffff #define CAPTURE_OFF 0 #define BIT_SEVEN_HIGH (1<<7) #define BIT_EIGHT_HIGH (1<<8) #define I2C_BITS (BT848_INT_RACK | BT848_INT_I2CDONE) #define TDEC_BITS (BT848_INT_FDSR | BT848_INT_FBUS) static int oformat_meteor_to_bt( u_long format ); static u_int pixfmt_swap_flags( int pixfmt ); /* * bt848 RISC programming routines. */ #ifdef BT848_DUMP static int dump_bt848( bktr_ptr_t bktr ); #endif static void yuvpack_prog( bktr_ptr_t bktr, char i_flag, int cols, int rows, int interlace ); static void yuv422_prog( bktr_ptr_t bktr, char i_flag, int cols, int rows, int interlace ); static void yuv12_prog( bktr_ptr_t bktr, char i_flag, int cols, int rows, int interlace ); static void rgb_prog( bktr_ptr_t bktr, char i_flag, int cols, int rows, int interlace ); static void rgb_vbi_prog( bktr_ptr_t bktr, char i_flag, int cols, int rows, int interlace ); static void build_dma_prog( bktr_ptr_t bktr, char i_flag ); static bool_t getline(bktr_reg_t *, int); static bool_t notclipped(bktr_reg_t * , int , int); static bool_t split(bktr_reg_t *, volatile u_long **, int, u_long, int, volatile u_char ** , int ); static void start_capture( bktr_ptr_t bktr, unsigned type ); static void set_fps( bktr_ptr_t bktr, u_short fps ); /* * Remote Control Functions */ static void remote_read(bktr_ptr_t bktr, struct bktr_remote *remote); /* * ioctls common to both video & tuner. */ static int common_ioctl( bktr_ptr_t bktr, ioctl_cmd_t cmd, caddr_t arg ); #if !defined(BKTR_USE_FREEBSD_SMBUS) /* * i2c primitives for low level control of i2c bus. Added for MSP34xx control */ static void i2c_start( bktr_ptr_t bktr); static void i2c_stop( bktr_ptr_t bktr); static int i2c_write_byte( bktr_ptr_t bktr, unsigned char data); static int i2c_read_byte( bktr_ptr_t bktr, unsigned char *data, int last ); #endif /* * the common attach code, used by all OS versions. */ void common_bktr_attach( bktr_ptr_t bktr, int unit, u_long pci_id, u_int rev ) { vm_offset_t buf = 0; int need_to_allocate_memory = 1; #ifdef BKTR_NEW_MSP34XX_DRIVER int err; #endif /***************************************/ /* *** OS Specific memory routines *** */ /***************************************/ #if defined(__NetBSD__) || defined(__OpenBSD__) /* allocate space for dma program */ bktr->dma_prog = get_bktr_mem(bktr, &bktr->dm_prog, DMA_PROG_ALLOC); bktr->odd_dma_prog = get_bktr_mem(bktr, &bktr->dm_oprog, DMA_PROG_ALLOC); /* allocate space for the VBI buffer */ bktr->vbidata = get_bktr_mem(bktr, &bktr->dm_vbidata, VBI_DATA_SIZE); bktr->vbibuffer = get_bktr_mem(bktr, &bktr->dm_vbibuffer, VBI_BUFFER_SIZE); /* allocate space for pixel buffer */ if ( BROOKTREE_ALLOC ) buf = get_bktr_mem(bktr, &bktr->dm_mem, BROOKTREE_ALLOC); else buf = 0; #endif #if defined(__FreeBSD__) || defined(__bsdi__) /* If this is a module, check if there is any currently saved contiguous memory */ #if defined(BKTR_FREEBSD_MODULE) if (bktr_has_stored_addresses(unit) == 1) { /* recover the addresses */ bktr->dma_prog = bktr_retrieve_address(unit, BKTR_MEM_DMA_PROG); bktr->odd_dma_prog = bktr_retrieve_address(unit, BKTR_MEM_ODD_DMA_PROG); bktr->vbidata = bktr_retrieve_address(unit, BKTR_MEM_VBIDATA); bktr->vbibuffer = bktr_retrieve_address(unit, BKTR_MEM_VBIBUFFER); buf = bktr_retrieve_address(unit, BKTR_MEM_BUF); need_to_allocate_memory = 0; } #endif if (need_to_allocate_memory == 1) { /* allocate space for dma program */ bktr->dma_prog = get_bktr_mem(unit, DMA_PROG_ALLOC); bktr->odd_dma_prog = get_bktr_mem(unit, DMA_PROG_ALLOC); /* allocte space for the VBI buffer */ bktr->vbidata = get_bktr_mem(unit, VBI_DATA_SIZE); bktr->vbibuffer = get_bktr_mem(unit, VBI_BUFFER_SIZE); /* allocate space for pixel buffer */ if ( BROOKTREE_ALLOC ) buf = get_bktr_mem(unit, BROOKTREE_ALLOC); else buf = 0; } #endif /* FreeBSD or BSDi */ +#ifdef USE_VBIMUTEX + mtx_init(&bktr->vbimutex, "bktr vbi lock", NULL, MTX_DEF); +#endif /* If this is a module, save the current contiguous memory */ #if defined(BKTR_FREEBSD_MODULE) bktr_store_address(unit, BKTR_MEM_DMA_PROG, bktr->dma_prog); bktr_store_address(unit, BKTR_MEM_ODD_DMA_PROG, bktr->odd_dma_prog); bktr_store_address(unit, BKTR_MEM_VBIDATA, bktr->vbidata); bktr_store_address(unit, BKTR_MEM_VBIBUFFER, bktr->vbibuffer); bktr_store_address(unit, BKTR_MEM_BUF, buf); #endif if ( bootverbose ) { printf("%s: buffer size %d, addr %p\n", bktr_name(bktr), BROOKTREE_ALLOC, (void *)(uintptr_t)vtophys(buf)); } if ( buf != 0 ) { bktr->bigbuf = buf; bktr->alloc_pages = BROOKTREE_ALLOC_PAGES; bzero((caddr_t) bktr->bigbuf, BROOKTREE_ALLOC); } else { bktr->alloc_pages = 0; } bktr->flags = METEOR_INITALIZED | METEOR_AUTOMODE | METEOR_DEV0 | METEOR_RGB16; bktr->dma_prog_loaded = FALSE; bktr->cols = 640; bktr->rows = 480; bktr->frames = 1; /* one frame */ bktr->format = METEOR_GEO_RGB16; bktr->pixfmt = oformat_meteor_to_bt( bktr->format ); bktr->pixfmt_compat = TRUE; bktr->vbiinsert = 0; bktr->vbistart = 0; bktr->vbisize = 0; bktr->vbiflags = 0; /* using the pci device id and revision id */ /* and determine the card type */ if (PCI_VENDOR(pci_id) == PCI_VENDOR_BROOKTREE) { switch (PCI_PRODUCT(pci_id)) { case PCI_PRODUCT_BROOKTREE_BT848: if (rev == 0x12) bktr->id = BROOKTREE_848A; else bktr->id = BROOKTREE_848; break; case PCI_PRODUCT_BROOKTREE_BT849: bktr->id = BROOKTREE_849A; break; case PCI_PRODUCT_BROOKTREE_BT878: bktr->id = BROOKTREE_878; break; case PCI_PRODUCT_BROOKTREE_BT879: bktr->id = BROOKTREE_879; break; } }; bktr->clr_on_start = FALSE; /* defaults for the tuner section of the card */ bktr->tflags = TUNER_INITALIZED; bktr->tuner.frequency = 0; bktr->tuner.channel = 0; bktr->tuner.chnlset = DEFAULT_CHNLSET; bktr->tuner.afc = 0; bktr->tuner.radio_mode = 0; bktr->audio_mux_select = 0; bktr->audio_mute_state = FALSE; bktr->bt848_card = -1; bktr->bt848_tuner = -1; bktr->reverse_mute = -1; bktr->slow_msp_audio = 0; bktr->msp_use_mono_source = 0; bktr->msp_source_selected = -1; bktr->audio_mux_present = 1; #if defined(__FreeBSD__) #ifdef BKTR_NEW_MSP34XX_DRIVER /* get hint on short programming of the msp34xx, so we know */ /* if the decision what thread to start should be overwritten */ if ( (err = resource_int_value("bktr", unit, "mspsimple", &(bktr->mspsimple)) ) != 0 ) bktr->mspsimple = -1; /* fall back to default */ #endif #endif probeCard( bktr, TRUE, unit ); /* Initialise any MSP34xx or TDA98xx audio chips */ init_audio_devices( bktr ); #ifdef BKTR_NEW_MSP34XX_DRIVER /* setup the kenrel thread */ err = msp_attach( bktr ); if ( err != 0 ) /* error doing kernel thread stuff, disable msp3400c */ bktr->card.msp3400c = 0; #endif } /* Copy the vbi lines from 'vbidata' into the circular buffer, 'vbibuffer'. * The circular buffer holds 'n' fixed size data blocks. * vbisize is the number of bytes in the circular buffer * vbiread is the point we reading data out of the circular buffer * vbiinsert is the point we insert data into the circular buffer */ static void vbidecode(bktr_ptr_t bktr) { unsigned char *dest; unsigned int *seq_dest; /* Check if there is room in the buffer to insert the data. */ if (bktr->vbisize + VBI_DATA_SIZE > VBI_BUFFER_SIZE) return; /* Copy the VBI data into the next free slot in the buffer. */ /* 'dest' is the point in vbibuffer where we want to insert new data */ dest = (unsigned char *)bktr->vbibuffer + bktr->vbiinsert; memcpy(dest, (unsigned char*)bktr->vbidata, VBI_DATA_SIZE); /* Write the VBI sequence number to the end of the vbi data */ /* This is used by the AleVT teletext program */ seq_dest = (unsigned int *)((unsigned char *)bktr->vbibuffer + bktr->vbiinsert + (VBI_DATA_SIZE - sizeof(bktr->vbi_sequence_number))); *seq_dest = bktr->vbi_sequence_number; /* And increase the VBI sequence number */ /* This can wrap around */ bktr->vbi_sequence_number++; /* Increment the vbiinsert pointer */ /* This can wrap around */ bktr->vbiinsert += VBI_DATA_SIZE; bktr->vbiinsert = (bktr->vbiinsert % VBI_BUFFER_SIZE); /* And increase the amount of vbi data in the buffer */ bktr->vbisize = bktr->vbisize + VBI_DATA_SIZE; } /* * the common interrupt handler. * Returns a 0 or 1 depending on whether the interrupt has handled. * In the OS specific section, bktr_intr() is defined which calls this * common interrupt handler. */ int common_bktr_intr( void *arg ) { bktr_ptr_t bktr; u_long bktr_status; u_char dstatus; u_long field; u_long w_field; u_long req_field; bktr = (bktr_ptr_t) arg; /* * check to see if any interrupts are unmasked on this device. If * none are, then we likely got here by way of being on a PCI shared * interrupt dispatch list. */ if (INL(bktr, BKTR_INT_MASK) == ALL_INTS_DISABLED) return 0; /* bail out now, before we do something we shouldn't */ if (!(bktr->flags & METEOR_OPEN)) { OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED); OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED); /* return; ?? */ } /* record and clear the INTerrupt status bits */ bktr_status = INL(bktr, BKTR_INT_STAT); OUTL(bktr, BKTR_INT_STAT, bktr_status & ~I2C_BITS); /* don't touch i2c */ /* record and clear the device status register */ dstatus = INB(bktr, BKTR_DSTATUS); OUTB(bktr, BKTR_DSTATUS, 0x00); #if defined( STATUS_SUM ) /* add any new device status or INTerrupt status bits */ status_sum |= (bktr_status & ~(BT848_INT_RSV0|BT848_INT_RSV1)); status_sum |= ((dstatus & (BT848_DSTATUS_COF|BT848_DSTATUS_LOF)) << 6); #endif /* STATUS_SUM */ /* printf( "%s: STATUS %x %x %x \n", bktr_name(bktr), dstatus, bktr_status, INL(bktr, BKTR_RISC_COUNT) ); */ /* if risc was disabled re-start process again */ /* if there was one of the following errors re-start again */ if ( !(bktr_status & BT848_INT_RISC_EN) || ((bktr_status &(/* BT848_INT_FBUS | */ /* BT848_INT_FTRGT | */ /* BT848_INT_FDSR | */ BT848_INT_PPERR | BT848_INT_RIPERR | BT848_INT_PABORT | BT848_INT_OCERR | BT848_INT_SCERR) ) != 0) || ((INB(bktr, BKTR_TDEC) == 0) && (bktr_status & TDEC_BITS)) ) { u_short tdec_save = INB(bktr, BKTR_TDEC); OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED); OUTB(bktr, BKTR_CAP_CTL, CAPTURE_OFF); OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED); /* Reset temporal decimation counter */ OUTB(bktr, BKTR_TDEC, 0); OUTB(bktr, BKTR_TDEC, tdec_save); /* Reset to no-fields captured state */ if (bktr->flags & (METEOR_CONTIN | METEOR_SYNCAP)) { switch(bktr->flags & METEOR_ONLY_FIELDS_MASK) { case METEOR_ONLY_ODD_FIELDS: bktr->flags |= METEOR_WANT_ODD; break; case METEOR_ONLY_EVEN_FIELDS: bktr->flags |= METEOR_WANT_EVEN; break; default: bktr->flags |= METEOR_WANT_MASK; break; } } OUTL(bktr, BKTR_RISC_STRT_ADD, vtophys(bktr->dma_prog)); OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_ENABLED); OUTW(bktr, BKTR_GPIO_DMA_CTL, bktr->capcontrol); OUTL(bktr, BKTR_INT_MASK, BT848_INT_MYSTERYBIT | BT848_INT_RISCI | BT848_INT_VSYNC | BT848_INT_FMTCHG); OUTB(bktr, BKTR_CAP_CTL, bktr->bktr_cap_ctl); return 1; } /* If this is not a RISC program interrupt, return */ if (!(bktr_status & BT848_INT_RISCI)) return 0; /** printf( "%s: intr status %x %x %x\n", bktr_name(bktr), bktr_status, dstatus, INL(bktr, BKTR_RISC_COUNT) ); */ /* * Disable future interrupts if a capture mode is not selected. * This can happen when we are in the process of closing or * changing capture modes, otherwise it shouldn't happen. */ if (!(bktr->flags & METEOR_CAP_MASK)) OUTB(bktr, BKTR_CAP_CTL, CAPTURE_OFF); /* Determine which field generated this interrupt */ field = ( bktr_status & BT848_INT_FIELD ) ? EVEN_F : ODD_F; /* * Process the VBI data if it is being captured. We do this once * both Odd and Even VBI data is captured. Therefore we do this * in the Even field interrupt handler. */ + LOCK_VBI(bktr); if ( (bktr->vbiflags & VBI_CAPTURE) &&(bktr->vbiflags & VBI_OPEN) &&(field==EVEN_F)) { /* Put VBI data into circular buffer */ vbidecode(bktr); /* If someone is blocked on reading from /dev/vbi, wake them */ if (bktr->vbi_read_blocked) { bktr->vbi_read_blocked = FALSE; wakeup(VBI_SLEEP); } /* If someone has a select() on /dev/vbi, inform them */ if (SEL_WAITING(&bktr->vbi_select)) { selwakeuppri(&bktr->vbi_select, VBIPRI); } } + UNLOCK_VBI(bktr); /* * Register the completed field * (For dual-field mode, require fields from the same frame) */ switch ( bktr->flags & METEOR_WANT_MASK ) { case METEOR_WANT_ODD : w_field = ODD_F ; break; case METEOR_WANT_EVEN : w_field = EVEN_F ; break; default : w_field = (ODD_F|EVEN_F); break; } switch ( bktr->flags & METEOR_ONLY_FIELDS_MASK ) { case METEOR_ONLY_ODD_FIELDS : req_field = ODD_F ; break; case METEOR_ONLY_EVEN_FIELDS : req_field = EVEN_F ; break; default : req_field = (ODD_F|EVEN_F); break; } if (( field == EVEN_F ) && ( w_field == EVEN_F )) bktr->flags &= ~METEOR_WANT_EVEN; else if (( field == ODD_F ) && ( req_field == ODD_F ) && ( w_field == ODD_F )) bktr->flags &= ~METEOR_WANT_ODD; else if (( field == ODD_F ) && ( req_field == (ODD_F|EVEN_F) ) && ( w_field == (ODD_F|EVEN_F) )) bktr->flags &= ~METEOR_WANT_ODD; else if (( field == ODD_F ) && ( req_field == (ODD_F|EVEN_F) ) && ( w_field == ODD_F )) { bktr->flags &= ~METEOR_WANT_ODD; bktr->flags |= METEOR_WANT_EVEN; } else { /* We're out of sync. Start over. */ if (bktr->flags & (METEOR_CONTIN | METEOR_SYNCAP)) { switch(bktr->flags & METEOR_ONLY_FIELDS_MASK) { case METEOR_ONLY_ODD_FIELDS: bktr->flags |= METEOR_WANT_ODD; break; case METEOR_ONLY_EVEN_FIELDS: bktr->flags |= METEOR_WANT_EVEN; break; default: bktr->flags |= METEOR_WANT_MASK; break; } } return 1; } /* * If we have a complete frame. */ if (!(bktr->flags & METEOR_WANT_MASK)) { bktr->frames_captured++; /* * post the completion time. */ if (bktr->flags & METEOR_WANT_TS) { struct timeval *ts; if ((u_int) bktr->alloc_pages * PAGE_SIZE <= (bktr->frame_size + sizeof(struct timeval))) { ts =(struct timeval *)bktr->bigbuf + bktr->frame_size; /* doesn't work in synch mode except * for first frame */ /* XXX */ microtime(ts); } } /* * Wake up the user in single capture mode. */ if (bktr->flags & METEOR_SINGLE) { /* stop dma */ OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED); /* disable risc, leave fifo running */ OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_ENABLED); wakeup(BKTR_SLEEP); } /* * If the user requested to be notified via signal, * let them know the frame is complete. */ if (bktr->proc != NULL) { PROC_LOCK(bktr->proc); psignal( bktr->proc, bktr->signal); PROC_UNLOCK(bktr->proc); } /* * Reset the want flags if in continuous or * synchronous capture mode. */ /* * XXX NOTE (Luigi): * currently we only support 3 capture modes: odd only, even only, * odd+even interlaced (odd field first). A fourth mode (non interlaced, * either even OR odd) could provide 60 (50 for PAL) pictures per * second, but it would require this routine to toggle the desired frame * each time, and one more different DMA program for the Bt848. * As a consequence, this fourth mode is currently unsupported. */ if (bktr->flags & (METEOR_CONTIN | METEOR_SYNCAP)) { switch(bktr->flags & METEOR_ONLY_FIELDS_MASK) { case METEOR_ONLY_ODD_FIELDS: bktr->flags |= METEOR_WANT_ODD; break; case METEOR_ONLY_EVEN_FIELDS: bktr->flags |= METEOR_WANT_EVEN; break; default: bktr->flags |= METEOR_WANT_MASK; break; } } } return 1; } /* * */ extern int bt848_format; /* used to set the default format, PAL or NTSC */ int video_open( bktr_ptr_t bktr ) { int frame_rate, video_format=0; if (bktr->flags & METEOR_OPEN) /* device is busy */ return( EBUSY ); bktr->flags |= METEOR_OPEN; #ifdef BT848_DUMP dump_bt848( bt848 ); #endif bktr->clr_on_start = FALSE; OUTB(bktr, BKTR_DSTATUS, 0x00); /* clear device status reg. */ OUTB(bktr, BKTR_ADC, SYNC_LEVEL); #if BKTR_SYSTEM_DEFAULT == BROOKTREE_PAL video_format = 0; #else video_format = 1; #endif if (bt848_format == 0 ) video_format = 0; if (bt848_format == 1 ) video_format = 1; if (video_format == 1 ) { OUTB(bktr, BKTR_IFORM, BT848_IFORM_F_NTSCM); bktr->format_params = BT848_IFORM_F_NTSCM; } else { OUTB(bktr, BKTR_IFORM, BT848_IFORM_F_PALBDGHI); bktr->format_params = BT848_IFORM_F_PALBDGHI; } OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | format_params[bktr->format_params].iform_xtsel); /* work around for new Hauppauge 878 cards */ if ((bktr->card.card_id == CARD_HAUPPAUGE) && (bktr->id==BROOKTREE_878 || bktr->id==BROOKTREE_879) ) OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX3); else OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX1); OUTB(bktr, BKTR_ADELAY, format_params[bktr->format_params].adelay); OUTB(bktr, BKTR_BDELAY, format_params[bktr->format_params].bdelay); frame_rate = format_params[bktr->format_params].frame_rate; /* enable PLL mode using 28Mhz crystal for PAL/SECAM users */ if (bktr->xtal_pll_mode == BT848_USE_PLL) { OUTB(bktr, BKTR_TGCTRL, 0); OUTB(bktr, BKTR_PLL_F_LO, 0xf9); OUTB(bktr, BKTR_PLL_F_HI, 0xdc); OUTB(bktr, BKTR_PLL_F_XCI, 0x8e); } bktr->flags = (bktr->flags & ~METEOR_DEV_MASK) | METEOR_DEV0; bktr->max_clip_node = 0; OUTB(bktr, BKTR_COLOR_CTL, BT848_COLOR_CTL_GAMMA | BT848_COLOR_CTL_RGB_DED); OUTB(bktr, BKTR_E_HSCALE_LO, 170); OUTB(bktr, BKTR_O_HSCALE_LO, 170); OUTB(bktr, BKTR_E_DELAY_LO, 0x72); OUTB(bktr, BKTR_O_DELAY_LO, 0x72); OUTB(bktr, BKTR_E_SCLOOP, 0); OUTB(bktr, BKTR_O_SCLOOP, 0); OUTB(bktr, BKTR_VBI_PACK_SIZE, 0); OUTB(bktr, BKTR_VBI_PACK_DEL, 0); bktr->fifo_errors = 0; bktr->dma_errors = 0; bktr->frames_captured = 0; bktr->even_fields_captured = 0; bktr->odd_fields_captured = 0; bktr->proc = NULL; set_fps(bktr, frame_rate); bktr->video.addr = 0; bktr->video.width = 0; bktr->video.banksize = 0; bktr->video.ramsize = 0; bktr->pixfmt_compat = TRUE; bktr->format = METEOR_GEO_RGB16; bktr->pixfmt = oformat_meteor_to_bt( bktr->format ); bktr->capture_area_enabled = FALSE; OUTL(bktr, BKTR_INT_MASK, BT848_INT_MYSTERYBIT); /* if you take this out triton based motherboards will operate unreliably */ return( 0 ); } int vbi_open( bktr_ptr_t bktr ) { - if (bktr->vbiflags & VBI_OPEN) /* device is busy */ + + LOCK_VBI(bktr); + + if (bktr->vbiflags & VBI_OPEN) { /* device is busy */ + UNLOCK_VBI(bktr); return( EBUSY ); + } bktr->vbiflags |= VBI_OPEN; /* reset the VBI circular buffer pointers and clear the buffers */ bktr->vbiinsert = 0; bktr->vbistart = 0; bktr->vbisize = 0; bktr->vbi_sequence_number = 0; bktr->vbi_read_blocked = FALSE; bzero((caddr_t) bktr->vbibuffer, VBI_BUFFER_SIZE); bzero((caddr_t) bktr->vbidata, VBI_DATA_SIZE); + UNLOCK_VBI(bktr); + return( 0 ); } /* * */ int tuner_open( bktr_ptr_t bktr ) { if ( !(bktr->tflags & TUNER_INITALIZED) ) /* device not found */ return( ENXIO ); if ( bktr->tflags & TUNER_OPEN ) /* already open */ return( 0 ); bktr->tflags |= TUNER_OPEN; bktr->tuner.frequency = 0; bktr->tuner.channel = 0; bktr->tuner.chnlset = DEFAULT_CHNLSET; bktr->tuner.afc = 0; bktr->tuner.radio_mode = 0; /* enable drivers on the GPIO port that control the MUXes */ OUTL(bktr, BKTR_GPIO_OUT_EN, INL(bktr, BKTR_GPIO_OUT_EN) | bktr->card.gpio_mux_bits); /* unmute the audio stream */ set_audio( bktr, AUDIO_UNMUTE ); /* Initialise any audio chips, eg MSP34xx or TDA98xx */ init_audio_devices( bktr ); return( 0 ); } /* * */ int video_close( bktr_ptr_t bktr ) { bktr->flags &= ~(METEOR_OPEN | METEOR_SINGLE | METEOR_CAP_MASK | METEOR_WANT_MASK); OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED); OUTB(bktr, BKTR_CAP_CTL, CAPTURE_OFF); bktr->dma_prog_loaded = FALSE; OUTB(bktr, BKTR_TDEC, 0); OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED); /** FIXME: is 0xf magic, wouldn't 0x00 work ??? */ OUTL(bktr, BKTR_SRESET, 0xf); OUTL(bktr, BKTR_INT_STAT, ALL_INTS_CLEARED); return( 0 ); } /* * tuner close handle, * place holder for tuner specific operations on a close. */ int tuner_close( bktr_ptr_t bktr ) { bktr->tflags &= ~TUNER_OPEN; /* mute the audio by switching the mux */ set_audio( bktr, AUDIO_MUTE ); /* disable drivers on the GPIO port that control the MUXes */ OUTL(bktr, BKTR_GPIO_OUT_EN, INL(bktr, BKTR_GPIO_OUT_EN) & ~bktr->card.gpio_mux_bits); return( 0 ); } int vbi_close( bktr_ptr_t bktr ) { + LOCK_VBI(bktr); + bktr->vbiflags &= ~VBI_OPEN; + UNLOCK_VBI(bktr); + return( 0 ); } /* * */ int video_read(bktr_ptr_t bktr, int unit, dev_t dev, struct uio *uio) { int status; int count; if (bktr->bigbuf == 0) /* no frame buffer allocated (ioctl failed) */ return( ENOMEM ); if (bktr->flags & METEOR_CAP_MASK) return( EIO ); /* already capturing */ OUTB(bktr, BKTR_CAP_CTL, bktr->bktr_cap_ctl); count = bktr->rows * bktr->cols * pixfmt_table[ bktr->pixfmt ].public.Bpp; if ((int) uio->uio_iov->iov_len < count) return( EINVAL ); bktr->flags &= ~(METEOR_CAP_MASK | METEOR_WANT_MASK); /* capture one frame */ start_capture(bktr, METEOR_SINGLE); /* wait for capture to complete */ OUTL(bktr, BKTR_INT_STAT, ALL_INTS_CLEARED); OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_ENABLED); OUTW(bktr, BKTR_GPIO_DMA_CTL, bktr->capcontrol); OUTL(bktr, BKTR_INT_MASK, BT848_INT_MYSTERYBIT | BT848_INT_RISCI | BT848_INT_VSYNC | BT848_INT_FMTCHG); status = tsleep(BKTR_SLEEP, BKTRPRI, "captur", 0); if (!status) /* successful capture */ status = uiomove((caddr_t)bktr->bigbuf, count, uio); else printf ("%s: read: tsleep error %d\n", bktr_name(bktr), status); bktr->flags &= ~(METEOR_SINGLE | METEOR_WANT_MASK); return( status ); } /* * Read VBI data from the vbi circular buffer * The buffer holds vbi data blocks which are the same size * vbiinsert is the position we will insert the next item into the buffer * vbistart is the actual position in the buffer we want to read from * vbisize is the exact number of bytes in the buffer left to read */ int vbi_read(bktr_ptr_t bktr, struct uio *uio, int ioflag) { - int readsize, readsize2; + int readsize, readsize2, start; int status; + /* + * XXX - vbi_read() should be protected against being re-entered + * while it is unlocked for the uiomove. + */ + LOCK_VBI(bktr); while(bktr->vbisize == 0) { if (ioflag & IO_NDELAY) { - return EWOULDBLOCK; + status = EWOULDBLOCK; + goto out; } bktr->vbi_read_blocked = TRUE; +#ifdef USE_VBIMUTEX + if ((status = msleep(VBI_SLEEP, &bktr->vbimutex, VBIPRI, "vbi", + 0))) { + goto out; + } +#else if ((status = tsleep(VBI_SLEEP, VBIPRI, "vbi", 0))) { - return status; + goto out; } +#endif } /* Now we have some data to give to the user */ /* We cannot read more bytes than there are in * the circular buffer */ readsize = (int)uio->uio_iov->iov_len; if (readsize > bktr->vbisize) readsize = bktr->vbisize; /* Check if we can read this number of bytes without having * to wrap around the circular buffer */ if((bktr->vbistart + readsize) >= VBI_BUFFER_SIZE) { /* We need to wrap around */ readsize2 = VBI_BUFFER_SIZE - bktr->vbistart; - status = uiomove((caddr_t)bktr->vbibuffer + bktr->vbistart, readsize2, uio); - status += uiomove((caddr_t)bktr->vbibuffer, (readsize - readsize2), uio); + start = bktr->vbistart; + UNLOCK_VBI(bktr); + status = uiomove((caddr_t)bktr->vbibuffer + start, readsize2, uio); + if (status == 0) + status = uiomove((caddr_t)bktr->vbibuffer, (readsize - readsize2), uio); } else { + UNLOCK_VBI(bktr); /* We do not need to wrap around */ status = uiomove((caddr_t)bktr->vbibuffer + bktr->vbistart, readsize, uio); } + LOCK_VBI(bktr); + /* Update the number of bytes left to read */ bktr->vbisize -= readsize; /* Update vbistart */ bktr->vbistart += readsize; bktr->vbistart = bktr->vbistart % VBI_BUFFER_SIZE; /* wrap around if needed */ + +out: + UNLOCK_VBI(bktr); return( status ); } /* * video ioctls */ int video_ioctl( bktr_ptr_t bktr, int unit, ioctl_cmd_t cmd, caddr_t arg, struct thread* td ) { volatile u_char c_temp; unsigned int temp; unsigned int temp_iform; unsigned int error; struct meteor_geomet *geo; struct meteor_counts *counts; struct meteor_video *video; struct bktr_capture_area *cap_area; vm_offset_t buf; int i; int sig; char char_temp; switch ( cmd ) { case BT848SCLIP: /* set clip region */ bktr->max_clip_node = 0; memcpy(&bktr->clip_list, arg, sizeof(bktr->clip_list)); for (i = 0; i < BT848_MAX_CLIP_NODE; i++) { if (bktr->clip_list[i].y_min == 0 && bktr->clip_list[i].y_max == 0) break; } bktr->max_clip_node = i; /* make sure that the list contains a valid clip secquence */ /* the clip rectangles should be sorted by x then by y as the second order sort key */ /* clip rectangle list is terminated by y_min and y_max set to 0 */ /* to disable clipping set y_min and y_max to 0 in the first clip rectangle . The first clip rectangle is clip_list[0]. */ if (bktr->max_clip_node == 0 && (bktr->clip_list[0].y_min != 0 && bktr->clip_list[0].y_max != 0)) { return EINVAL; } for (i = 0; i < BT848_MAX_CLIP_NODE - 1 ; i++) { if (bktr->clip_list[i].y_min == 0 && bktr->clip_list[i].y_max == 0) { break; } if ( bktr->clip_list[i+1].y_min != 0 && bktr->clip_list[i+1].y_max != 0 && bktr->clip_list[i].x_min > bktr->clip_list[i+1].x_min ) { bktr->max_clip_node = 0; return (EINVAL); } if (bktr->clip_list[i].x_min >= bktr->clip_list[i].x_max || bktr->clip_list[i].y_min >= bktr->clip_list[i].y_max || bktr->clip_list[i].x_min < 0 || bktr->clip_list[i].x_max < 0 || bktr->clip_list[i].y_min < 0 || bktr->clip_list[i].y_max < 0 ) { bktr->max_clip_node = 0; return (EINVAL); } } bktr->dma_prog_loaded = FALSE; break; case METEORSTATUS: /* get Bt848 status */ c_temp = INB(bktr, BKTR_DSTATUS); temp = 0; if (!(c_temp & 0x40)) temp |= METEOR_STATUS_HCLK; if (!(c_temp & 0x10)) temp |= METEOR_STATUS_FIDT; *(u_short *)arg = temp; break; case BT848SFMT: /* set input format */ temp = *(unsigned long*)arg & BT848_IFORM_FORMAT; temp_iform = INB(bktr, BKTR_IFORM); temp_iform &= ~BT848_IFORM_FORMAT; temp_iform &= ~BT848_IFORM_XTSEL; OUTB(bktr, BKTR_IFORM, (temp_iform | temp | format_params[temp].iform_xtsel)); switch( temp ) { case BT848_IFORM_F_AUTO: bktr->flags = (bktr->flags & ~METEOR_FORM_MASK) | METEOR_AUTOMODE; break; case BT848_IFORM_F_NTSCM: case BT848_IFORM_F_NTSCJ: bktr->flags = (bktr->flags & ~METEOR_FORM_MASK) | METEOR_NTSC; OUTB(bktr, BKTR_ADELAY, format_params[temp].adelay); OUTB(bktr, BKTR_BDELAY, format_params[temp].bdelay); bktr->format_params = temp; break; case BT848_IFORM_F_PALBDGHI: case BT848_IFORM_F_PALN: case BT848_IFORM_F_SECAM: case BT848_IFORM_F_RSVD: case BT848_IFORM_F_PALM: bktr->flags = (bktr->flags & ~METEOR_FORM_MASK) | METEOR_PAL; OUTB(bktr, BKTR_ADELAY, format_params[temp].adelay); OUTB(bktr, BKTR_BDELAY, format_params[temp].bdelay); bktr->format_params = temp; break; } bktr->dma_prog_loaded = FALSE; break; case METEORSFMT: /* set input format */ temp_iform = INB(bktr, BKTR_IFORM); temp_iform &= ~BT848_IFORM_FORMAT; temp_iform &= ~BT848_IFORM_XTSEL; switch(*(unsigned long *)arg & METEOR_FORM_MASK ) { case 0: /* default */ case METEOR_FMT_NTSC: bktr->flags = (bktr->flags & ~METEOR_FORM_MASK) | METEOR_NTSC; OUTB(bktr, BKTR_IFORM, temp_iform | BT848_IFORM_F_NTSCM | format_params[BT848_IFORM_F_NTSCM].iform_xtsel); OUTB(bktr, BKTR_ADELAY, format_params[BT848_IFORM_F_NTSCM].adelay); OUTB(bktr, BKTR_BDELAY, format_params[BT848_IFORM_F_NTSCM].bdelay); bktr->format_params = BT848_IFORM_F_NTSCM; break; case METEOR_FMT_PAL: bktr->flags = (bktr->flags & ~METEOR_FORM_MASK) | METEOR_PAL; OUTB(bktr, BKTR_IFORM, temp_iform | BT848_IFORM_F_PALBDGHI | format_params[BT848_IFORM_F_PALBDGHI].iform_xtsel); OUTB(bktr, BKTR_ADELAY, format_params[BT848_IFORM_F_PALBDGHI].adelay); OUTB(bktr, BKTR_BDELAY, format_params[BT848_IFORM_F_PALBDGHI].bdelay); bktr->format_params = BT848_IFORM_F_PALBDGHI; break; case METEOR_FMT_AUTOMODE: bktr->flags = (bktr->flags & ~METEOR_FORM_MASK) | METEOR_AUTOMODE; OUTB(bktr, BKTR_IFORM, temp_iform | BT848_IFORM_F_AUTO | format_params[BT848_IFORM_F_AUTO].iform_xtsel); break; default: return( EINVAL ); } bktr->dma_prog_loaded = FALSE; break; case METEORGFMT: /* get input format */ *(u_long *)arg = bktr->flags & METEOR_FORM_MASK; break; case BT848GFMT: /* get input format */ *(u_long *)arg = INB(bktr, BKTR_IFORM) & BT848_IFORM_FORMAT; break; case METEORSCOUNT: /* (re)set error counts */ counts = (struct meteor_counts *) arg; bktr->fifo_errors = counts->fifo_errors; bktr->dma_errors = counts->dma_errors; bktr->frames_captured = counts->frames_captured; bktr->even_fields_captured = counts->even_fields_captured; bktr->odd_fields_captured = counts->odd_fields_captured; break; case METEORGCOUNT: /* get error counts */ counts = (struct meteor_counts *) arg; counts->fifo_errors = bktr->fifo_errors; counts->dma_errors = bktr->dma_errors; counts->frames_captured = bktr->frames_captured; counts->even_fields_captured = bktr->even_fields_captured; counts->odd_fields_captured = bktr->odd_fields_captured; break; case METEORGVIDEO: video = (struct meteor_video *)arg; video->addr = bktr->video.addr; video->width = bktr->video.width; video->banksize = bktr->video.banksize; video->ramsize = bktr->video.ramsize; break; case METEORSVIDEO: video = (struct meteor_video *)arg; bktr->video.addr = video->addr; bktr->video.width = video->width; bktr->video.banksize = video->banksize; bktr->video.ramsize = video->ramsize; break; case METEORSFPS: set_fps(bktr, *(u_short *)arg); break; case METEORGFPS: *(u_short *)arg = bktr->fps; break; case METEORSHUE: /* set hue */ OUTB(bktr, BKTR_HUE, (*(u_char *) arg) & 0xff); break; case METEORGHUE: /* get hue */ *(u_char *)arg = INB(bktr, BKTR_HUE); break; case METEORSBRIG: /* set brightness */ char_temp = ( *(u_char *)arg & 0xff) - 128; OUTB(bktr, BKTR_BRIGHT, char_temp); break; case METEORGBRIG: /* get brightness */ *(u_char *)arg = INB(bktr, BKTR_BRIGHT); break; case METEORSCSAT: /* set chroma saturation */ temp = (int)*(u_char *)arg; OUTB(bktr, BKTR_SAT_U_LO, (temp << 1) & 0xff); OUTB(bktr, BKTR_SAT_V_LO, (temp << 1) & 0xff); OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) & ~(BT848_E_CONTROL_SAT_U_MSB | BT848_E_CONTROL_SAT_V_MSB)); OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) & ~(BT848_O_CONTROL_SAT_U_MSB | BT848_O_CONTROL_SAT_V_MSB)); if ( temp & BIT_SEVEN_HIGH ) { OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) | (BT848_E_CONTROL_SAT_U_MSB | BT848_E_CONTROL_SAT_V_MSB)); OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) | (BT848_O_CONTROL_SAT_U_MSB | BT848_O_CONTROL_SAT_V_MSB)); } break; case METEORGCSAT: /* get chroma saturation */ temp = (INB(bktr, BKTR_SAT_V_LO) >> 1) & 0xff; if ( INB(bktr, BKTR_E_CONTROL) & BT848_E_CONTROL_SAT_V_MSB ) temp |= BIT_SEVEN_HIGH; *(u_char *)arg = (u_char)temp; break; case METEORSCONT: /* set contrast */ temp = (int)*(u_char *)arg & 0xff; temp <<= 1; OUTB(bktr, BKTR_CONTRAST_LO, temp & 0xff); OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) & ~BT848_E_CONTROL_CON_MSB); OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) & ~BT848_O_CONTROL_CON_MSB); OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) | (((temp & 0x100) >> 6 ) & BT848_E_CONTROL_CON_MSB)); OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) | (((temp & 0x100) >> 6 ) & BT848_O_CONTROL_CON_MSB)); break; case METEORGCONT: /* get contrast */ temp = (int)INB(bktr, BKTR_CONTRAST_LO) & 0xff; temp |= ((int)INB(bktr, BKTR_O_CONTROL) & 0x04) << 6; *(u_char *)arg = (u_char)((temp >> 1) & 0xff); break; case BT848SCBUF: /* set Clear-Buffer-on-start flag */ bktr->clr_on_start = (*(int *)arg != 0); break; case BT848GCBUF: /* get Clear-Buffer-on-start flag */ *(int *)arg = (int) bktr->clr_on_start; break; case METEORSSIGNAL: sig = *(int *)arg; /* Historically, applications used METEOR_SIG_MODE_MASK * to reset signal delivery. */ if (sig == METEOR_SIG_MODE_MASK) sig = 0; if (sig < 0 || sig > _SIG_MAXSIG) return (EINVAL); bktr->signal = sig; bktr->proc = sig ? td->td_proc : NULL; break; case METEORGSIGNAL: *(int *)arg = bktr->signal; break; case METEORCAPTUR: temp = bktr->flags; switch (*(int *) arg) { case METEOR_CAP_SINGLE: if (bktr->bigbuf==0) /* no frame buffer allocated */ return( ENOMEM ); /* already capturing */ if (temp & METEOR_CAP_MASK) return( EIO ); start_capture(bktr, METEOR_SINGLE); /* wait for capture to complete */ OUTL(bktr, BKTR_INT_STAT, ALL_INTS_CLEARED); OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_ENABLED); OUTW(bktr, BKTR_GPIO_DMA_CTL, bktr->capcontrol); OUTL(bktr, BKTR_INT_MASK, BT848_INT_MYSTERYBIT | BT848_INT_RISCI | BT848_INT_VSYNC | BT848_INT_FMTCHG); OUTB(bktr, BKTR_CAP_CTL, bktr->bktr_cap_ctl); error = tsleep(BKTR_SLEEP, BKTRPRI, "captur", hz); if (error && (error != ERESTART)) { /* Here if we didn't get complete frame */ #ifdef DIAGNOSTIC printf( "%s: ioctl: tsleep error %d %x\n", bktr_name(bktr), error, INL(bktr, BKTR_RISC_COUNT)); #endif /* stop dma */ OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED); /* disable risc, leave fifo running */ OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_ENABLED); } bktr->flags &= ~(METEOR_SINGLE|METEOR_WANT_MASK); /* FIXME: should we set bt848->int_stat ??? */ break; case METEOR_CAP_CONTINOUS: if (bktr->bigbuf==0) /* no frame buffer allocated */ return( ENOMEM ); /* already capturing */ if (temp & METEOR_CAP_MASK) return( EIO ); start_capture(bktr, METEOR_CONTIN); /* Clear the interrypt status register */ OUTL(bktr, BKTR_INT_STAT, INL(bktr, BKTR_INT_STAT)); OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_ENABLED); OUTW(bktr, BKTR_GPIO_DMA_CTL, bktr->capcontrol); OUTB(bktr, BKTR_CAP_CTL, bktr->bktr_cap_ctl); OUTL(bktr, BKTR_INT_MASK, BT848_INT_MYSTERYBIT | BT848_INT_RISCI | BT848_INT_VSYNC | BT848_INT_FMTCHG); #ifdef BT848_DUMP dump_bt848( bt848 ); #endif break; case METEOR_CAP_STOP_CONT: if (bktr->flags & METEOR_CONTIN) { /* turn off capture */ OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED); OUTB(bktr, BKTR_CAP_CTL, CAPTURE_OFF); OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED); bktr->flags &= ~(METEOR_CONTIN | METEOR_WANT_MASK); } } break; case METEORSETGEO: /* can't change parameters while capturing */ if (bktr->flags & METEOR_CAP_MASK) return( EBUSY ); geo = (struct meteor_geomet *) arg; error = 0; /* Either even or odd, if even & odd, then these a zero */ if ((geo->oformat & METEOR_GEO_ODD_ONLY) && (geo->oformat & METEOR_GEO_EVEN_ONLY)) { printf( "%s: ioctl: Geometry odd or even only.\n", bktr_name(bktr)); return( EINVAL ); } /* set/clear even/odd flags */ if (geo->oformat & METEOR_GEO_ODD_ONLY) bktr->flags |= METEOR_ONLY_ODD_FIELDS; else bktr->flags &= ~METEOR_ONLY_ODD_FIELDS; if (geo->oformat & METEOR_GEO_EVEN_ONLY) bktr->flags |= METEOR_ONLY_EVEN_FIELDS; else bktr->flags &= ~METEOR_ONLY_EVEN_FIELDS; if (geo->columns <= 0) { printf( "%s: ioctl: %d: columns must be greater than zero.\n", bktr_name(bktr), geo->columns); error = EINVAL; } else if ((geo->columns & 0x3fe) != geo->columns) { printf( "%s: ioctl: %d: columns too large or not even.\n", bktr_name(bktr), geo->columns); error = EINVAL; } if (geo->rows <= 0) { printf( "%s: ioctl: %d: rows must be greater than zero.\n", bktr_name(bktr), geo->rows); error = EINVAL; } else if (((geo->rows & 0x7fe) != geo->rows) || ((geo->oformat & METEOR_GEO_FIELD_MASK) && ((geo->rows & 0x3fe) != geo->rows)) ) { printf( "%s: ioctl: %d: rows too large or not even.\n", bktr_name(bktr), geo->rows); error = EINVAL; } if (geo->frames > 32) { printf("%s: ioctl: too many frames.\n", bktr_name(bktr)); error = EINVAL; } if (error) return( error ); bktr->dma_prog_loaded = FALSE; OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED); OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED); if ((temp=(geo->rows * geo->columns * geo->frames * 2))) { if (geo->oformat & METEOR_GEO_RGB24) temp = temp * 2; /* meteor_mem structure for SYNC Capture */ if (geo->frames > 1) temp += PAGE_SIZE; temp = btoc(temp); if ((int) temp > bktr->alloc_pages && bktr->video.addr == 0) { /*****************************/ /* *** OS Dependant code *** */ /*****************************/ #if defined(__NetBSD__) || defined(__OpenBSD__) bus_dmamap_t dmamap; buf = get_bktr_mem(bktr, &dmamap, temp * PAGE_SIZE); if (buf != 0) { free_bktr_mem(bktr, bktr->dm_mem, bktr->bigbuf); bktr->dm_mem = dmamap; #else buf = get_bktr_mem(unit, temp*PAGE_SIZE); if (buf != 0) { kmem_free(kernel_map, bktr->bigbuf, (bktr->alloc_pages * PAGE_SIZE)); #endif bktr->bigbuf = buf; bktr->alloc_pages = temp; if (bootverbose) printf( "%s: ioctl: Allocating %d bytes\n", bktr_name(bktr), temp*PAGE_SIZE); } else error = ENOMEM; } } if (error) return error; bktr->rows = geo->rows; bktr->cols = geo->columns; bktr->frames = geo->frames; /* Pixel format (if in meteor pixfmt compatibility mode) */ if ( bktr->pixfmt_compat ) { bktr->format = METEOR_GEO_YUV_422; switch (geo->oformat & METEOR_GEO_OUTPUT_MASK) { case 0: /* default */ case METEOR_GEO_RGB16: bktr->format = METEOR_GEO_RGB16; break; case METEOR_GEO_RGB24: bktr->format = METEOR_GEO_RGB24; break; case METEOR_GEO_YUV_422: bktr->format = METEOR_GEO_YUV_422; if (geo->oformat & METEOR_GEO_YUV_12) bktr->format = METEOR_GEO_YUV_12; break; case METEOR_GEO_YUV_PACKED: bktr->format = METEOR_GEO_YUV_PACKED; break; } bktr->pixfmt = oformat_meteor_to_bt( bktr->format ); } if (bktr->flags & METEOR_CAP_MASK) { if (bktr->flags & (METEOR_CONTIN|METEOR_SYNCAP)) { switch(bktr->flags & METEOR_ONLY_FIELDS_MASK) { case METEOR_ONLY_ODD_FIELDS: bktr->flags |= METEOR_WANT_ODD; break; case METEOR_ONLY_EVEN_FIELDS: bktr->flags |= METEOR_WANT_EVEN; break; default: bktr->flags |= METEOR_WANT_MASK; break; } start_capture(bktr, METEOR_CONTIN); OUTL(bktr, BKTR_INT_STAT, INL(bktr, BKTR_INT_STAT)); OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_ENABLED); OUTW(bktr, BKTR_GPIO_DMA_CTL, bktr->capcontrol); OUTL(bktr, BKTR_INT_MASK, BT848_INT_MYSTERYBIT | BT848_INT_VSYNC | BT848_INT_FMTCHG); } } break; /* end of METEORSETGEO */ /* FIXME. The Capture Area currently has the following restrictions: GENERAL y_offset may need to be even in interlaced modes RGB24 - Interlaced mode x_size must be greater than or equal to 1.666*METEORSETGEO width (cols) y_size must be greater than or equal to METEORSETGEO height (rows) RGB24 - Even Only (or Odd Only) mode x_size must be greater than or equal to 1.666*METEORSETGEO width (cols) y_size must be greater than or equal to 2*METEORSETGEO height (rows) YUV12 - Interlaced mode x_size must be greater than or equal to METEORSETGEO width (cols) y_size must be greater than or equal to METEORSETGEO height (rows) YUV12 - Even Only (or Odd Only) mode x_size must be greater than or equal to METEORSETGEO width (cols) y_size must be greater than or equal to 2*METEORSETGEO height (rows) */ case BT848_SCAPAREA: /* set capture area of each video frame */ /* can't change parameters while capturing */ if (bktr->flags & METEOR_CAP_MASK) return( EBUSY ); cap_area = (struct bktr_capture_area *) arg; bktr->capture_area_x_offset = cap_area->x_offset; bktr->capture_area_y_offset = cap_area->y_offset; bktr->capture_area_x_size = cap_area->x_size; bktr->capture_area_y_size = cap_area->y_size; bktr->capture_area_enabled = TRUE; bktr->dma_prog_loaded = FALSE; break; case BT848_GCAPAREA: /* get capture area of each video frame */ cap_area = (struct bktr_capture_area *) arg; if (bktr->capture_area_enabled == FALSE) { cap_area->x_offset = 0; cap_area->y_offset = 0; cap_area->x_size = format_params[ bktr->format_params].scaled_hactive; cap_area->y_size = format_params[ bktr->format_params].vactive; } else { cap_area->x_offset = bktr->capture_area_x_offset; cap_area->y_offset = bktr->capture_area_y_offset; cap_area->x_size = bktr->capture_area_x_size; cap_area->y_size = bktr->capture_area_y_size; } break; default: return common_ioctl( bktr, cmd, arg ); } return( 0 ); } /* * tuner ioctls */ int tuner_ioctl( bktr_ptr_t bktr, int unit, ioctl_cmd_t cmd, caddr_t arg, struct thread* td ) { int tmp_int; unsigned int temp, temp1; int offset; int count; u_char *buf; u_long par; u_char write; int i2c_addr; int i2c_port; u_long data; switch ( cmd ) { case REMOTE_GETKEY: /* Read the last key pressed by the Remote Control */ if (bktr->remote_control == 0) return (EINVAL); remote_read(bktr, (struct bktr_remote *)arg); break; #if defined( TUNER_AFC ) case TVTUNER_SETAFC: bktr->tuner.afc = (*(int *)arg != 0); break; case TVTUNER_GETAFC: *(int *)arg = bktr->tuner.afc; /* XXX Perhaps use another bit to indicate AFC success? */ break; #endif /* TUNER_AFC */ case TVTUNER_SETCHNL: temp_mute( bktr, TRUE ); temp = tv_channel( bktr, (int)*(unsigned long *)arg ); if ( temp < 0 ) { temp_mute( bktr, FALSE ); return( EINVAL ); } *(unsigned long *)arg = temp; /* after every channel change, we must restart the MSP34xx */ /* audio chip to reselect NICAM STEREO or MONO audio */ if ( bktr->card.msp3400c ) msp_autodetect( bktr ); /* after every channel change, we must restart the DPL35xx */ if ( bktr->card.dpl3518a ) dpl_autodetect( bktr ); temp_mute( bktr, FALSE ); break; case TVTUNER_GETCHNL: *(unsigned long *)arg = bktr->tuner.channel; break; case TVTUNER_SETTYPE: temp = *(unsigned long *)arg; if ( (temp < CHNLSET_MIN) || (temp > CHNLSET_MAX) ) return( EINVAL ); bktr->tuner.chnlset = temp; break; case TVTUNER_GETTYPE: *(unsigned long *)arg = bktr->tuner.chnlset; break; case TVTUNER_GETSTATUS: temp = get_tuner_status( bktr ); *(unsigned long *)arg = temp & 0xff; break; case TVTUNER_SETFREQ: temp_mute( bktr, TRUE ); temp = tv_freq( bktr, (int)*(unsigned long *)arg, TV_FREQUENCY); temp_mute( bktr, FALSE ); if ( temp < 0 ) { temp_mute( bktr, FALSE ); return( EINVAL ); } *(unsigned long *)arg = temp; /* after every channel change, we must restart the MSP34xx */ /* audio chip to reselect NICAM STEREO or MONO audio */ if ( bktr->card.msp3400c ) msp_autodetect( bktr ); /* after every channel change, we must restart the DPL35xx */ if ( bktr->card.dpl3518a ) dpl_autodetect( bktr ); temp_mute( bktr, FALSE ); break; case TVTUNER_GETFREQ: *(unsigned long *)arg = bktr->tuner.frequency; break; case TVTUNER_GETCHNLSET: return tuner_getchnlset((struct bktr_chnlset *)arg); case BT848_SAUDIO: /* set audio channel */ if ( set_audio( bktr, *(int*)arg ) < 0 ) return( EIO ); break; /* hue is a 2's compliment number, -90' to +89.3' in 0.7' steps */ case BT848_SHUE: /* set hue */ OUTB(bktr, BKTR_HUE, (u_char)(*(int*)arg & 0xff)); break; case BT848_GHUE: /* get hue */ *(int*)arg = (signed char)(INB(bktr, BKTR_HUE) & 0xff); break; /* brightness is a 2's compliment #, -50 to +%49.6% in 0.39% steps */ case BT848_SBRIG: /* set brightness */ OUTB(bktr, BKTR_BRIGHT, (u_char)(*(int *)arg & 0xff)); break; case BT848_GBRIG: /* get brightness */ *(int *)arg = (signed char)(INB(bktr, BKTR_BRIGHT) & 0xff); break; /* */ case BT848_SCSAT: /* set chroma saturation */ tmp_int = *(int*)arg; temp = INB(bktr, BKTR_E_CONTROL); temp1 = INB(bktr, BKTR_O_CONTROL); if ( tmp_int & BIT_EIGHT_HIGH ) { temp |= (BT848_E_CONTROL_SAT_U_MSB | BT848_E_CONTROL_SAT_V_MSB); temp1 |= (BT848_O_CONTROL_SAT_U_MSB | BT848_O_CONTROL_SAT_V_MSB); } else { temp &= ~(BT848_E_CONTROL_SAT_U_MSB | BT848_E_CONTROL_SAT_V_MSB); temp1 &= ~(BT848_O_CONTROL_SAT_U_MSB | BT848_O_CONTROL_SAT_V_MSB); } OUTB(bktr, BKTR_SAT_U_LO, (u_char)(tmp_int & 0xff)); OUTB(bktr, BKTR_SAT_V_LO, (u_char)(tmp_int & 0xff)); OUTB(bktr, BKTR_E_CONTROL, temp); OUTB(bktr, BKTR_O_CONTROL, temp1); break; case BT848_GCSAT: /* get chroma saturation */ tmp_int = (int)(INB(bktr, BKTR_SAT_V_LO) & 0xff); if ( INB(bktr, BKTR_E_CONTROL) & BT848_E_CONTROL_SAT_V_MSB ) tmp_int |= BIT_EIGHT_HIGH; *(int*)arg = tmp_int; break; /* */ case BT848_SVSAT: /* set chroma V saturation */ tmp_int = *(int*)arg; temp = INB(bktr, BKTR_E_CONTROL); temp1 = INB(bktr, BKTR_O_CONTROL); if ( tmp_int & BIT_EIGHT_HIGH) { temp |= BT848_E_CONTROL_SAT_V_MSB; temp1 |= BT848_O_CONTROL_SAT_V_MSB; } else { temp &= ~BT848_E_CONTROL_SAT_V_MSB; temp1 &= ~BT848_O_CONTROL_SAT_V_MSB; } OUTB(bktr, BKTR_SAT_V_LO, (u_char)(tmp_int & 0xff)); OUTB(bktr, BKTR_E_CONTROL, temp); OUTB(bktr, BKTR_O_CONTROL, temp1); break; case BT848_GVSAT: /* get chroma V saturation */ tmp_int = (int)INB(bktr, BKTR_SAT_V_LO) & 0xff; if ( INB(bktr, BKTR_E_CONTROL) & BT848_E_CONTROL_SAT_V_MSB ) tmp_int |= BIT_EIGHT_HIGH; *(int*)arg = tmp_int; break; /* */ case BT848_SUSAT: /* set chroma U saturation */ tmp_int = *(int*)arg; temp = INB(bktr, BKTR_E_CONTROL); temp1 = INB(bktr, BKTR_O_CONTROL); if ( tmp_int & BIT_EIGHT_HIGH ) { temp |= BT848_E_CONTROL_SAT_U_MSB; temp1 |= BT848_O_CONTROL_SAT_U_MSB; } else { temp &= ~BT848_E_CONTROL_SAT_U_MSB; temp1 &= ~BT848_O_CONTROL_SAT_U_MSB; } OUTB(bktr, BKTR_SAT_U_LO, (u_char)(tmp_int & 0xff)); OUTB(bktr, BKTR_E_CONTROL, temp); OUTB(bktr, BKTR_O_CONTROL, temp1); break; case BT848_GUSAT: /* get chroma U saturation */ tmp_int = (int)INB(bktr, BKTR_SAT_U_LO) & 0xff; if ( INB(bktr, BKTR_E_CONTROL) & BT848_E_CONTROL_SAT_U_MSB ) tmp_int |= BIT_EIGHT_HIGH; *(int*)arg = tmp_int; break; /* lr 970528 luma notch etc - 3 high bits of e_control/o_control */ case BT848_SLNOTCH: /* set luma notch */ tmp_int = (*(int *)arg & 0x7) << 5 ; OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) & ~0xe0); OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) & ~0xe0); OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) | tmp_int); OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) | tmp_int); break; case BT848_GLNOTCH: /* get luma notch */ *(int *)arg = (int) ( (INB(bktr, BKTR_E_CONTROL) & 0xe0) >> 5) ; break; /* */ case BT848_SCONT: /* set contrast */ tmp_int = *(int*)arg; temp = INB(bktr, BKTR_E_CONTROL); temp1 = INB(bktr, BKTR_O_CONTROL); if ( tmp_int & BIT_EIGHT_HIGH ) { temp |= BT848_E_CONTROL_CON_MSB; temp1 |= BT848_O_CONTROL_CON_MSB; } else { temp &= ~BT848_E_CONTROL_CON_MSB; temp1 &= ~BT848_O_CONTROL_CON_MSB; } OUTB(bktr, BKTR_CONTRAST_LO, (u_char)(tmp_int & 0xff)); OUTB(bktr, BKTR_E_CONTROL, temp); OUTB(bktr, BKTR_O_CONTROL, temp1); break; case BT848_GCONT: /* get contrast */ tmp_int = (int)INB(bktr, BKTR_CONTRAST_LO) & 0xff; if ( INB(bktr, BKTR_E_CONTROL) & BT848_E_CONTROL_CON_MSB ) tmp_int |= BIT_EIGHT_HIGH; *(int*)arg = tmp_int; break; /* FIXME: SCBARS and CCBARS require a valid int * */ /* argument to succeed, but its not used; consider */ /* using the arg to store the on/off state so */ /* there's only one ioctl() needed to turn cbars on/off */ case BT848_SCBARS: /* set colorbar output */ OUTB(bktr, BKTR_COLOR_CTL, INB(bktr, BKTR_COLOR_CTL) | BT848_COLOR_CTL_COLOR_BARS); break; case BT848_CCBARS: /* clear colorbar output */ OUTB(bktr, BKTR_COLOR_CTL, INB(bktr, BKTR_COLOR_CTL) & ~(BT848_COLOR_CTL_COLOR_BARS)); break; case BT848_GAUDIO: /* get audio channel */ temp = bktr->audio_mux_select; if ( bktr->audio_mute_state == TRUE ) temp |= AUDIO_MUTE; *(int*)arg = temp; break; case BT848_SBTSC: /* set audio channel */ if ( set_BTSC( bktr, *(int*)arg ) < 0 ) return( EIO ); break; case BT848_WEEPROM: /* write eeprom */ offset = (((struct eeProm *)arg)->offset); count = (((struct eeProm *)arg)->count); buf = &(((struct eeProm *)arg)->bytes[ 0 ]); if ( writeEEProm( bktr, offset, count, buf ) < 0 ) return( EIO ); break; case BT848_REEPROM: /* read eeprom */ offset = (((struct eeProm *)arg)->offset); count = (((struct eeProm *)arg)->count); buf = &(((struct eeProm *)arg)->bytes[ 0 ]); if ( readEEProm( bktr, offset, count, buf ) < 0 ) return( EIO ); break; case BT848_SIGNATURE: offset = (((struct eeProm *)arg)->offset); count = (((struct eeProm *)arg)->count); buf = &(((struct eeProm *)arg)->bytes[ 0 ]); if ( signCard( bktr, offset, count, buf ) < 0 ) return( EIO ); break; /* Ioctl's for direct gpio access */ #ifdef BKTR_GPIO_ACCESS case BT848_GPIO_GET_EN: *(int*)arg = INL(bktr, BKTR_GPIO_OUT_EN); break; case BT848_GPIO_SET_EN: OUTL(bktr, BKTR_GPIO_OUT_EN, *(int*)arg); break; case BT848_GPIO_GET_DATA: *(int*)arg = INL(bktr, BKTR_GPIO_DATA); break; case BT848_GPIO_SET_DATA: OUTL(bktr, BKTR_GPIO_DATA, *(int*)arg); break; #endif /* BKTR_GPIO_ACCESS */ /* Ioctl's for running the tuner device in radio mode */ case RADIO_GETMODE: *(unsigned char *)arg = bktr->tuner.radio_mode; break; case RADIO_SETMODE: bktr->tuner.radio_mode = *(unsigned char *)arg; break; case RADIO_GETFREQ: *(unsigned long *)arg = bktr->tuner.frequency; break; case RADIO_SETFREQ: /* The argument to this ioctl is NOT freq*16. It is ** freq*100. */ temp=(int)*(unsigned long *)arg; #ifdef BKTR_RADIO_DEBUG printf("%s: arg=%d temp=%d\n", bktr_name(bktr), (int)*(unsigned long *)arg, temp); #endif #ifndef BKTR_RADIO_NOFREQCHECK /* According to the spec. sheet the band: 87.5MHz-108MHz */ /* is supported. */ if(temp<8750 || temp>10800) { printf("%s: Radio frequency out of range\n", bktr_name(bktr)); return(EINVAL); } #endif temp_mute( bktr, TRUE ); temp = tv_freq( bktr, temp, FM_RADIO_FREQUENCY ); temp_mute( bktr, FALSE ); #ifdef BKTR_RADIO_DEBUG if(temp) printf("%s: tv_freq returned: %d\n", bktr_name(bktr), temp); #endif if ( temp < 0 ) return( EINVAL ); *(unsigned long *)arg = temp; break; /* Luigi's I2CWR ioctl */ case BT848_I2CWR: par = *(u_long *)arg; write = (par >> 24) & 0xff ; i2c_addr = (par >> 16) & 0xff ; i2c_port = (par >> 8) & 0xff ; data = (par) & 0xff ; if (write) { i2cWrite( bktr, i2c_addr, i2c_port, data); } else { data = i2cRead( bktr, i2c_addr); } *(u_long *)arg = (par & 0xffffff00) | ( data & 0xff ); break; #ifdef BT848_MSP_READ /* I2C ioctls to allow userland access to the MSP chip */ case BT848_MSP_READ: { struct bktr_msp_control *msp; msp = (struct bktr_msp_control *) arg; msp->data = msp_dpl_read(bktr, bktr->msp_addr, msp->function, msp->address); break; } case BT848_MSP_WRITE: { struct bktr_msp_control *msp; msp = (struct bktr_msp_control *) arg; msp_dpl_write(bktr, bktr->msp_addr, msp->function, msp->address, msp->data ); break; } case BT848_MSP_RESET: msp_dpl_reset(bktr, bktr->msp_addr); break; #endif default: return common_ioctl( bktr, cmd, arg ); } return( 0 ); } /* * common ioctls */ static int common_ioctl( bktr_ptr_t bktr, ioctl_cmd_t cmd, caddr_t arg ) { int pixfmt; unsigned int temp; struct meteor_pixfmt *pf_pub; switch (cmd) { case METEORSINPUT: /* set input device */ /*Bt848 has 3 MUX Inputs. Bt848A/849A/878/879 has 4 MUX Inputs*/ /* On the original bt848 boards, */ /* Tuner is MUX0, RCA is MUX1, S-Video is MUX2 */ /* On the Hauppauge bt878 boards, */ /* Tuner is MUX0, RCA is MUX3 */ /* Unfortunatly Meteor driver codes DEV_RCA as DEV_0, so we */ /* stick with this system in our Meteor Emulation */ switch(*(unsigned long *)arg & METEOR_DEV_MASK) { /* this is the RCA video input */ case 0: /* default */ case METEOR_INPUT_DEV0: /* METEOR_INPUT_DEV_RCA: */ bktr->flags = (bktr->flags & ~METEOR_DEV_MASK) | METEOR_DEV0; OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) & ~BT848_IFORM_MUXSEL); /* work around for new Hauppauge 878 cards */ if ((bktr->card.card_id == CARD_HAUPPAUGE) && (bktr->id==BROOKTREE_878 || bktr->id==BROOKTREE_879) ) OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX3); else OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX1); OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) & ~BT848_E_CONTROL_COMP); OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) & ~BT848_O_CONTROL_COMP); set_audio( bktr, AUDIO_EXTERN ); break; /* this is the tuner input */ case METEOR_INPUT_DEV1: bktr->flags = (bktr->flags & ~METEOR_DEV_MASK) | METEOR_DEV1; OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) & ~BT848_IFORM_MUXSEL); OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX0); OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) & ~BT848_E_CONTROL_COMP); OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) & ~BT848_O_CONTROL_COMP); set_audio( bktr, AUDIO_TUNER ); break; /* this is the S-VHS input, but with a composite camera */ case METEOR_INPUT_DEV2: bktr->flags = (bktr->flags & ~METEOR_DEV_MASK) | METEOR_DEV2; OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) & ~BT848_IFORM_MUXSEL); OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX2); OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) & ~BT848_E_CONTROL_COMP); OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_E_CONTROL) & ~BT848_O_CONTROL_COMP); set_audio( bktr, AUDIO_EXTERN ); break; /* this is the S-VHS input */ case METEOR_INPUT_DEV_SVIDEO: bktr->flags = (bktr->flags & ~METEOR_DEV_MASK) | METEOR_DEV_SVIDEO; OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) & ~BT848_IFORM_MUXSEL); OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX2); OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) | BT848_E_CONTROL_COMP); OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) | BT848_O_CONTROL_COMP); set_audio( bktr, AUDIO_EXTERN ); break; case METEOR_INPUT_DEV3: if ((bktr->id == BROOKTREE_848A) || (bktr->id == BROOKTREE_849A) || (bktr->id == BROOKTREE_878) || (bktr->id == BROOKTREE_879) ) { bktr->flags = (bktr->flags & ~METEOR_DEV_MASK) | METEOR_DEV3; OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) & ~BT848_IFORM_MUXSEL); /* work around for new Hauppauge 878 cards */ if ((bktr->card.card_id == CARD_HAUPPAUGE) && (bktr->id==BROOKTREE_878 || bktr->id==BROOKTREE_879) ) OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX1); else OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX3); OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) & ~BT848_E_CONTROL_COMP); OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) & ~BT848_O_CONTROL_COMP); set_audio( bktr, AUDIO_EXTERN ); break; } default: return( EINVAL ); } break; case METEORGINPUT: /* get input device */ *(u_long *)arg = bktr->flags & METEOR_DEV_MASK; break; case METEORSACTPIXFMT: if (( *(int *)arg < 0 ) || ( *(int *)arg >= PIXFMT_TABLE_SIZE )) return( EINVAL ); bktr->pixfmt = *(int *)arg; OUTB(bktr, BKTR_COLOR_CTL, (INB(bktr, BKTR_COLOR_CTL) & 0xf0) | pixfmt_swap_flags( bktr->pixfmt )); bktr->pixfmt_compat = FALSE; break; case METEORGACTPIXFMT: *(int *)arg = bktr->pixfmt; break; case METEORGSUPPIXFMT : pf_pub = (struct meteor_pixfmt *)arg; pixfmt = pf_pub->index; if (( pixfmt < 0 ) || ( pixfmt >= PIXFMT_TABLE_SIZE )) return( EINVAL ); memcpy( pf_pub, &pixfmt_table[ pixfmt ].public, sizeof( *pf_pub ) ); /* Patch in our format index */ pf_pub->index = pixfmt; break; #if defined( STATUS_SUM ) case BT848_GSTATUS: /* reap status */ { DECLARE_INTR_MASK(s); DISABLE_INTR(s); temp = status_sum; status_sum = 0; ENABLE_INTR(s); *(u_int*)arg = temp; break; } #endif /* STATUS_SUM */ default: return( ENOTTY ); } return( 0 ); } /****************************************************************************** * bt848 RISC programming routines: */ /* * */ #ifdef BT848_DEBUG static int dump_bt848( bktr_ptr_t bktr ) { int r[60]={ 4, 8, 0xc, 0x8c, 0x10, 0x90, 0x14, 0x94, 0x18, 0x98, 0x1c, 0x9c, 0x20, 0xa0, 0x24, 0xa4, 0x28, 0x2c, 0xac, 0x30, 0x34, 0x38, 0x3c, 0x40, 0xc0, 0x48, 0x4c, 0xcc, 0x50, 0xd0, 0xd4, 0x60, 0x64, 0x68, 0x6c, 0xec, 0xd8, 0xdc, 0xe0, 0xe4, 0, 0, 0, 0 }; int i; for (i = 0; i < 40; i+=4) { printf("%s: Reg:value : \t%x:%x \t%x:%x \t %x:%x \t %x:%x\n", bktr_name(bktr), r[i], INL(bktr, r[i]), r[i+1], INL(bktr, r[i+1]), r[i+2], INL(bktr, r[i+2]), r[i+3], INL(bktr, r[i+3]])); } printf("%s: INT STAT %x \n", bktr_name(bktr), INL(bktr, BKTR_INT_STAT)); printf("%s: Reg INT_MASK %x \n", bktr_name(bktr), INL(bktr, BKTR_INT_MASK)); printf("%s: Reg GPIO_DMA_CTL %x \n", bktr_name(bktr), INW(bktr, BKTR_GPIO_DMA_CTL)); return( 0 ); } #endif /* * build write instruction */ #define BKTR_FM1 0x6 /* packed data to follow */ #define BKTR_FM3 0xe /* planar data to follow */ #define BKTR_VRE 0x4 /* Marks the end of the even field */ #define BKTR_VRO 0xC /* Marks the end of the odd field */ #define BKTR_PXV 0x0 /* valid word (never used) */ #define BKTR_EOL 0x1 /* last dword, 4 bytes */ #define BKTR_SOL 0x2 /* first dword */ #define OP_WRITE (0x1 << 28) #define OP_SKIP (0x2 << 28) #define OP_WRITEC (0x5 << 28) #define OP_JUMP (0x7 << 28) #define OP_SYNC (0x8 << 28) #define OP_WRITE123 (0x9 << 28) #define OP_WRITES123 (0xb << 28) #define OP_SOL (1 << 27) /* first instr for scanline */ #define OP_EOL (1 << 26) #define BKTR_RESYNC (1 << 15) #define BKTR_GEN_IRQ (1 << 24) /* * The RISC status bits can be set/cleared in the RISC programs * and tested in the Interrupt Handler */ #define BKTR_SET_RISC_STATUS_BIT0 (1 << 16) #define BKTR_SET_RISC_STATUS_BIT1 (1 << 17) #define BKTR_SET_RISC_STATUS_BIT2 (1 << 18) #define BKTR_SET_RISC_STATUS_BIT3 (1 << 19) #define BKTR_CLEAR_RISC_STATUS_BIT0 (1 << 20) #define BKTR_CLEAR_RISC_STATUS_BIT1 (1 << 21) #define BKTR_CLEAR_RISC_STATUS_BIT2 (1 << 22) #define BKTR_CLEAR_RISC_STATUS_BIT3 (1 << 23) #define BKTR_TEST_RISC_STATUS_BIT0 (1 << 28) #define BKTR_TEST_RISC_STATUS_BIT1 (1 << 29) #define BKTR_TEST_RISC_STATUS_BIT2 (1 << 30) #define BKTR_TEST_RISC_STATUS_BIT3 (1 << 31) static bool_t notclipped (bktr_reg_t * bktr, int x, int width) { int i; bktr_clip_t * clip_node; bktr->clip_start = -1; bktr->last_y = 0; bktr->y = 0; bktr->y2 = width; bktr->line_length = width; bktr->yclip = -1; bktr->yclip2 = -1; bktr->current_col = 0; if (bktr->max_clip_node == 0 ) return TRUE; clip_node = (bktr_clip_t *) &bktr->clip_list[0]; for (i = 0; i < bktr->max_clip_node; i++ ) { clip_node = (bktr_clip_t *) &bktr->clip_list[i]; if (x >= clip_node->x_min && x <= clip_node->x_max ) { bktr->clip_start = i; return FALSE; } } return TRUE; } static bool_t getline(bktr_reg_t *bktr, int x ) { int i, j; bktr_clip_t * clip_node ; if (bktr->line_length == 0 || bktr->current_col >= bktr->line_length) return FALSE; bktr->y = min(bktr->last_y, bktr->line_length); bktr->y2 = bktr->line_length; bktr->yclip = bktr->yclip2 = -1; for (i = bktr->clip_start; i < bktr->max_clip_node; i++ ) { clip_node = (bktr_clip_t *) &bktr->clip_list[i]; if (x >= clip_node->x_min && x <= clip_node->x_max) { if (bktr->last_y <= clip_node->y_min) { bktr->y = min(bktr->last_y, bktr->line_length); bktr->y2 = min(clip_node->y_min, bktr->line_length); bktr->yclip = min(clip_node->y_min, bktr->line_length); bktr->yclip2 = min(clip_node->y_max, bktr->line_length); bktr->last_y = bktr->yclip2; bktr->clip_start = i; for (j = i+1; j < bktr->max_clip_node; j++ ) { clip_node = (bktr_clip_t *) &bktr->clip_list[j]; if (x >= clip_node->x_min && x <= clip_node->x_max) { if (bktr->last_y >= clip_node->y_min) { bktr->yclip2 = min(clip_node->y_max, bktr->line_length); bktr->last_y = bktr->yclip2; bktr->clip_start = j; } } else break ; } return TRUE; } } } if (bktr->current_col <= bktr->line_length) { bktr->current_col = bktr->line_length; return TRUE; } return FALSE; } static bool_t split(bktr_reg_t * bktr, volatile u_long **dma_prog, int width , u_long operation, int pixel_width, volatile u_char ** target_buffer, int cols ) { u_long flag, flag2; struct meteor_pixfmt *pf = &pixfmt_table[ bktr->pixfmt ].public; u_int skip, start_skip; /* For RGB24, we need to align the component in FIFO Byte Lane 0 */ /* to the 1st byte in the mem dword containing our start addr. */ /* BTW, we know this pixfmt's 1st byte is Blue; thus the start addr */ /* must be Blue. */ start_skip = 0; if (( pf->type == METEOR_PIXTYPE_RGB ) && ( pf->Bpp == 3 )) switch ( ((uintptr_t) (volatile void *) *target_buffer) % 4 ) { case 2 : start_skip = 4 ; break; case 1 : start_skip = 8 ; break; } if ((width * pixel_width) < DMA_BT848_SPLIT ) { if ( width == cols) { flag = OP_SOL | OP_EOL; } else if (bktr->current_col == 0 ) { flag = OP_SOL; } else if (bktr->current_col == cols) { flag = OP_EOL; } else flag = 0; skip = 0; if (( flag & OP_SOL ) && ( start_skip > 0 )) { *(*dma_prog)++ = OP_SKIP | OP_SOL | start_skip; flag &= ~OP_SOL; skip = start_skip; } *(*dma_prog)++ = operation | flag | (width * pixel_width - skip); if (operation != OP_SKIP ) *(*dma_prog)++ = (uintptr_t) (volatile void *) *target_buffer; *target_buffer += width * pixel_width; bktr->current_col += width; } else { if (bktr->current_col == 0 && width == cols) { flag = OP_SOL ; flag2 = OP_EOL; } else if (bktr->current_col == 0 ) { flag = OP_SOL; flag2 = 0; } else if (bktr->current_col >= cols) { flag = 0; flag2 = OP_EOL; } else { flag = 0; flag2 = 0; } skip = 0; if (( flag & OP_SOL ) && ( start_skip > 0 )) { *(*dma_prog)++ = OP_SKIP | OP_SOL | start_skip; flag &= ~OP_SOL; skip = start_skip; } *(*dma_prog)++ = operation | flag | (width * pixel_width / 2 - skip); if (operation != OP_SKIP ) *(*dma_prog)++ = (uintptr_t) (volatile void *) *target_buffer ; *target_buffer += (width * pixel_width / 2) ; if ( operation == OP_WRITE ) operation = OP_WRITEC; *(*dma_prog)++ = operation | flag2 | (width * pixel_width / 2); *target_buffer += (width * pixel_width / 2) ; bktr->current_col += width; } return TRUE; } /* * Generate the RISC instructions to capture both VBI and video images */ static void rgb_vbi_prog( bktr_ptr_t bktr, char i_flag, int cols, int rows, int interlace ) { int i; volatile u_long target_buffer, buffer, target,width; volatile u_long pitch; volatile u_long *dma_prog; /* DMA prog is an array of 32 bit RISC instructions */ volatile u_long *loop_point; struct meteor_pixfmt_internal *pf_int = &pixfmt_table[ bktr->pixfmt ]; u_int Bpp = pf_int->public.Bpp; unsigned int vbisamples; /* VBI samples per line */ unsigned int vbilines; /* VBI lines per field */ unsigned int num_dwords; /* DWORDS per line */ vbisamples = format_params[bktr->format_params].vbi_num_samples; vbilines = format_params[bktr->format_params].vbi_num_lines; num_dwords = vbisamples/4; OUTB(bktr, BKTR_COLOR_FMT, pf_int->color_fmt); OUTB(bktr, BKTR_ADC, SYNC_LEVEL); OUTB(bktr, BKTR_VBI_PACK_SIZE, ((num_dwords)) & 0xff); OUTB(bktr, BKTR_VBI_PACK_DEL, ((num_dwords)>> 8) & 0x01); /* no hdelay */ /* no ext frame */ OUTB(bktr, BKTR_OFORM, 0x00); OUTB(bktr, BKTR_E_VSCALE_HI, INB(bktr, BKTR_E_VSCALE_HI) | 0x40); /* set chroma comb */ OUTB(bktr, BKTR_O_VSCALE_HI, INB(bktr, BKTR_O_VSCALE_HI) | 0x40); OUTB(bktr, BKTR_E_VSCALE_HI, INB(bktr, BKTR_E_VSCALE_HI) & ~0x80); /* clear Ycomb */ OUTB(bktr, BKTR_O_VSCALE_HI, INB(bktr, BKTR_O_VSCALE_HI) & ~0x80); /* disable gamma correction removal */ OUTB(bktr, BKTR_COLOR_CTL, INB(bktr, BKTR_COLOR_CTL) | BT848_COLOR_CTL_GAMMA); if (cols > 385 ) { OUTB(bktr, BKTR_E_VTC, 0); OUTB(bktr, BKTR_O_VTC, 0); } else { OUTB(bktr, BKTR_E_VTC, 1); OUTB(bktr, BKTR_O_VTC, 1); } bktr->capcontrol = 3 << 2 | 3; dma_prog = (u_long *) bktr->dma_prog; /* Construct Write */ if (bktr->video.addr) { target_buffer = (u_long) bktr->video.addr; pitch = bktr->video.width; } else { target_buffer = (u_long) vtophys(bktr->bigbuf); pitch = cols*Bpp; } buffer = target_buffer; /* Wait for the VRE sync marking the end of the Even and * the start of the Odd field. Resync here. */ *dma_prog++ = OP_SYNC | BKTR_RESYNC |BKTR_VRE; *dma_prog++ = 0; loop_point = dma_prog; /* store the VBI data */ /* look for sync with packed data */ *dma_prog++ = OP_SYNC | BKTR_FM1; *dma_prog++ = 0; for(i = 0; i < vbilines; i++) { *dma_prog++ = OP_WRITE | OP_SOL | OP_EOL | vbisamples; *dma_prog++ = (u_long) vtophys((caddr_t)bktr->vbidata + (i * VBI_LINE_SIZE)); } if ( (i_flag == 2/*Odd*/) || (i_flag==3) /*interlaced*/ ) { /* store the Odd field video image */ /* look for sync with packed data */ *dma_prog++ = OP_SYNC | BKTR_FM1; *dma_prog++ = 0; /* NULL WORD */ width = cols; for (i = 0; i < (rows/interlace); i++) { target = target_buffer; if ( notclipped(bktr, i, width)) { split(bktr, (volatile u_long **) &dma_prog, bktr->y2 - bktr->y, OP_WRITE, Bpp, (volatile u_char **)(uintptr_t)&target, cols); } else { while(getline(bktr, i)) { if (bktr->y != bktr->y2 ) { split(bktr, (volatile u_long **) &dma_prog, bktr->y2 - bktr->y, OP_WRITE, Bpp, (volatile u_char **)(uintptr_t)&target, cols); } if (bktr->yclip != bktr->yclip2 ) { split(bktr,(volatile u_long **) &dma_prog, bktr->yclip2 - bktr->yclip, OP_SKIP, Bpp, (volatile u_char **)(uintptr_t)&target, cols); } } } target_buffer += interlace * pitch; } } /* end if */ /* Grab the Even field */ /* Look for the VRO, end of Odd field, marker */ *dma_prog++ = OP_SYNC | BKTR_GEN_IRQ | BKTR_RESYNC | BKTR_VRO; *dma_prog++ = 0; /* NULL WORD */ /* store the VBI data */ /* look for sync with packed data */ *dma_prog++ = OP_SYNC | BKTR_FM1; *dma_prog++ = 0; for(i = 0; i < vbilines; i++) { *dma_prog++ = OP_WRITE | OP_SOL | OP_EOL | vbisamples; *dma_prog++ = (u_long) vtophys((caddr_t)bktr->vbidata + ((i+MAX_VBI_LINES) * VBI_LINE_SIZE)); } /* store the video image */ if (i_flag == 1) /*Even Only*/ target_buffer = buffer; if (i_flag == 3) /*interlaced*/ target_buffer = buffer+pitch; if ((i_flag == 1) /*Even Only*/ || (i_flag==3) /*interlaced*/) { /* look for sync with packed data */ *dma_prog++ = OP_SYNC | BKTR_FM1; *dma_prog++ = 0; /* NULL WORD */ width = cols; for (i = 0; i < (rows/interlace); i++) { target = target_buffer; if ( notclipped(bktr, i, width)) { split(bktr, (volatile u_long **) &dma_prog, bktr->y2 - bktr->y, OP_WRITE, Bpp, (volatile u_char **)(uintptr_t)&target, cols); } else { while(getline(bktr, i)) { if (bktr->y != bktr->y2 ) { split(bktr, (volatile u_long **) &dma_prog, bktr->y2 - bktr->y, OP_WRITE, Bpp, (volatile u_char **)(uintptr_t)&target, cols); } if (bktr->yclip != bktr->yclip2 ) { split(bktr, (volatile u_long **) &dma_prog, bktr->yclip2 - bktr->yclip, OP_SKIP, Bpp, (volatile u_char **)(uintptr_t) &target, cols); } } } target_buffer += interlace * pitch; } } /* Look for end of 'Even Field' */ *dma_prog++ = OP_SYNC | BKTR_GEN_IRQ | BKTR_RESYNC | BKTR_VRE; *dma_prog++ = 0; /* NULL WORD */ *dma_prog++ = OP_JUMP ; *dma_prog++ = (u_long ) vtophys(loop_point) ; *dma_prog++ = 0; /* NULL WORD */ } static void rgb_prog( bktr_ptr_t bktr, char i_flag, int cols, int rows, int interlace ) { int i; volatile u_long target_buffer, buffer, target,width; volatile u_long pitch; volatile u_long *dma_prog; struct meteor_pixfmt_internal *pf_int = &pixfmt_table[ bktr->pixfmt ]; u_int Bpp = pf_int->public.Bpp; OUTB(bktr, BKTR_COLOR_FMT, pf_int->color_fmt); OUTB(bktr, BKTR_VBI_PACK_SIZE, 0); OUTB(bktr, BKTR_VBI_PACK_DEL, 0); OUTB(bktr, BKTR_ADC, SYNC_LEVEL); OUTB(bktr, BKTR_OFORM, 0x00); OUTB(bktr, BKTR_E_VSCALE_HI, INB(bktr, BKTR_E_VSCALE_HI) | 0x40); /* set chroma comb */ OUTB(bktr, BKTR_O_VSCALE_HI, INB(bktr, BKTR_O_VSCALE_HI) | 0x40); OUTB(bktr, BKTR_E_VSCALE_HI, INB(bktr, BKTR_E_VSCALE_HI) & ~0x80); /* clear Ycomb */ OUTB(bktr, BKTR_O_VSCALE_HI, INB(bktr, BKTR_O_VSCALE_HI) & ~0x80); /* disable gamma correction removal */ OUTB(bktr, BKTR_COLOR_CTL, INB(bktr, BKTR_COLOR_CTL) | BT848_COLOR_CTL_GAMMA); if (cols > 385 ) { OUTB(bktr, BKTR_E_VTC, 0); OUTB(bktr, BKTR_O_VTC, 0); } else { OUTB(bktr, BKTR_E_VTC, 1); OUTB(bktr, BKTR_O_VTC, 1); } bktr->capcontrol = 3 << 2 | 3; dma_prog = (u_long *) bktr->dma_prog; /* Construct Write */ if (bktr->video.addr) { target_buffer = (u_long) bktr->video.addr; pitch = bktr->video.width; } else { target_buffer = (u_long) vtophys(bktr->bigbuf); pitch = cols*Bpp; } buffer = target_buffer; /* contruct sync : for video packet format */ *dma_prog++ = OP_SYNC | BKTR_RESYNC | BKTR_FM1; /* sync, mode indicator packed data */ *dma_prog++ = 0; /* NULL WORD */ width = cols; for (i = 0; i < (rows/interlace); i++) { target = target_buffer; if ( notclipped(bktr, i, width)) { split(bktr, (volatile u_long **) &dma_prog, bktr->y2 - bktr->y, OP_WRITE, Bpp, (volatile u_char **)(uintptr_t)&target, cols); } else { while(getline(bktr, i)) { if (bktr->y != bktr->y2 ) { split(bktr, (volatile u_long **) &dma_prog, bktr->y2 - bktr->y, OP_WRITE, Bpp, (volatile u_char **)(uintptr_t)&target, cols); } if (bktr->yclip != bktr->yclip2 ) { split(bktr,(volatile u_long **) &dma_prog, bktr->yclip2 - bktr->yclip, OP_SKIP, Bpp, (volatile u_char **)(uintptr_t)&target, cols); } } } target_buffer += interlace * pitch; } switch (i_flag) { case 1: /* sync vre */ *dma_prog++ = OP_SYNC | BKTR_GEN_IRQ | BKTR_VRO; *dma_prog++ = 0; /* NULL WORD */ *dma_prog++ = OP_JUMP; *dma_prog++ = (u_long ) vtophys(bktr->dma_prog); return; case 2: /* sync vro */ *dma_prog++ = OP_SYNC | BKTR_GEN_IRQ | BKTR_VRE; *dma_prog++ = 0; /* NULL WORD */ *dma_prog++ = OP_JUMP; *dma_prog++ = (u_long ) vtophys(bktr->dma_prog); return; case 3: /* sync vro */ *dma_prog++ = OP_SYNC | BKTR_GEN_IRQ | BKTR_RESYNC | BKTR_VRO; *dma_prog++ = 0; /* NULL WORD */ *dma_prog++ = OP_JUMP; ; *dma_prog = (u_long ) vtophys(bktr->odd_dma_prog); break; } if (interlace == 2) { target_buffer = buffer + pitch; dma_prog = (u_long *) bktr->odd_dma_prog; /* sync vre IRQ bit */ *dma_prog++ = OP_SYNC | BKTR_RESYNC | BKTR_FM1; *dma_prog++ = 0; /* NULL WORD */ width = cols; for (i = 0; i < (rows/interlace); i++) { target = target_buffer; if ( notclipped(bktr, i, width)) { split(bktr, (volatile u_long **) &dma_prog, bktr->y2 - bktr->y, OP_WRITE, Bpp, (volatile u_char **)(uintptr_t)&target, cols); } else { while(getline(bktr, i)) { if (bktr->y != bktr->y2 ) { split(bktr, (volatile u_long **) &dma_prog, bktr->y2 - bktr->y, OP_WRITE, Bpp, (volatile u_char **)(uintptr_t)&target, cols); } if (bktr->yclip != bktr->yclip2 ) { split(bktr, (volatile u_long **) &dma_prog, bktr->yclip2 - bktr->yclip, OP_SKIP, Bpp, (volatile u_char **)(uintptr_t)&target, cols); } } } target_buffer += interlace * pitch; } } /* sync vre IRQ bit */ *dma_prog++ = OP_SYNC | BKTR_GEN_IRQ | BKTR_RESYNC | BKTR_VRE; *dma_prog++ = 0; /* NULL WORD */ *dma_prog++ = OP_JUMP ; *dma_prog++ = (u_long ) vtophys(bktr->dma_prog) ; *dma_prog++ = 0; /* NULL WORD */ } /* * */ static void yuvpack_prog( bktr_ptr_t bktr, char i_flag, int cols, int rows, int interlace ) { int i; volatile unsigned int inst; volatile unsigned int inst3; volatile u_long target_buffer, buffer; volatile u_long *dma_prog; struct meteor_pixfmt_internal *pf_int = &pixfmt_table[ bktr->pixfmt ]; int b; OUTB(bktr, BKTR_COLOR_FMT, pf_int->color_fmt); OUTB(bktr, BKTR_E_SCLOOP, INB(bktr, BKTR_E_SCLOOP) | BT848_E_SCLOOP_CAGC); /* enable chroma comb */ OUTB(bktr, BKTR_O_SCLOOP, INB(bktr, BKTR_O_SCLOOP) | BT848_O_SCLOOP_CAGC); OUTB(bktr, BKTR_COLOR_CTL, INB(bktr, BKTR_COLOR_CTL) | BT848_COLOR_CTL_RGB_DED | BT848_COLOR_CTL_GAMMA); OUTB(bktr, BKTR_ADC, SYNC_LEVEL); bktr->capcontrol = 1 << 6 | 1 << 4 | 1 << 2 | 3; bktr->capcontrol = 3 << 2 | 3; dma_prog = (u_long *) bktr->dma_prog; /* Construct Write */ /* write , sol, eol */ inst = OP_WRITE | OP_SOL | (cols); /* write , sol, eol */ inst3 = OP_WRITE | OP_EOL | (cols); if (bktr->video.addr) target_buffer = (u_long) bktr->video.addr; else target_buffer = (u_long) vtophys(bktr->bigbuf); buffer = target_buffer; /* contruct sync : for video packet format */ /* sync, mode indicator packed data */ *dma_prog++ = OP_SYNC | BKTR_RESYNC | BKTR_FM1; *dma_prog++ = 0; /* NULL WORD */ b = cols; for (i = 0; i < (rows/interlace); i++) { *dma_prog++ = inst; *dma_prog++ = target_buffer; *dma_prog++ = inst3; *dma_prog++ = target_buffer + b; target_buffer += interlace*(cols * 2); } switch (i_flag) { case 1: /* sync vre */ *dma_prog++ = OP_SYNC | BKTR_GEN_IRQ | BKTR_VRE; *dma_prog++ = 0; /* NULL WORD */ *dma_prog++ = OP_JUMP; *dma_prog++ = (u_long ) vtophys(bktr->dma_prog); return; case 2: /* sync vro */ *dma_prog++ = OP_SYNC | BKTR_GEN_IRQ | BKTR_VRO; *dma_prog++ = 0; /* NULL WORD */ *dma_prog++ = OP_JUMP; *dma_prog++ = (u_long ) vtophys(bktr->dma_prog); return; case 3: /* sync vro */ *dma_prog++ = OP_SYNC | BKTR_GEN_IRQ | BKTR_RESYNC | BKTR_VRO; *dma_prog++ = 0; /* NULL WORD */ *dma_prog++ = OP_JUMP ; *dma_prog = (u_long ) vtophys(bktr->odd_dma_prog); break; } if (interlace == 2) { target_buffer = (u_long) buffer + cols*2; dma_prog = (u_long * ) bktr->odd_dma_prog; /* sync vre */ *dma_prog++ = OP_SYNC | BKTR_RESYNC | BKTR_FM1; *dma_prog++ = 0; /* NULL WORD */ for (i = 0; i < (rows/interlace) ; i++) { *dma_prog++ = inst; *dma_prog++ = target_buffer; *dma_prog++ = inst3; *dma_prog++ = target_buffer + b; target_buffer += interlace * ( cols*2); } } /* sync vro IRQ bit */ *dma_prog++ = OP_SYNC | BKTR_GEN_IRQ | BKTR_RESYNC | BKTR_VRE; *dma_prog++ = 0; /* NULL WORD */ *dma_prog++ = OP_JUMP ; *dma_prog++ = (u_long ) vtophys(bktr->dma_prog); *dma_prog++ = OP_JUMP; *dma_prog++ = (u_long ) vtophys(bktr->dma_prog); *dma_prog++ = 0; /* NULL WORD */ } /* * */ static void yuv422_prog( bktr_ptr_t bktr, char i_flag, int cols, int rows, int interlace ){ int i; volatile unsigned int inst; volatile u_long target_buffer, t1, buffer; volatile u_long *dma_prog; struct meteor_pixfmt_internal *pf_int = &pixfmt_table[ bktr->pixfmt ]; OUTB(bktr, BKTR_COLOR_FMT, pf_int->color_fmt); dma_prog = (u_long *) bktr->dma_prog; bktr->capcontrol = 1 << 6 | 1 << 4 | 3; OUTB(bktr, BKTR_ADC, SYNC_LEVEL); OUTB(bktr, BKTR_OFORM, 0x00); OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) | BT848_E_CONTROL_LDEC); /* disable luma decimation */ OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) | BT848_O_CONTROL_LDEC); OUTB(bktr, BKTR_E_SCLOOP, INB(bktr, BKTR_E_SCLOOP) | BT848_E_SCLOOP_CAGC); /* chroma agc enable */ OUTB(bktr, BKTR_O_SCLOOP, INB(bktr, BKTR_O_SCLOOP) | BT848_O_SCLOOP_CAGC); OUTB(bktr, BKTR_E_VSCALE_HI, INB(bktr, BKTR_E_VSCALE_HI) & ~0x80); /* clear Ycomb */ OUTB(bktr, BKTR_O_VSCALE_HI, INB(bktr, BKTR_O_VSCALE_HI) & ~0x80); OUTB(bktr, BKTR_E_VSCALE_HI, INB(bktr, BKTR_E_VSCALE_HI) | 0x40); /* set chroma comb */ OUTB(bktr, BKTR_O_VSCALE_HI, INB(bktr, BKTR_O_VSCALE_HI) | 0x40); /* disable gamma correction removal */ OUTB(bktr, BKTR_COLOR_CTL, INB(bktr, BKTR_COLOR_CTL) | BT848_COLOR_CTL_GAMMA); /* Construct Write */ inst = OP_WRITE123 | OP_SOL | OP_EOL | (cols); if (bktr->video.addr) target_buffer = (u_long) bktr->video.addr; else target_buffer = (u_long) vtophys(bktr->bigbuf); buffer = target_buffer; t1 = buffer; /* contruct sync : for video packet format */ *dma_prog++ = OP_SYNC | 1 << 15 | BKTR_FM3; /*sync, mode indicator packed data*/ *dma_prog++ = 0; /* NULL WORD */ for (i = 0; i < (rows/interlace ) ; i++) { *dma_prog++ = inst; *dma_prog++ = cols/2 | cols/2 << 16; *dma_prog++ = target_buffer; *dma_prog++ = t1 + (cols*rows) + i*cols/2 * interlace; *dma_prog++ = t1 + (cols*rows) + (cols*rows/2) + i*cols/2 * interlace; target_buffer += interlace*cols; } switch (i_flag) { case 1: *dma_prog++ = OP_SYNC | 1 << 24 | BKTR_VRE; /*sync vre*/ *dma_prog++ = 0; /* NULL WORD */ *dma_prog++ = OP_JUMP ; *dma_prog++ = (u_long ) vtophys(bktr->dma_prog); return; case 2: *dma_prog++ = OP_SYNC | 1 << 24 | BKTR_VRO; /*sync vre*/ *dma_prog++ = 0; /* NULL WORD */ *dma_prog++ = OP_JUMP; *dma_prog++ = (u_long ) vtophys(bktr->dma_prog); return; case 3: *dma_prog++ = OP_SYNC | 1 << 24 | 1 << 15 | BKTR_VRO; *dma_prog++ = 0; /* NULL WORD */ *dma_prog++ = OP_JUMP ; *dma_prog = (u_long ) vtophys(bktr->odd_dma_prog); break; } if (interlace == 2) { dma_prog = (u_long * ) bktr->odd_dma_prog; target_buffer = (u_long) buffer + cols; t1 = buffer + cols/2; *dma_prog++ = OP_SYNC | 1 << 15 | BKTR_FM3; *dma_prog++ = 0; /* NULL WORD */ for (i = 0; i < (rows/interlace ) ; i++) { *dma_prog++ = inst; *dma_prog++ = cols/2 | cols/2 << 16; *dma_prog++ = target_buffer; *dma_prog++ = t1 + (cols*rows) + i*cols/2 * interlace; *dma_prog++ = t1 + (cols*rows) + (cols*rows/2) + i*cols/2 * interlace; target_buffer += interlace*cols; } } *dma_prog++ = OP_SYNC | 1 << 24 | 1 << 15 | BKTR_VRE; *dma_prog++ = 0; /* NULL WORD */ *dma_prog++ = OP_JUMP ; *dma_prog++ = (u_long ) vtophys(bktr->dma_prog) ; *dma_prog++ = 0; /* NULL WORD */ } /* * */ static void yuv12_prog( bktr_ptr_t bktr, char i_flag, int cols, int rows, int interlace ){ int i; volatile unsigned int inst; volatile unsigned int inst1; volatile u_long target_buffer, t1, buffer; volatile u_long *dma_prog; struct meteor_pixfmt_internal *pf_int = &pixfmt_table[ bktr->pixfmt ]; OUTB(bktr, BKTR_COLOR_FMT, pf_int->color_fmt); dma_prog = (u_long *) bktr->dma_prog; bktr->capcontrol = 1 << 6 | 1 << 4 | 3; OUTB(bktr, BKTR_ADC, SYNC_LEVEL); OUTB(bktr, BKTR_OFORM, 0x0); /* Construct Write */ inst = OP_WRITE123 | OP_SOL | OP_EOL | (cols); inst1 = OP_WRITES123 | OP_SOL | OP_EOL | (cols); if (bktr->video.addr) target_buffer = (u_long) bktr->video.addr; else target_buffer = (u_long) vtophys(bktr->bigbuf); buffer = target_buffer; t1 = buffer; *dma_prog++ = OP_SYNC | 1 << 15 | BKTR_FM3; /*sync, mode indicator packed data*/ *dma_prog++ = 0; /* NULL WORD */ for (i = 0; i < (rows/interlace )/2 ; i++) { *dma_prog++ = inst; *dma_prog++ = cols/2 | (cols/2 << 16); *dma_prog++ = target_buffer; *dma_prog++ = t1 + (cols*rows) + i*cols/2 * interlace; *dma_prog++ = t1 + (cols*rows) + (cols*rows/4) + i*cols/2 * interlace; target_buffer += interlace*cols; *dma_prog++ = inst1; *dma_prog++ = cols/2 | (cols/2 << 16); *dma_prog++ = target_buffer; target_buffer += interlace*cols; } switch (i_flag) { case 1: *dma_prog++ = OP_SYNC | 1 << 24 | BKTR_VRE; /*sync vre*/ *dma_prog++ = 0; /* NULL WORD */ *dma_prog++ = OP_JUMP; *dma_prog++ = (u_long ) vtophys(bktr->dma_prog); return; case 2: *dma_prog++ = OP_SYNC | 1 << 24 | BKTR_VRO; /*sync vro*/ *dma_prog++ = 0; /* NULL WORD */ *dma_prog++ = OP_JUMP; *dma_prog++ = (u_long ) vtophys(bktr->dma_prog); return; case 3: *dma_prog++ = OP_SYNC | 1 << 24 | 1 << 15 | BKTR_VRO; *dma_prog++ = 0; /* NULL WORD */ *dma_prog++ = OP_JUMP ; *dma_prog = (u_long ) vtophys(bktr->odd_dma_prog); break; } if (interlace == 2) { dma_prog = (u_long * ) bktr->odd_dma_prog; target_buffer = (u_long) buffer + cols; t1 = buffer + cols/2; *dma_prog++ = OP_SYNC | 1 << 15 | BKTR_FM3; *dma_prog++ = 0; /* NULL WORD */ for (i = 0; i < ((rows/interlace )/2 ) ; i++) { *dma_prog++ = inst; *dma_prog++ = cols/2 | (cols/2 << 16); *dma_prog++ = target_buffer; *dma_prog++ = t1 + (cols*rows) + i*cols/2 * interlace; *dma_prog++ = t1 + (cols*rows) + (cols*rows/4) + i*cols/2 * interlace; target_buffer += interlace*cols; *dma_prog++ = inst1; *dma_prog++ = cols/2 | (cols/2 << 16); *dma_prog++ = target_buffer; target_buffer += interlace*cols; } } *dma_prog++ = OP_SYNC | 1 << 24 | 1 << 15 | BKTR_VRE; *dma_prog++ = 0; /* NULL WORD */ *dma_prog++ = OP_JUMP; *dma_prog++ = (u_long ) vtophys(bktr->dma_prog); *dma_prog++ = 0; /* NULL WORD */ } /* * */ static void build_dma_prog( bktr_ptr_t bktr, char i_flag ) { int rows, cols, interlace; int tmp_int; unsigned int temp; struct format_params *fp; struct meteor_pixfmt_internal *pf_int = &pixfmt_table[ bktr->pixfmt ]; fp = &format_params[bktr->format_params]; OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED); /* disable FIFO & RISC, leave other bits alone */ OUTW(bktr, BKTR_GPIO_DMA_CTL, INW(bktr, BKTR_GPIO_DMA_CTL) & ~FIFO_RISC_ENABLED); /* set video parameters */ if (bktr->capture_area_enabled) temp = ((quad_t ) fp->htotal* (quad_t) bktr->capture_area_x_size * 4096 / fp->scaled_htotal / bktr->cols) - 4096; else temp = ((quad_t ) fp->htotal* (quad_t) fp->scaled_hactive * 4096 / fp->scaled_htotal / bktr->cols) - 4096; /* printf("%s: HSCALE value is %d\n", bktr_name(bktr), temp); */ OUTB(bktr, BKTR_E_HSCALE_LO, temp & 0xff); OUTB(bktr, BKTR_O_HSCALE_LO, temp & 0xff); OUTB(bktr, BKTR_E_HSCALE_HI, (temp >> 8) & 0xff); OUTB(bktr, BKTR_O_HSCALE_HI, (temp >> 8) & 0xff); /* horizontal active */ temp = bktr->cols; /* printf("%s: HACTIVE value is %d\n", bktr_name(bktr), temp); */ OUTB(bktr, BKTR_E_HACTIVE_LO, temp & 0xff); OUTB(bktr, BKTR_O_HACTIVE_LO, temp & 0xff); OUTB(bktr, BKTR_E_CROP, INB(bktr, BKTR_E_CROP) & ~0x3); OUTB(bktr, BKTR_O_CROP, INB(bktr, BKTR_O_CROP) & ~0x3); OUTB(bktr, BKTR_E_CROP, INB(bktr, BKTR_E_CROP) | ((temp >> 8) & 0x3)); OUTB(bktr, BKTR_O_CROP, INB(bktr, BKTR_O_CROP) | ((temp >> 8) & 0x3)); /* horizontal delay */ if (bktr->capture_area_enabled) temp = ( (fp->hdelay* fp->scaled_hactive + bktr->capture_area_x_offset* fp->scaled_htotal) * bktr->cols) / (bktr->capture_area_x_size * fp->hactive); else temp = (fp->hdelay * bktr->cols) / fp->hactive; temp = temp & 0x3fe; /* printf("%s: HDELAY value is %d\n", bktr_name(bktr), temp); */ OUTB(bktr, BKTR_E_DELAY_LO, temp & 0xff); OUTB(bktr, BKTR_O_DELAY_LO, temp & 0xff); OUTB(bktr, BKTR_E_CROP, INB(bktr, BKTR_E_CROP) & ~0xc); OUTB(bktr, BKTR_O_CROP, INB(bktr, BKTR_O_CROP) & ~0xc); OUTB(bktr, BKTR_E_CROP, INB(bktr, BKTR_E_CROP) | ((temp >> 6) & 0xc)); OUTB(bktr, BKTR_O_CROP, INB(bktr, BKTR_O_CROP) | ((temp >> 6) & 0xc)); /* vertical scale */ if (bktr->capture_area_enabled) { if (bktr->flags & METEOR_ONLY_ODD_FIELDS || bktr->flags & METEOR_ONLY_EVEN_FIELDS) tmp_int = 65536 - (((bktr->capture_area_y_size * 256 + (bktr->rows/2)) / bktr->rows) - 512); else { tmp_int = 65536 - (((bktr->capture_area_y_size * 512 + (bktr->rows / 2)) / bktr->rows) - 512); } } else { if (bktr->flags & METEOR_ONLY_ODD_FIELDS || bktr->flags & METEOR_ONLY_EVEN_FIELDS) tmp_int = 65536 - (((fp->vactive * 256 + (bktr->rows/2)) / bktr->rows) - 512); else { tmp_int = 65536 - (((fp->vactive * 512 + (bktr->rows / 2)) / bktr->rows) - 512); } } tmp_int &= 0x1fff; /* printf("%s: VSCALE value is %d\n", bktr_name(bktr), tmp_int); */ OUTB(bktr, BKTR_E_VSCALE_LO, tmp_int & 0xff); OUTB(bktr, BKTR_O_VSCALE_LO, tmp_int & 0xff); OUTB(bktr, BKTR_E_VSCALE_HI, INB(bktr, BKTR_E_VSCALE_HI) & ~0x1f); OUTB(bktr, BKTR_O_VSCALE_HI, INB(bktr, BKTR_O_VSCALE_HI) & ~0x1f); OUTB(bktr, BKTR_E_VSCALE_HI, INB(bktr, BKTR_E_VSCALE_HI) | ((tmp_int >> 8) & 0x1f)); OUTB(bktr, BKTR_O_VSCALE_HI, INB(bktr, BKTR_O_VSCALE_HI) | ((tmp_int >> 8) & 0x1f)); /* vertical active */ if (bktr->capture_area_enabled) temp = bktr->capture_area_y_size; else temp = fp->vactive; /* printf("%s: VACTIVE is %d\n", bktr_name(bktr), temp); */ OUTB(bktr, BKTR_E_CROP, INB(bktr, BKTR_E_CROP) & ~0x30); OUTB(bktr, BKTR_E_CROP, INB(bktr, BKTR_E_CROP) | ((temp >> 4) & 0x30)); OUTB(bktr, BKTR_E_VACTIVE_LO, temp & 0xff); OUTB(bktr, BKTR_O_CROP, INB(bktr, BKTR_O_CROP) & ~0x30); OUTB(bktr, BKTR_O_CROP, INB(bktr, BKTR_O_CROP) | ((temp >> 4) & 0x30)); OUTB(bktr, BKTR_O_VACTIVE_LO, temp & 0xff); /* vertical delay */ if (bktr->capture_area_enabled) temp = fp->vdelay + (bktr->capture_area_y_offset); else temp = fp->vdelay; /* printf("%s: VDELAY is %d\n", bktr_name(bktr), temp); */ OUTB(bktr, BKTR_E_CROP, INB(bktr, BKTR_E_CROP) & ~0xC0); OUTB(bktr, BKTR_E_CROP, INB(bktr, BKTR_E_CROP) | ((temp >> 2) & 0xC0)); OUTB(bktr, BKTR_E_VDELAY_LO, temp & 0xff); OUTB(bktr, BKTR_O_CROP, INB(bktr, BKTR_O_CROP) & ~0xC0); OUTB(bktr, BKTR_O_CROP, INB(bktr, BKTR_O_CROP) | ((temp >> 2) & 0xC0)); OUTB(bktr, BKTR_O_VDELAY_LO, temp & 0xff); /* end of video params */ if ((bktr->xtal_pll_mode == BT848_USE_PLL) && (fp->iform_xtsel==BT848_IFORM_X_XT1)) { OUTB(bktr, BKTR_TGCTRL, BT848_TGCTRL_TGCKI_PLL); /* Select PLL mode */ } else { OUTB(bktr, BKTR_TGCTRL, BT848_TGCTRL_TGCKI_XTAL); /* Select Normal xtal 0/xtal 1 mode */ } /* capture control */ switch (i_flag) { case 1: bktr->bktr_cap_ctl = (BT848_CAP_CTL_DITH_FRAME | BT848_CAP_CTL_EVEN); OUTB(bktr, BKTR_E_VSCALE_HI, INB(bktr, BKTR_E_VSCALE_HI) & ~0x20); OUTB(bktr, BKTR_O_VSCALE_HI, INB(bktr, BKTR_O_VSCALE_HI) & ~0x20); interlace = 1; break; case 2: bktr->bktr_cap_ctl = (BT848_CAP_CTL_DITH_FRAME | BT848_CAP_CTL_ODD); OUTB(bktr, BKTR_E_VSCALE_HI, INB(bktr, BKTR_E_VSCALE_HI) & ~0x20); OUTB(bktr, BKTR_O_VSCALE_HI, INB(bktr, BKTR_O_VSCALE_HI) & ~0x20); interlace = 1; break; default: bktr->bktr_cap_ctl = (BT848_CAP_CTL_DITH_FRAME | BT848_CAP_CTL_EVEN | BT848_CAP_CTL_ODD); OUTB(bktr, BKTR_E_VSCALE_HI, INB(bktr, BKTR_E_VSCALE_HI) | 0x20); OUTB(bktr, BKTR_O_VSCALE_HI, INB(bktr, BKTR_O_VSCALE_HI) | 0x20); interlace = 2; break; } OUTL(bktr, BKTR_RISC_STRT_ADD, vtophys(bktr->dma_prog)); rows = bktr->rows; cols = bktr->cols; bktr->vbiflags &= ~VBI_CAPTURE; /* default - no vbi capture */ /* RGB Grabs. If /dev/vbi is already open, or we are a PAL/SECAM */ /* user, then use the rgb_vbi RISC program. */ /* Otherwise, use the normal rgb RISC program */ if (pf_int->public.type == METEOR_PIXTYPE_RGB) { if ( (bktr->vbiflags & VBI_OPEN) ||(bktr->format_params == BT848_IFORM_F_PALBDGHI) ||(bktr->format_params == BT848_IFORM_F_SECAM) ){ bktr->bktr_cap_ctl |= BT848_CAP_CTL_VBI_EVEN | BT848_CAP_CTL_VBI_ODD; bktr->vbiflags |= VBI_CAPTURE; rgb_vbi_prog(bktr, i_flag, cols, rows, interlace); return; } else { rgb_prog(bktr, i_flag, cols, rows, interlace); return; } } if ( pf_int->public.type == METEOR_PIXTYPE_YUV ) { yuv422_prog(bktr, i_flag, cols, rows, interlace); OUTB(bktr, BKTR_COLOR_CTL, (INB(bktr, BKTR_COLOR_CTL) & 0xf0) | pixfmt_swap_flags( bktr->pixfmt )); return; } if ( pf_int->public.type == METEOR_PIXTYPE_YUV_PACKED ) { yuvpack_prog(bktr, i_flag, cols, rows, interlace); OUTB(bktr, BKTR_COLOR_CTL, (INB(bktr, BKTR_COLOR_CTL) & 0xf0) | pixfmt_swap_flags( bktr->pixfmt )); return; } if ( pf_int->public.type == METEOR_PIXTYPE_YUV_12 ) { yuv12_prog(bktr, i_flag, cols, rows, interlace); OUTB(bktr, BKTR_COLOR_CTL, (INB(bktr, BKTR_COLOR_CTL) & 0xf0) | pixfmt_swap_flags( bktr->pixfmt )); return; } return; } /****************************************************************************** * video & video capture specific routines: */ /* * */ static void start_capture( bktr_ptr_t bktr, unsigned type ) { u_char i_flag; struct format_params *fp; fp = &format_params[bktr->format_params]; /* If requested, clear out capture buf first */ if (bktr->clr_on_start && (bktr->video.addr == 0)) { bzero((caddr_t)bktr->bigbuf, (size_t)bktr->rows * bktr->cols * bktr->frames * pixfmt_table[ bktr->pixfmt ].public.Bpp); } OUTB(bktr, BKTR_DSTATUS, 0); OUTL(bktr, BKTR_INT_STAT, INL(bktr, BKTR_INT_STAT)); bktr->flags |= type; bktr->flags &= ~METEOR_WANT_MASK; switch(bktr->flags & METEOR_ONLY_FIELDS_MASK) { case METEOR_ONLY_EVEN_FIELDS: bktr->flags |= METEOR_WANT_EVEN; i_flag = 1; break; case METEOR_ONLY_ODD_FIELDS: bktr->flags |= METEOR_WANT_ODD; i_flag = 2; break; default: bktr->flags |= METEOR_WANT_MASK; i_flag = 3; break; } /* TDEC is only valid for continuous captures */ if ( type == METEOR_SINGLE ) { u_short fps_save = bktr->fps; set_fps(bktr, fp->frame_rate); bktr->fps = fps_save; } else set_fps(bktr, bktr->fps); if (bktr->dma_prog_loaded == FALSE) { build_dma_prog(bktr, i_flag); bktr->dma_prog_loaded = TRUE; } OUTL(bktr, BKTR_RISC_STRT_ADD, vtophys(bktr->dma_prog)); } /* * */ static void set_fps( bktr_ptr_t bktr, u_short fps ) { struct format_params *fp; int i_flag; fp = &format_params[bktr->format_params]; switch(bktr->flags & METEOR_ONLY_FIELDS_MASK) { case METEOR_ONLY_EVEN_FIELDS: bktr->flags |= METEOR_WANT_EVEN; i_flag = 1; break; case METEOR_ONLY_ODD_FIELDS: bktr->flags |= METEOR_WANT_ODD; i_flag = 1; break; default: bktr->flags |= METEOR_WANT_MASK; i_flag = 2; break; } OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED); OUTL(bktr, BKTR_INT_STAT, ALL_INTS_CLEARED); bktr->fps = fps; OUTB(bktr, BKTR_TDEC, 0); if (fps < fp->frame_rate) OUTB(bktr, BKTR_TDEC, i_flag*(fp->frame_rate - fps) & 0x3f); else OUTB(bktr, BKTR_TDEC, 0); return; } /* * Given a pixfmt index, compute the bt848 swap_flags necessary to * achieve the specified swapping. * Note that without bt swapping, 2Bpp and 3Bpp modes are written * byte-swapped, and 4Bpp modes are byte and word swapped (see Table 6 * and read R->L). * Note also that for 3Bpp, we may additionally need to do some creative * SKIPing to align the FIFO bytelines with the target buffer (see split()). * This is abstracted here: e.g. no swaps = RGBA; byte & short swap = ABGR * as one would expect. */ static u_int pixfmt_swap_flags( int pixfmt ) { struct meteor_pixfmt *pf = &pixfmt_table[ pixfmt ].public; u_int swapf = 0; switch ( pf->Bpp ) { case 2 : swapf = ( pf->swap_bytes ? 0 : BSWAP ); break; case 3 : /* no swaps supported for 3bpp - makes no sense w/ bt848 */ break; case 4 : if ( pf->swap_bytes ) swapf = pf->swap_shorts ? 0 : WSWAP; else swapf = pf->swap_shorts ? BSWAP : (BSWAP | WSWAP); break; } return swapf; } /* * Converts meteor-defined pixel formats (e.g. METEOR_GEO_RGB16) into * our pixfmt_table indices. */ static int oformat_meteor_to_bt( u_long format ) { int i; struct meteor_pixfmt *pf1, *pf2; /* Find format in compatibility table */ for ( i = 0; i < METEOR_PIXFMT_TABLE_SIZE; i++ ) if ( meteor_pixfmt_table[i].meteor_format == format ) break; if ( i >= METEOR_PIXFMT_TABLE_SIZE ) return -1; pf1 = &meteor_pixfmt_table[i].public; /* Match it with an entry in master pixel format table */ for ( i = 0; i < PIXFMT_TABLE_SIZE; i++ ) { pf2 = &pixfmt_table[i].public; if (( pf1->type == pf2->type ) && ( pf1->Bpp == pf2->Bpp ) && !bcmp( pf1->masks, pf2->masks, sizeof( pf1->masks )) && ( pf1->swap_bytes == pf2->swap_bytes ) && ( pf1->swap_shorts == pf2->swap_shorts )) break; } if ( i >= PIXFMT_TABLE_SIZE ) return -1; return i; } /****************************************************************************** * i2c primitives: */ /* */ #define I2CBITTIME (0x5<<4) /* 5 * 0.48uS */ #define I2CBITTIME_878 (1 << 7) #define I2C_READ 0x01 #define I2C_COMMAND (I2CBITTIME | \ BT848_DATA_CTL_I2CSCL | \ BT848_DATA_CTL_I2CSDA) #define I2C_COMMAND_878 (I2CBITTIME_878 | \ BT848_DATA_CTL_I2CSCL | \ BT848_DATA_CTL_I2CSDA) /* Select between old i2c code and new iicbus / smbus code */ #if defined(BKTR_USE_FREEBSD_SMBUS) /* * The hardware interface is actually SMB commands */ int i2cWrite( bktr_ptr_t bktr, int addr, int byte1, int byte2 ) { char cmd; if (bktr->id == BROOKTREE_848 || bktr->id == BROOKTREE_848A || bktr->id == BROOKTREE_849A) cmd = I2C_COMMAND; else cmd = I2C_COMMAND_878; if (byte2 != -1) { if (smbus_writew(bktr->i2c_sc.smbus, addr, cmd, (short)(((byte2 & 0xff) << 8) | (byte1 & 0xff)))) return (-1); } else { if (smbus_writeb(bktr->i2c_sc.smbus, addr, cmd, (char)(byte1 & 0xff))) return (-1); } /* return OK */ return( 0 ); } int i2cRead( bktr_ptr_t bktr, int addr ) { char result; char cmd; if (bktr->id == BROOKTREE_848 || bktr->id == BROOKTREE_848A || bktr->id == BROOKTREE_849A) cmd = I2C_COMMAND; else cmd = I2C_COMMAND_878; if (smbus_readb(bktr->i2c_sc.smbus, addr, cmd, &result)) return (-1); return ((int)((unsigned char)result)); } #define IICBUS(bktr) ((bktr)->i2c_sc.iicbus) /* The MSP34xx and DPL35xx Audio chip require i2c bus writes of up */ /* to 5 bytes which the bt848 automated i2c bus controller cannot handle */ /* Therefore we need low level control of the i2c bus hardware */ /* Write to the MSP or DPL registers */ void msp_dpl_write(bktr_ptr_t bktr, int i2c_addr, unsigned char dev, unsigned int addr, unsigned int data) { unsigned char addr_l, addr_h, data_h, data_l ; addr_h = (addr >>8) & 0xff; addr_l = addr & 0xff; data_h = (data >>8) & 0xff; data_l = data & 0xff; iicbus_start(IICBUS(bktr), i2c_addr, 0 /* no timeout? */); iicbus_write_byte(IICBUS(bktr), dev, 0); iicbus_write_byte(IICBUS(bktr), addr_h, 0); iicbus_write_byte(IICBUS(bktr), addr_l, 0); iicbus_write_byte(IICBUS(bktr), data_h, 0); iicbus_write_byte(IICBUS(bktr), data_l, 0); iicbus_stop(IICBUS(bktr)); return; } /* Read from the MSP or DPL registers */ unsigned int msp_dpl_read(bktr_ptr_t bktr, int i2c_addr, unsigned char dev, unsigned int addr) { unsigned int data; unsigned char addr_l, addr_h, dev_r; int read; u_char data_read[2]; addr_h = (addr >>8) & 0xff; addr_l = addr & 0xff; dev_r = dev+1; /* XXX errors ignored */ iicbus_start(IICBUS(bktr), i2c_addr, 0 /* no timeout? */); iicbus_write_byte(IICBUS(bktr), dev_r, 0); iicbus_write_byte(IICBUS(bktr), addr_h, 0); iicbus_write_byte(IICBUS(bktr), addr_l, 0); iicbus_repeated_start(IICBUS(bktr), i2c_addr +1, 0 /* no timeout? */); iicbus_read(IICBUS(bktr), data_read, 2, &read, IIC_LAST_READ, 0); iicbus_stop(IICBUS(bktr)); data = (data_read[0]<<8) | data_read[1]; return (data); } /* Reset the MSP or DPL chip */ /* The user can block the reset (which is handy if you initialise the * MSP and/or DPL audio in another operating system first (eg in Windows) */ void msp_dpl_reset( bktr_ptr_t bktr, int i2c_addr ) { #ifndef BKTR_NO_MSP_RESET /* put into reset mode */ iicbus_start(IICBUS(bktr), i2c_addr, 0 /* no timeout? */); iicbus_write_byte(IICBUS(bktr), 0x00, 0); iicbus_write_byte(IICBUS(bktr), 0x80, 0); iicbus_write_byte(IICBUS(bktr), 0x00, 0); iicbus_stop(IICBUS(bktr)); /* put back to operational mode */ iicbus_start(IICBUS(bktr), i2c_addr, 0 /* no timeout? */); iicbus_write_byte(IICBUS(bktr), 0x00, 0); iicbus_write_byte(IICBUS(bktr), 0x00, 0); iicbus_write_byte(IICBUS(bktr), 0x00, 0); iicbus_stop(IICBUS(bktr)); #endif return; } static void remote_read(bktr_ptr_t bktr, struct bktr_remote *remote) { int read; /* XXX errors ignored */ iicbus_start(IICBUS(bktr), bktr->remote_control_addr, 0 /* no timeout? */); iicbus_read(IICBUS(bktr), remote->data, 3, &read, IIC_LAST_READ, 0); iicbus_stop(IICBUS(bktr)); return; } #else /* defined(BKTR_USE_FREEBSD_SMBUS) */ /* * Program the i2c bus directly */ int i2cWrite( bktr_ptr_t bktr, int addr, int byte1, int byte2 ) { u_long x; u_long data; /* clear status bits */ OUTL(bktr, BKTR_INT_STAT, BT848_INT_RACK | BT848_INT_I2CDONE); /* build the command datum */ if (bktr->id == BROOKTREE_848 || bktr->id == BROOKTREE_848A || bktr->id == BROOKTREE_849A) { data = ((addr & 0xff) << 24) | ((byte1 & 0xff) << 16) | I2C_COMMAND; } else { data = ((addr & 0xff) << 24) | ((byte1 & 0xff) << 16) | I2C_COMMAND_878; } if ( byte2 != -1 ) { data |= ((byte2 & 0xff) << 8); data |= BT848_DATA_CTL_I2CW3B; } /* write the address and data */ OUTL(bktr, BKTR_I2C_DATA_CTL, data); /* wait for completion */ for ( x = 0x7fffffff; x; --x ) { /* safety valve */ if ( INL(bktr, BKTR_INT_STAT) & BT848_INT_I2CDONE ) break; } /* check for ACK */ if ( !x || !(INL(bktr, BKTR_INT_STAT) & BT848_INT_RACK) ) return( -1 ); /* return OK */ return( 0 ); } /* * */ int i2cRead( bktr_ptr_t bktr, int addr ) { u_long x; /* clear status bits */ OUTL(bktr, BKTR_INT_STAT, BT848_INT_RACK | BT848_INT_I2CDONE); /* write the READ address */ /* The Bt878 and Bt879 differed on the treatment of i2c commands */ if (bktr->id == BROOKTREE_848 || bktr->id == BROOKTREE_848A || bktr->id == BROOKTREE_849A) { OUTL(bktr, BKTR_I2C_DATA_CTL, ((addr & 0xff) << 24) | I2C_COMMAND); } else { OUTL(bktr, BKTR_I2C_DATA_CTL, ((addr & 0xff) << 24) | I2C_COMMAND_878); } /* wait for completion */ for ( x = 0x7fffffff; x; --x ) { /* safety valve */ if ( INL(bktr, BKTR_INT_STAT) & BT848_INT_I2CDONE ) break; } /* check for ACK */ if ( !x || !(INL(bktr, BKTR_INT_STAT) & BT848_INT_RACK) ) return( -1 ); /* it was a read */ return( (INL(bktr, BKTR_I2C_DATA_CTL) >> 8) & 0xff ); } /* The MSP34xx Audio chip require i2c bus writes of up to 5 bytes which the */ /* bt848 automated i2c bus controller cannot handle */ /* Therefore we need low level control of the i2c bus hardware */ /* Idea for the following functions are from elsewhere in this driver and */ /* from the Linux BTTV i2c driver by Gerd Knorr */ #define BITD 40 static void i2c_start( bktr_ptr_t bktr) { OUTL(bktr, BKTR_I2C_DATA_CTL, 1); DELAY( BITD ); /* release data */ OUTL(bktr, BKTR_I2C_DATA_CTL, 3); DELAY( BITD ); /* release clock */ OUTL(bktr, BKTR_I2C_DATA_CTL, 2); DELAY( BITD ); /* lower data */ OUTL(bktr, BKTR_I2C_DATA_CTL, 0); DELAY( BITD ); /* lower clock */ } static void i2c_stop( bktr_ptr_t bktr) { OUTL(bktr, BKTR_I2C_DATA_CTL, 0); DELAY( BITD ); /* lower clock & data */ OUTL(bktr, BKTR_I2C_DATA_CTL, 2); DELAY( BITD ); /* release clock */ OUTL(bktr, BKTR_I2C_DATA_CTL, 3); DELAY( BITD ); /* release data */ } static int i2c_write_byte( bktr_ptr_t bktr, unsigned char data) { int x; int status; /* write out the byte */ for ( x = 7; x >= 0; --x ) { if ( data & (1<= 0; --x ) { OUTL(bktr, BKTR_I2C_DATA_CTL, 3); DELAY( BITD ); /* strobe clock */ bit = INL(bktr, BKTR_I2C_DATA_CTL) & 1; /* read the data bit */ if ( bit ) byte |= (1<>8) & 0xff; addr_l = addr & 0xff; data_h = (data >>8) & 0xff; data_l = data & 0xff; i2c_start(bktr); i2c_write_byte(bktr, msp_w_addr); i2c_write_byte(bktr, dev); i2c_write_byte(bktr, addr_h); i2c_write_byte(bktr, addr_l); i2c_write_byte(bktr, data_h); i2c_write_byte(bktr, data_l); i2c_stop(bktr); } /* Read from the MSP or DPL registers */ unsigned int msp_dpl_read(bktr_ptr_t bktr, int i2c_addr, unsigned char dev, unsigned int addr){ unsigned int data; unsigned char addr_l, addr_h, data_1, data_2, dev_r ; addr_h = (addr >>8) & 0xff; addr_l = addr & 0xff; dev_r = dev+1; i2c_start(bktr); i2c_write_byte(bktr,i2c_addr); i2c_write_byte(bktr,dev_r); i2c_write_byte(bktr,addr_h); i2c_write_byte(bktr,addr_l); i2c_start(bktr); i2c_write_byte(bktr,i2c_addr+1); i2c_read_byte(bktr,&data_1, 0); i2c_read_byte(bktr,&data_2, 1); i2c_stop(bktr); data = (data_1<<8) | data_2; return data; } /* Reset the MSP or DPL chip */ /* The user can block the reset (which is handy if you initialise the * MSP audio in another operating system first (eg in Windows) */ void msp_dpl_reset( bktr_ptr_t bktr, int i2c_addr ) { #ifndef BKTR_NO_MSP_RESET /* put into reset mode */ i2c_start(bktr); i2c_write_byte(bktr, i2c_addr); i2c_write_byte(bktr, 0x00); i2c_write_byte(bktr, 0x80); i2c_write_byte(bktr, 0x00); i2c_stop(bktr); /* put back to operational mode */ i2c_start(bktr); i2c_write_byte(bktr, i2c_addr); i2c_write_byte(bktr, 0x00); i2c_write_byte(bktr, 0x00); i2c_write_byte(bktr, 0x00); i2c_stop(bktr); #endif return; } static void remote_read(bktr_ptr_t bktr, struct bktr_remote *remote) { /* XXX errors ignored */ i2c_start(bktr); i2c_write_byte(bktr,bktr->remote_control_addr); i2c_read_byte(bktr,&(remote->data[0]), 0); i2c_read_byte(bktr,&(remote->data[1]), 0); i2c_read_byte(bktr,&(remote->data[2]), 0); i2c_stop(bktr); return; } #endif /* defined(BKTR_USE_FREEBSD_SMBUS) */ #if defined( I2C_SOFTWARE_PROBE ) /* * we are keeping this around for any parts that we need to probe * but that CANNOT be probed via an i2c read. * this is necessary because the hardware i2c mechanism * cannot be programmed for 1 byte writes. * currently there are no known i2c parts that we need to probe * and that cannot be safely read. */ static int i2cProbe( bktr_ptr_t bktr, int addr ); #define BITD 40 #define EXTRA_START /* * probe for an I2C device at addr. */ static int i2cProbe( bktr_ptr_t bktr, int addr ) { int x, status; /* the START */ #if defined( EXTRA_START ) OUTL(bktr, BKTR_I2C_DATA_CTL, 1); DELAY( BITD ); /* release data */ OUTL(bktr, BKTR_I2C_DATA_CTL, 3); DELAY( BITD ); /* release clock */ #endif /* EXTRA_START */ OUTL(bktr, BKTR_I2C_DATA_CTL, 2); DELAY( BITD ); /* lower data */ OUTL(bktr, BKTR_I2C_DATA_CTL, 0); DELAY( BITD ); /* lower clock */ /* write addr */ for ( x = 7; x >= 0; --x ) { if ( addr & (1< __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 dependant 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 #if __FreeBSD_version >= 500014 #include #else #include #endif #include #include #include #include #include #if (__FreeBSD_version >=400000) #include /* used by smbus and newbus */ #endif #if (__FreeBSD_version >=300000) #include /* used by bus space */ #include /* used by bus space and newbus */ #include #endif #if (__FreeBSD_version >=400000) #include /* used by newbus */ #include /* used by newbus */ #endif #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 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 #include #include #include #include #include #include #include #include #include #include #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 *** */ /****************************/ #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_BAR(0); 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 +#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_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); } + LOCK_VBI(bktr); 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); + UNLOCK_VBI(bktr); 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__ */ Index: head/sys/dev/bktr/bktr_os.h =================================================================== --- head/sys/dev/bktr/bktr_os.h (revision 123087) +++ head/sys/dev/bktr/bktr_os.h (revision 123088) @@ -1,78 +1,85 @@ /* $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. * */ /* * 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. */ /******************************/ /* *** Memory Allocation *** */ /******************************/ #if (defined(__FreeBSD__) || defined(__bsdi__)) vm_offset_t get_bktr_mem( int unit, unsigned size ); #endif #if (defined(__NetBSD__) || defined(__OpenBSD__)) vm_offset_t get_bktr_mem(bktr_ptr_t, bus_dmamap_t *, unsigned size); void free_bktr_mem(bktr_ptr_t, bus_dmamap_t, vm_offset_t); #endif /************************************/ /* *** Interrupt Enable/Disable *** */ /************************************/ #if defined(__FreeBSD__) #if (__FreeBSD_version >=500000) +#define USE_VBIMUTEX #define DECLARE_INTR_MASK(s) /* no need to declare 's' */ -#define DISABLE_INTR(s) critical_enter() -#define ENABLE_INTR(s) critical_exit() +#define DISABLE_INTR(s) +#define ENABLE_INTR(s) #else #define DECLARE_INTR_MASK(s) intrmask_t s #define DISABLE_INTR(s) s=spltty() #define ENABLE_INTR(s) splx(s) #endif #else #define DECLARE_INTR_MASK(s) /* no need to declare 's' */ #define DISABLE_INTR(s) disable_intr() #define ENABLE_INTR(s) enable_intr() #endif - +#ifdef USE_VBIMUTEX +#define LOCK_VBI(bktr) mtx_lock(&bktr->vbimutex) +#define UNLOCK_VBI(bktr) mtx_unlock(&bktr->vbimutex) +#else +#define LOCK_VBI(bktr) +#define UNLOCK_VBI(bktr) +#endif Index: head/sys/dev/bktr/bktr_reg.h =================================================================== --- head/sys/dev/bktr/bktr_reg.h (revision 123087) +++ head/sys/dev/bktr/bktr_reg.h (revision 123088) @@ -1,739 +1,742 @@ /* * $FreeBSD$ * * Copyright (c) 1999 Roger Hardiman * Copyright (c) 1998 Amancio Hasty * Copyright (c) 1995 Mark Tinguely and Jim Lowe * 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 Mark Tinguely and Jim Lowe * 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. * */ #ifdef __NetBSD__ #include /* struct device */ #include #include /* struct selinfo */ # ifdef DEBUG # define bootverbose 1 # else # define bootverbose 0 # endif #endif /* * The kernel options for the driver now all begin with BKTR. * Support the older kernel options on FreeBSD and OpenBSD. * */ #if defined(__FreeBSD__) || defined(__OpenBSD__) #if defined(BROOKTREE_ALLOC_PAGES) #define BKTR_ALLOC_PAGES BROOKTREE_ALLOC_PAGES #endif #if defined(BROOKTREE_SYSTEM_DEFAULT) #define BKTR_SYSTEM_DEFAULT BROOKTREE_SYSTEM_DEFAULT #endif #if defined(OVERRIDE_CARD) #define BKTR_OVERRIDE_CARD OVERRIDE_CARD #endif #if defined(OVERRIDE_TUNER) #define BKTR_OVERRIDE_TUNER OVERRIDE_TUNER #endif #if defined(OVERRIDE_DBX) #define BKTR_OVERRIDE_DBX OVERRIDE_DBX #endif #if defined(OVERRIDE_MSP) #define BKTR_OVERRIDE_MSP OVERRIDE_MSP #endif #endif #ifndef PCI_LATENCY_TIMER #define PCI_LATENCY_TIMER 0x0c /* pci timer register */ #endif /* * Definitions for the Brooktree 848/878 video capture to pci interface. */ #ifndef __NetBSD__ #define PCI_VENDOR_SHIFT 0 #define PCI_VENDOR_MASK 0xffff #define PCI_VENDOR(id) \ (((id) >> PCI_VENDOR_SHIFT) & PCI_VENDOR_MASK) #define PCI_PRODUCT_SHIFT 16 #define PCI_PRODUCT_MASK 0xffff #define PCI_PRODUCT(id) \ (((id) >> PCI_PRODUCT_SHIFT) & PCI_PRODUCT_MASK) /* PCI vendor ID */ #define PCI_VENDOR_BROOKTREE 0x109e /* Brooktree */ /* Brooktree products */ #define PCI_PRODUCT_BROOKTREE_BT848 0x0350 /* Bt848 Video Capture */ #define PCI_PRODUCT_BROOKTREE_BT849 0x0351 /* Bt849 Video Capture */ #define PCI_PRODUCT_BROOKTREE_BT878 0x036e /* Bt878 Video Capture */ #define PCI_PRODUCT_BROOKTREE_BT879 0x036f /* Bt879 Video Capture */ #endif #define BROOKTREE_848 1 #define BROOKTREE_848A 2 #define BROOKTREE_849A 3 #define BROOKTREE_878 4 #define BROOKTREE_879 5 typedef volatile u_int bregister_t; /* * if other persuasion endian, then compiler will probably require that * these next * macros be reversed */ #define BTBYTE(what) bregister_t what:8; int :24 #define BTWORD(what) bregister_t what:16; int: 16 #define BTLONG(what) bregister_t what:32 struct bt848_registers { BTBYTE (dstatus); /* 0, 1,2,3 */ #define BT848_DSTATUS_PRES (1<<7) #define BT848_DSTATUS_HLOC (1<<6) #define BT848_DSTATUS_FIELD (1<<5) #define BT848_DSTATUS_NUML (1<<4) #define BT848_DSTATUS_CSEL (1<<3) #define BT848_DSTATUS_PLOCK (1<<2) #define BT848_DSTATUS_LOF (1<<1) #define BT848_DSTATUS_COF (1<<0) BTBYTE (iform); /* 4, 5,6,7 */ #define BT848_IFORM_MUXSEL (0x3<<5) # define BT848_IFORM_M_MUX1 (0x03<<5) # define BT848_IFORM_M_MUX0 (0x02<<5) # define BT848_IFORM_M_MUX2 (0x01<<5) # define BT848_IFORM_M_MUX3 (0x0) # define BT848_IFORM_M_RSVD (0x00<<5) #define BT848_IFORM_XTSEL (0x3<<3) # define BT848_IFORM_X_AUTO (0x03<<3) # define BT848_IFORM_X_XT1 (0x02<<3) # define BT848_IFORM_X_XT0 (0x01<<3) # define BT848_IFORM_X_RSVD (0x00<<3) BTBYTE (tdec); /* 8, 9,a,b */ BTBYTE (e_crop); /* c, d,e,f */ BTBYTE (e_vdelay_lo); /* 10, 11,12,13 */ BTBYTE (e_vactive_lo); /* 14, 15,16,17 */ BTBYTE (e_delay_lo); /* 18, 19,1a,1b */ BTBYTE (e_hactive_lo); /* 1c, 1d,1e,1f */ BTBYTE (e_hscale_hi); /* 20, 21,22,23 */ BTBYTE (e_hscale_lo); /* 24, 25,26,27 */ BTBYTE (bright); /* 28, 29,2a,2b */ BTBYTE (e_control); /* 2c, 2d,2e,2f */ #define BT848_E_CONTROL_LNOTCH (1<<7) #define BT848_E_CONTROL_COMP (1<<6) #define BT848_E_CONTROL_LDEC (1<<5) #define BT848_E_CONTROL_CBSENSE (1<<4) #define BT848_E_CONTROL_RSVD (1<<3) #define BT848_E_CONTROL_CON_MSB (1<<2) #define BT848_E_CONTROL_SAT_U_MSB (1<<1) #define BT848_E_CONTROL_SAT_V_MSB (1<<0) BTBYTE (contrast_lo); /* 30, 31,32,33 */ BTBYTE (sat_u_lo); /* 34, 35,36,37 */ BTBYTE (sat_v_lo); /* 38, 39,3a,3b */ BTBYTE (hue); /* 3c, 3d,3e,3f */ BTBYTE (e_scloop); /* 40, 41,42,43 */ #define BT848_E_SCLOOP_RSVD1 (1<<7) #define BT848_E_SCLOOP_CAGC (1<<6) #define BT848_E_SCLOOP_CKILL (1<<5) #define BT848_E_SCLOOP_HFILT (0x3<<3) # define BT848_E_SCLOOP_HFILT_ICON (0x3<<3) # define BT848_E_SCLOOP_HFILT_QCIF (0x2<<3) # define BT848_E_SCLOOP_HFILT_CIF (0x1<<3) # define BT848_E_SCLOOP_HFILT_AUTO (0x0<<3) #define BT848_E_SCLOOP_RSVD0 (0x7<<0) int :32; /* 44, 45,46,47 */ BTBYTE (oform); /* 48, 49,4a,4b */ BTBYTE (e_vscale_hi); /* 4c, 4d,4e,4f */ BTBYTE (e_vscale_lo); /* 50, 51,52,53 */ BTBYTE (test); /* 54, 55,56,57 */ int :32; /* 58, 59,5a,5b */ int :32; /* 5c, 5d,5e,5f */ BTLONG (adelay); /* 60, 61,62,63 */ BTBYTE (bdelay); /* 64, 65,66,67 */ BTBYTE (adc); /* 68, 69,6a,6b */ #define BT848_ADC_RESERVED (0x80) /* required pattern */ #define BT848_ADC_SYNC_T (1<<5) #define BT848_ADC_AGC_EN (1<<4) #define BT848_ADC_CLK_SLEEP (1<<3) #define BT848_ADC_Y_SLEEP (1<<2) #define BT848_ADC_C_SLEEP (1<<1) #define BT848_ADC_CRUSH (1<<0) BTBYTE (e_vtc); /* 6c, 6d,6e,6f */ int :32; /* 70, 71,72,73 */ int :32; /* 74, 75,76,77 */ int :32; /* 78, 79,7a,7b */ BTLONG (sreset); /* 7c, 7d,7e,7f */ u_char filler1[0x84-0x80]; BTBYTE (tgctrl); /* 84, 85,86,87 */ #define BT848_TGCTRL_TGCKI (3<<3) #define BT848_TGCTRL_TGCKI_XTAL (0<<3) #define BT848_TGCTRL_TGCKI_PLL (1<<3) #define BT848_TGCTRL_TGCKI_GPCLK (2<<3) #define BT848_TGCTRL_TGCKI_GPCLK_I (3<<3) u_char filler[0x8c-0x88]; BTBYTE (o_crop); /* 8c, 8d,8e,8f */ BTBYTE (o_vdelay_lo); /* 90, 91,92,93 */ BTBYTE (o_vactive_lo); /* 94, 95,96,97 */ BTBYTE (o_delay_lo); /* 98, 99,9a,9b */ BTBYTE (o_hactive_lo); /* 9c, 9d,9e,9f */ BTBYTE (o_hscale_hi); /* a0, a1,a2,a3 */ BTBYTE (o_hscale_lo); /* a4, a5,a6,a7 */ int :32; /* a8, a9,aa,ab */ BTBYTE (o_control); /* ac, ad,ae,af */ #define BT848_O_CONTROL_LNOTCH (1<<7) #define BT848_O_CONTROL_COMP (1<<6) #define BT848_O_CONTROL_LDEC (1<<5) #define BT848_O_CONTROL_CBSENSE (1<<4) #define BT848_O_CONTROL_RSVD (1<<3) #define BT848_O_CONTROL_CON_MSB (1<<2) #define BT848_O_CONTROL_SAT_U_MSB (1<<1) #define BT848_O_CONTROL_SAT_V_MSB (1<<0) u_char fillter4[16]; BTBYTE (o_scloop); /* c0, c1,c2,c3 */ #define BT848_O_SCLOOP_RSVD1 (1<<7) #define BT848_O_SCLOOP_CAGC (1<<6) #define BT848_O_SCLOOP_CKILL (1<<5) #define BT848_O_SCLOOP_HFILT (0x3<<3) #define BT848_O_SCLOOP_HFILT_ICON (0x3<<3) #define BT848_O_SCLOOP_HFILT_QCIF (0x2<<3) #define BT848_O_SCLOOP_HFILT_CIF (0x1<<3) #define BT848_O_SCLOOP_HFILT_AUTO (0x0<<3) #define BT848_O_SCLOOP_RSVD0 (0x7<<0) int :32; /* c4, c5,c6,c7 */ int :32; /* c8, c9,ca,cb */ BTBYTE (o_vscale_hi); /* cc, cd,ce,cf */ BTBYTE (o_vscale_lo); /* d0, d1,d2,d3 */ BTBYTE (color_fmt); /* d4, d5,d6,d7 */ bregister_t color_ctl_swap :4; /* d8 */ #define BT848_COLOR_CTL_WSWAP_ODD (1<<3) #define BT848_COLOR_CTL_WSWAP_EVEN (1<<2) #define BT848_COLOR_CTL_BSWAP_ODD (1<<1) #define BT848_COLOR_CTL_BSWAP_EVEN (1<<0) bregister_t color_ctl_gamma :1; bregister_t color_ctl_rgb_ded :1; bregister_t color_ctl_color_bars :1; bregister_t color_ctl_ext_frmrate :1; #define BT848_COLOR_CTL_GAMMA (1<<4) #define BT848_COLOR_CTL_RGB_DED (1<<5) #define BT848_COLOR_CTL_COLOR_BARS (1<<6) #define BT848_COLOR_CTL_EXT_FRMRATE (1<<7) int :24; /* d9,da,db */ BTBYTE (cap_ctl); /* dc, dd,de,df */ #define BT848_CAP_CTL_DITH_FRAME (1<<4) #define BT848_CAP_CTL_VBI_ODD (1<<3) #define BT848_CAP_CTL_VBI_EVEN (1<<2) #define BT848_CAP_CTL_ODD (1<<1) #define BT848_CAP_CTL_EVEN (1<<0) BTBYTE (vbi_pack_size); /* e0, e1,e2,e3 */ BTBYTE (vbi_pack_del); /* e4, e5,e6,e7 */ int :32; /* e8, e9,ea,eb */ BTBYTE (o_vtc); /* ec, ed,ee,ef */ BTBYTE (pll_f_lo); /* f0, f1,f2,f3 */ BTBYTE (pll_f_hi); /* f4, f5,f6,f7 */ BTBYTE (pll_f_xci); /* f8, f9,fa,fb */ #define BT848_PLL_F_C (1<<6) #define BT848_PLL_F_X (1<<7) u_char filler2[0x100-0xfc]; BTLONG (int_stat); /* 100, 101,102,103 */ BTLONG (int_mask); /* 104, 105,106,107 */ #define BT848_INT_RISCS (0xf<<28) #define BT848_INT_RISC_EN (1<<27) #define BT848_INT_RACK (1<<25) #define BT848_INT_FIELD (1<<24) #define BT848_INT_MYSTERYBIT (1<<23) #define BT848_INT_SCERR (1<<19) #define BT848_INT_OCERR (1<<18) #define BT848_INT_PABORT (1<<17) #define BT848_INT_RIPERR (1<<16) #define BT848_INT_PPERR (1<<15) #define BT848_INT_FDSR (1<<14) #define BT848_INT_FTRGT (1<<13) #define BT848_INT_FBUS (1<<12) #define BT848_INT_RISCI (1<<11) #define BT848_INT_GPINT (1<<9) #define BT848_INT_I2CDONE (1<<8) #define BT848_INT_RSV1 (1<<7) #define BT848_INT_RSV0 (1<<6) #define BT848_INT_VPRES (1<<5) #define BT848_INT_HLOCK (1<<4) #define BT848_INT_OFLOW (1<<3) #define BT848_INT_HSYNC (1<<2) #define BT848_INT_VSYNC (1<<1) #define BT848_INT_FMTCHG (1<<0) int :32; /* 108, 109,10a,10b */ BTWORD (gpio_dma_ctl); /* 10c, 10d,10e,10f */ #define BT848_DMA_CTL_PL23TP4 (0<<6) /* planar1 trigger 4 */ #define BT848_DMA_CTL_PL23TP8 (1<<6) /* planar1 trigger 8 */ #define BT848_DMA_CTL_PL23TP16 (2<<6) /* planar1 trigger 16 */ #define BT848_DMA_CTL_PL23TP32 (3<<6) /* planar1 trigger 32 */ #define BT848_DMA_CTL_PL1TP4 (0<<4) /* planar1 trigger 4 */ #define BT848_DMA_CTL_PL1TP8 (1<<4) /* planar1 trigger 8 */ #define BT848_DMA_CTL_PL1TP16 (2<<4) /* planar1 trigger 16 */ #define BT848_DMA_CTL_PL1TP32 (3<<4) /* planar1 trigger 32 */ #define BT848_DMA_CTL_PKTP4 (0<<2) /* packed trigger 4 */ #define BT848_DMA_CTL_PKTP8 (1<<2) /* packed trigger 8 */ #define BT848_DMA_CTL_PKTP16 (2<<2) /* packed trigger 16 */ #define BT848_DMA_CTL_PKTP32 (3<<2) /* packed trigger 32 */ #define BT848_DMA_CTL_RISC_EN (1<<1) #define BT848_DMA_CTL_FIFO_EN (1<<0) BTLONG (i2c_data_ctl); /* 110, 111,112,113 */ #define BT848_DATA_CTL_I2CDIV (0xf<<4) #define BT848_DATA_CTL_I2CSYNC (1<<3) #define BT848_DATA_CTL_I2CW3B (1<<2) #define BT848_DATA_CTL_I2CSCL (1<<1) #define BT848_DATA_CTL_I2CSDA (1<<0) BTLONG (risc_strt_add); /* 114, 115,116,117 */ BTLONG (gpio_out_en); /* 118, 119,11a,11b */ /* really 24 bits */ BTLONG (gpio_reg_inp); /* 11c, 11d,11e,11f */ /* really 24 bits */ BTLONG (risc_count); /* 120, 121,122,123 */ u_char filler3[0x200-0x124]; BTLONG (gpio_data); /* 200, 201,202,203 */ /* really 24 bits */ }; #define BKTR_DSTATUS 0x000 #define BKTR_IFORM 0x004 #define BKTR_TDEC 0x008 #define BKTR_E_CROP 0x00C #define BKTR_O_CROP 0x08C #define BKTR_E_VDELAY_LO 0x010 #define BKTR_O_VDELAY_LO 0x090 #define BKTR_E_VACTIVE_LO 0x014 #define BKTR_O_VACTIVE_LO 0x094 #define BKTR_E_DELAY_LO 0x018 #define BKTR_O_DELAY_LO 0x098 #define BKTR_E_HACTIVE_LO 0x01C #define BKTR_O_HACTIVE_LO 0x09C #define BKTR_E_HSCALE_HI 0x020 #define BKTR_O_HSCALE_HI 0x0A0 #define BKTR_E_HSCALE_LO 0x024 #define BKTR_O_HSCALE_LO 0x0A4 #define BKTR_BRIGHT 0x028 #define BKTR_E_CONTROL 0x02C #define BKTR_O_CONTROL 0x0AC #define BKTR_CONTRAST_LO 0x030 #define BKTR_SAT_U_LO 0x034 #define BKTR_SAT_V_LO 0x038 #define BKTR_HUE 0x03C #define BKTR_E_SCLOOP 0x040 #define BKTR_O_SCLOOP 0x0C0 #define BKTR_OFORM 0x048 #define BKTR_E_VSCALE_HI 0x04C #define BKTR_O_VSCALE_HI 0x0CC #define BKTR_E_VSCALE_LO 0x050 #define BKTR_O_VSCALE_LO 0x0D0 #define BKTR_TEST 0x054 #define BKTR_ADELAY 0x060 #define BKTR_BDELAY 0x064 #define BKTR_ADC 0x068 #define BKTR_E_VTC 0x06C #define BKTR_O_VTC 0x0EC #define BKTR_SRESET 0x07C #define BKTR_COLOR_FMT 0x0D4 #define BKTR_COLOR_CTL 0x0D8 #define BKTR_CAP_CTL 0x0DC #define BKTR_VBI_PACK_SIZE 0x0E0 #define BKTR_VBI_PACK_DEL 0x0E4 #define BKTR_INT_STAT 0x100 #define BKTR_INT_MASK 0x104 #define BKTR_RISC_COUNT 0x120 #define BKTR_RISC_STRT_ADD 0x114 #define BKTR_GPIO_DMA_CTL 0x10C #define BKTR_GPIO_OUT_EN 0x118 #define BKTR_GPIO_REG_INP 0x11C #define BKTR_GPIO_DATA 0x200 #define BKTR_I2C_DATA_CTL 0x110 #define BKTR_TGCTRL 0x084 #define BKTR_PLL_F_LO 0x0F0 #define BKTR_PLL_F_HI 0x0F4 #define BKTR_PLL_F_XCI 0x0F8 /* * device support for onboard tv tuners */ /* description of the LOGICAL tuner */ struct TVTUNER { int frequency; u_char chnlset; u_char channel; u_char band; u_char afc; u_char radio_mode; /* current mode of the radio mode */ }; /* description of the PHYSICAL tuner */ struct TUNER { char* name; u_char type; u_char pllControl[4]; u_char bandLimits[ 2 ]; u_char bandAddrs[ 4 ]; /* 3 first for the 3 TV ** bands. Last for radio ** band (0x00=NoRadio). */ }; /* description of the card */ #define EEPROMBLOCKSIZE 32 struct CARDTYPE { unsigned int card_id; /* card id (from #define's) */ char* name; const struct TUNER* tuner; /* Tuner details */ u_char tuner_pllAddr; /* Tuner i2c address */ u_char dbx; /* Has DBX chip? */ u_char msp3400c; /* Has msp3400c chip? */ u_char dpl3518a; /* Has dpl3518a chip? */ u_char eepromAddr; u_char eepromSize; /* bytes / EEPROMBLOCKSIZE */ u_int audiomuxs[ 5 ]; /* tuner, ext (line-in) */ /* int/unused (radio) */ /* mute, present */ u_int gpio_mux_bits; /* GPIO mask for audio mux */ }; struct format_params { /* Total lines, lines before image, image lines */ int vtotal, vdelay, vactive; /* Total unscaled horizontal pixels, pixels before image, image pixels */ int htotal, hdelay, hactive; /* Scaled horizontal image pixels, Total Scaled horizontal pixels */ int scaled_hactive, scaled_htotal; /* frame rate . for ntsc is 30 frames per second */ int frame_rate; /* A-delay and B-delay */ u_char adelay, bdelay; /* Iform XTSEL value */ int iform_xtsel; /* VBI number of lines per field, and number of samples per line */ int vbi_num_lines, vbi_num_samples; }; #if defined(BKTR_USE_FREEBSD_SMBUS) struct bktr_i2c_softc { int bus_owned; device_t iicbb; device_t smbus; }; #endif /* Bt848/878 register access * The registers can either be access via a memory mapped structure * or accessed via bus_space. * bus_0pace access allows cross platform support, where as the * memory mapped structure method only works on 32 bit processors * with the right type of endianness. */ #if defined(__NetBSD__) || ( defined(__FreeBSD__) && (__FreeBSD_version >=300000) ) #define INB(bktr,offset) bus_space_read_1((bktr)->memt,(bktr)->memh,(offset)) #define INW(bktr,offset) bus_space_read_2((bktr)->memt,(bktr)->memh,(offset)) #define INL(bktr,offset) bus_space_read_4((bktr)->memt,(bktr)->memh,(offset)) #define OUTB(bktr,offset,value) bus_space_write_1((bktr)->memt,(bktr)->memh,(offset),(value)) #define OUTW(bktr,offset,value) bus_space_write_2((bktr)->memt,(bktr)->memh,(offset),(value)) #define OUTL(bktr,offset,value) bus_space_write_4((bktr)->memt,(bktr)->memh,(offset),(value)) #else #define INB(bktr,offset) *(volatile unsigned char*) ((int)((bktr)->memh)+(offset)) #define INW(bktr,offset) *(volatile unsigned short*)((int)((bktr)->memh)+(offset)) #define INL(bktr,offset) *(volatile unsigned int*) ((int)((bktr)->memh)+(offset)) #define OUTB(bktr,offset,value) *(volatile unsigned char*) ((int)((bktr)->memh)+(offset)) = (value) #define OUTW(bktr,offset,value) *(volatile unsigned short*)((int)((bktr)->memh)+(offset)) = (value) #define OUTL(bktr,offset,value) *(volatile unsigned int*) ((int)((bktr)->memh)+(offset)) = (value) #endif typedef struct bktr_clip bktr_clip_t; /* * BrookTree 848 info structure, one per bt848 card installed. */ struct bktr_softc { #if defined (__bsdi__) struct device bktr_dev; /* base device */ struct isadev bktr_id; /* ISA device */ struct intrhand bktr_ih; /* interrupt vectoring */ #define pcici_t pci_devaddr_t #endif #if defined(__NetBSD__) struct device bktr_dev; /* base device */ bus_dma_tag_t dmat; /* DMA tag */ bus_space_tag_t memt; bus_space_handle_t memh; bus_size_t obmemsz; /* size of en card (bytes) */ void *ih; bus_dmamap_t dm_prog; bus_dmamap_t dm_oprog; bus_dmamap_t dm_mem; bus_dmamap_t dm_vbidata; bus_dmamap_t dm_vbibuffer; #endif #if defined(__OpenBSD__) struct device bktr_dev; /* base device */ bus_dma_tag_t dmat; /* DMA tag */ bus_space_tag_t memt; bus_space_handle_t memh; bus_size_t obmemsz; /* size of en card (bytes) */ void *ih; bus_dmamap_t dm_prog; bus_dmamap_t dm_oprog; bus_dmamap_t dm_mem; bus_dmamap_t dm_vbidata; bus_dmamap_t dm_vbibuffer; size_t dm_mapsize; pci_chipset_tag_t pc; /* Opaque PCI chipset tag */ pcitag_t tag; /* PCI tag, for doing PCI commands */ vm_offset_t phys_base; /* Bt848 register physical address */ #endif #if defined (__FreeBSD__) #if (__FreeBSD_version < 400000) vm_offset_t phys_base; /* 2.x Bt848 register physical address */ pcici_t tag; /* 2.x PCI tag, for doing PCI commands */ #endif #if (__FreeBSD_version >= 400000) int mem_rid; /* 4.x resource id */ struct resource *res_mem; /* 4.x resource descriptor for registers */ int irq_rid; /* 4.x resource id */ struct resource *res_irq; /* 4.x resource descriptor for interrupt */ void *res_ih; /* 4.x newbus interrupt handler cookie */ dev_t bktrdev; /* 4.x device entry for /dev/bktrN */ dev_t tunerdev; /* 4.x device entry for /dev/tunerN */ dev_t vbidev; /* 4.x device entry for /dev/vbiN */ dev_t bktrdev_alias; /* alias /dev/bktr to /dev/bktr0 */ dev_t tunerdev_alias; /* alias /dev/tuner to /dev/tuner0 */ dev_t vbidev_alias; /* alias /dev/vbi to /dev/vbi0 */ #endif + #if (__FreeBSD_version >= 500000) + struct mtx vbimutex; /* Mutex protecting vbi buffer */ + #endif #if (__FreeBSD_version >= 310000) bus_space_tag_t memt; /* Bus space register access functions */ bus_space_handle_t memh; /* Bus space register access functions */ bus_size_t obmemsz;/* Size of card (bytes) */ #endif #if defined(BKTR_USE_FREEBSD_SMBUS) struct bktr_i2c_softc i2c_sc; /* bt848_i2c device */ #endif char bktr_xname[7]; /* device name and unit number */ #endif /* The following definitions are for the contiguous memory */ #ifdef __NetBSD__ vaddr_t bigbuf; /* buffer that holds the captured image */ vaddr_t vbidata; /* RISC program puts VBI data from the current frame here */ vaddr_t vbibuffer; /* Circular buffer holding VBI data for the user */ vaddr_t dma_prog; /* RISC prog for single and/or even field capture*/ vaddr_t odd_dma_prog; /* RISC program for Odd field capture */ #else vm_offset_t bigbuf; /* buffer that holds the captured image */ vm_offset_t vbidata; /* RISC program puts VBI data from the current frame here */ vm_offset_t vbibuffer; /* Circular buffer holding VBI data for the user */ vm_offset_t dma_prog; /* RISC prog for single and/or even field capture*/ vm_offset_t odd_dma_prog;/* RISC program for Odd field capture */ #endif /* the following definitions are common over all platforms */ int alloc_pages; /* number of pages in bigbuf */ int vbiinsert; /* Position for next write into circular buffer */ int vbistart; /* Position of last read from circular buffer */ int vbisize; /* Number of bytes in the circular buffer */ u_long vbi_sequence_number; /* sequence number for VBI */ int vbi_read_blocked; /* user process blocked on read() from /dev/vbi */ struct selinfo vbi_select; /* Data used by select() on /dev/vbi */ struct proc *proc; /* process to receive raised signal */ int signal; /* signal to send to process */ int clr_on_start; /* clear cap buf on capture start? */ #define METEOR_SIG_MODE_MASK 0xffff0000 #define METEOR_SIG_FIELD_MODE 0x00010000 #define METEOR_SIG_FRAME_MODE 0x00000000 char dma_prog_loaded; struct meteor_mem *mem; /* used to control sync. multi-frame output */ u_long synch_wait; /* wait for free buffer before continuing */ short current; /* frame number in buffer (1-frames) */ short rows; /* number of rows in a frame */ short cols; /* number of columns in a frame */ int capture_area_x_offset; /* Usually the full 640x480(NTSC) image is */ int capture_area_y_offset; /* captured. The capture area allows for */ int capture_area_x_size; /* example 320x200 pixels from the centre */ int capture_area_y_size; /* of the video image to be captured. */ char capture_area_enabled; /* When TRUE use user's capture area. */ int pixfmt; /* active pixel format (idx into fmt tbl) */ int pixfmt_compat; /* Y/N - in meteor pix fmt compat mode */ u_long format; /* frame format rgb, yuv, etc.. */ short frames; /* number of frames allocated */ int frame_size; /* number of bytes in a frame */ u_long fifo_errors; /* number of fifo capture errors since open */ u_long dma_errors; /* number of DMA capture errors since open */ u_long frames_captured;/* number of frames captured since open */ u_long even_fields_captured; /* number of even fields captured */ u_long odd_fields_captured; /* number of odd fields captured */ u_long range_enable; /* enable range checking ?? */ u_short capcontrol; /* reg 0xdc capture control */ u_short bktr_cap_ctl; volatile u_int flags; #define METEOR_INITALIZED 0x00000001 #define METEOR_OPEN 0x00000002 #define METEOR_MMAP 0x00000004 #define METEOR_INTR 0x00000008 #define METEOR_READ 0x00000010 /* XXX never gets referenced */ #define METEOR_SINGLE 0x00000020 /* get single frame */ #define METEOR_CONTIN 0x00000040 /* continuously get frames */ #define METEOR_SYNCAP 0x00000080 /* synchronously get frames */ #define METEOR_CAP_MASK 0x000000f0 #define METEOR_NTSC 0x00000100 #define METEOR_PAL 0x00000200 #define METEOR_SECAM 0x00000400 #define BROOKTREE_NTSC 0x00000100 /* used in video open() and */ #define BROOKTREE_PAL 0x00000200 /* in the kernel config */ #define BROOKTREE_SECAM 0x00000400 /* file */ #define METEOR_AUTOMODE 0x00000800 #define METEOR_FORM_MASK 0x00000f00 #define METEOR_DEV0 0x00001000 #define METEOR_DEV1 0x00002000 #define METEOR_DEV2 0x00004000 #define METEOR_DEV3 0x00008000 #define METEOR_DEV_SVIDEO 0x00006000 #define METEOR_DEV_RGB 0x0000a000 #define METEOR_DEV_MASK 0x0000f000 #define METEOR_RGB16 0x00010000 #define METEOR_RGB24 0x00020000 #define METEOR_YUV_PACKED 0x00040000 #define METEOR_YUV_PLANAR 0x00080000 #define METEOR_WANT_EVEN 0x00100000 /* want even frame */ #define METEOR_WANT_ODD 0x00200000 /* want odd frame */ #define METEOR_WANT_MASK 0x00300000 #define METEOR_ONLY_EVEN_FIELDS 0x01000000 #define METEOR_ONLY_ODD_FIELDS 0x02000000 #define METEOR_ONLY_FIELDS_MASK 0x03000000 #define METEOR_YUV_422 0x04000000 #define METEOR_OUTPUT_FMT_MASK 0x040f0000 #define METEOR_WANT_TS 0x08000000 /* time-stamp a frame */ #define METEOR_RGB 0x20000000 /* meteor rgb unit */ #define METEOR_FIELD_MODE 0x80000000 u_char tflags; /* Tuner flags (/dev/tuner) */ #define TUNER_INITALIZED 0x00000001 #define TUNER_OPEN 0x00000002 u_char vbiflags; /* VBI flags (/dev/vbi) */ #define VBI_INITALIZED 0x00000001 #define VBI_OPEN 0x00000002 #define VBI_CAPTURE 0x00000004 u_short fps; /* frames per second */ struct meteor_video video; struct TVTUNER tuner; struct CARDTYPE card; u_char audio_mux_select; /* current mode of the audio */ u_char audio_mute_state; /* mute state of the audio */ u_char format_params; u_long current_sol; u_long current_col; int clip_start; int line_length; int last_y; int y; int y2; int yclip; int yclip2; int max_clip_node; bktr_clip_t clip_list[100]; int reverse_mute; /* Swap the GPIO values for Mute and TV Audio */ int bt848_tuner; int bt848_card; u_long id; #define BT848_USE_XTALS 0 #define BT848_USE_PLL 1 int xtal_pll_mode; /* Use XTAL or PLL mode for PAL/SECAM */ int remote_control; /* remote control detected */ int remote_control_addr; /* remote control i2c address */ char msp_version_string[9]; /* MSP version string 34xxx-xx */ int msp_addr; /* MSP i2c address */ char dpl_version_string[9]; /* DPL version string 35xxx-xx */ int dpl_addr; /* DPL i2c address */ int slow_msp_audio; /* 0 = use fast MSP3410/3415 programming sequence */ /* 1 = use slow MSP3410/3415 programming sequence */ /* 2 = use Tuner's Mono audio output via the MSP chip */ int msp_use_mono_source; /* use Tuner's Mono audio output via the MSP chip */ int audio_mux_present; /* 1 = has audio mux on GPIO lines, 0 = no audio mux */ int msp_source_selected; /* 0 = TV source, 1 = Line In source, 2 = FM Radio Source */ #ifdef BKTR_NEW_MSP34XX_DRIVER /* msp3400c related data */ void * msp3400c_info; int stereo_once; int amsound; int mspsimple; int dolby; #endif }; typedef struct bktr_softc bktr_reg_t; typedef struct bktr_softc* bktr_ptr_t; #define Bt848_MAX_SIGN 16 struct bt848_card_sig { int card; int tuner; u_char signature[Bt848_MAX_SIGN]; }; /***********************************************************/ /* ioctl_cmd_t int on old versions, u_long on new versions */ /***********************************************************/ #if (__FreeBSD__ == 2) typedef int ioctl_cmd_t; #endif #if defined(__FreeBSD__) #if (__FreeBSD_version >= 300000) typedef u_long ioctl_cmd_t; #endif #endif #if defined(__NetBSD__) || defined(__OpenBSD__) typedef u_long ioctl_cmd_t; #endif