diff --git a/sys/conf/files.i386 b/sys/conf/files.i386 index 41235be1b991..635483c170ec 100644 --- a/sys/conf/files.i386 +++ b/sys/conf/files.i386 @@ -1,7 +1,7 @@ # This file tells config what files go into building a kernel, # files marked standard are always included. # -# $Id$ +# $Id: files.i386,v 1.152 1997/02/22 09:31:42 peter Exp $ # aic7xxx_asm optional ahc device-driver \ dependency "$S/dev/aic7xxx/aic7xxx_asm.c" \ @@ -276,4 +276,5 @@ gnu/i386/fpemul/wm_sqrt.s optional gpl_math_emulate gnu/i386/isa/dgb.c optional dgb device-driver gnu/i386/isa/nic3008.c optional nic device-driver gnu/i386/isa/nic3009.c optional nnic device-driver +pci/brooktree848.c optional bktr device-driver pci/wd82371.c optional wd device-driver diff --git a/sys/dev/bktr/bktr_core.c b/sys/dev/bktr/bktr_core.c new file mode 100644 index 000000000000..c482b666e23c --- /dev/null +++ b/sys/dev/bktr/bktr_core.c @@ -0,0 +1,2442 @@ +/* BT848 1.3-ALPHA Driver for Brooktree's Bt848 based cards. + 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. For starters, the BT848 is a one chipset solution and + it incorporates a RISC engine to control the DMA transfers -- + that is it the actual dma process is control by a program which + resides in the hosts memory also the register definitions between + the Philips chipsets and the Bt848 are very different. + + The original copyright notice by Mark and Jim is included mostly + to honor their fantastic work in the Matrox Meteor driver! + + Enjoy, + Amancio + + $Id$ + */ + +/* + * 1. Redistributions of source code must retain the + * Copyright (c) 1997 Amancio Hasty + * 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 + * 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. + */ + +/* Change History: +1.0 1/24/97 First Alpha release + +1.1 2/20/97 Added video ioctl so we can do PCI To PCI + data transfers. This is for capturing data + directly to a vga frame buffer which has + a linear frame buffer. Minor code clean-up. + +1.3 2/23/97 Fixed system lock-up reported by + Randall Hopper . This + problem seems somehow to be exhibited only + in his system. I changed the setting of + INT_MASK for CAP_CONTINUOUS to be exactly + the same as CAP_SINGLE apparently setting + bit 23 cleared the system lock up. + version 1.1 of the driver has been reported + to work with STB's WinTv, Hauppage's Wincast/Tv + and last but not least with the Intel Smart + Video Recorder. + +1.4 3/9/97 Merged code to support tuners on STB and WinCast + cards. + Modifications to the contrast and chroma ioctls. + Textual cleanup. +*/ + +#include "bktr.h" + +#if NBKTR > 0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef DEVFS +#include +#endif /* DEVFS */ +#include + +#include +#include +#include +#include +#include + +/* + * XXX: include code to support specific tuners. + * once we add auto-probe code to detect tuner types this can go away. + * + * the STB card has a TEMIC tuner, others(?) have the PHILIPS tuner. + * check the label on the metal can to be sure! + * + * in your kernel config file set one of: +options TEMIC_TUNER # STB TV PCI +options PHILIPS_TUNER # WinCast/TV + * + * alternately, in this file, you can select one of: + * +#define TEMIC_TUNER +#define PHILIPS_TUNER + */ +#if !defined( TEMIC_TUNER ) && !defined( PHILIPS_TUNER ) +#define PHILIPS_TUNER +#endif + +/* + * XXX: the 'options' aspect of this is a REAL KLUDGE, fix it! + * XXX: we need to support additional sets of frequencies. + * + * this selects the set of frequencies used by the tuner. + * in your kernel config file set one of: +options DEFAULT_TUNERTYPE=1 # TUNERTYPE_NABCST +options DEFAULT_TUNERTYPE=2 # TUNERTYPE_CABLEIRC + * + * alternately, in this file, you can select one of: + * +#define DEFAULT_TUNERTYPE TUNERTYPE_NABCST +#define DEFAULT_TUNERTYPE TUNERTYPE_CABLEIRC + */ +#if !defined( DEFAULT_TUNERTYPE ) +#define DEFAULT_TUNERTYPE TUNERTYPE_NABCST +#endif + +/* + * XXX: hack to allow multiple programs to open the device, + * ie., a tv client and a remote control + * we need to make this a MINOR UNIT type thing someday... + */ +#define MULTIPLE_OPENS + + +#include "pci.h" +#if NPCI > 0 + +#include +#include +#endif + +#include +#include /* extensions to ioctl_meteor.h */ +#include + +/* + * tuner specific functions + */ +static int tv_channel __P(( bktr_reg_t* bktr, int channel )); +static int tuner_status __P(( bktr_reg_t* bktr )); + + +#define METPRI (PZERO+8)|PCATCH + +static void bktr_intr __P((void *arg)); +static bt_enable_cnt; +static u_long btl_status_prev; +/* + * Allocate enough memory for: + * 768x576 RGB 16 or YUV (16 storage bits/pixel) = 884736 = 216 pages + * + * You may override this using the options "METEOR_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) + +static bktr_reg_t brooktree[NBKTR]; +#define BROOKTRE_NUM(mtr) ((bktr - &brooktree[0])/sizeof(bktr_reg_t)) + +#define BKTRPRI (PZERO+8)|PCATCH + +static char* bktr_probe (pcici_t tag, pcidi_t type); +static void bktr_attach(pcici_t tag, int unit); +int dump_bt848( volatile u_char *bt848 ); + +void yuvpack_prog( bktr_reg_t * bktr, char i_flag, int cols, + int rows, int interlace) ; + +void yuv422_prog( bktr_reg_t * bktr, char i_flag, int cols, + int rows, int interlace); +void rgb_prog( bktr_reg_t * bktr, char i_flag, int cols, + int rows, int pixel_width, int interlace) ; +void start_capture(bktr_reg_t *bktr, unsigned type); +void build_dma_prog( bktr_reg_t * bktr, char i_flag); + +static u_long bktr_count; + +static struct pci_device bktr_device = { + "bktr", + bktr_probe, + bktr_attach, + &bktr_count +}; + +DATA_SET (pcidevice_set, bktr_device); + +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; + +#define CDEV_MAJOR 79 +static struct cdevsw bktr_cdevsw = +{ + bktr_open, bktr_close, bktr_read, bktr_write, + bktr_ioctl, nostop, nullreset, nodevtotty, + seltrue, bktr_mmap, NULL, "bktr", + NULL, -1 +}; + + +/* + * + */ +static char* +bktr_probe( pcici_t tag, pcidi_t type ) +{ + switch (type) { + case BROOKTREE_848_ID: + return("BrookTree 848"); + }; + + return ((char *)0); +} + + +/* + * interrupt handling routine complete meteor_read() if using interrupts + */ +static void +bktr_intr( void *arg ) +{ + bktr_reg_t *bktr = (bktr_reg_t *) arg; + volatile u_long *btl_reg, t_pc; + volatile u_char *bt848, *bt_reg, s_status; + volatile u_short *bts_reg; + u_long bktr_status, *bktr_pc; + +#if 0 +/* XXX: what is this for??? */ + u_long next_base = (u_long)(vtophys(bktr->bigbuf)), stat; +#endif + + bt848 = bktr->base; + bt_reg = (u_char *) &bt848; + s_status = *bt_reg; + *bt_reg = 0; + + if (!(bktr->flags & METEOR_OPEN)) { + bts_reg = (u_short *) &bt848[BKTR_GPIO_DMA_CTL]; + *bts_reg = 0; + btl_reg = (u_long *) &bt848[BKTR_INT_MASK]; + *btl_reg = 0; + } + + btl_reg = (u_long *) &bt848[BKTR_INT_STAT]; + bktr_status = *btl_reg ; + *btl_reg = *btl_reg; + *btl_reg = 0; + if (*btl_reg & (1 << 25)) + *btl_reg |= 1 << 8; + bktr_pc = (u_long *) &bt848[BKTR_RISC_COUNT]; + t_pc = *bktr_pc; + + /* printf(" STATUS %x %x %x \n", s_status, bktr_status, t_pc); */ + + if (!((bktr_status & 0x800) || (bktr_status & 1 << 19 ))) { + btl_status_prev = bktr_status; + /* return; */ + } + + /* if risc was disabled re-start process again */ + if (!(bktr_status & (1 << 27)) || ((bktr_status & 0xfe000) != 0) ) { + + btl_reg = (u_long *) &bt848[BKTR_INT_STAT]; + *btl_reg = *btl_reg; + + bts_reg = (u_short *) &bt848[BKTR_GPIO_DMA_CTL]; + *bts_reg = 0; + + btl_reg = (u_long *) &bt848[BKTR_INT_MASK]; + *btl_reg = 0; + + btl_reg = (u_long *) &bt848[BKTR_RISC_STRT_ADD] ; + *btl_reg = vtophys(bktr->dma_prog); + + bts_reg = (u_short *) &bt848[BKTR_GPIO_DMA_CTL]; + *bts_reg = 1; + *bts_reg = bktr->capcontrol; + + btl_reg = (u_long *) &bt848[BKTR_INT_MASK]; + *btl_reg = 1 << 23 | 1 << 11 | 2 | 1; + + return; + } + + btl_reg = (u_long *) &bt848[BKTR_CAP_CTL]; + if (!(bktr_status & (1 << 11))) return; + + bktr_pc = (u_long *) &bt848[BKTR_RISC_COUNT]; + + /*printf("intr status %x %x %x\n", bktr_status, s_status, *bktr_pc);*/ + + /* + * 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)) + *btl_reg = 0; + + /* + * 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) { + + if (!(bktr_status & (1 << 24))) + return; + + /* stop dma */ + btl_reg = (u_long *) &bt848[BKTR_INT_MASK]; + *btl_reg = 0; + bts_reg = (u_short *) &bt848[BKTR_GPIO_DMA_CTL]; + *bts_reg = 1; /* disable risc and fifo */ + wakeup((caddr_t)bktr); + } + + /* + * If the user requested to be notified via signal, + * let them know the frame is complete. + */ + if (bktr->proc && !(bktr->signal & METEOR_SIG_MODE_MASK)) + psignal(bktr->proc, bktr->signal&(~METEOR_SIG_MODE_MASK)); + + /* + * Reset the want flags if in continuous or + * synchronous capture mode. + */ + 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; +} + + +/* + * + */ +int +dump_bt848( volatile u_char *bt848 ) +{ + u_long *bt_long; + u_short *bt_short; + 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(" Reg:value : \t%x:%x \t%x:%x \t %x:%x \t %x:%x\n", + r[i], bt848[r[i]], + r[i+1], bt848[r[i+1]], + r[i+2], bt848[r[i+2]], + r[i+3], bt848[r[i+3]]); + } + + bt_long = (u_long *) &bt848[BKTR_INT_STAT]; + printf(" Reg 100 %x \n", *bt_long); + + bt_long = (u_long *) &bt848[BKTR_INT_MASK]; + printf(" Reg 104 %x \n", *bt_long); + + bt_long = (u_long *) &bt848[BKTR_GPIO_DMA_CTL]; + printf(" Reg 10C %x \n", *bt_long); + + return 0; +} + + +/* + * build write instruction + */ +#define BKTR_FM1 0x6 +#define BKTR_FM3 0xe +#define BKTR_VRE 0x4 +#define BKTR_VRO 0xC +#define BKTR_PXV 0x0 +#define BKTR_EOL 0x1 +#define BKTR_SOL 0x2 + +#define OP_WRITE 0x1 << 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 +#define OP_EOL 1 << 26 + +void +rgb_prog( bktr_reg_t * bktr, char i_flag, int cols, + int rows, int pixel_width, int interlace ) +{ + int i; + int byte_count; + volatile unsigned int inst; + volatile unsigned int inst2; + volatile unsigned int inst3; + volatile u_long target_buffer, buffer; + volatile u_char *bt848, *bt_reg; + volatile u_short *bts_reg; + volatile u_long pitch; + volatile u_long *dma_prog, *foo, *btl_reg, *t_test; + int b, c; + + bt848 = bktr->base; + + /* color format : rgb32 */ + if (bktr->depth == 4) + bt848[BKTR_COLOR_FMT] = 0; + else + bt848[BKTR_COLOR_FMT] = 0x33; + + bt848[BKTR_COLOR_CTL] = 0x40; + bt848[BKTR_COLOR_CTL] = 0x10; + +#if 0 + bt848[0x10] = 0x1C; + bt848[0x90] = 0x1C; +#endif + + bt848[BKTR_VBI_PACK_SIZE] = 0; + bt848[BKTR_VBI_PACK_DEL] = 0; + + bt848[BKTR_ADC] = 0x81; + bt848[BKTR_COLOR_CTL] = 0x20; + + bt848[BKTR_E_VSCALE_HI] |= 0xc0; + bt848[BKTR_O_VSCALE_HI] |= 0xc0; + + bktr->capcontrol = 3 << 2 | 3; + + dma_prog = (u_long *) bktr->dma_prog; + + /* Construct Write */ + bt_enable_cnt = 0; + + b = (cols * pixel_width ) / 2; + + /* write, sol, eol */ + inst = OP_WRITE | OP_SOL | bt_enable_cnt << 12 | (b); + inst2 = OP_WRITE | bt_enable_cnt << 12 | (cols * pixel_width/2); + /* write , sol, eol */ + inst3 = OP_WRITE | OP_EOL | bt_enable_cnt << 12 | (b); + + 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*pixel_width; + } + + buffer = target_buffer; + + /* contruct sync : for video packet format */ + *dma_prog++ = OP_SYNC | 0xC << 24 | 1 << 15 | BKTR_FM1; + + /* sync, mode indicator packed data */ + *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*pitch; + } + + switch (i_flag) { + case 1: + /* sync vre */ + *dma_prog++ = OP_SYNC | 0xC << 24 | 1 << 24 | BKTR_VRE; + *dma_prog++ = 0; /* NULL WORD */ + + *dma_prog++ = OP_JUMP | 0xC << 24; + *dma_prog++ = (u_long ) vtophys(bktr->dma_prog); + return; + + case 2: + /* sync vre */ + *dma_prog++ = OP_SYNC | 1 << 24 | 1 << 20 | BKTR_VRO; + *dma_prog++ = 0; /* NULL WORD */ + + *dma_prog++ = OP_JUMP; + *dma_prog++ = (u_long ) vtophys(bktr->dma_prog); + return; + + case 3: + /* sync vre */ + *dma_prog++ = OP_SYNC | 0xC << 24 | 1 << 24 | 1 << 15 | BKTR_VRO; + *dma_prog++ = 0; /* NULL WORD */ + *dma_prog++ = OP_JUMP | 0xc << 24 ; + *dma_prog = (u_long ) vtophys(bktr->odd_dma_prog); + break; + } + + if (interlace == 2) { + + target_buffer = (u_long) buffer + pitch; + + dma_prog = (u_long *) bktr->odd_dma_prog; + + /* sync vre IRQ bit */ + *dma_prog++ = OP_SYNC | 0xc << 24 | 1 << 15 | 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 * pitch; + } + } + + /* sync vre IRQ bit */ + *dma_prog++ = OP_SYNC | 0xc << 24 | 1 << 24 | 1 << 15 | BKTR_VRE; + *dma_prog++ = 0; /* NULL WORD */ + *dma_prog++ = OP_JUMP | 0xc << 24; + *dma_prog++ = (u_long ) vtophys(bktr->dma_prog) ; + *dma_prog++ = 0; /* NULL WORD */ +} + + +/* + * + */ +void +yuvpack_prog( bktr_reg_t *bktr, char i_flag, int cols, int rows, int interlace) +{ + int i; + int byte_count; + volatile unsigned int inst; + volatile unsigned int inst2; + volatile unsigned int inst3; + volatile u_long target_buffer, buffer; + volatile u_char *bt848, *bt_reg; + volatile u_short *bts_reg; + volatile u_long *dma_prog, *foo, *btl_reg; + int b; + + bt848 = bktr->base; + + /* color format : yuvpack */ + bt848[BKTR_COLOR_FMT] = 0x44; + + bt848[BKTR_E_SCLOOP] |= 0x40; /* enable chroma comb */ + bt848[BKTR_O_SCLOOP] |= 0x40; + + bt848[BKTR_COLOR_CTL] = 0x30; + bt848[BKTR_ADC] = 0x81; + + bktr->capcontrol = 1 << 6 | 1 << 4 | 1 << 2 | 3; + bktr->capcontrol = 1 << 5 | 1 << 4 | 1 << 2 | 3; + + dma_prog = (u_long *) bktr->dma_prog; + + /* Construct Write */ + bt_enable_cnt = 0; + + /* write , sol, eol */ + inst = OP_WRITE | OP_SOL | 0xf << 16 | bt_enable_cnt << 12 | (cols*2); + /* write , sol, eol */ + inst3 = OP_WRITE | OP_EOL | 0xf << 16 | bt_enable_cnt << 12 | (cols); + inst2 = OP_WRITE | bt_enable_cnt << 12 | (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 | 1 << 24 | 1 << 15 | 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 | 1 << 24 | BKTR_VRE; + *dma_prog++ = 0; /* NULL WORD */ + + *dma_prog++ = OP_JUMP; + *dma_prog++ = (u_long ) vtophys(bktr->dma_prog); + return; + + case 2: + /* sync vre */ + *dma_prog++ = OP_SYNC | 1 << 24 | 1 << 20 | BKTR_VRO; + *dma_prog++ = 0; /* NULL WORD */ + *dma_prog++ = OP_JUMP; + *dma_prog++ = (u_long ) vtophys(bktr->dma_prog); + return; + + case 3: + /* sync vre */ + *dma_prog++ = OP_SYNC | 1 << 24 | 0xf << 16 | BKTR_VRE; + *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 | 1 << 24 | 0xf << 16 | 1 << 15 | 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 vre IRQ bit */ + *dma_prog++ = OP_SYNC | 1 << 24 | 0xf << 16 | BKTR_VRO; + *dma_prog++ = 0; /* NULL WORD */ + *dma_prog++ = OP_JUMP | 0xf << 16; + *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 */ +} + + +/* + * + */ +void +yuv422_prog( bktr_reg_t * bktr, char i_flag, int cols, + int rows, int interlace) +{ + int i, j; + int byte_count; + volatile unsigned int inst; + volatile unsigned int inst2; + volatile unsigned int instskip, instskip2, instskip3; + volatile unsigned int inst3; + volatile u_long target_buffer, t1, buffer; + volatile u_char *bt848, *bt_reg; + volatile u_short *bts_reg; + volatile u_long *dma_prog, *foo, *btl_reg; + int b, b1; + + bt848 = bktr->base; + dma_prog = (u_long *) bktr->dma_prog; + + bktr->capcontrol = 1 << 6 | 1 << 4 | 3; + + bt848[BKTR_ADC] = 0x81 ; + bt848[BKTR_OFORM] = 0x00; + + bt848[BKTR_E_CONTROL] |= 0x20; /* disable luma decimation */ + bt848[BKTR_O_CONTROL] |= 0x20; + + bt848[BKTR_E_SCLOOP] |= 0x40; /* chroma agc enable */ + bt848[BKTR_O_SCLOOP] |= 0x40; + + bt848[BKTR_E_VSCALE_HI] |= 0xc0; /* luma comb and comb enable */ + bt848[BKTR_O_VSCALE_HI] |= 0xc0; + + bt848[BKTR_COLOR_FMT] = 0x88; + + bt848[BKTR_COLOR_CTL] = 0x10; /* disable gamma correction */ + + bt_enable_cnt = 0; + + /* Construct Write */ + inst = OP_WRITE123 | OP_SOL | OP_EOL | bt_enable_cnt << 12 | (cols); + inst2 = OP_WRITES123 | OP_SOL | OP_EOL | bt_enable_cnt << 12 | (cols); + + if (bktr->video.addr) + target_buffer = (u_long) bktr->video.addr; + else + target_buffer = (u_long) vtophys(bktr->bigbuf); + + buffer = target_buffer; + + t1 = target_buffer; + + /* contruct sync : for video packet format */ + *dma_prog++ = OP_SYNC | 0xC << 24 | 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 | 0xC << 24 | 1 << 24 | BKTR_VRE; /*sync vre*/ + *dma_prog++ = 0; /* NULL WORD */ + + *dma_prog++ = OP_JUMP | 0xc << 24; + *dma_prog++ = (u_long ) vtophys(bktr->dma_prog); + return; + break; + case 2: + *dma_prog++ = OP_SYNC | 0xC << 24 | 1 << 24 | BKTR_VRO; /*sync vre*/ + *dma_prog++ = 0; /* NULL WORD */ + + *dma_prog++ = OP_JUMP; + *dma_prog++ = (u_long ) vtophys(bktr->dma_prog); + return; + break; + case 3: + *dma_prog++ = OP_SYNC | 0xc << 24 | 1 << 15 | BKTR_VRO; + *dma_prog++ = 0; /* NULL WORD */ + + *dma_prog++ = OP_JUMP | 0xc << 24 ; + *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 = target_buffer + cols/2; + *dma_prog++ = OP_SYNC | 0xc << 24 | 1 << 24 | 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 | 0xC << 24 | 1 << 24 | BKTR_VRE; + *dma_prog++ = 0; /* NULL WORD */ + *dma_prog++ = OP_JUMP | 0xC << 24;; + *dma_prog++ = (u_long ) vtophys(bktr->dma_prog) ; + *dma_prog++ = 0; /* NULL WORD */ +} + + +/* + * + */ +void +build_dma_prog( bktr_reg_t * bktr, char i_flag) +{ + int i; + int pixel_width, rows, cols, byte_count, interlace; + volatile unsigned int inst; + volatile unsigned int inst2; + volatile unsigned int inst3; + volatile u_long target_buffer; + volatile u_char *bt848, *bt_reg; + volatile u_short *bts_reg; + volatile u_long * dma_prog, *foo, *btl_reg; + int b; + + bt848 = bktr->base; + btl_reg = (u_long *) &bt848[BKTR_INT_MASK] ; + *btl_reg = 0; + + bts_reg = (u_short * ) &bt848[BKTR_GPIO_DMA_CTL]; + *bts_reg &= ~3; + + /* capture control */ + switch (i_flag) { + case 1: + bt848[BKTR_CAP_CTL] = 0x11; + bt848[BKTR_E_VSCALE_HI] &= ~0x20; + bt848[BKTR_O_VSCALE_HI] &= ~0x20; + interlace = 1; + break; + case 2: + bt848[BKTR_CAP_CTL] = 0x12; + bt848[BKTR_E_VSCALE_HI] &= ~0x20; + bt848[BKTR_O_VSCALE_HI] &= ~0x20; + interlace = 1; + break; + default: + bt848[0xdc] = 0x13; + bt848[BKTR_E_VSCALE_HI] |= 0x20; + bt848[BKTR_O_VSCALE_HI] |= 0x20; + interlace = 2; + break; + } + + btl_reg = (u_long *) &bt848[BKTR_RISC_STRT_ADD] ; + *btl_reg = vtophys(bktr->dma_prog); + + pixel_width = bktr->depth; + rows = bktr->rows; + cols = bktr->cols; + + if (bktr->format == METEOR_GEO_RGB24 || + bktr->format == METEOR_GEO_RGB16) { + rgb_prog(bktr, i_flag, cols, rows, pixel_width, interlace); + return; + } + + if (bktr->format == METEOR_GEO_YUV_422 ){ + yuv422_prog(bktr, i_flag, cols, rows, interlace); + return; + } + + if (bktr->format == METEOR_GEO_YUV_PACKED ){ + yuvpack_prog(bktr, i_flag, cols, rows, interlace); + return; + } + + return; +} + + +/* + * + */ +void +start_capture(bktr_reg_t *bktr, unsigned type) +{ + volatile u_char * bt848, *bt_reg, i_flag; + volatile u_short *bts_reg; + volatile u_long *btl_reg; + bt848 = (u_char *) bktr->base; + + *bt848 = 0; + btl_reg = (u_long *) &bt848[BKTR_INT_STAT]; + *btl_reg = *btl_reg; + + bktr->flags |= type; + 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; + } + + if (!bktr->dma_prog_loaded) { + build_dma_prog(bktr, i_flag); + bktr->dma_prog_loaded = 1; + } + +/*XXX + switch(bktr->flags & METEOR_ONLY_FIELDS_MASK) { + default: + *bts_reg |= 0xb; + } +*/ + + btl_reg = (u_long *) &bt848[BKTR_RISC_STRT_ADD]; + *btl_reg = vtophys(bktr->dma_prog); + +/*XXX + bts_reg = (u_short *) &bt848[BKTR_GPIO_DMA_CTL]; + *bts_reg = 0x3; +*/ + +} + +/* + * + */ +static void +set_fps(bktr_reg_t *bktr, u_short fps) +{ + volatile u_char * bt848, *bt_reg; + volatile u_long * btl_reg; + volatile u_short * bts_reg; + bt848 = (u_char *) bktr->base; + + bts_reg = (u_short *) &bt848[BKTR_GPIO_DMA_CTL]; + *bts_reg = 0; + btl_reg = (u_long *) &bt848[BKTR_INT_STAT]; + *btl_reg = 0xffffffff; + + bktr->fps = fps; + + if ( fps == 30 ) { + bt848[BKTR_TDEC] = 0; + return; + } else { + bt848[BKTR_TDEC] = (int) (((float) fps / 30.0) * 60.0) & 0x3f; + bt848[BKTR_TDEC] |= 0x80; + } + + if ( bktr->flags & METEOR_CAP_MASK ) { + + btl_reg = (u_long *) &bt848[BKTR_INT_STAT]; + *btl_reg = 0xffffffff; + btl_reg = (u_long *) &bt848[BKTR_RISC_STRT_ADD]; + *btl_reg = vtophys(bktr->dma_prog); + + bts_reg = (u_short *) &bt848[BKTR_GPIO_DMA_CTL]; + *bts_reg = 1; + *bts_reg = bktr->capcontrol; + btl_reg = (u_long *) &bt848[BKTR_INT_MASK]; + *btl_reg = 1 << 11 | 2 | 1; + } + + return; + +} + + +/* + * There is also a problem with range checking on the 7116. + * It seems to only work for 22 bits, so the max size we can allocate + * is 22 bits long or 4194304 bytes assuming that we put the beginning + * of the buffer on a 2^24 bit boundary. The range registers will use + * the top 8 bits of the dma start registers along with the bottom 22 + * bits of the range register to determine if we go out of range. + * This makes getting memory a real kludge. + * + */ + +#define RANGE_BOUNDARY (1<<22) +static vm_offset_t +get_bktr_mem( int unit, unsigned size ) +{ + vm_offset_t addr = 0; + + addr = vm_page_alloc_contig(size, 0x100000, 0xffffffff, 1<<24); + if (addr == 0) + addr = vm_page_alloc_contig(size, 0x100000, 0xffffffff, + PAGE_SIZE); + if (addr == 0) { + printf("meteor%d: Unable to allocate %d bytes of memory.\n", + unit, size); + } + return addr; +} + + +/* + * Initialize the 7116, 7196 and the RGB module. + */ +static void +bktr_init ( bktr_reg_t *bktr ) +{ + return; +} + + +static void +bktr_attach( pcici_t tag, int unit ) +{ + bktr_reg_t *bktr; + volatile u_char *bt848; + volatile u_long *btl_reg; +#ifdef BROOKTREE_IRQ + u_long old_irq, new_irq; +#endif + u_char *test; + vm_offset_t buf; + u_long latency; + u_long foo,fun; + bt_enable_cnt = 0; + bktr = &brooktree[unit]; + if (unit >= NBKTR) { + printf("brooktree%d: attach: only %d units configured.\n", + unit, NBKTR); + printf("brooktree%d: attach: invalid unit number.\n", unit); + return ; + } + + + bktr->tag = tag; + pci_map_mem(tag, PCI_MAP_REG_START, (vm_offset_t *) &bktr->base, + &bktr->phys_base); + + fun = pci_conf_read(tag, PCI_COMMAND_STATUS_REG); + +#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 + /* setup the interrupt handling routine */ + pci_map_int(tag, bktr_intr, (void*) bktr, &net_imask); + +/* + * PCI latency timer. 32 is a good value for 4 bus mastering slots, if + * you have more than for, then 16 would probably be a better value. + * + */ +#ifndef BROOKTREE_DEF_LATENCY_VALUE +#define BROOKTREE_DEF_LATENCY_VALUE 10 +#endif + latency = pci_conf_read(tag, PCI_LATENCY_TIMER); + 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_conf_write(tag, PCI_LATENCY_TIMER, latency<<8); + } + if ( bootverbose ) { + printf(" %d.\n", latency); + } + + /* bktr_init(bktr); set up the bt848 */ + + /* allocate space for dma program */ + bktr->dma_prog = get_bktr_mem(unit, 8); + bktr->odd_dma_prog = get_bktr_mem(unit, 8); + if ( BROOKTREE_ALLOC ) + buf = get_bktr_mem(unit, BROOKTREE_ALLOC); + else + buf = 0; + + if ( bootverbose ) { + printf("bktr%d: buffer size %d, addr 0x%x\n", + unit, BROOKTREE_ALLOC, vtophys(buf)); + } + + bktr->bigbuf = buf; + bktr->alloc_pages = BROOKTREE_ALLOC_PAGES; + if ( buf != 0 ) { + bzero((caddr_t) buf, BROOKTREE_ALLOC); + buf = vtophys(buf); + +#ifdef amancio /* 640x480 RGB 16 */ + +amancio : setup dma risc program + bktr->base->dma1e = buf; + bktr->base->dma1o = buf + 0x500; + bktr->base->dma_end_e = + bktr->base->dma_end_o = buf + METEOR_ALLOC; +end of setup up dma risc program + /* 1 frame of 640x480 RGB 16 */ + bktr->flags |= METEOR_INITALIZED | METEOR_AUTOMODE | METEOR_DEV0 | + METEOR_RGB16; +#endif /* amancio */ + + bktr->flags = METEOR_INITALIZED | METEOR_AUTOMODE | METEOR_DEV0 | METEOR_RGB16; + bktr->dma_prog_loaded = 0; + bktr->cols = 640; + bktr->rows = 480; + bktr->depth = 2; /* two bytes per pixel */ + bktr->frames = 1; /* one frame */ + bt848 = bktr->base; + btl_reg = (u_long *) &bt848[BKTR_INT_MASK]; + *btl_reg = 0; + bt848[BKTR_GPIO_DMA_CTL] = 0; + } +#ifdef DEVFS + bktr->devfs_token = devfs_add_devswf(&bktr_cdevsw, unit, + DV_CHR, 0, 0, 0644, "brooktree"); +#endif /* DEVFS */ +} + +#define UNIT(x) ((x) & 0x07) + + +/*--------------------------------------------------------- +** +** BrookTree 848 character device driver routines +** +**--------------------------------------------------------- +*/ + + +int +bktr_open( dev_t dev, int flags, int fmt, struct proc *p ) +{ + bktr_reg_t *bktr; + int unit; + int i; + volatile u_char *bt848; + volatile u_char *bt_reg; + volatile u_long *btl_reg; + + unit = UNIT(minor(dev)); + if (unit >= NBKTR) /* unit out of range */ + return(ENXIO); + + bktr = &(brooktree[unit]); + + if (!(bktr->flags & METEOR_INITALIZED)) /* device not found */ + return(ENXIO); + +#if defined( MULTIPLE_OPENS ) + if (bktr->flags & METEOR_OPEN) /* device already open */ + return 0; +#else + if (bktr->flags & METEOR_OPEN) /* device is busy */ + return(EBUSY); +#endif /* MULTIPLE_OPENS */ + + bktr->flags |= METEOR_OPEN; + + bt848 = bktr->base; + + /* dump_bt848(bt848); */ + *bt848 = 0x3; + *bt848 = 0xc0; + + bt848[BKTR_ADC] = 0x81; + + bt848[BKTR_IFORM] = 0x69; + + bt848[BKTR_COLOR_CTL] = 0x20; + + bt848[BKTR_E_HSCALE_LO] = 0xaa; + bt848[BKTR_O_HSCALE_LO] = 0xaa; + + bt848[BKTR_E_DELAY_LO] = 0x72; + bt848[BKTR_O_DELAY_LO] = 0x72; + bt848[BKTR_E_SCLOOP] = 0; + bt848[BKTR_O_SCLOOP] = 0; + + bt848[BKTR_VBI_PACK_SIZE] = 0; + bt848[BKTR_VBI_PACK_DEL] = 0; + + bzero((u_char *) bktr->bigbuf, 640*480*4); + bktr->flags |= METEOR_OPEN; + bktr->fifo_errors = 0; + bktr->dma_errors = 0; + bktr->frames_captured = 0; + bktr->even_fields_captured = 0; + bktr->odd_fields_captured = 0; + bktr->proc = (struct proc *)0; + set_fps(bktr, 30); + bktr->video.addr = 0; + bktr->video.width = 0; + bktr->video.banksize = 0; + bktr->video.ramsize = 0; + + /* defaults for the tuner section of the card */ + bktr->tuner.frequency = 0; + bktr->tuner.tunertype = DEFAULT_TUNERTYPE; + + btl_reg = (u_long *) &bt848[BKTR_INT_MASK]; + *btl_reg = 1 << 23; + + return(0); +} + +int +bktr_close( dev_t dev, int flags, int fmt, struct proc *p ) +{ + bktr_reg_t *bktr; + int unit; + volatile u_char *bt848; + volatile u_long *btl_reg; + u_short *bts_reg; +#ifdef METEOR_DEALLOC_ABOVE + int temp; +#endif + unit = UNIT(minor(dev)); + if (unit >= NBKTR) /* unit out of range */ + return(ENXIO); + + bktr = &(brooktree[unit]); + + bktr->flags &= ~METEOR_OPEN; + bktr->flags &= ~(METEOR_SINGLE | METEOR_WANT_MASK); + bktr->flags &= ~(METEOR_CAP_MASK|METEOR_WANT_MASK); + bt848 = bktr->base; + bts_reg = (u_short *) &bt848[BKTR_GPIO_DMA_CTL]; + *bts_reg = 0; + bt848[BKTR_CAP_CTL] = 0; + + bktr->dma_prog_loaded = 0; + bt848[BKTR_TDEC] = 0; + btl_reg = (u_long *) &bt848[BKTR_INT_MASK]; + *btl_reg = 0; + + bt848[BKTR_SRESET] = 0xf; + btl_reg = (u_long *) &bt848[BKTR_INT_STAT] ; + *btl_reg = 0xffffffff; + + return(0); +} + + +/* + * + */ +int +bktr_read( dev_t dev, struct uio *uio, int ioflag ) +{ + bktr_reg_t *bktr; + int unit; + int status; + int count; + volatile u_char *bt848; + u_short *bts_reg; + + unit = UNIT(minor(dev)); + if (unit >= NBKTR) /* unit out of range */ + return(ENXIO); + + bktr = &(brooktree[unit]); + if (bktr->bigbuf == 0) /* no frame buffer allocated (ioctl failed) */ + return(ENOMEM); + + if (bktr->flags & METEOR_CAP_MASK) + return(EIO); /* already capturing */ + + bt848 = (u_char *) bktr->base; + + + count = bktr->rows * bktr->cols * bktr->depth; + if ((int) uio->uio_iov->iov_len < count) + return(EINVAL); + bktr->flags &= ~(METEOR_CAP_MASK|METEOR_WANT_MASK); + + /* Start capture */ + bts_reg = (u_short *) &bt848[BKTR_GPIO_DMA_CTL]; + *bts_reg = 0x1; + *bts_reg = 0x3; + + status=tsleep((caddr_t)bktr, METPRI, "capturing", 0); + if (!status) /* successful capture */ + status = uiomove((caddr_t)bktr->bigbuf, count, uio); + else + printf ("meteor%d: read: tsleep error %d\n", unit, status); + + bktr->flags &= ~(METEOR_SINGLE | METEOR_WANT_MASK); + + return(status); +} + + +/* + * + */ +int +bktr_write( dev_t dev, struct uio *uio, int ioflag ) +{ + return(0); +} + + +/* + * + */ +int +bktr_ioctl( dev_t dev, int cmd, caddr_t arg, int flag, struct proc *pr ) +{ + bktr_reg_t *bktr; + int unit; + int status; + int count; + int tmp_int; + volatile u_char *bt848, c_temp; + volatile u_short *bts_reg, s_temp; + volatile u_long *btl_reg; + unsigned int temp, temp1; + unsigned int error; + struct meteor_geomet *geo; + struct meteor_counts *cnt; + struct meteor_video *video; + u_long *foo; + vm_offset_t buf; + + unit = UNIT(minor(dev)); + if (unit >= NBKTR) /* unit out of range */ + return(ENXIO); + + + bktr = &(brooktree[unit]); + if (bktr->bigbuf == 0) /* no frame buffer allocated (ioctl failed) */ + return(ENOMEM); + + bt848 = bktr->base; + switch (cmd) { + + case TVTUNER_SETCHNL: + temp = tv_channel( bktr, (int)*(unsigned long *)arg ); + if ( temp < 0 ) return EIO; + *(unsigned long *)arg = temp; + break; + + case TVTUNER_GETCHNL: + *(unsigned long *)arg = bktr->tuner.channel; + break; + + case TVTUNER_SETTYPE: + bktr->tuner.tunertype = *(unsigned long *)arg; + break; + + case TVTUNER_GETTYPE: + *(unsigned long *)arg = bktr->tuner.tunertype; + break; + + case TVTUNER_GETSTATUS: + temp = tuner_status( bktr ); + *(unsigned long *)arg = temp & 0xff; + break; + + case METEORSTATUS: /* get 7196 status */ + c_temp = bt848[0]; + temp = 0; + if (!(c_temp & 0x40)) temp |= METEOR_STATUS_HCLK; + if (!(c_temp & 0x10)) temp |= METEOR_STATUS_FIDT; + *(u_short *)arg = temp; + break; + + case METEORSINPUT: /* set input device */ + switch(*(unsigned long *)arg & METEOR_DEV_MASK) { + case 0: /* default */ + case METEOR_INPUT_DEV0: + bktr->flags = (bktr->flags & ~METEOR_DEV_MASK) + | METEOR_DEV0; + bt848[BKTR_IFORM] &= ~0x60; + bt848[BKTR_IFORM] |= 0x60; + bt848[BKTR_E_CONTROL] &= ~0x40; + bt848[BKTR_O_CONTROL] &= ~0x40; + break; + + case METEOR_INPUT_DEV1: + bktr->flags = (bktr->flags & ~METEOR_DEV_MASK) + | METEOR_DEV1; + bt848[BKTR_IFORM] &= ~0x60; + bt848[BKTR_IFORM] |= 0x40; + bt848[BKTR_E_CONTROL] &= ~0x40; + bt848[BKTR_O_CONTROL] &= ~0x40; + break; + + case METEOR_INPUT_DEV2: + bktr->flags = (bktr->flags & ~METEOR_DEV_MASK) + | METEOR_DEV2; + bt848[BKTR_IFORM] &= ~0x60; + bt848[BKTR_IFORM] |= 0x20; + bt848[BKTR_E_CONTROL] |= 0x40; + bt848[BKTR_O_CONTROL] |= 0x40; + break; + + case METEOR_INPUT_DEV_SVIDEO: + bktr->flags = (bktr->flags & ~METEOR_DEV_MASK) + | METEOR_DEV2; + bt848[BKTR_IFORM] &= ~0x60; + bt848[BKTR_IFORM] |= 0x20; + bt848[BKTR_E_CONTROL] |= 0x40; + bt848[BKTR_O_CONTROL] |= 0x40; + break; + + default: + return EINVAL; + } + break; + + case METEORGINPUT: /* get input device */ + *(u_long *)arg = bktr->flags & METEOR_DEV_MASK; + break; + + case METEORSFMT: /* set input format */ + switch(*(unsigned long *)arg & METEOR_FORM_MASK ) { + case 0: /* default */ + case METEOR_FMT_NTSC: + bktr->flags = (bktr->flags & ~METEOR_FORM_MASK) | + METEOR_NTSC; + bt848[BKTR_IFORM] &= ~0x3; + bt848[BKTR_IFORM] |= 1; + break; + + case METEOR_FMT_AUTOMODE: + bktr->flags = (bktr->flags & ~METEOR_FORM_MASK) | + METEOR_AUTOMODE; + bt848[BKTR_IFORM] &= ~0x3; + break; + + default: + return EINVAL; + } + break; + + case METEORGFMT: /* get input format */ + *(u_long *)arg = bktr->flags & METEOR_FORM_MASK; + break; + + case METEORSCOUNT: /* (re)set error counts */ + cnt = (struct meteor_counts *) arg; + bktr->fifo_errors = cnt->fifo_errors; + bktr->dma_errors = cnt->dma_errors; + bktr->frames_captured = cnt->frames_captured; + bktr->even_fields_captured = cnt->even_fields_captured; + bktr->odd_fields_captured = cnt->odd_fields_captured; + break; + + case METEORGCOUNT: /* get error counts */ + cnt = (struct meteor_counts *) arg; + cnt->fifo_errors = bktr->fifo_errors; + cnt->dma_errors = bktr->dma_errors; + cnt->frames_captured = bktr->frames_captured; + cnt->even_fields_captured = bktr->even_fields_captured; + cnt->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 */ + bt848[BKTR_HUE] = (*(u_char *) arg) & 0xff; + break; + + case METEORGHUE: /* get hue */ + *(u_char *)arg = bt848[BKTR_HUE]; + break; + + case METEORSBRIG: /* set brightness */ + bt848[BKTR_BRIGHT] = *(u_char *)arg & 0xff; + break; + + case METEORGBRIG: /* get brightness */ + *(u_char *)arg = bt848[BKTR_BRIGHT]; + break; + + case METEORSCSAT: /* set chroma saturation */ +#if defined( OLD_METEORSCSAT ) + s_temp = *(u_short *)arg ; + s_temp = s_temp << 1; + + bt848[BKTR_SAT_U_LO] = s_temp; + bt848[BKTR_SAT_V_LO] = s_temp; + s_temp = s_temp >> 8; + + bt848[BKTR_E_CONTROL] &= ~0x3; + bt848[BKTR_O_CONTROL] &= ~0x3; + bt848[BKTR_E_CONTROL] |= s_temp & 0x3; + bt848[BKTR_O_CONTROL] |= s_temp & 0x3; + break; +#endif /* OLD_METEORSCSAT */ + temp = (int)*(u_char *)arg; + + bt848[BKTR_SAT_U_LO] = bt848[BKTR_SAT_V_LO] = + (temp << 1) & 0xff; + + bt848[BKTR_E_CONTROL] &= ~0x3; /* clear U/V MSBs */ + bt848[BKTR_O_CONTROL] &= ~0x3; /* clear U/V MSBs */ + + if ( temp & 0x80 ) { + bt848[BKTR_E_CONTROL] |= 0x3; /* */ + bt848[BKTR_O_CONTROL] |= 0x3; + } + break; + + case METEORGCSAT: /* get chroma saturation */ +#if defined( OLD_METEORGCSAT ) + *(u_short *)arg = (bt848[BKTR_E_CONTROL] << 8) & 0x10 | bt848[BKTR_SAT_U_LO]; + break; +#endif /* OLD_METEORGCSAT */ + temp = (bt848[BKTR_SAT_V_LO] >> 1) & 0xff; + if ( bt848[BKTR_E_CONTROL] & 0x01 ) + temp |= 0x80; + *(u_char *)arg = (u_char)temp; + break; + + case METEORSCONT: /* set contrast */ + temp = (int)*(u_char *)arg & 0xff; + temp <<= 1; + bt848[BKTR_CONTRAST_LO] = temp & 0xff; + bt848[BKTR_E_CONTROL] &= ~0x4; + bt848[BKTR_O_CONTROL] &= ~0x4; + bt848[BKTR_E_CONTROL] |= ((temp & 0x100) >> 6 ) & 0x4 ; + bt848[BKTR_O_CONTROL] |= ((temp & 0x100) >> 6 ) & 0x4 ; + break; + + case METEORGCONT: /* get contrast */ +#if defined( OLD_METEORGCONT ) + *(u_short *)arg = bt848[BKTR_CONTRAST_LO] | ((bt848[BKTR_O_CONTROL] & 4) << 2); + break; +#endif /* OLD_METEORGCONT */ + temp = (int)bt848[BKTR_CONTRAST_LO] & 0xff; + temp |= ((int)bt848[BKTR_O_CONTROL] & 0x04) << 6; + *(u_char *)arg = (u_char)((temp >> 1) & 0xff); + break; + + case METEORSSIGNAL: + bktr->signal = *(int *) arg; + bktr->proc = pr; + 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); + + /* if (temp & METEOR_CAP_MASK) + return(EIO); already capturing */ + + start_capture(bktr, METEOR_SINGLE); + bktr->flags |= METEOR_SINGLE; + bktr->flags &= ~METEOR_WANT_MASK; + + /* wait for capture to complete */ + btl_reg = (u_long *) &bt848[BKTR_INT_STAT]; + *btl_reg = 0xffffffff; + + btl_reg = (u_long *) &bt848[BKTR_GPIO_OUT_EN]; + *btl_reg = 1; + bts_reg = (u_short *) &bt848[BKTR_GPIO_DMA_CTL]; + *bts_reg = 0x1; + *bts_reg = bktr->capcontrol; + + btl_reg = (u_long *) &bt848[BKTR_INT_MASK]; + + *btl_reg = 1 << 23 | 1 << 11 | 2 | 1; + + error=tsleep((caddr_t)bktr, METPRI, "capturing", hz); + + if (error) { + btl_reg = (u_long *) &bt848[BKTR_RISC_COUNT]; + + printf("bktr%d: ioctl: tsleep error %d %x\n", + unit, error, *btl_reg); + } + bktr->flags &= ~(METEOR_SINGLE|METEOR_WANT_MASK); + btl_reg = (u_long *) &bt848[BKTR_INT_STAT]; + break; + + case METEOR_CAP_CONTINOUS: + if (bktr->bigbuf==0) /* no frame buffer allocated */ + return(ENOMEM); + + if (temp & METEOR_CAP_MASK) + return(EIO); /* already capturing */ + + start_capture(bktr, METEOR_CONTIN); + btl_reg = (u_long *) &bt848[BKTR_INT_STAT]; + *btl_reg = *btl_reg; + + bts_reg = (u_short *) &bt848[BKTR_GPIO_DMA_CTL]; + + *bts_reg = 1; + *bts_reg = bktr->capcontrol; + + btl_reg = (u_long *) &bt848[BKTR_INT_MASK]; + *btl_reg = 1 << 23 | 1 << 11 | 2 | 1; + + /* dump_bt848(bt848); */ + break; + + case METEOR_CAP_STOP_CONT: + if (bktr->flags & METEOR_CONTIN) { + /* turn off capture */ + btl_reg = (u_long *) &bt848[BKTR_INT_MASK]; + *btl_reg = 0; + bts_reg = (u_short *)&bt848[BKTR_GPIO_DMA_CTL]; + *bts_reg = 0; + + bktr->flags &= ~(METEOR_CONTIN|METEOR_WANT_MASK); + } + } + break; + + case METEORSETGEO: + + 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("bktr%d: ioctl: Geometry odd or even only.\n", + unit); + + 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; + + /* can't change parameters while capturing */ +/* XXX: + if (bktr->flags & METEOR_CAP_MASK) + return(EBUSY); +*/ + if ((geo->columns & 0x3fe) != geo->columns) { + printf( + "bktr%d: ioctl: %d: columns too large or not even.\n", + unit, geo->columns); + error = EINVAL; + } + if (((geo->rows & 0x7fe) != geo->rows) || + ((geo->oformat & METEOR_GEO_FIELD_MASK) && + ((geo->rows & 0x3fe) != geo->rows)) ) { + printf( + "bktr%d: ioctl: %d: rows too large or not even.\n", + unit, geo->rows); + error = EINVAL; + } + if (geo->frames > 32) { + printf("bktr%d: ioctl: too many frames.\n", unit); + + error = EINVAL; + } + + if (error) return error; + bktr->dma_prog_loaded = 0; + bts_reg = (u_short *) &bt848[BKTR_GPIO_DMA_CTL]; + *bts_reg = 0; + + btl_reg = (u_long *) &bt848[BKTR_INT_MASK]; + *btl_reg = 0; + + 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) { + buf = get_bktr_mem(unit, temp*PAGE_SIZE); + if (buf != 0) { + kmem_free(kernel_map, bktr->bigbuf, + (bktr->alloc_pages * PAGE_SIZE)); + bktr->bigbuf = buf; + bktr->alloc_pages = temp; + if (bootverbose) + printf( + "meteor%d: ioctl: Allocating %d bytes\n", + unit, temp*PAGE_SIZE); + } else { + error = ENOMEM; + } + } + } + + if (error) + return error; + + bktr->rows = geo->rows; + bktr->cols = geo->columns; + bktr->frames = geo->frames; + + /* horizontal scale */ + /* temp = ((910.0/( (float) bktr->cols *1.21875)) - 1.0) * 4096.0;*/ + /* temp = ((910.0/( (float) bktr->cols *1.212)) - 1.0) * 4096.0; */ + temp = ((910.0/( (float) bktr->cols *1.21875)) - 1.0) * 4096.0; + /* temp = ((754.0/(float) bktr->cols) - 1 ) * 4096.0;*/ + + bt848[BKTR_E_HSCALE_LO] = temp & 0xff; + bt848[BKTR_O_HSCALE_LO] = temp & 0xff; + bt848[BKTR_E_HSCALE_HI] = ( temp >> 8 ) & 0xff; + bt848[BKTR_O_HSCALE_HI] = ( temp >> 8 ) & 0xff; + + /* horizontal active */ + temp = bktr->cols; + bt848[BKTR_E_HACTIVE_LO] = temp & 0xff; + bt848[BKTR_O_HACTIVE_LO] = temp & 0xff; + bt848[BKTR_EVEN_CROP] &= ~0x3; + bt848[BKTR_ODD_CROP] &= ~0x3; + bt848[BKTR_EVEN_CROP] |= (temp >> 8 ) & 0x3; + bt848[BKTR_ODD_CROP] |= (temp >> 8 ) & 0x3; + + /* horizontal delay */ + temp = ((135.0/754.0) * (float) bktr->cols) ; + temp = temp + 2; + temp = temp & 0x3fe; + bt848[BKTR_E_DELAY_LO] = temp & 0xff; + bt848[BKTR_O_DELAY_LO] = temp & 0xff; + bt848[BKTR_EVEN_CROP] &= ~0xc; + bt848[BKTR_ODD_CROP] &= ~0xc; + bt848[BKTR_EVEN_CROP] |= (temp >> 6) & 0xc; + bt848[BKTR_ODD_CROP] |= (temp >> 6) & 0xc; + + /* vscale */ + if (geo->oformat & METEOR_GEO_ODD_ONLY || + geo->oformat & METEOR_GEO_EVEN_ONLY) { + tmp_int = 65536.0 - (((240.0/(float) bktr->rows) - 1.0) * 512.0); + } else { + tmp_int = 65536 - (((480.0/(float) bktr->rows) - 1.0) * 512); + } + tmp_int &= 0x1fff; + + /* Vertical scaling */ + bt848[BKTR_E_VSCALE_LO] = tmp_int & 0xff; + bt848[BKTR_O_VSCALE_LO] = tmp_int & 0xff; + bt848[BKTR_E_VSCALE_HI] &= ~0x1f; + bt848[BKTR_O_VSCALE_HI] &= ~0x1f; + bt848[BKTR_E_VSCALE_HI] |= (tmp_int >> 8) & 0x1f; + bt848[BKTR_O_VSCALE_HI] |= (tmp_int >> 8) & 0x1f; + + 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; + bktr->depth = 2; + break; + case METEOR_GEO_RGB24: + bktr->format = METEOR_GEO_RGB24; + bktr->depth = 4; + break; + case METEOR_GEO_YUV_422: + bktr->format = METEOR_GEO_YUV_422; + break; + case METEOR_GEO_YUV_PACKED: + bktr->format = METEOR_GEO_YUV_PACKED; + break; + } + +/* + if (geo->oformat & METEOR_GEO_YUV_12 ) + bktr->format |= METEOR_GEO_YUV_12; + else if (geo->oformat & METEOR_GEO_YUV_9 ) + bktr->format |= METEOR_GEO_YUV_9; +*/ + + 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); + btl_reg = (u_long *) &bt848[BKTR_INT_STAT]; + *btl_reg = *btl_reg; + bts_reg = (u_short *)&bt848[BKTR_GPIO_DMA_CTL]; + *bts_reg = 0x1; + *bts_reg = bktr->capcontrol; + btl_reg = (u_long *) &bt848[BKTR_INT_MASK]; + *btl_reg = 1 << 23 | 2 | 1; + } + } + + break; + default: +#if 0 +/* XXX */ + error = ENOTTY; + break; +#else + return ENODEV; +#endif /* 0 */ + } + + return 0; +} + + +/* + * + */ +int +bktr_mmap( dev_t dev, int offset, int nprot ) +{ + int unit; + bktr_reg_t *bktr; + + unit = UNIT(minor(dev)); + + if (unit >= NBKTR) /* at this point could this happen? */ + return(-1); + + bktr = &(brooktree[unit]); + + if (nprot & PROT_EXEC) + return -1; + + if (offset >= bktr->alloc_pages * PAGE_SIZE) + return -1; + + return i386_btop(vtophys(bktr->bigbuf) + offset); +} + + +/****************************************************************************** + * tuner specific routines: + */ + +/** XXX FIXME: this should be a kernel option */ +#define IF_FREQUENCY 4575 /* M/N IF frequency */ + +/* guaranteed address for any TSA5522 */ +#define TSA5522_WADDR 0xc2 +#define TSA5522_RADDR 0xc3 + +/* + * bit 7: CONTROL BYTE = 1 + * bit 6: CP = 0 moderate speed tuning, better FM + * bit 5: T2 = 0 normal operation + * bit 4: T1 = 0 normal operation + * bit 3: T0 = 1 normal operation + * bit 2: RSA = 1 62.5kHz + * bit 1: RSB = 1 62.5kHz + * bit 0: OS = 0 normal operation + */ +#define TSA5522_CONTROL 0x8e + +#if defined( TEMIC_TUNER ) + +#define TSA5522_BANDA 0x02 +#define TSA5522_BANDB 0x04 +#define TSA5522_BANDC 0x01 + +#elif defined( PHILIPS_TUNER ) + +#define TSA5522_BANDA 0xa0 +#define TSA5522_BANDB 0x90 +#define TSA5522_BANDC 0x30 + +#else + +#error you must define a tuner type + +#endif /* XXXXXX_TUNER */ + +/* scaling factor for frequencies expressed as ints */ +#define FREQFACTOR 100 + + +/******************************* i2c primitives ******************************/ + +/* delays for the I2C bus transactions */ +#define NDELAY 0 +#if defined ( ORIGINAL_DELAYS ) +#define SDELAY 2 +#define LDELAY 20 +#else +#define SDELAY 10 +#define LDELAY 40 +#endif /* ORIGINAL_DELAYS */ + +/* macros to show the details more clearly */ +typedef volatile u_long* i2c_regptr_t; + +/* + * primitives for the I2C clock phases + */ +static inline void +DataLo_ClockLo( i2c_regptr_t bti2c, int delay ) +{ + *bti2c = 0; + if ( delay ) + DELAY( delay ); +} +static inline void +DataHi_ClockLo( i2c_regptr_t bti2c, int delay ) +{ + *bti2c = 1; + if ( delay ) + DELAY( delay ); +} + +static inline void +DataLo_ClockHi( i2c_regptr_t bti2c, int delay ) +{ + *bti2c = 2; + if ( delay ) + DELAY( delay ); +} + +static inline void +DataHi_ClockHi( i2c_regptr_t bti2c, int delay ) +{ + *bti2c = 3; + if ( delay ) + DELAY( delay ); +} + +static inline int +DataRead( i2c_regptr_t bti2c ) +{ + return ( *bti2c & 1 ); +} + + +/* forward reference */ +static int i2cWrite( i2c_regptr_t, u_char ); + +/* + * start an I2C bus transaction + */ +static void +i2cStart( i2c_regptr_t bti2c, int address ) +{ + +#if 1 + /* ensure the proper starting state */ + DataHi_ClockLo( bti2c, LDELAY ); /* release data */ + DataHi_ClockHi( bti2c, LDELAY ); /* release clock */ +#endif + DataLo_ClockHi( bti2c, LDELAY ); /* lower data */ + DataLo_ClockLo( bti2c, LDELAY ); /* lower clock */ + + /* send the address of the device */ + i2cWrite( bti2c, address ); +} + +/* + * stop an I2C bus transaction + */ +static void +i2cStop( i2c_regptr_t bti2c ) +{ + DataLo_ClockLo( bti2c, LDELAY ); /* lower clock & data */ + DataLo_ClockHi( bti2c, LDELAY ); /* release clock */ + DataHi_ClockHi( bti2c, LDELAY ); /* release data */ +} + +/* + * place a '1' bit on the I2C bus + */ +static void +i2cHi( i2c_regptr_t bti2c ) +{ + DataHi_ClockLo( bti2c, LDELAY ); /* assert HI data */ + DataHi_ClockHi( bti2c, LDELAY ); /* strobe clock */ + DataHi_ClockLo( bti2c, LDELAY ); /* release clock */ +} + +/* + * place a '0' bit on the I2C bus + */ +static void +i2cLo( i2c_regptr_t bti2c ) +{ + DataLo_ClockLo( bti2c, LDELAY ); /* assert LO data */ + DataLo_ClockHi( bti2c, LDELAY ); /* strobe clock */ + DataLo_ClockLo( bti2c, LDELAY ); /* release clock */ +} + +/* + * give an 'ACK' to the slave + */ +static void +i2cGrantAck( i2c_regptr_t bti2c ) +{ + DataLo_ClockLo( bti2c, LDELAY ); /* assert LO data */ + DataLo_ClockHi( bti2c, LDELAY ); /* strobe clock */ + DataLo_ClockLo( bti2c, LDELAY ); /* remove clock */ + DataHi_ClockLo( bti2c, NDELAY ); /* float data */ +} + +/* + * get an 'ACK' from the slave + */ +static int +i2cAck( i2c_regptr_t bti2c ) +{ + int acknowledge; + + DataHi_ClockLo( bti2c, LDELAY ); /* float data */ + DataHi_ClockHi( bti2c, LDELAY ); /* strobe clock */ + + acknowledge = DataRead( bti2c ); /* read ACK bit */ + + DataHi_ClockLo( bti2c, LDELAY ); /* release clock */ + + return acknowledge; +} + +/* + * read a byte from the I2C bus + */ +static int +i2cRead( i2c_regptr_t bti2c ) +{ + int x; + int byte; + + DataHi_ClockLo( bti2c, SDELAY ); /* float data */ + + for ( byte = 0, x = 7; x >= 0; --x ) { + DataHi_ClockHi( bti2c, SDELAY ); /* strobe clock */ + + if ( DataRead( bti2c ) ) /* read data */ + byte |= (1<= 0; --x ) + (byte & (1<base[ BKTR_I2C_CONTROL ] + +/* + * set the frequency of the tuner + */ +static int +tv_freq( bktr_reg_t* bktr, int frequency ) +{ + i2c_regptr_t bti2c; + u_char band; + int N; + int order; + + /* select the band based on frequency */ + if ( frequency < (160 * FREQFACTOR) ) + band = TSA5522_BANDA; + else if ( frequency < (454 * FREQFACTOR) ) + band = TSA5522_BANDB; + else + band = TSA5522_BANDC; + + /* + * N = 16 * { fRF(pc) + fIF(pc) } + * where: + * pc is picture carrier, fRF & fIF are in mHz + * + * frequency is mHz to 2 decimal places, ie. 5525 == 55.25 mHz, + * dont want to do float in a driver! + */ + N = 16 * ((frequency + IF_FREQUENCY) / FREQFACTOR); + + /* get the i2c register address */ + bti2c = I2C_REGADDR(); + + /* send the data to the TSA5522 */ + disable_intr(); + i2cStart( bti2c, TSA5522_WADDR ); + + /* the data sheet wants the order set according to direction */ + if ( frequency > bktr->tuner.frequency ) { + i2cWrite( bti2c, (N >> 8) & 0x7f ); /* divisor MSB */ + i2cWrite( bti2c, N & 0xff ); /* divisor LSB */ + i2cWrite( bti2c, TSA5522_CONTROL ); /* control bits */ + i2cWrite( bti2c, band ); /* band select */ + } + else { + i2cWrite( bti2c, TSA5522_CONTROL ); /* control bits */ + i2cWrite( bti2c, band ); /* band select */ + i2cWrite( bti2c, (N >> 8) & 0x7f ); /* divisor MSB */ + i2cWrite( bti2c, N & 0xff ); /* divisor LSB */ + } + + i2cStop( bti2c ); + enable_intr(); + + return 0; +} + + +/* + * North American Broadcast Channels: + * + * IF freq: 45.75 mHz + * + * Chnl Freq + * 2 55.25 mHz + * 3 61.25 mHz + * 4 67.25 mHz + * + * 5 77.25 mHz + * 6 83.25 mHz + * + * 7 175.25 mHz + * 13 211.25 mHz + * + * 14 471.25 mHz + * 83 885.25 mHz + */ +static int +frequency_nabcst( int channel ) +{ + /* legal channels are 2 thru 83 */ + if ( channel > 83 ) + return -1; + + /* channels 14 thru 83 */ + if ( channel >= 14 ) + return 47125 + ((channel-14) * 600 ); + + /* channels 7 thru 13 */ + if ( channel >= 7 ) + return 17525 + ((channel-7) * 600 ); + + /* channels 5 thru 6 */ + if ( channel >= 5 ) + return 7725 + ((channel-5) * 600 ); + + /* channels 2 thru 4 */ + if ( channel >= 2 ) + return 5525 + ((channel-2) * 600 ); + + /* legal channels are 2 thru 83 */ + return -1; +} + + +/* + * North American Cable Channels, IRC(?): + * + * IF freq: 45.75 mHz + * + * Chnl Freq + * 2 55.25 mHz + * 3 61.25 mHz + * 4 67.25 mHz + * + * 5 77.25 mHz + * 6 83.25 mHz + * + * 7 175.25 mHz + * 13 211.25 mHz + * + * 14 121.25 mHz + * 22 169.25 mHz + * + * 23 217.25 mHz + * 94 643.25 mHz + * + * 95 91.25 mHz + * 99 115.25 mHz + */ +static int +frequency_irccable( int channel ) +{ + /* legal channels are 2 thru 99 */ + if ( channel > 99 ) + return -1; + + /* channels 95 thru 99 */ + if ( channel >= 95 ) + return 9125 + ((channel-95) * 600 ); + + /* channels 23 thru 94 */ + if ( channel >= 23 ) + return 21725 + ((channel-23) * 600 ); + + /* channels 14 thru 22 */ + if ( channel >= 14 ) + return 12125 + ((channel-14) * 600 ); + + /* channels 7 thru 13 */ + if ( channel >= 7 ) + return 17525 + ((channel-7) * 600 ); + + /* channels 5 thru 6 */ + if ( channel >= 5 ) + return 7725 + ((channel-5) * 600 ); + + /* channels 2 thru 4 */ + if ( channel >= 2 ) + return 5525 + ((channel-2) * 600 ); + + /* legal channels are 2 thru 99 */ + return -1; +} + + +/* + * set the channel of the tuner + */ +static int +tv_channel( bktr_reg_t* bktr, int channel ) +{ + int frequency, status; + + /* calculate the frequency according to tuner type */ + switch ( bktr->tuner.tunertype ) { + case TUNERTYPE_NABCST: + frequency = frequency_nabcst( channel ); + break; + + case TUNERTYPE_CABLEIRC: + frequency = frequency_irccable( channel ); + break; + + /* FIXME: */ + case TUNERTYPE_CABLEHRC: + case TUNERTYPE_WEUROPE: + default: + return -1; + } + + /* check the result of channel to frequency conversion */ + if ( frequency < 0 ) + return -1; + + /* set the new frequency */ + if ( tv_freq( bktr, frequency ) < 0 ) + return -1; + + /* OK to update records */ + bktr->tuner.frequency = frequency; + bktr->tuner.channel = channel; + + return channel; +} + + +/* + * set the channel of the tuner + */ +static int +tuner_status( bktr_reg_t* bktr ) +{ + i2c_regptr_t bti2c; + int status; + + /* get the i2c register address */ + bti2c = I2C_REGADDR(); + + /* send the request to the TSA5522 */ + disable_intr(); + i2cStart( bti2c, TSA5522_RADDR ); + + status = i2cRead( bti2c ); + + i2cStop( bti2c ); + enable_intr(); + + return status; +} + + +/* + * + */ +static bktr_devsw_installed = 0; + +static void +bktr_drvinit( void *unused ) +{ + dev_t dev; + + if ( ! bktr_devsw_installed ) { + dev = makedev(CDEV_MAJOR, 0); + cdevsw_add(&dev,&bktr_cdevsw, NULL); + bktr_devsw_installed = 1; + } +} + +SYSINIT(bktrdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,bktr_drvinit,NULL) + +#endif /* NBKTR > 0 */ diff --git a/sys/dev/bktr/bktr_reg.h b/sys/dev/bktr/bktr_reg.h new file mode 100644 index 000000000000..b3b19c004102 --- /dev/null +++ b/sys/dev/bktr/bktr_reg.h @@ -0,0 +1,188 @@ +/* + * 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. + * + * $Id$ + */ +#ifndef PCI_LATENCY_TIMER +#define PCI_LATENCY_TIMER 0x0c /* pci timer register */ +#endif + +/* + * Definitions for the Philips SAA7116 digital video to pci interface. + */ +#define BROOKTREE_848_ID 0x0350109E + +typedef volatile u_int breg_t; + + +#define BKTR_DSTATUS 0x000 +#define BKTR_IFORM 0x004 +#define BKTR_TDEC 0x008 +#define BKTR_EVEN_CROP 0x00C +#define BKTR_ODD_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_CONTROL 0x110 + + +/* + * device support for onboard tv tuners + */ +struct tvtuner { + int frequency; + u_char tunertype; + u_char channel; + u_char band; +}; + + +/* + * BrookTree 848 info structure, one per bt848 card installed. + */ +typedef struct bktr_softc { + char * base; /* saa7116 register physical address */ + vm_offset_t phys_base; /* saa7116 register physical address */ + pcici_t tag; /* PCI tag, for doing PCI commands */ + vm_offset_t bigbuf; /* buffer that holds the captured image */ + int alloc_pages; /* number of pages in bigbuf */ + struct proc *proc; /* process to receive raised signal */ + int signal; /* signal to send to process */ +#define METEOR_SIG_MODE_MASK 0xffff0000 +#define METEOR_SIG_FIELD_MODE 0x00010000 +#define METEOR_SIG_FRAME_MODE 0x00000000 + vm_offset_t dma_prog; + vm_offset_t odd_dma_prog; + 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 */ + short depth; /* number of byte per pixel */ + 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 */ + unsigned 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 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_short fps; /* frames per second */ +#ifdef DEVFS + void *devfs_token; +#endif + struct meteor_video video; + struct tvtuner tuner; +} bktr_reg_t; + + diff --git a/sys/dev/bktr/ioctl_bt848.h b/sys/dev/bktr/ioctl_bt848.h new file mode 100644 index 000000000000..159a764b9826 --- /dev/null +++ b/sys/dev/bktr/ioctl_bt848.h @@ -0,0 +1,34 @@ +/* + * extensions to ioctl_meteor.h for the bt848 cards + * + * $Id$ + */ + +/* + * tuner types for the + */ +#define TUNERTYPE_NABCST 1 +#define TUNERTYPE_CABLEIRC 2 +#define TUNERTYPE_CABLEHRC 3 +#define TUNERTYPE_WEUROPE 4 + + +/* + * XXX: this is a hack, should be in ioctl_meteor.h + * here to avoid touching that file for now... + */ +#define TVTUNER_SETCHNL _IOW('x', 32, unsigned int) /* set channel */ +#define TVTUNER_GETCHNL _IOR('x', 32, unsigned int) /* get channel */ +#define TVTUNER_SETTYPE _IOW('x', 33, unsigned int) /* set tuner type */ +#define TVTUNER_GETTYPE _IOR('x', 33, unsigned int) /* get tuner type */ +#define TVTUNER_GETSTATUS _IOR('x', 34, unsigned int) /* get tuner status */ + + +/* + * XXX: more bad magic, + * we need to fix the METEORGINPUT to return something public + * duplicate them here for now... + */ +#define METEOR_DEV0 0x00001000 +#define METEOR_DEV1 0x00002000 +#define METEOR_DEV2 0x00004000 diff --git a/sys/i386/conf/files.i386 b/sys/i386/conf/files.i386 index 41235be1b991..635483c170ec 100644 --- a/sys/i386/conf/files.i386 +++ b/sys/i386/conf/files.i386 @@ -1,7 +1,7 @@ # This file tells config what files go into building a kernel, # files marked standard are always included. # -# $Id$ +# $Id: files.i386,v 1.152 1997/02/22 09:31:42 peter Exp $ # aic7xxx_asm optional ahc device-driver \ dependency "$S/dev/aic7xxx/aic7xxx_asm.c" \ @@ -276,4 +276,5 @@ gnu/i386/fpemul/wm_sqrt.s optional gpl_math_emulate gnu/i386/isa/dgb.c optional dgb device-driver gnu/i386/isa/nic3008.c optional nic device-driver gnu/i386/isa/nic3009.c optional nnic device-driver +pci/brooktree848.c optional bktr device-driver pci/wd82371.c optional wd device-driver diff --git a/sys/i386/include/ioctl_bt848.h b/sys/i386/include/ioctl_bt848.h new file mode 100644 index 000000000000..159a764b9826 --- /dev/null +++ b/sys/i386/include/ioctl_bt848.h @@ -0,0 +1,34 @@ +/* + * extensions to ioctl_meteor.h for the bt848 cards + * + * $Id$ + */ + +/* + * tuner types for the + */ +#define TUNERTYPE_NABCST 1 +#define TUNERTYPE_CABLEIRC 2 +#define TUNERTYPE_CABLEHRC 3 +#define TUNERTYPE_WEUROPE 4 + + +/* + * XXX: this is a hack, should be in ioctl_meteor.h + * here to avoid touching that file for now... + */ +#define TVTUNER_SETCHNL _IOW('x', 32, unsigned int) /* set channel */ +#define TVTUNER_GETCHNL _IOR('x', 32, unsigned int) /* get channel */ +#define TVTUNER_SETTYPE _IOW('x', 33, unsigned int) /* set tuner type */ +#define TVTUNER_GETTYPE _IOR('x', 33, unsigned int) /* get tuner type */ +#define TVTUNER_GETSTATUS _IOR('x', 34, unsigned int) /* get tuner status */ + + +/* + * XXX: more bad magic, + * we need to fix the METEORGINPUT to return something public + * duplicate them here for now... + */ +#define METEOR_DEV0 0x00001000 +#define METEOR_DEV1 0x00002000 +#define METEOR_DEV2 0x00004000 diff --git a/sys/pci/README.bt848 b/sys/pci/README.bt848 new file mode 100644 index 000000000000..ec3aa5afa4e2 --- /dev/null +++ b/sys/pci/README.bt848 @@ -0,0 +1,52 @@ +------------------------------------------------------------------------------- +There are 3 files necessary for the bt848 driver: + +src/sys/i386/include/ioctl_bt848.h +src/sys/pci/brktree_reg.h +src/sys/pci/brooktree848.c + +Note that src/sys/i386/include/ioctl_meteor.h is no longer modifed in any way +to support the bt848 boards (unless there were prio modifications that I am +unaware of). + +------------------------------------------------------------------------------- +There are 2 settings that you need to make based on the type of card you have. + +-- +1: + +First, you need include code to support specific tuners. Once we add +auto-probe code to detect tuner types this can go away. + +The STB card has a TEMIC tuner, others(?) have the PHILIPS tuner. Check +the label on the metal can to be sure! + +In your kernel config file set ONE of: + +options TEMIC_TUNER # STB TV PCI +options PHILIPS_TUNER # WinCast/TV + +Or, in pci/brooktree848.c, you can define ONE of: + +#define TEMIC_TUNER +#define PHILIPS_TUNER + +PHILIPS_TUNER is the default if you don't do one of the above. + +-- +2: + +These options select the set of frequencies used by the tuner. In your +kernel config file set ONE of: + +options DEFAULT_TUNERTYPE=1 # TUNERTYPE_NABCST +options DEFAULT_TUNERTYPE=2 # TUNERTYPE_CABLEIRC + +Or, in pci/brooktree848.c, you can define ONE of: + +#define DEFAULT_TUNERTYPE TUNERTYPE_NABCST +#define DEFAULT_TUNERTYPE TUNERTYPE_CABLEIRC + +TUNERTYPE_NABCST (North American Broadcast frequencies) is the default. +TUNERTYPE_CABLEIRC selects the IRC cable frequencies. +Subroutines for other frequencies are yet to be written. diff --git a/sys/pci/brktree_reg.h b/sys/pci/brktree_reg.h new file mode 100644 index 000000000000..b3b19c004102 --- /dev/null +++ b/sys/pci/brktree_reg.h @@ -0,0 +1,188 @@ +/* + * 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. + * + * $Id$ + */ +#ifndef PCI_LATENCY_TIMER +#define PCI_LATENCY_TIMER 0x0c /* pci timer register */ +#endif + +/* + * Definitions for the Philips SAA7116 digital video to pci interface. + */ +#define BROOKTREE_848_ID 0x0350109E + +typedef volatile u_int breg_t; + + +#define BKTR_DSTATUS 0x000 +#define BKTR_IFORM 0x004 +#define BKTR_TDEC 0x008 +#define BKTR_EVEN_CROP 0x00C +#define BKTR_ODD_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_CONTROL 0x110 + + +/* + * device support for onboard tv tuners + */ +struct tvtuner { + int frequency; + u_char tunertype; + u_char channel; + u_char band; +}; + + +/* + * BrookTree 848 info structure, one per bt848 card installed. + */ +typedef struct bktr_softc { + char * base; /* saa7116 register physical address */ + vm_offset_t phys_base; /* saa7116 register physical address */ + pcici_t tag; /* PCI tag, for doing PCI commands */ + vm_offset_t bigbuf; /* buffer that holds the captured image */ + int alloc_pages; /* number of pages in bigbuf */ + struct proc *proc; /* process to receive raised signal */ + int signal; /* signal to send to process */ +#define METEOR_SIG_MODE_MASK 0xffff0000 +#define METEOR_SIG_FIELD_MODE 0x00010000 +#define METEOR_SIG_FRAME_MODE 0x00000000 + vm_offset_t dma_prog; + vm_offset_t odd_dma_prog; + 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 */ + short depth; /* number of byte per pixel */ + 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 */ + unsigned 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 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_short fps; /* frames per second */ +#ifdef DEVFS + void *devfs_token; +#endif + struct meteor_video video; + struct tvtuner tuner; +} bktr_reg_t; + + diff --git a/sys/pci/brooktree848.c b/sys/pci/brooktree848.c new file mode 100644 index 000000000000..c482b666e23c --- /dev/null +++ b/sys/pci/brooktree848.c @@ -0,0 +1,2442 @@ +/* BT848 1.3-ALPHA Driver for Brooktree's Bt848 based cards. + 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. For starters, the BT848 is a one chipset solution and + it incorporates a RISC engine to control the DMA transfers -- + that is it the actual dma process is control by a program which + resides in the hosts memory also the register definitions between + the Philips chipsets and the Bt848 are very different. + + The original copyright notice by Mark and Jim is included mostly + to honor their fantastic work in the Matrox Meteor driver! + + Enjoy, + Amancio + + $Id$ + */ + +/* + * 1. Redistributions of source code must retain the + * Copyright (c) 1997 Amancio Hasty + * 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 + * 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. + */ + +/* Change History: +1.0 1/24/97 First Alpha release + +1.1 2/20/97 Added video ioctl so we can do PCI To PCI + data transfers. This is for capturing data + directly to a vga frame buffer which has + a linear frame buffer. Minor code clean-up. + +1.3 2/23/97 Fixed system lock-up reported by + Randall Hopper . This + problem seems somehow to be exhibited only + in his system. I changed the setting of + INT_MASK for CAP_CONTINUOUS to be exactly + the same as CAP_SINGLE apparently setting + bit 23 cleared the system lock up. + version 1.1 of the driver has been reported + to work with STB's WinTv, Hauppage's Wincast/Tv + and last but not least with the Intel Smart + Video Recorder. + +1.4 3/9/97 Merged code to support tuners on STB and WinCast + cards. + Modifications to the contrast and chroma ioctls. + Textual cleanup. +*/ + +#include "bktr.h" + +#if NBKTR > 0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef DEVFS +#include +#endif /* DEVFS */ +#include + +#include +#include +#include +#include +#include + +/* + * XXX: include code to support specific tuners. + * once we add auto-probe code to detect tuner types this can go away. + * + * the STB card has a TEMIC tuner, others(?) have the PHILIPS tuner. + * check the label on the metal can to be sure! + * + * in your kernel config file set one of: +options TEMIC_TUNER # STB TV PCI +options PHILIPS_TUNER # WinCast/TV + * + * alternately, in this file, you can select one of: + * +#define TEMIC_TUNER +#define PHILIPS_TUNER + */ +#if !defined( TEMIC_TUNER ) && !defined( PHILIPS_TUNER ) +#define PHILIPS_TUNER +#endif + +/* + * XXX: the 'options' aspect of this is a REAL KLUDGE, fix it! + * XXX: we need to support additional sets of frequencies. + * + * this selects the set of frequencies used by the tuner. + * in your kernel config file set one of: +options DEFAULT_TUNERTYPE=1 # TUNERTYPE_NABCST +options DEFAULT_TUNERTYPE=2 # TUNERTYPE_CABLEIRC + * + * alternately, in this file, you can select one of: + * +#define DEFAULT_TUNERTYPE TUNERTYPE_NABCST +#define DEFAULT_TUNERTYPE TUNERTYPE_CABLEIRC + */ +#if !defined( DEFAULT_TUNERTYPE ) +#define DEFAULT_TUNERTYPE TUNERTYPE_NABCST +#endif + +/* + * XXX: hack to allow multiple programs to open the device, + * ie., a tv client and a remote control + * we need to make this a MINOR UNIT type thing someday... + */ +#define MULTIPLE_OPENS + + +#include "pci.h" +#if NPCI > 0 + +#include +#include +#endif + +#include +#include /* extensions to ioctl_meteor.h */ +#include + +/* + * tuner specific functions + */ +static int tv_channel __P(( bktr_reg_t* bktr, int channel )); +static int tuner_status __P(( bktr_reg_t* bktr )); + + +#define METPRI (PZERO+8)|PCATCH + +static void bktr_intr __P((void *arg)); +static bt_enable_cnt; +static u_long btl_status_prev; +/* + * Allocate enough memory for: + * 768x576 RGB 16 or YUV (16 storage bits/pixel) = 884736 = 216 pages + * + * You may override this using the options "METEOR_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) + +static bktr_reg_t brooktree[NBKTR]; +#define BROOKTRE_NUM(mtr) ((bktr - &brooktree[0])/sizeof(bktr_reg_t)) + +#define BKTRPRI (PZERO+8)|PCATCH + +static char* bktr_probe (pcici_t tag, pcidi_t type); +static void bktr_attach(pcici_t tag, int unit); +int dump_bt848( volatile u_char *bt848 ); + +void yuvpack_prog( bktr_reg_t * bktr, char i_flag, int cols, + int rows, int interlace) ; + +void yuv422_prog( bktr_reg_t * bktr, char i_flag, int cols, + int rows, int interlace); +void rgb_prog( bktr_reg_t * bktr, char i_flag, int cols, + int rows, int pixel_width, int interlace) ; +void start_capture(bktr_reg_t *bktr, unsigned type); +void build_dma_prog( bktr_reg_t * bktr, char i_flag); + +static u_long bktr_count; + +static struct pci_device bktr_device = { + "bktr", + bktr_probe, + bktr_attach, + &bktr_count +}; + +DATA_SET (pcidevice_set, bktr_device); + +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; + +#define CDEV_MAJOR 79 +static struct cdevsw bktr_cdevsw = +{ + bktr_open, bktr_close, bktr_read, bktr_write, + bktr_ioctl, nostop, nullreset, nodevtotty, + seltrue, bktr_mmap, NULL, "bktr", + NULL, -1 +}; + + +/* + * + */ +static char* +bktr_probe( pcici_t tag, pcidi_t type ) +{ + switch (type) { + case BROOKTREE_848_ID: + return("BrookTree 848"); + }; + + return ((char *)0); +} + + +/* + * interrupt handling routine complete meteor_read() if using interrupts + */ +static void +bktr_intr( void *arg ) +{ + bktr_reg_t *bktr = (bktr_reg_t *) arg; + volatile u_long *btl_reg, t_pc; + volatile u_char *bt848, *bt_reg, s_status; + volatile u_short *bts_reg; + u_long bktr_status, *bktr_pc; + +#if 0 +/* XXX: what is this for??? */ + u_long next_base = (u_long)(vtophys(bktr->bigbuf)), stat; +#endif + + bt848 = bktr->base; + bt_reg = (u_char *) &bt848; + s_status = *bt_reg; + *bt_reg = 0; + + if (!(bktr->flags & METEOR_OPEN)) { + bts_reg = (u_short *) &bt848[BKTR_GPIO_DMA_CTL]; + *bts_reg = 0; + btl_reg = (u_long *) &bt848[BKTR_INT_MASK]; + *btl_reg = 0; + } + + btl_reg = (u_long *) &bt848[BKTR_INT_STAT]; + bktr_status = *btl_reg ; + *btl_reg = *btl_reg; + *btl_reg = 0; + if (*btl_reg & (1 << 25)) + *btl_reg |= 1 << 8; + bktr_pc = (u_long *) &bt848[BKTR_RISC_COUNT]; + t_pc = *bktr_pc; + + /* printf(" STATUS %x %x %x \n", s_status, bktr_status, t_pc); */ + + if (!((bktr_status & 0x800) || (bktr_status & 1 << 19 ))) { + btl_status_prev = bktr_status; + /* return; */ + } + + /* if risc was disabled re-start process again */ + if (!(bktr_status & (1 << 27)) || ((bktr_status & 0xfe000) != 0) ) { + + btl_reg = (u_long *) &bt848[BKTR_INT_STAT]; + *btl_reg = *btl_reg; + + bts_reg = (u_short *) &bt848[BKTR_GPIO_DMA_CTL]; + *bts_reg = 0; + + btl_reg = (u_long *) &bt848[BKTR_INT_MASK]; + *btl_reg = 0; + + btl_reg = (u_long *) &bt848[BKTR_RISC_STRT_ADD] ; + *btl_reg = vtophys(bktr->dma_prog); + + bts_reg = (u_short *) &bt848[BKTR_GPIO_DMA_CTL]; + *bts_reg = 1; + *bts_reg = bktr->capcontrol; + + btl_reg = (u_long *) &bt848[BKTR_INT_MASK]; + *btl_reg = 1 << 23 | 1 << 11 | 2 | 1; + + return; + } + + btl_reg = (u_long *) &bt848[BKTR_CAP_CTL]; + if (!(bktr_status & (1 << 11))) return; + + bktr_pc = (u_long *) &bt848[BKTR_RISC_COUNT]; + + /*printf("intr status %x %x %x\n", bktr_status, s_status, *bktr_pc);*/ + + /* + * 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)) + *btl_reg = 0; + + /* + * 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) { + + if (!(bktr_status & (1 << 24))) + return; + + /* stop dma */ + btl_reg = (u_long *) &bt848[BKTR_INT_MASK]; + *btl_reg = 0; + bts_reg = (u_short *) &bt848[BKTR_GPIO_DMA_CTL]; + *bts_reg = 1; /* disable risc and fifo */ + wakeup((caddr_t)bktr); + } + + /* + * If the user requested to be notified via signal, + * let them know the frame is complete. + */ + if (bktr->proc && !(bktr->signal & METEOR_SIG_MODE_MASK)) + psignal(bktr->proc, bktr->signal&(~METEOR_SIG_MODE_MASK)); + + /* + * Reset the want flags if in continuous or + * synchronous capture mode. + */ + 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; +} + + +/* + * + */ +int +dump_bt848( volatile u_char *bt848 ) +{ + u_long *bt_long; + u_short *bt_short; + 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(" Reg:value : \t%x:%x \t%x:%x \t %x:%x \t %x:%x\n", + r[i], bt848[r[i]], + r[i+1], bt848[r[i+1]], + r[i+2], bt848[r[i+2]], + r[i+3], bt848[r[i+3]]); + } + + bt_long = (u_long *) &bt848[BKTR_INT_STAT]; + printf(" Reg 100 %x \n", *bt_long); + + bt_long = (u_long *) &bt848[BKTR_INT_MASK]; + printf(" Reg 104 %x \n", *bt_long); + + bt_long = (u_long *) &bt848[BKTR_GPIO_DMA_CTL]; + printf(" Reg 10C %x \n", *bt_long); + + return 0; +} + + +/* + * build write instruction + */ +#define BKTR_FM1 0x6 +#define BKTR_FM3 0xe +#define BKTR_VRE 0x4 +#define BKTR_VRO 0xC +#define BKTR_PXV 0x0 +#define BKTR_EOL 0x1 +#define BKTR_SOL 0x2 + +#define OP_WRITE 0x1 << 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 +#define OP_EOL 1 << 26 + +void +rgb_prog( bktr_reg_t * bktr, char i_flag, int cols, + int rows, int pixel_width, int interlace ) +{ + int i; + int byte_count; + volatile unsigned int inst; + volatile unsigned int inst2; + volatile unsigned int inst3; + volatile u_long target_buffer, buffer; + volatile u_char *bt848, *bt_reg; + volatile u_short *bts_reg; + volatile u_long pitch; + volatile u_long *dma_prog, *foo, *btl_reg, *t_test; + int b, c; + + bt848 = bktr->base; + + /* color format : rgb32 */ + if (bktr->depth == 4) + bt848[BKTR_COLOR_FMT] = 0; + else + bt848[BKTR_COLOR_FMT] = 0x33; + + bt848[BKTR_COLOR_CTL] = 0x40; + bt848[BKTR_COLOR_CTL] = 0x10; + +#if 0 + bt848[0x10] = 0x1C; + bt848[0x90] = 0x1C; +#endif + + bt848[BKTR_VBI_PACK_SIZE] = 0; + bt848[BKTR_VBI_PACK_DEL] = 0; + + bt848[BKTR_ADC] = 0x81; + bt848[BKTR_COLOR_CTL] = 0x20; + + bt848[BKTR_E_VSCALE_HI] |= 0xc0; + bt848[BKTR_O_VSCALE_HI] |= 0xc0; + + bktr->capcontrol = 3 << 2 | 3; + + dma_prog = (u_long *) bktr->dma_prog; + + /* Construct Write */ + bt_enable_cnt = 0; + + b = (cols * pixel_width ) / 2; + + /* write, sol, eol */ + inst = OP_WRITE | OP_SOL | bt_enable_cnt << 12 | (b); + inst2 = OP_WRITE | bt_enable_cnt << 12 | (cols * pixel_width/2); + /* write , sol, eol */ + inst3 = OP_WRITE | OP_EOL | bt_enable_cnt << 12 | (b); + + 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*pixel_width; + } + + buffer = target_buffer; + + /* contruct sync : for video packet format */ + *dma_prog++ = OP_SYNC | 0xC << 24 | 1 << 15 | BKTR_FM1; + + /* sync, mode indicator packed data */ + *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*pitch; + } + + switch (i_flag) { + case 1: + /* sync vre */ + *dma_prog++ = OP_SYNC | 0xC << 24 | 1 << 24 | BKTR_VRE; + *dma_prog++ = 0; /* NULL WORD */ + + *dma_prog++ = OP_JUMP | 0xC << 24; + *dma_prog++ = (u_long ) vtophys(bktr->dma_prog); + return; + + case 2: + /* sync vre */ + *dma_prog++ = OP_SYNC | 1 << 24 | 1 << 20 | BKTR_VRO; + *dma_prog++ = 0; /* NULL WORD */ + + *dma_prog++ = OP_JUMP; + *dma_prog++ = (u_long ) vtophys(bktr->dma_prog); + return; + + case 3: + /* sync vre */ + *dma_prog++ = OP_SYNC | 0xC << 24 | 1 << 24 | 1 << 15 | BKTR_VRO; + *dma_prog++ = 0; /* NULL WORD */ + *dma_prog++ = OP_JUMP | 0xc << 24 ; + *dma_prog = (u_long ) vtophys(bktr->odd_dma_prog); + break; + } + + if (interlace == 2) { + + target_buffer = (u_long) buffer + pitch; + + dma_prog = (u_long *) bktr->odd_dma_prog; + + /* sync vre IRQ bit */ + *dma_prog++ = OP_SYNC | 0xc << 24 | 1 << 15 | 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 * pitch; + } + } + + /* sync vre IRQ bit */ + *dma_prog++ = OP_SYNC | 0xc << 24 | 1 << 24 | 1 << 15 | BKTR_VRE; + *dma_prog++ = 0; /* NULL WORD */ + *dma_prog++ = OP_JUMP | 0xc << 24; + *dma_prog++ = (u_long ) vtophys(bktr->dma_prog) ; + *dma_prog++ = 0; /* NULL WORD */ +} + + +/* + * + */ +void +yuvpack_prog( bktr_reg_t *bktr, char i_flag, int cols, int rows, int interlace) +{ + int i; + int byte_count; + volatile unsigned int inst; + volatile unsigned int inst2; + volatile unsigned int inst3; + volatile u_long target_buffer, buffer; + volatile u_char *bt848, *bt_reg; + volatile u_short *bts_reg; + volatile u_long *dma_prog, *foo, *btl_reg; + int b; + + bt848 = bktr->base; + + /* color format : yuvpack */ + bt848[BKTR_COLOR_FMT] = 0x44; + + bt848[BKTR_E_SCLOOP] |= 0x40; /* enable chroma comb */ + bt848[BKTR_O_SCLOOP] |= 0x40; + + bt848[BKTR_COLOR_CTL] = 0x30; + bt848[BKTR_ADC] = 0x81; + + bktr->capcontrol = 1 << 6 | 1 << 4 | 1 << 2 | 3; + bktr->capcontrol = 1 << 5 | 1 << 4 | 1 << 2 | 3; + + dma_prog = (u_long *) bktr->dma_prog; + + /* Construct Write */ + bt_enable_cnt = 0; + + /* write , sol, eol */ + inst = OP_WRITE | OP_SOL | 0xf << 16 | bt_enable_cnt << 12 | (cols*2); + /* write , sol, eol */ + inst3 = OP_WRITE | OP_EOL | 0xf << 16 | bt_enable_cnt << 12 | (cols); + inst2 = OP_WRITE | bt_enable_cnt << 12 | (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 | 1 << 24 | 1 << 15 | 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 | 1 << 24 | BKTR_VRE; + *dma_prog++ = 0; /* NULL WORD */ + + *dma_prog++ = OP_JUMP; + *dma_prog++ = (u_long ) vtophys(bktr->dma_prog); + return; + + case 2: + /* sync vre */ + *dma_prog++ = OP_SYNC | 1 << 24 | 1 << 20 | BKTR_VRO; + *dma_prog++ = 0; /* NULL WORD */ + *dma_prog++ = OP_JUMP; + *dma_prog++ = (u_long ) vtophys(bktr->dma_prog); + return; + + case 3: + /* sync vre */ + *dma_prog++ = OP_SYNC | 1 << 24 | 0xf << 16 | BKTR_VRE; + *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 | 1 << 24 | 0xf << 16 | 1 << 15 | 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 vre IRQ bit */ + *dma_prog++ = OP_SYNC | 1 << 24 | 0xf << 16 | BKTR_VRO; + *dma_prog++ = 0; /* NULL WORD */ + *dma_prog++ = OP_JUMP | 0xf << 16; + *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 */ +} + + +/* + * + */ +void +yuv422_prog( bktr_reg_t * bktr, char i_flag, int cols, + int rows, int interlace) +{ + int i, j; + int byte_count; + volatile unsigned int inst; + volatile unsigned int inst2; + volatile unsigned int instskip, instskip2, instskip3; + volatile unsigned int inst3; + volatile u_long target_buffer, t1, buffer; + volatile u_char *bt848, *bt_reg; + volatile u_short *bts_reg; + volatile u_long *dma_prog, *foo, *btl_reg; + int b, b1; + + bt848 = bktr->base; + dma_prog = (u_long *) bktr->dma_prog; + + bktr->capcontrol = 1 << 6 | 1 << 4 | 3; + + bt848[BKTR_ADC] = 0x81 ; + bt848[BKTR_OFORM] = 0x00; + + bt848[BKTR_E_CONTROL] |= 0x20; /* disable luma decimation */ + bt848[BKTR_O_CONTROL] |= 0x20; + + bt848[BKTR_E_SCLOOP] |= 0x40; /* chroma agc enable */ + bt848[BKTR_O_SCLOOP] |= 0x40; + + bt848[BKTR_E_VSCALE_HI] |= 0xc0; /* luma comb and comb enable */ + bt848[BKTR_O_VSCALE_HI] |= 0xc0; + + bt848[BKTR_COLOR_FMT] = 0x88; + + bt848[BKTR_COLOR_CTL] = 0x10; /* disable gamma correction */ + + bt_enable_cnt = 0; + + /* Construct Write */ + inst = OP_WRITE123 | OP_SOL | OP_EOL | bt_enable_cnt << 12 | (cols); + inst2 = OP_WRITES123 | OP_SOL | OP_EOL | bt_enable_cnt << 12 | (cols); + + if (bktr->video.addr) + target_buffer = (u_long) bktr->video.addr; + else + target_buffer = (u_long) vtophys(bktr->bigbuf); + + buffer = target_buffer; + + t1 = target_buffer; + + /* contruct sync : for video packet format */ + *dma_prog++ = OP_SYNC | 0xC << 24 | 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 | 0xC << 24 | 1 << 24 | BKTR_VRE; /*sync vre*/ + *dma_prog++ = 0; /* NULL WORD */ + + *dma_prog++ = OP_JUMP | 0xc << 24; + *dma_prog++ = (u_long ) vtophys(bktr->dma_prog); + return; + break; + case 2: + *dma_prog++ = OP_SYNC | 0xC << 24 | 1 << 24 | BKTR_VRO; /*sync vre*/ + *dma_prog++ = 0; /* NULL WORD */ + + *dma_prog++ = OP_JUMP; + *dma_prog++ = (u_long ) vtophys(bktr->dma_prog); + return; + break; + case 3: + *dma_prog++ = OP_SYNC | 0xc << 24 | 1 << 15 | BKTR_VRO; + *dma_prog++ = 0; /* NULL WORD */ + + *dma_prog++ = OP_JUMP | 0xc << 24 ; + *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 = target_buffer + cols/2; + *dma_prog++ = OP_SYNC | 0xc << 24 | 1 << 24 | 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 | 0xC << 24 | 1 << 24 | BKTR_VRE; + *dma_prog++ = 0; /* NULL WORD */ + *dma_prog++ = OP_JUMP | 0xC << 24;; + *dma_prog++ = (u_long ) vtophys(bktr->dma_prog) ; + *dma_prog++ = 0; /* NULL WORD */ +} + + +/* + * + */ +void +build_dma_prog( bktr_reg_t * bktr, char i_flag) +{ + int i; + int pixel_width, rows, cols, byte_count, interlace; + volatile unsigned int inst; + volatile unsigned int inst2; + volatile unsigned int inst3; + volatile u_long target_buffer; + volatile u_char *bt848, *bt_reg; + volatile u_short *bts_reg; + volatile u_long * dma_prog, *foo, *btl_reg; + int b; + + bt848 = bktr->base; + btl_reg = (u_long *) &bt848[BKTR_INT_MASK] ; + *btl_reg = 0; + + bts_reg = (u_short * ) &bt848[BKTR_GPIO_DMA_CTL]; + *bts_reg &= ~3; + + /* capture control */ + switch (i_flag) { + case 1: + bt848[BKTR_CAP_CTL] = 0x11; + bt848[BKTR_E_VSCALE_HI] &= ~0x20; + bt848[BKTR_O_VSCALE_HI] &= ~0x20; + interlace = 1; + break; + case 2: + bt848[BKTR_CAP_CTL] = 0x12; + bt848[BKTR_E_VSCALE_HI] &= ~0x20; + bt848[BKTR_O_VSCALE_HI] &= ~0x20; + interlace = 1; + break; + default: + bt848[0xdc] = 0x13; + bt848[BKTR_E_VSCALE_HI] |= 0x20; + bt848[BKTR_O_VSCALE_HI] |= 0x20; + interlace = 2; + break; + } + + btl_reg = (u_long *) &bt848[BKTR_RISC_STRT_ADD] ; + *btl_reg = vtophys(bktr->dma_prog); + + pixel_width = bktr->depth; + rows = bktr->rows; + cols = bktr->cols; + + if (bktr->format == METEOR_GEO_RGB24 || + bktr->format == METEOR_GEO_RGB16) { + rgb_prog(bktr, i_flag, cols, rows, pixel_width, interlace); + return; + } + + if (bktr->format == METEOR_GEO_YUV_422 ){ + yuv422_prog(bktr, i_flag, cols, rows, interlace); + return; + } + + if (bktr->format == METEOR_GEO_YUV_PACKED ){ + yuvpack_prog(bktr, i_flag, cols, rows, interlace); + return; + } + + return; +} + + +/* + * + */ +void +start_capture(bktr_reg_t *bktr, unsigned type) +{ + volatile u_char * bt848, *bt_reg, i_flag; + volatile u_short *bts_reg; + volatile u_long *btl_reg; + bt848 = (u_char *) bktr->base; + + *bt848 = 0; + btl_reg = (u_long *) &bt848[BKTR_INT_STAT]; + *btl_reg = *btl_reg; + + bktr->flags |= type; + 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; + } + + if (!bktr->dma_prog_loaded) { + build_dma_prog(bktr, i_flag); + bktr->dma_prog_loaded = 1; + } + +/*XXX + switch(bktr->flags & METEOR_ONLY_FIELDS_MASK) { + default: + *bts_reg |= 0xb; + } +*/ + + btl_reg = (u_long *) &bt848[BKTR_RISC_STRT_ADD]; + *btl_reg = vtophys(bktr->dma_prog); + +/*XXX + bts_reg = (u_short *) &bt848[BKTR_GPIO_DMA_CTL]; + *bts_reg = 0x3; +*/ + +} + +/* + * + */ +static void +set_fps(bktr_reg_t *bktr, u_short fps) +{ + volatile u_char * bt848, *bt_reg; + volatile u_long * btl_reg; + volatile u_short * bts_reg; + bt848 = (u_char *) bktr->base; + + bts_reg = (u_short *) &bt848[BKTR_GPIO_DMA_CTL]; + *bts_reg = 0; + btl_reg = (u_long *) &bt848[BKTR_INT_STAT]; + *btl_reg = 0xffffffff; + + bktr->fps = fps; + + if ( fps == 30 ) { + bt848[BKTR_TDEC] = 0; + return; + } else { + bt848[BKTR_TDEC] = (int) (((float) fps / 30.0) * 60.0) & 0x3f; + bt848[BKTR_TDEC] |= 0x80; + } + + if ( bktr->flags & METEOR_CAP_MASK ) { + + btl_reg = (u_long *) &bt848[BKTR_INT_STAT]; + *btl_reg = 0xffffffff; + btl_reg = (u_long *) &bt848[BKTR_RISC_STRT_ADD]; + *btl_reg = vtophys(bktr->dma_prog); + + bts_reg = (u_short *) &bt848[BKTR_GPIO_DMA_CTL]; + *bts_reg = 1; + *bts_reg = bktr->capcontrol; + btl_reg = (u_long *) &bt848[BKTR_INT_MASK]; + *btl_reg = 1 << 11 | 2 | 1; + } + + return; + +} + + +/* + * There is also a problem with range checking on the 7116. + * It seems to only work for 22 bits, so the max size we can allocate + * is 22 bits long or 4194304 bytes assuming that we put the beginning + * of the buffer on a 2^24 bit boundary. The range registers will use + * the top 8 bits of the dma start registers along with the bottom 22 + * bits of the range register to determine if we go out of range. + * This makes getting memory a real kludge. + * + */ + +#define RANGE_BOUNDARY (1<<22) +static vm_offset_t +get_bktr_mem( int unit, unsigned size ) +{ + vm_offset_t addr = 0; + + addr = vm_page_alloc_contig(size, 0x100000, 0xffffffff, 1<<24); + if (addr == 0) + addr = vm_page_alloc_contig(size, 0x100000, 0xffffffff, + PAGE_SIZE); + if (addr == 0) { + printf("meteor%d: Unable to allocate %d bytes of memory.\n", + unit, size); + } + return addr; +} + + +/* + * Initialize the 7116, 7196 and the RGB module. + */ +static void +bktr_init ( bktr_reg_t *bktr ) +{ + return; +} + + +static void +bktr_attach( pcici_t tag, int unit ) +{ + bktr_reg_t *bktr; + volatile u_char *bt848; + volatile u_long *btl_reg; +#ifdef BROOKTREE_IRQ + u_long old_irq, new_irq; +#endif + u_char *test; + vm_offset_t buf; + u_long latency; + u_long foo,fun; + bt_enable_cnt = 0; + bktr = &brooktree[unit]; + if (unit >= NBKTR) { + printf("brooktree%d: attach: only %d units configured.\n", + unit, NBKTR); + printf("brooktree%d: attach: invalid unit number.\n", unit); + return ; + } + + + bktr->tag = tag; + pci_map_mem(tag, PCI_MAP_REG_START, (vm_offset_t *) &bktr->base, + &bktr->phys_base); + + fun = pci_conf_read(tag, PCI_COMMAND_STATUS_REG); + +#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 + /* setup the interrupt handling routine */ + pci_map_int(tag, bktr_intr, (void*) bktr, &net_imask); + +/* + * PCI latency timer. 32 is a good value for 4 bus mastering slots, if + * you have more than for, then 16 would probably be a better value. + * + */ +#ifndef BROOKTREE_DEF_LATENCY_VALUE +#define BROOKTREE_DEF_LATENCY_VALUE 10 +#endif + latency = pci_conf_read(tag, PCI_LATENCY_TIMER); + 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_conf_write(tag, PCI_LATENCY_TIMER, latency<<8); + } + if ( bootverbose ) { + printf(" %d.\n", latency); + } + + /* bktr_init(bktr); set up the bt848 */ + + /* allocate space for dma program */ + bktr->dma_prog = get_bktr_mem(unit, 8); + bktr->odd_dma_prog = get_bktr_mem(unit, 8); + if ( BROOKTREE_ALLOC ) + buf = get_bktr_mem(unit, BROOKTREE_ALLOC); + else + buf = 0; + + if ( bootverbose ) { + printf("bktr%d: buffer size %d, addr 0x%x\n", + unit, BROOKTREE_ALLOC, vtophys(buf)); + } + + bktr->bigbuf = buf; + bktr->alloc_pages = BROOKTREE_ALLOC_PAGES; + if ( buf != 0 ) { + bzero((caddr_t) buf, BROOKTREE_ALLOC); + buf = vtophys(buf); + +#ifdef amancio /* 640x480 RGB 16 */ + +amancio : setup dma risc program + bktr->base->dma1e = buf; + bktr->base->dma1o = buf + 0x500; + bktr->base->dma_end_e = + bktr->base->dma_end_o = buf + METEOR_ALLOC; +end of setup up dma risc program + /* 1 frame of 640x480 RGB 16 */ + bktr->flags |= METEOR_INITALIZED | METEOR_AUTOMODE | METEOR_DEV0 | + METEOR_RGB16; +#endif /* amancio */ + + bktr->flags = METEOR_INITALIZED | METEOR_AUTOMODE | METEOR_DEV0 | METEOR_RGB16; + bktr->dma_prog_loaded = 0; + bktr->cols = 640; + bktr->rows = 480; + bktr->depth = 2; /* two bytes per pixel */ + bktr->frames = 1; /* one frame */ + bt848 = bktr->base; + btl_reg = (u_long *) &bt848[BKTR_INT_MASK]; + *btl_reg = 0; + bt848[BKTR_GPIO_DMA_CTL] = 0; + } +#ifdef DEVFS + bktr->devfs_token = devfs_add_devswf(&bktr_cdevsw, unit, + DV_CHR, 0, 0, 0644, "brooktree"); +#endif /* DEVFS */ +} + +#define UNIT(x) ((x) & 0x07) + + +/*--------------------------------------------------------- +** +** BrookTree 848 character device driver routines +** +**--------------------------------------------------------- +*/ + + +int +bktr_open( dev_t dev, int flags, int fmt, struct proc *p ) +{ + bktr_reg_t *bktr; + int unit; + int i; + volatile u_char *bt848; + volatile u_char *bt_reg; + volatile u_long *btl_reg; + + unit = UNIT(minor(dev)); + if (unit >= NBKTR) /* unit out of range */ + return(ENXIO); + + bktr = &(brooktree[unit]); + + if (!(bktr->flags & METEOR_INITALIZED)) /* device not found */ + return(ENXIO); + +#if defined( MULTIPLE_OPENS ) + if (bktr->flags & METEOR_OPEN) /* device already open */ + return 0; +#else + if (bktr->flags & METEOR_OPEN) /* device is busy */ + return(EBUSY); +#endif /* MULTIPLE_OPENS */ + + bktr->flags |= METEOR_OPEN; + + bt848 = bktr->base; + + /* dump_bt848(bt848); */ + *bt848 = 0x3; + *bt848 = 0xc0; + + bt848[BKTR_ADC] = 0x81; + + bt848[BKTR_IFORM] = 0x69; + + bt848[BKTR_COLOR_CTL] = 0x20; + + bt848[BKTR_E_HSCALE_LO] = 0xaa; + bt848[BKTR_O_HSCALE_LO] = 0xaa; + + bt848[BKTR_E_DELAY_LO] = 0x72; + bt848[BKTR_O_DELAY_LO] = 0x72; + bt848[BKTR_E_SCLOOP] = 0; + bt848[BKTR_O_SCLOOP] = 0; + + bt848[BKTR_VBI_PACK_SIZE] = 0; + bt848[BKTR_VBI_PACK_DEL] = 0; + + bzero((u_char *) bktr->bigbuf, 640*480*4); + bktr->flags |= METEOR_OPEN; + bktr->fifo_errors = 0; + bktr->dma_errors = 0; + bktr->frames_captured = 0; + bktr->even_fields_captured = 0; + bktr->odd_fields_captured = 0; + bktr->proc = (struct proc *)0; + set_fps(bktr, 30); + bktr->video.addr = 0; + bktr->video.width = 0; + bktr->video.banksize = 0; + bktr->video.ramsize = 0; + + /* defaults for the tuner section of the card */ + bktr->tuner.frequency = 0; + bktr->tuner.tunertype = DEFAULT_TUNERTYPE; + + btl_reg = (u_long *) &bt848[BKTR_INT_MASK]; + *btl_reg = 1 << 23; + + return(0); +} + +int +bktr_close( dev_t dev, int flags, int fmt, struct proc *p ) +{ + bktr_reg_t *bktr; + int unit; + volatile u_char *bt848; + volatile u_long *btl_reg; + u_short *bts_reg; +#ifdef METEOR_DEALLOC_ABOVE + int temp; +#endif + unit = UNIT(minor(dev)); + if (unit >= NBKTR) /* unit out of range */ + return(ENXIO); + + bktr = &(brooktree[unit]); + + bktr->flags &= ~METEOR_OPEN; + bktr->flags &= ~(METEOR_SINGLE | METEOR_WANT_MASK); + bktr->flags &= ~(METEOR_CAP_MASK|METEOR_WANT_MASK); + bt848 = bktr->base; + bts_reg = (u_short *) &bt848[BKTR_GPIO_DMA_CTL]; + *bts_reg = 0; + bt848[BKTR_CAP_CTL] = 0; + + bktr->dma_prog_loaded = 0; + bt848[BKTR_TDEC] = 0; + btl_reg = (u_long *) &bt848[BKTR_INT_MASK]; + *btl_reg = 0; + + bt848[BKTR_SRESET] = 0xf; + btl_reg = (u_long *) &bt848[BKTR_INT_STAT] ; + *btl_reg = 0xffffffff; + + return(0); +} + + +/* + * + */ +int +bktr_read( dev_t dev, struct uio *uio, int ioflag ) +{ + bktr_reg_t *bktr; + int unit; + int status; + int count; + volatile u_char *bt848; + u_short *bts_reg; + + unit = UNIT(minor(dev)); + if (unit >= NBKTR) /* unit out of range */ + return(ENXIO); + + bktr = &(brooktree[unit]); + if (bktr->bigbuf == 0) /* no frame buffer allocated (ioctl failed) */ + return(ENOMEM); + + if (bktr->flags & METEOR_CAP_MASK) + return(EIO); /* already capturing */ + + bt848 = (u_char *) bktr->base; + + + count = bktr->rows * bktr->cols * bktr->depth; + if ((int) uio->uio_iov->iov_len < count) + return(EINVAL); + bktr->flags &= ~(METEOR_CAP_MASK|METEOR_WANT_MASK); + + /* Start capture */ + bts_reg = (u_short *) &bt848[BKTR_GPIO_DMA_CTL]; + *bts_reg = 0x1; + *bts_reg = 0x3; + + status=tsleep((caddr_t)bktr, METPRI, "capturing", 0); + if (!status) /* successful capture */ + status = uiomove((caddr_t)bktr->bigbuf, count, uio); + else + printf ("meteor%d: read: tsleep error %d\n", unit, status); + + bktr->flags &= ~(METEOR_SINGLE | METEOR_WANT_MASK); + + return(status); +} + + +/* + * + */ +int +bktr_write( dev_t dev, struct uio *uio, int ioflag ) +{ + return(0); +} + + +/* + * + */ +int +bktr_ioctl( dev_t dev, int cmd, caddr_t arg, int flag, struct proc *pr ) +{ + bktr_reg_t *bktr; + int unit; + int status; + int count; + int tmp_int; + volatile u_char *bt848, c_temp; + volatile u_short *bts_reg, s_temp; + volatile u_long *btl_reg; + unsigned int temp, temp1; + unsigned int error; + struct meteor_geomet *geo; + struct meteor_counts *cnt; + struct meteor_video *video; + u_long *foo; + vm_offset_t buf; + + unit = UNIT(minor(dev)); + if (unit >= NBKTR) /* unit out of range */ + return(ENXIO); + + + bktr = &(brooktree[unit]); + if (bktr->bigbuf == 0) /* no frame buffer allocated (ioctl failed) */ + return(ENOMEM); + + bt848 = bktr->base; + switch (cmd) { + + case TVTUNER_SETCHNL: + temp = tv_channel( bktr, (int)*(unsigned long *)arg ); + if ( temp < 0 ) return EIO; + *(unsigned long *)arg = temp; + break; + + case TVTUNER_GETCHNL: + *(unsigned long *)arg = bktr->tuner.channel; + break; + + case TVTUNER_SETTYPE: + bktr->tuner.tunertype = *(unsigned long *)arg; + break; + + case TVTUNER_GETTYPE: + *(unsigned long *)arg = bktr->tuner.tunertype; + break; + + case TVTUNER_GETSTATUS: + temp = tuner_status( bktr ); + *(unsigned long *)arg = temp & 0xff; + break; + + case METEORSTATUS: /* get 7196 status */ + c_temp = bt848[0]; + temp = 0; + if (!(c_temp & 0x40)) temp |= METEOR_STATUS_HCLK; + if (!(c_temp & 0x10)) temp |= METEOR_STATUS_FIDT; + *(u_short *)arg = temp; + break; + + case METEORSINPUT: /* set input device */ + switch(*(unsigned long *)arg & METEOR_DEV_MASK) { + case 0: /* default */ + case METEOR_INPUT_DEV0: + bktr->flags = (bktr->flags & ~METEOR_DEV_MASK) + | METEOR_DEV0; + bt848[BKTR_IFORM] &= ~0x60; + bt848[BKTR_IFORM] |= 0x60; + bt848[BKTR_E_CONTROL] &= ~0x40; + bt848[BKTR_O_CONTROL] &= ~0x40; + break; + + case METEOR_INPUT_DEV1: + bktr->flags = (bktr->flags & ~METEOR_DEV_MASK) + | METEOR_DEV1; + bt848[BKTR_IFORM] &= ~0x60; + bt848[BKTR_IFORM] |= 0x40; + bt848[BKTR_E_CONTROL] &= ~0x40; + bt848[BKTR_O_CONTROL] &= ~0x40; + break; + + case METEOR_INPUT_DEV2: + bktr->flags = (bktr->flags & ~METEOR_DEV_MASK) + | METEOR_DEV2; + bt848[BKTR_IFORM] &= ~0x60; + bt848[BKTR_IFORM] |= 0x20; + bt848[BKTR_E_CONTROL] |= 0x40; + bt848[BKTR_O_CONTROL] |= 0x40; + break; + + case METEOR_INPUT_DEV_SVIDEO: + bktr->flags = (bktr->flags & ~METEOR_DEV_MASK) + | METEOR_DEV2; + bt848[BKTR_IFORM] &= ~0x60; + bt848[BKTR_IFORM] |= 0x20; + bt848[BKTR_E_CONTROL] |= 0x40; + bt848[BKTR_O_CONTROL] |= 0x40; + break; + + default: + return EINVAL; + } + break; + + case METEORGINPUT: /* get input device */ + *(u_long *)arg = bktr->flags & METEOR_DEV_MASK; + break; + + case METEORSFMT: /* set input format */ + switch(*(unsigned long *)arg & METEOR_FORM_MASK ) { + case 0: /* default */ + case METEOR_FMT_NTSC: + bktr->flags = (bktr->flags & ~METEOR_FORM_MASK) | + METEOR_NTSC; + bt848[BKTR_IFORM] &= ~0x3; + bt848[BKTR_IFORM] |= 1; + break; + + case METEOR_FMT_AUTOMODE: + bktr->flags = (bktr->flags & ~METEOR_FORM_MASK) | + METEOR_AUTOMODE; + bt848[BKTR_IFORM] &= ~0x3; + break; + + default: + return EINVAL; + } + break; + + case METEORGFMT: /* get input format */ + *(u_long *)arg = bktr->flags & METEOR_FORM_MASK; + break; + + case METEORSCOUNT: /* (re)set error counts */ + cnt = (struct meteor_counts *) arg; + bktr->fifo_errors = cnt->fifo_errors; + bktr->dma_errors = cnt->dma_errors; + bktr->frames_captured = cnt->frames_captured; + bktr->even_fields_captured = cnt->even_fields_captured; + bktr->odd_fields_captured = cnt->odd_fields_captured; + break; + + case METEORGCOUNT: /* get error counts */ + cnt = (struct meteor_counts *) arg; + cnt->fifo_errors = bktr->fifo_errors; + cnt->dma_errors = bktr->dma_errors; + cnt->frames_captured = bktr->frames_captured; + cnt->even_fields_captured = bktr->even_fields_captured; + cnt->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 */ + bt848[BKTR_HUE] = (*(u_char *) arg) & 0xff; + break; + + case METEORGHUE: /* get hue */ + *(u_char *)arg = bt848[BKTR_HUE]; + break; + + case METEORSBRIG: /* set brightness */ + bt848[BKTR_BRIGHT] = *(u_char *)arg & 0xff; + break; + + case METEORGBRIG: /* get brightness */ + *(u_char *)arg = bt848[BKTR_BRIGHT]; + break; + + case METEORSCSAT: /* set chroma saturation */ +#if defined( OLD_METEORSCSAT ) + s_temp = *(u_short *)arg ; + s_temp = s_temp << 1; + + bt848[BKTR_SAT_U_LO] = s_temp; + bt848[BKTR_SAT_V_LO] = s_temp; + s_temp = s_temp >> 8; + + bt848[BKTR_E_CONTROL] &= ~0x3; + bt848[BKTR_O_CONTROL] &= ~0x3; + bt848[BKTR_E_CONTROL] |= s_temp & 0x3; + bt848[BKTR_O_CONTROL] |= s_temp & 0x3; + break; +#endif /* OLD_METEORSCSAT */ + temp = (int)*(u_char *)arg; + + bt848[BKTR_SAT_U_LO] = bt848[BKTR_SAT_V_LO] = + (temp << 1) & 0xff; + + bt848[BKTR_E_CONTROL] &= ~0x3; /* clear U/V MSBs */ + bt848[BKTR_O_CONTROL] &= ~0x3; /* clear U/V MSBs */ + + if ( temp & 0x80 ) { + bt848[BKTR_E_CONTROL] |= 0x3; /* */ + bt848[BKTR_O_CONTROL] |= 0x3; + } + break; + + case METEORGCSAT: /* get chroma saturation */ +#if defined( OLD_METEORGCSAT ) + *(u_short *)arg = (bt848[BKTR_E_CONTROL] << 8) & 0x10 | bt848[BKTR_SAT_U_LO]; + break; +#endif /* OLD_METEORGCSAT */ + temp = (bt848[BKTR_SAT_V_LO] >> 1) & 0xff; + if ( bt848[BKTR_E_CONTROL] & 0x01 ) + temp |= 0x80; + *(u_char *)arg = (u_char)temp; + break; + + case METEORSCONT: /* set contrast */ + temp = (int)*(u_char *)arg & 0xff; + temp <<= 1; + bt848[BKTR_CONTRAST_LO] = temp & 0xff; + bt848[BKTR_E_CONTROL] &= ~0x4; + bt848[BKTR_O_CONTROL] &= ~0x4; + bt848[BKTR_E_CONTROL] |= ((temp & 0x100) >> 6 ) & 0x4 ; + bt848[BKTR_O_CONTROL] |= ((temp & 0x100) >> 6 ) & 0x4 ; + break; + + case METEORGCONT: /* get contrast */ +#if defined( OLD_METEORGCONT ) + *(u_short *)arg = bt848[BKTR_CONTRAST_LO] | ((bt848[BKTR_O_CONTROL] & 4) << 2); + break; +#endif /* OLD_METEORGCONT */ + temp = (int)bt848[BKTR_CONTRAST_LO] & 0xff; + temp |= ((int)bt848[BKTR_O_CONTROL] & 0x04) << 6; + *(u_char *)arg = (u_char)((temp >> 1) & 0xff); + break; + + case METEORSSIGNAL: + bktr->signal = *(int *) arg; + bktr->proc = pr; + 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); + + /* if (temp & METEOR_CAP_MASK) + return(EIO); already capturing */ + + start_capture(bktr, METEOR_SINGLE); + bktr->flags |= METEOR_SINGLE; + bktr->flags &= ~METEOR_WANT_MASK; + + /* wait for capture to complete */ + btl_reg = (u_long *) &bt848[BKTR_INT_STAT]; + *btl_reg = 0xffffffff; + + btl_reg = (u_long *) &bt848[BKTR_GPIO_OUT_EN]; + *btl_reg = 1; + bts_reg = (u_short *) &bt848[BKTR_GPIO_DMA_CTL]; + *bts_reg = 0x1; + *bts_reg = bktr->capcontrol; + + btl_reg = (u_long *) &bt848[BKTR_INT_MASK]; + + *btl_reg = 1 << 23 | 1 << 11 | 2 | 1; + + error=tsleep((caddr_t)bktr, METPRI, "capturing", hz); + + if (error) { + btl_reg = (u_long *) &bt848[BKTR_RISC_COUNT]; + + printf("bktr%d: ioctl: tsleep error %d %x\n", + unit, error, *btl_reg); + } + bktr->flags &= ~(METEOR_SINGLE|METEOR_WANT_MASK); + btl_reg = (u_long *) &bt848[BKTR_INT_STAT]; + break; + + case METEOR_CAP_CONTINOUS: + if (bktr->bigbuf==0) /* no frame buffer allocated */ + return(ENOMEM); + + if (temp & METEOR_CAP_MASK) + return(EIO); /* already capturing */ + + start_capture(bktr, METEOR_CONTIN); + btl_reg = (u_long *) &bt848[BKTR_INT_STAT]; + *btl_reg = *btl_reg; + + bts_reg = (u_short *) &bt848[BKTR_GPIO_DMA_CTL]; + + *bts_reg = 1; + *bts_reg = bktr->capcontrol; + + btl_reg = (u_long *) &bt848[BKTR_INT_MASK]; + *btl_reg = 1 << 23 | 1 << 11 | 2 | 1; + + /* dump_bt848(bt848); */ + break; + + case METEOR_CAP_STOP_CONT: + if (bktr->flags & METEOR_CONTIN) { + /* turn off capture */ + btl_reg = (u_long *) &bt848[BKTR_INT_MASK]; + *btl_reg = 0; + bts_reg = (u_short *)&bt848[BKTR_GPIO_DMA_CTL]; + *bts_reg = 0; + + bktr->flags &= ~(METEOR_CONTIN|METEOR_WANT_MASK); + } + } + break; + + case METEORSETGEO: + + 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("bktr%d: ioctl: Geometry odd or even only.\n", + unit); + + 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; + + /* can't change parameters while capturing */ +/* XXX: + if (bktr->flags & METEOR_CAP_MASK) + return(EBUSY); +*/ + if ((geo->columns & 0x3fe) != geo->columns) { + printf( + "bktr%d: ioctl: %d: columns too large or not even.\n", + unit, geo->columns); + error = EINVAL; + } + if (((geo->rows & 0x7fe) != geo->rows) || + ((geo->oformat & METEOR_GEO_FIELD_MASK) && + ((geo->rows & 0x3fe) != geo->rows)) ) { + printf( + "bktr%d: ioctl: %d: rows too large or not even.\n", + unit, geo->rows); + error = EINVAL; + } + if (geo->frames > 32) { + printf("bktr%d: ioctl: too many frames.\n", unit); + + error = EINVAL; + } + + if (error) return error; + bktr->dma_prog_loaded = 0; + bts_reg = (u_short *) &bt848[BKTR_GPIO_DMA_CTL]; + *bts_reg = 0; + + btl_reg = (u_long *) &bt848[BKTR_INT_MASK]; + *btl_reg = 0; + + 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) { + buf = get_bktr_mem(unit, temp*PAGE_SIZE); + if (buf != 0) { + kmem_free(kernel_map, bktr->bigbuf, + (bktr->alloc_pages * PAGE_SIZE)); + bktr->bigbuf = buf; + bktr->alloc_pages = temp; + if (bootverbose) + printf( + "meteor%d: ioctl: Allocating %d bytes\n", + unit, temp*PAGE_SIZE); + } else { + error = ENOMEM; + } + } + } + + if (error) + return error; + + bktr->rows = geo->rows; + bktr->cols = geo->columns; + bktr->frames = geo->frames; + + /* horizontal scale */ + /* temp = ((910.0/( (float) bktr->cols *1.21875)) - 1.0) * 4096.0;*/ + /* temp = ((910.0/( (float) bktr->cols *1.212)) - 1.0) * 4096.0; */ + temp = ((910.0/( (float) bktr->cols *1.21875)) - 1.0) * 4096.0; + /* temp = ((754.0/(float) bktr->cols) - 1 ) * 4096.0;*/ + + bt848[BKTR_E_HSCALE_LO] = temp & 0xff; + bt848[BKTR_O_HSCALE_LO] = temp & 0xff; + bt848[BKTR_E_HSCALE_HI] = ( temp >> 8 ) & 0xff; + bt848[BKTR_O_HSCALE_HI] = ( temp >> 8 ) & 0xff; + + /* horizontal active */ + temp = bktr->cols; + bt848[BKTR_E_HACTIVE_LO] = temp & 0xff; + bt848[BKTR_O_HACTIVE_LO] = temp & 0xff; + bt848[BKTR_EVEN_CROP] &= ~0x3; + bt848[BKTR_ODD_CROP] &= ~0x3; + bt848[BKTR_EVEN_CROP] |= (temp >> 8 ) & 0x3; + bt848[BKTR_ODD_CROP] |= (temp >> 8 ) & 0x3; + + /* horizontal delay */ + temp = ((135.0/754.0) * (float) bktr->cols) ; + temp = temp + 2; + temp = temp & 0x3fe; + bt848[BKTR_E_DELAY_LO] = temp & 0xff; + bt848[BKTR_O_DELAY_LO] = temp & 0xff; + bt848[BKTR_EVEN_CROP] &= ~0xc; + bt848[BKTR_ODD_CROP] &= ~0xc; + bt848[BKTR_EVEN_CROP] |= (temp >> 6) & 0xc; + bt848[BKTR_ODD_CROP] |= (temp >> 6) & 0xc; + + /* vscale */ + if (geo->oformat & METEOR_GEO_ODD_ONLY || + geo->oformat & METEOR_GEO_EVEN_ONLY) { + tmp_int = 65536.0 - (((240.0/(float) bktr->rows) - 1.0) * 512.0); + } else { + tmp_int = 65536 - (((480.0/(float) bktr->rows) - 1.0) * 512); + } + tmp_int &= 0x1fff; + + /* Vertical scaling */ + bt848[BKTR_E_VSCALE_LO] = tmp_int & 0xff; + bt848[BKTR_O_VSCALE_LO] = tmp_int & 0xff; + bt848[BKTR_E_VSCALE_HI] &= ~0x1f; + bt848[BKTR_O_VSCALE_HI] &= ~0x1f; + bt848[BKTR_E_VSCALE_HI] |= (tmp_int >> 8) & 0x1f; + bt848[BKTR_O_VSCALE_HI] |= (tmp_int >> 8) & 0x1f; + + 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; + bktr->depth = 2; + break; + case METEOR_GEO_RGB24: + bktr->format = METEOR_GEO_RGB24; + bktr->depth = 4; + break; + case METEOR_GEO_YUV_422: + bktr->format = METEOR_GEO_YUV_422; + break; + case METEOR_GEO_YUV_PACKED: + bktr->format = METEOR_GEO_YUV_PACKED; + break; + } + +/* + if (geo->oformat & METEOR_GEO_YUV_12 ) + bktr->format |= METEOR_GEO_YUV_12; + else if (geo->oformat & METEOR_GEO_YUV_9 ) + bktr->format |= METEOR_GEO_YUV_9; +*/ + + 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); + btl_reg = (u_long *) &bt848[BKTR_INT_STAT]; + *btl_reg = *btl_reg; + bts_reg = (u_short *)&bt848[BKTR_GPIO_DMA_CTL]; + *bts_reg = 0x1; + *bts_reg = bktr->capcontrol; + btl_reg = (u_long *) &bt848[BKTR_INT_MASK]; + *btl_reg = 1 << 23 | 2 | 1; + } + } + + break; + default: +#if 0 +/* XXX */ + error = ENOTTY; + break; +#else + return ENODEV; +#endif /* 0 */ + } + + return 0; +} + + +/* + * + */ +int +bktr_mmap( dev_t dev, int offset, int nprot ) +{ + int unit; + bktr_reg_t *bktr; + + unit = UNIT(minor(dev)); + + if (unit >= NBKTR) /* at this point could this happen? */ + return(-1); + + bktr = &(brooktree[unit]); + + if (nprot & PROT_EXEC) + return -1; + + if (offset >= bktr->alloc_pages * PAGE_SIZE) + return -1; + + return i386_btop(vtophys(bktr->bigbuf) + offset); +} + + +/****************************************************************************** + * tuner specific routines: + */ + +/** XXX FIXME: this should be a kernel option */ +#define IF_FREQUENCY 4575 /* M/N IF frequency */ + +/* guaranteed address for any TSA5522 */ +#define TSA5522_WADDR 0xc2 +#define TSA5522_RADDR 0xc3 + +/* + * bit 7: CONTROL BYTE = 1 + * bit 6: CP = 0 moderate speed tuning, better FM + * bit 5: T2 = 0 normal operation + * bit 4: T1 = 0 normal operation + * bit 3: T0 = 1 normal operation + * bit 2: RSA = 1 62.5kHz + * bit 1: RSB = 1 62.5kHz + * bit 0: OS = 0 normal operation + */ +#define TSA5522_CONTROL 0x8e + +#if defined( TEMIC_TUNER ) + +#define TSA5522_BANDA 0x02 +#define TSA5522_BANDB 0x04 +#define TSA5522_BANDC 0x01 + +#elif defined( PHILIPS_TUNER ) + +#define TSA5522_BANDA 0xa0 +#define TSA5522_BANDB 0x90 +#define TSA5522_BANDC 0x30 + +#else + +#error you must define a tuner type + +#endif /* XXXXXX_TUNER */ + +/* scaling factor for frequencies expressed as ints */ +#define FREQFACTOR 100 + + +/******************************* i2c primitives ******************************/ + +/* delays for the I2C bus transactions */ +#define NDELAY 0 +#if defined ( ORIGINAL_DELAYS ) +#define SDELAY 2 +#define LDELAY 20 +#else +#define SDELAY 10 +#define LDELAY 40 +#endif /* ORIGINAL_DELAYS */ + +/* macros to show the details more clearly */ +typedef volatile u_long* i2c_regptr_t; + +/* + * primitives for the I2C clock phases + */ +static inline void +DataLo_ClockLo( i2c_regptr_t bti2c, int delay ) +{ + *bti2c = 0; + if ( delay ) + DELAY( delay ); +} +static inline void +DataHi_ClockLo( i2c_regptr_t bti2c, int delay ) +{ + *bti2c = 1; + if ( delay ) + DELAY( delay ); +} + +static inline void +DataLo_ClockHi( i2c_regptr_t bti2c, int delay ) +{ + *bti2c = 2; + if ( delay ) + DELAY( delay ); +} + +static inline void +DataHi_ClockHi( i2c_regptr_t bti2c, int delay ) +{ + *bti2c = 3; + if ( delay ) + DELAY( delay ); +} + +static inline int +DataRead( i2c_regptr_t bti2c ) +{ + return ( *bti2c & 1 ); +} + + +/* forward reference */ +static int i2cWrite( i2c_regptr_t, u_char ); + +/* + * start an I2C bus transaction + */ +static void +i2cStart( i2c_regptr_t bti2c, int address ) +{ + +#if 1 + /* ensure the proper starting state */ + DataHi_ClockLo( bti2c, LDELAY ); /* release data */ + DataHi_ClockHi( bti2c, LDELAY ); /* release clock */ +#endif + DataLo_ClockHi( bti2c, LDELAY ); /* lower data */ + DataLo_ClockLo( bti2c, LDELAY ); /* lower clock */ + + /* send the address of the device */ + i2cWrite( bti2c, address ); +} + +/* + * stop an I2C bus transaction + */ +static void +i2cStop( i2c_regptr_t bti2c ) +{ + DataLo_ClockLo( bti2c, LDELAY ); /* lower clock & data */ + DataLo_ClockHi( bti2c, LDELAY ); /* release clock */ + DataHi_ClockHi( bti2c, LDELAY ); /* release data */ +} + +/* + * place a '1' bit on the I2C bus + */ +static void +i2cHi( i2c_regptr_t bti2c ) +{ + DataHi_ClockLo( bti2c, LDELAY ); /* assert HI data */ + DataHi_ClockHi( bti2c, LDELAY ); /* strobe clock */ + DataHi_ClockLo( bti2c, LDELAY ); /* release clock */ +} + +/* + * place a '0' bit on the I2C bus + */ +static void +i2cLo( i2c_regptr_t bti2c ) +{ + DataLo_ClockLo( bti2c, LDELAY ); /* assert LO data */ + DataLo_ClockHi( bti2c, LDELAY ); /* strobe clock */ + DataLo_ClockLo( bti2c, LDELAY ); /* release clock */ +} + +/* + * give an 'ACK' to the slave + */ +static void +i2cGrantAck( i2c_regptr_t bti2c ) +{ + DataLo_ClockLo( bti2c, LDELAY ); /* assert LO data */ + DataLo_ClockHi( bti2c, LDELAY ); /* strobe clock */ + DataLo_ClockLo( bti2c, LDELAY ); /* remove clock */ + DataHi_ClockLo( bti2c, NDELAY ); /* float data */ +} + +/* + * get an 'ACK' from the slave + */ +static int +i2cAck( i2c_regptr_t bti2c ) +{ + int acknowledge; + + DataHi_ClockLo( bti2c, LDELAY ); /* float data */ + DataHi_ClockHi( bti2c, LDELAY ); /* strobe clock */ + + acknowledge = DataRead( bti2c ); /* read ACK bit */ + + DataHi_ClockLo( bti2c, LDELAY ); /* release clock */ + + return acknowledge; +} + +/* + * read a byte from the I2C bus + */ +static int +i2cRead( i2c_regptr_t bti2c ) +{ + int x; + int byte; + + DataHi_ClockLo( bti2c, SDELAY ); /* float data */ + + for ( byte = 0, x = 7; x >= 0; --x ) { + DataHi_ClockHi( bti2c, SDELAY ); /* strobe clock */ + + if ( DataRead( bti2c ) ) /* read data */ + byte |= (1<= 0; --x ) + (byte & (1<base[ BKTR_I2C_CONTROL ] + +/* + * set the frequency of the tuner + */ +static int +tv_freq( bktr_reg_t* bktr, int frequency ) +{ + i2c_regptr_t bti2c; + u_char band; + int N; + int order; + + /* select the band based on frequency */ + if ( frequency < (160 * FREQFACTOR) ) + band = TSA5522_BANDA; + else if ( frequency < (454 * FREQFACTOR) ) + band = TSA5522_BANDB; + else + band = TSA5522_BANDC; + + /* + * N = 16 * { fRF(pc) + fIF(pc) } + * where: + * pc is picture carrier, fRF & fIF are in mHz + * + * frequency is mHz to 2 decimal places, ie. 5525 == 55.25 mHz, + * dont want to do float in a driver! + */ + N = 16 * ((frequency + IF_FREQUENCY) / FREQFACTOR); + + /* get the i2c register address */ + bti2c = I2C_REGADDR(); + + /* send the data to the TSA5522 */ + disable_intr(); + i2cStart( bti2c, TSA5522_WADDR ); + + /* the data sheet wants the order set according to direction */ + if ( frequency > bktr->tuner.frequency ) { + i2cWrite( bti2c, (N >> 8) & 0x7f ); /* divisor MSB */ + i2cWrite( bti2c, N & 0xff ); /* divisor LSB */ + i2cWrite( bti2c, TSA5522_CONTROL ); /* control bits */ + i2cWrite( bti2c, band ); /* band select */ + } + else { + i2cWrite( bti2c, TSA5522_CONTROL ); /* control bits */ + i2cWrite( bti2c, band ); /* band select */ + i2cWrite( bti2c, (N >> 8) & 0x7f ); /* divisor MSB */ + i2cWrite( bti2c, N & 0xff ); /* divisor LSB */ + } + + i2cStop( bti2c ); + enable_intr(); + + return 0; +} + + +/* + * North American Broadcast Channels: + * + * IF freq: 45.75 mHz + * + * Chnl Freq + * 2 55.25 mHz + * 3 61.25 mHz + * 4 67.25 mHz + * + * 5 77.25 mHz + * 6 83.25 mHz + * + * 7 175.25 mHz + * 13 211.25 mHz + * + * 14 471.25 mHz + * 83 885.25 mHz + */ +static int +frequency_nabcst( int channel ) +{ + /* legal channels are 2 thru 83 */ + if ( channel > 83 ) + return -1; + + /* channels 14 thru 83 */ + if ( channel >= 14 ) + return 47125 + ((channel-14) * 600 ); + + /* channels 7 thru 13 */ + if ( channel >= 7 ) + return 17525 + ((channel-7) * 600 ); + + /* channels 5 thru 6 */ + if ( channel >= 5 ) + return 7725 + ((channel-5) * 600 ); + + /* channels 2 thru 4 */ + if ( channel >= 2 ) + return 5525 + ((channel-2) * 600 ); + + /* legal channels are 2 thru 83 */ + return -1; +} + + +/* + * North American Cable Channels, IRC(?): + * + * IF freq: 45.75 mHz + * + * Chnl Freq + * 2 55.25 mHz + * 3 61.25 mHz + * 4 67.25 mHz + * + * 5 77.25 mHz + * 6 83.25 mHz + * + * 7 175.25 mHz + * 13 211.25 mHz + * + * 14 121.25 mHz + * 22 169.25 mHz + * + * 23 217.25 mHz + * 94 643.25 mHz + * + * 95 91.25 mHz + * 99 115.25 mHz + */ +static int +frequency_irccable( int channel ) +{ + /* legal channels are 2 thru 99 */ + if ( channel > 99 ) + return -1; + + /* channels 95 thru 99 */ + if ( channel >= 95 ) + return 9125 + ((channel-95) * 600 ); + + /* channels 23 thru 94 */ + if ( channel >= 23 ) + return 21725 + ((channel-23) * 600 ); + + /* channels 14 thru 22 */ + if ( channel >= 14 ) + return 12125 + ((channel-14) * 600 ); + + /* channels 7 thru 13 */ + if ( channel >= 7 ) + return 17525 + ((channel-7) * 600 ); + + /* channels 5 thru 6 */ + if ( channel >= 5 ) + return 7725 + ((channel-5) * 600 ); + + /* channels 2 thru 4 */ + if ( channel >= 2 ) + return 5525 + ((channel-2) * 600 ); + + /* legal channels are 2 thru 99 */ + return -1; +} + + +/* + * set the channel of the tuner + */ +static int +tv_channel( bktr_reg_t* bktr, int channel ) +{ + int frequency, status; + + /* calculate the frequency according to tuner type */ + switch ( bktr->tuner.tunertype ) { + case TUNERTYPE_NABCST: + frequency = frequency_nabcst( channel ); + break; + + case TUNERTYPE_CABLEIRC: + frequency = frequency_irccable( channel ); + break; + + /* FIXME: */ + case TUNERTYPE_CABLEHRC: + case TUNERTYPE_WEUROPE: + default: + return -1; + } + + /* check the result of channel to frequency conversion */ + if ( frequency < 0 ) + return -1; + + /* set the new frequency */ + if ( tv_freq( bktr, frequency ) < 0 ) + return -1; + + /* OK to update records */ + bktr->tuner.frequency = frequency; + bktr->tuner.channel = channel; + + return channel; +} + + +/* + * set the channel of the tuner + */ +static int +tuner_status( bktr_reg_t* bktr ) +{ + i2c_regptr_t bti2c; + int status; + + /* get the i2c register address */ + bti2c = I2C_REGADDR(); + + /* send the request to the TSA5522 */ + disable_intr(); + i2cStart( bti2c, TSA5522_RADDR ); + + status = i2cRead( bti2c ); + + i2cStop( bti2c ); + enable_intr(); + + return status; +} + + +/* + * + */ +static bktr_devsw_installed = 0; + +static void +bktr_drvinit( void *unused ) +{ + dev_t dev; + + if ( ! bktr_devsw_installed ) { + dev = makedev(CDEV_MAJOR, 0); + cdevsw_add(&dev,&bktr_cdevsw, NULL); + bktr_devsw_installed = 1; + } +} + +SYSINIT(bktrdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,bktr_drvinit,NULL) + +#endif /* NBKTR > 0 */ diff --git a/sys/sys/ioctl_bt848.h b/sys/sys/ioctl_bt848.h new file mode 100644 index 000000000000..159a764b9826 --- /dev/null +++ b/sys/sys/ioctl_bt848.h @@ -0,0 +1,34 @@ +/* + * extensions to ioctl_meteor.h for the bt848 cards + * + * $Id$ + */ + +/* + * tuner types for the + */ +#define TUNERTYPE_NABCST 1 +#define TUNERTYPE_CABLEIRC 2 +#define TUNERTYPE_CABLEHRC 3 +#define TUNERTYPE_WEUROPE 4 + + +/* + * XXX: this is a hack, should be in ioctl_meteor.h + * here to avoid touching that file for now... + */ +#define TVTUNER_SETCHNL _IOW('x', 32, unsigned int) /* set channel */ +#define TVTUNER_GETCHNL _IOR('x', 32, unsigned int) /* get channel */ +#define TVTUNER_SETTYPE _IOW('x', 33, unsigned int) /* set tuner type */ +#define TVTUNER_GETTYPE _IOR('x', 33, unsigned int) /* get tuner type */ +#define TVTUNER_GETSTATUS _IOR('x', 34, unsigned int) /* get tuner status */ + + +/* + * XXX: more bad magic, + * we need to fix the METEORGINPUT to return something public + * duplicate them here for now... + */ +#define METEOR_DEV0 0x00001000 +#define METEOR_DEV1 0x00002000 +#define METEOR_DEV2 0x00004000