summaryrefslogtreecommitdiff
path: root/sys/dev/pci/bktr
diff options
context:
space:
mode:
authorFederico G. Schwindt <fgsch@cvs.openbsd.org>2001-03-28 03:27:11 +0000
committerFederico G. Schwindt <fgsch@cvs.openbsd.org>2001-03-28 03:27:11 +0000
commita855235b1deb689850cb3c99f978fae62a08f9d0 (patch)
tree0d5f9f9316a1d86a659735e7845d6398d0309201 /sys/dev/pci/bktr
parent5ddcc378f217dbb5c667f485200c013e60ac7998 (diff)
Latest bktr driver from FreeBSD; thanks to Andres Gunnarsson
<andreas@crt.se> for testing.
Diffstat (limited to 'sys/dev/pci/bktr')
-rw-r--r--sys/dev/pci/bktr/bktr_audio.c634
-rw-r--r--sys/dev/pci/bktr/bktr_audio.h85
-rw-r--r--sys/dev/pci/bktr/bktr_card.c1268
-rw-r--r--sys/dev/pci/bktr/bktr_card.h88
-rw-r--r--sys/dev/pci/bktr/bktr_core.c4264
-rw-r--r--sys/dev/pci/bktr/bktr_core.h97
-rw-r--r--sys/dev/pci/bktr/bktr_os.c1703
-rw-r--r--sys/dev/pci/bktr/bktr_os.h73
-rw-r--r--sys/dev/pci/bktr/bktr_reg.h729
-rw-r--r--sys/dev/pci/bktr/bktr_tuner.c1017
-rw-r--r--sys/dev/pci/bktr/bktr_tuner.h104
11 files changed, 10062 insertions, 0 deletions
diff --git a/sys/dev/pci/bktr/bktr_audio.c b/sys/dev/pci/bktr/bktr_audio.c
new file mode 100644
index 00000000000..1f437c4e527
--- /dev/null
+++ b/sys/dev/pci/bktr/bktr_audio.c
@@ -0,0 +1,634 @@
+/* $OpenBSD: bktr_audio.c,v 1.1 2001/03/28 03:27:09 fgsch Exp $ */
+/* $FreeBSD: src/sys/dev/bktr/bktr_audio.c,v 1.8 2000/10/31 13:09:56 roger Exp $ */
+/*
+ * This is part of the Driver for Video Capture Cards (Frame grabbers)
+ * and TV Tuner cards using the Brooktree Bt848, Bt848A, Bt849A, Bt878, Bt879
+ * chipset.
+ * Copyright Roger Hardiman and Amancio Hasty.
+ *
+ * bktr_audio : This deals with controlling the audio on TV cards,
+ * controlling the Audio Multiplexer (audio source selector).
+ * controlling any MSP34xx stereo audio decoders.
+ * controlling any DPL35xx dolby surroud sound audio decoders.
+ * initialising TDA98xx audio devices.
+ *
+ */
+
+/*
+ * 1. Redistributions of source code must retain the
+ * Copyright (c) 1997 Amancio Hasty, 1999 Roger Hardiman
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Amancio Hasty and
+ * Roger Hardiman
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/vnode.h>
+
+#ifdef __FreeBSD__
+
+#if (__FreeBSD_version < 500000)
+#include <machine/clock.h> /* for DELAY */
+#endif
+
+#include <pci/pcivar.h>
+
+#if (__FreeBSD_version >=300000)
+#include <machine/bus_memio.h> /* for bus space */
+#include <machine/bus.h>
+#include <sys/bus.h>
+#endif
+#endif
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+#include <sys/proc.h>
+#include <dev/ic/bt8xx.h> /* NetBSD location of .h files */
+#include <dev/pci/bktr/bktr_reg.h>
+#include <dev/pci/bktr/bktr_core.h>
+#include <dev/pci/bktr/bktr_tuner.h>
+#include <dev/pci/bktr/bktr_card.h>
+#include <dev/pci/bktr/bktr_audio.h>
+#else
+#include <machine/ioctl_meteor.h> /* Traditional location of .h files */
+#include <machine/ioctl_bt848.h> /* extensions to ioctl_meteor.h */
+#include <dev/bktr/bktr_reg.h>
+#include <dev/bktr/bktr_core.h>
+#include <dev/bktr/bktr_tuner.h>
+#include <dev/bktr/bktr_card.h>
+#include <dev/bktr/bktr_audio.h>
+#endif
+
+/*
+ * Prototypes for the GV_BCTV specific functions.
+ */
+void set_bctv_audio( bktr_ptr_t bktr );
+void bctv_gpio_write( bktr_ptr_t bktr, int port, int val );
+/*int bctv_gpio_read( bktr_ptr_t bktr, int port );*/ /* Not used */
+
+
+
+/*
+ * init_audio_devices
+ * Reset any MSP34xx or TDA98xx audio devices.
+ */
+void init_audio_devices( bktr_ptr_t bktr ) {
+
+ /* enable stereo if appropriate on TDA audio chip */
+ if ( bktr->card.dbx )
+ init_BTSC( bktr );
+
+ /* reset the MSP34xx stereo audio chip */
+ if ( bktr->card.msp3400c )
+ msp_dpl_reset( bktr, bktr->msp_addr );
+
+ /* reset the DPL35xx dolby audio chip */
+ if ( bktr->card.dpl3518a )
+ msp_dpl_reset( bktr, bktr->dpl_addr );
+
+}
+
+
+/*
+ *
+ */
+#define AUDIOMUX_DISCOVER_NOT
+int
+set_audio( bktr_ptr_t bktr, int cmd )
+{
+ u_long temp;
+ volatile u_char idx;
+
+#if defined( AUDIOMUX_DISCOVER )
+ if ( cmd >= 200 )
+ cmd -= 200;
+ else
+#endif /* AUDIOMUX_DISCOVER */
+
+ /* check for existance of audio MUXes */
+ if ( !bktr->card.audiomuxs[ 4 ] )
+ return( -1 );
+
+ switch (cmd) {
+ case AUDIO_TUNER:
+#ifdef BKTR_REVERSEMUTE
+ bktr->audio_mux_select = 3;
+#else
+ bktr->audio_mux_select = 0;
+#endif
+
+ if (bktr->reverse_mute )
+ bktr->audio_mux_select = 0;
+ else
+ bktr->audio_mux_select = 3;
+
+ break;
+ case AUDIO_EXTERN:
+ bktr->audio_mux_select = 1;
+ break;
+ case AUDIO_INTERN:
+ bktr->audio_mux_select = 2;
+ break;
+ case AUDIO_MUTE:
+ bktr->audio_mute_state = TRUE; /* set mute */
+ break;
+ case AUDIO_UNMUTE:
+ bktr->audio_mute_state = FALSE; /* clear mute */
+ break;
+ default:
+ printf("%s: audio cmd error %02x\n", bktr_name(bktr),
+ cmd);
+ return( -1 );
+ }
+
+
+ /* Most cards have a simple audio multiplexer to select the
+ * audio source. The I/O_GV card has a more advanced multiplexer
+ * and requires special handling.
+ */
+ if ( bktr->bt848_card == CARD_IO_GV ) {
+ set_bctv_audio( bktr );
+ return( 0 );
+ }
+
+ /* Proceed with the simpler audio multiplexer code for the majority
+ * of Bt848 cards.
+ */
+
+ /*
+ * Leave the upper bits of the GPIO port alone in case they control
+ * something like the dbx or teletext chips. This doesn't guarantee
+ * success, but follows the rule of least astonishment.
+ */
+
+ if ( bktr->audio_mute_state == TRUE ) {
+#ifdef BKTR_REVERSEMUTE
+ idx = 0;
+#else
+ idx = 3;
+#endif
+
+ if (bktr->reverse_mute )
+ idx = 3;
+ else
+ idx = 0;
+
+ }
+ else
+ idx = bktr->audio_mux_select;
+
+
+ temp = INL(bktr, BKTR_GPIO_DATA) & ~bktr->card.gpio_mux_bits;
+#if defined( AUDIOMUX_DISCOVER )
+ OUTL(bktr, BKTR_GPIO_DATA, temp | (cmd & 0xff));
+ printf("%s: cmd: %d audio mux %x temp %x \n", bktr_name(bktr),
+ cmd, bktr->card.audiomuxs[ idx ], temp );
+#else
+ OUTL(bktr, BKTR_GPIO_DATA, temp | bktr->card.audiomuxs[ idx ]);
+#endif /* AUDIOMUX_DISCOVER */
+
+
+
+ /* Some new Hauppauge cards do not have an audio mux */
+ /* Instead we use the MSP34xx chip to select TV audio, Line-In */
+ /* FM Radio and Mute */
+ /* Examples of this are the Hauppauge 44xxx MSP34xx models */
+ /* It is ok to drive both the mux and the MSP34xx chip. */
+ /* If there is no mux, the MSP does the switching of the audio source */
+ /* If there is a mux, it does the switching of the audio source */
+
+ if ((bktr->card.msp3400c) && (bktr->audio_mux_present == 0)) {
+
+ if (bktr->audio_mute_state == TRUE ) {
+ msp_dpl_write(bktr, bktr->msp_addr, 0x12, 0x0000, 0x0000); /* volume to MUTE */
+ } else {
+ if(bktr->audio_mux_select == 0) { /* TV Tuner */
+ msp_dpl_write(bktr, bktr->msp_addr, 0x12, 0x0000, 0x7300); /* 0 db volume */
+ if (bktr->msp_source_selected != 0) msp_autodetect(bktr); /* setup TV audio mode */
+ bktr->msp_source_selected = 0;
+ }
+ if(bktr->audio_mux_select == 1) { /* Line In */
+ msp_dpl_write(bktr, bktr->msp_addr, 0x12, 0x0000, 0x7300); /* 0 db volume */
+ msp_dpl_write(bktr, bktr->msp_addr, 0x12, 0x000d, 0x1900); /* scart prescale */
+ msp_dpl_write(bktr, bktr->msp_addr, 0x12, 0x0008, 0x0220); /* SCART | STEREO */
+ msp_dpl_write(bktr, bktr->msp_addr, 0x12, 0x0013, 0x0000); /* DSP In = SC1_IN_L/R */
+ bktr->msp_source_selected = 1;
+ }
+
+ if(bktr->audio_mux_select == 2) { /* FM Radio */
+ msp_dpl_write(bktr, bktr->msp_addr, 0x12, 0x0000, 0x7300); /* 0 db volume */
+ msp_dpl_write(bktr, bktr->msp_addr, 0x12, 0x000d, 0x1900); /* scart prescale */
+ msp_dpl_write(bktr, bktr->msp_addr, 0x12, 0x0008, 0x0220); /* SCART | STEREO */
+ msp_dpl_write(bktr, bktr->msp_addr, 0x12, 0x0013, 0x0200); /* DSP In = SC2_IN_L/R */
+ bktr->msp_source_selected = 2;
+ }
+ }
+ }
+
+
+ return( 0 );
+}
+
+
+/*
+ *
+ */
+void
+temp_mute( bktr_ptr_t bktr, int flag )
+{
+ static int muteState = FALSE;
+
+ if ( flag == TRUE ) {
+ muteState = bktr->audio_mute_state;
+ set_audio( bktr, AUDIO_MUTE ); /* prevent 'click' */
+ }
+ else {
+ tsleep( BKTR_SLEEP, PZERO, "tuning", hz/8 );
+ if ( muteState == FALSE )
+ set_audio( bktr, AUDIO_UNMUTE );
+ }
+}
+
+/* address of BTSC/SAP decoder chip */
+#define TDA9850_WADDR 0xb6
+#define TDA9850_RADDR 0xb7
+
+
+/* registers in the TDA9850 BTSC/dbx chip */
+#define CON1ADDR 0x04
+#define CON2ADDR 0x05
+#define CON3ADDR 0x06
+#define CON4ADDR 0x07
+#define ALI1ADDR 0x08
+#define ALI2ADDR 0x09
+#define ALI3ADDR 0x0a
+
+/*
+ * initialise the dbx chip
+ * taken from the Linux bttv driver TDA9850 initialisation code
+ */
+void
+init_BTSC( bktr_ptr_t bktr )
+{
+ i2cWrite(bktr, TDA9850_WADDR, CON1ADDR, 0x08); /* noise threshold st */
+ i2cWrite(bktr, TDA9850_WADDR, CON2ADDR, 0x08); /* noise threshold sap */
+ i2cWrite(bktr, TDA9850_WADDR, CON3ADDR, 0x40); /* stereo mode */
+ i2cWrite(bktr, TDA9850_WADDR, CON4ADDR, 0x07); /* 0 dB input gain? */
+ i2cWrite(bktr, TDA9850_WADDR, ALI1ADDR, 0x10); /* wideband alignment? */
+ i2cWrite(bktr, TDA9850_WADDR, ALI2ADDR, 0x10); /* spectral alignment? */
+ i2cWrite(bktr, TDA9850_WADDR, ALI3ADDR, 0x03);
+}
+
+/*
+ * setup the dbx chip
+ * XXX FIXME: alot of work to be done here, this merely unmutes it.
+ */
+int
+set_BTSC( bktr_ptr_t bktr, int control )
+{
+ return( i2cWrite( bktr, TDA9850_WADDR, CON3ADDR, control ) );
+}
+
+/*
+ * CARD_GV_BCTV specific functions.
+ */
+
+#define BCTV_AUDIO_MAIN 0x10 /* main audio program */
+#define BCTV_AUDIO_SUB 0x20 /* sub audio program */
+#define BCTV_AUDIO_BOTH 0x30 /* main(L) + sub(R) program */
+
+#define BCTV_GPIO_REG0 1
+#define BCTV_GPIO_REG1 3
+
+#define BCTV_GR0_AUDIO_MODE 3
+#define BCTV_GR0_AUDIO_MAIN 0 /* main program */
+#define BCTV_GR0_AUDIO_SUB 3 /* sub program */
+#define BCTV_GR0_AUDIO_BOTH 1 /* main(L) + sub(R) */
+#define BCTV_GR0_AUDIO_MUTE 4 /* audio mute */
+#define BCTV_GR0_AUDIO_MONO 8 /* force mono */
+
+void
+set_bctv_audio( bktr_ptr_t bktr )
+{
+ int data;
+
+ switch (bktr->audio_mux_select) {
+ case 1: /* external */
+ case 2: /* internal */
+ bctv_gpio_write(bktr, BCTV_GPIO_REG1, 0);
+ break;
+ default: /* tuner */
+ bctv_gpio_write(bktr, BCTV_GPIO_REG1, 1);
+ break;
+ }
+/* switch (bktr->audio_sap_select) { */
+ switch (BCTV_AUDIO_BOTH) {
+ case BCTV_AUDIO_SUB:
+ data = BCTV_GR0_AUDIO_SUB;
+ break;
+ case BCTV_AUDIO_BOTH:
+ data = BCTV_GR0_AUDIO_BOTH;
+ break;
+ case BCTV_AUDIO_MAIN:
+ default:
+ data = BCTV_GR0_AUDIO_MAIN;
+ break;
+ }
+ if (bktr->audio_mute_state == TRUE)
+ data |= BCTV_GR0_AUDIO_MUTE;
+
+ bctv_gpio_write(bktr, BCTV_GPIO_REG0, data);
+
+ return;
+}
+
+/* gpio_data bit assignment */
+#define BCTV_GPIO_ADDR_MASK 0x000300
+#define BCTV_GPIO_WE 0x000400
+#define BCTV_GPIO_OE 0x000800
+#define BCTV_GPIO_VAL_MASK 0x00f000
+
+#define BCTV_GPIO_PORT_MASK 3
+#define BCTV_GPIO_ADDR_SHIFT 8
+#define BCTV_GPIO_VAL_SHIFT 12
+
+/* gpio_out_en value for read/write */
+#define BCTV_GPIO_OUT_RMASK 0x000f00
+#define BCTV_GPIO_OUT_WMASK 0x00ff00
+
+#define BCTV_BITS 100
+
+void
+bctv_gpio_write( bktr_ptr_t bktr, int port, int val )
+{
+ u_long data, outbits;
+
+ port &= BCTV_GPIO_PORT_MASK;
+ switch (port) {
+ case 1:
+ case 3:
+ data = ((val << BCTV_GPIO_VAL_SHIFT) & BCTV_GPIO_VAL_MASK) |
+ ((port << BCTV_GPIO_ADDR_SHIFT) & BCTV_GPIO_ADDR_MASK) |
+ BCTV_GPIO_WE | BCTV_GPIO_OE;
+ outbits = BCTV_GPIO_OUT_WMASK;
+ break;
+ default:
+ return;
+ }
+ OUTL(bktr, BKTR_GPIO_OUT_EN, 0);
+ OUTL(bktr, BKTR_GPIO_DATA, data);
+ OUTL(bktr, BKTR_GPIO_OUT_EN, outbits);
+ DELAY(BCTV_BITS);
+ OUTL(bktr, BKTR_GPIO_DATA, data & ~BCTV_GPIO_WE);
+ DELAY(BCTV_BITS);
+ OUTL(bktr, BKTR_GPIO_DATA, data);
+ DELAY(BCTV_BITS);
+ OUTL(bktr, BKTR_GPIO_DATA, ~0);
+ OUTL(bktr, BKTR_GPIO_OUT_EN, 0);
+}
+
+/* Not yet used
+int
+bctv_gpio_read( bktr_ptr_t bktr, int port )
+{
+ u_long data, outbits, ret;
+
+ port &= BCTV_GPIO_PORT_MASK;
+ switch (port) {
+ case 1:
+ case 3:
+ data = ((port << BCTV_GPIO_ADDR_SHIFT) & BCTV_GPIO_ADDR_MASK) |
+ BCTV_GPIO_WE | BCTV_GPIO_OE;
+ outbits = BCTV_GPIO_OUT_RMASK;
+ break;
+ default:
+ return( -1 );
+ }
+ OUTL(bktr, BKTR_GPIO_OUT_EN, 0);
+ OUTL(bktr, BKTR_GPIO_DATA, data);
+ OUTL(bktr, BKTR_GPIO_OUT_EN, outbits);
+ DELAY(BCTV_BITS);
+ OUTL(bktr, BKTR_GPIO_DATA, data & ~BCTV_GPIO_OE);
+ DELAY(BCTV_BITS);
+ ret = INL(bktr, BKTR_GPIO_DATA);
+ DELAY(BCTV_BITS);
+ OUTL(bktr, BKTR_GPIO_DATA, data);
+ DELAY(BCTV_BITS);
+ OUTL(bktr, BKTR_GPIO_DATA, ~0);
+ OUTL(bktr, BKTR_GPIO_OUT_EN, 0);
+ return( (ret & BCTV_GPIO_VAL_MASK) >> BCTV_GPIO_VAL_SHIFT );
+}
+*/
+
+/*
+ * setup the MSP34xx Stereo Audio Chip
+ * This uses the Auto Configuration Option on MSP3410D and MSP3415D chips
+ * and DBX mode selection for MSP3430G chips.
+ * For MSP3400C support, the full programming sequence is required and is
+ * not yet supported.
+ */
+
+/* Read the MSP version string */
+void msp_read_id( bktr_ptr_t bktr ){
+ int rev1=0, rev2=0;
+ rev1 = msp_dpl_read(bktr, bktr->msp_addr, 0x12, 0x001e);
+ rev2 = msp_dpl_read(bktr, bktr->msp_addr, 0x12, 0x001f);
+
+ sprintf(bktr->msp_version_string, "34%02d%c-%c%d",
+ (rev2>>8)&0xff, (rev1&0xff)+'@', ((rev1>>8)&0xff)+'@', rev2&0x1f);
+
+}
+
+
+/* Configure the MSP chip to Auto-detect the audio format.
+ * For the MSP3430G, we use fast autodetect mode
+ * For the MSP3410/3415 there are two schemes for this
+ * a) Fast autodetection - the chip is put into autodetect mode, and the function
+ * returns immediatly. This works in most cases and is the Default Mode.
+ * b) Slow mode. The function sets the MSP3410/3415 chip, then waits for feedback from
+ * the chip and re-programs it if needed.
+ */
+void msp_autodetect( bktr_ptr_t bktr ) {
+ int auto_detect, loops;
+ int stereo;
+
+ /* MSP3430G - countries with mono and DBX stereo */
+ if (strncmp("3430G", bktr->msp_version_string, 5) == 0){
+
+ msp_dpl_write(bktr, bktr->msp_addr, 0x10, 0x0030,0x2003);/* Enable Auto format detection */
+ msp_dpl_write(bktr, bktr->msp_addr, 0x10, 0x0020,0x0020);/* Standard Select Reg. = BTSC-Stereo*/
+ msp_dpl_write(bktr, bktr->msp_addr, 0x12, 0x000E,0x2403);/* darned if I know */
+ msp_dpl_write(bktr, bktr->msp_addr, 0x12, 0x0008,0x0320);/* Source select = (St or A) */
+ /* & Ch. Matrix = St */
+ msp_dpl_write(bktr, bktr->msp_addr, 0x12, 0x0000,0x7300);/* Set volume to 0db gain */
+ }
+
+
+ /* MSP3415D SPECIAL CASE Use the Tuner's Mono audio ouput for the MSP */
+ /* (for Hauppauge 44xxx card with Tuner Type 0x2a) */
+ else if ( ( (strncmp("3415D", bktr->msp_version_string, 5) == 0)
+ &&(bktr->msp_use_mono_source == 1)
+ )
+ || (bktr->slow_msp_audio == 2) ){
+ msp_dpl_write(bktr, bktr->msp_addr, 0x12, 0x0000, 0x7300); /* 0 db volume */
+ msp_dpl_write(bktr, bktr->msp_addr, 0x12, 0x000d, 0x1900); /* scart prescale */
+ msp_dpl_write(bktr, bktr->msp_addr, 0x12, 0x0008, 0x0220); /* SCART | STEREO */
+ msp_dpl_write(bktr, bktr->msp_addr, 0x12, 0x0013, 0x0100); /* DSP In = MONO IN */
+ }
+
+
+ /* MSP3410/MSP3415 - countries with mono, stereo using 2 FM channels and NICAM */
+ /* FAST sound scheme */
+ else if (bktr->slow_msp_audio == 0) {
+ msp_dpl_write(bktr, bktr->msp_addr, 0x12, 0x0000,0x7300);/* Set volume to 0db gain */
+ msp_dpl_write(bktr, bktr->msp_addr, 0x12, 0x0008,0x0000);/* Spkr Source = default(FM/AM) */
+ msp_dpl_write(bktr, bktr->msp_addr, 0x10, 0x0020,0x0001);/* Enable Auto format detection */
+ msp_dpl_write(bktr, bktr->msp_addr, 0x10, 0x0021,0x0001);/* Auto selection of NICAM/MONO mode */
+ }
+
+
+ /* MSP3410/MSP3415 - European Countries where the fast MSP3410/3415 programming fails */
+ /* SLOW sound scheme */
+ else if ( bktr->slow_msp_audio == 1) {
+ msp_dpl_write(bktr, bktr->msp_addr, 0x12, 0x0000,0x7300);/* Set volume to 0db gain */
+ msp_dpl_write(bktr, bktr->msp_addr, 0x10, 0x0020,0x0001);/* Enable Auto format detection */
+
+ /* wait for 0.5s max for terrestrial sound autodetection */
+ loops = 10;
+ do {
+ DELAY(100000);
+ auto_detect = msp_dpl_read(bktr, bktr->msp_addr, 0x10, 0x007e);
+ loops++;
+ } while (auto_detect > 0xff && loops < 50);
+ if (bootverbose)printf ("%s: Result of autodetect after %dms: %d\n",
+ bktr_name(bktr), loops*10, auto_detect);
+
+ /* Now set the audio baseband processing */
+ switch (auto_detect) {
+ case 0: /* no TV sound standard detected */
+ break;
+ case 2: /* M Dual FM */
+ break;
+ case 3: /* B/G Dual FM; German stereo */
+ /* Read the stereo detection value from DSP reg 0x0018 */
+ DELAY(20000);
+ stereo = msp_dpl_read(bktr, bktr->msp_addr, 0x12, 0x0018);
+ if (bootverbose)printf ("%s: Stereo reg 0x18 a: %d\n",
+ bktr_name(bktr), stereo);
+ DELAY(20000);
+ stereo = msp_dpl_read(bktr, bktr->msp_addr, 0x12, 0x0018);
+ if (bootverbose)printf ("%s: Stereo reg 0x18 b: %d\n",
+ bktr_name(bktr), stereo);
+ DELAY(20000);
+ stereo = msp_dpl_read(bktr, bktr->msp_addr, 0x12, 0x0018);
+ if (bootverbose)printf ("%s: Stereo reg 0x18 c: %d\n",
+ bktr_name(bktr), stereo);
+ if (stereo > 0x0100 && stereo < 0x8000) { /* Seems to be stereo */
+ msp_dpl_write(bktr, bktr->msp_addr, 0x12, 0x0008,0x0020);/* Loudspeaker set stereo*/
+ /*
+ set spatial effect strength to 50% enlargement
+ set spatial effect mode b, stereo basewidth enlargment only
+ */
+ msp_dpl_write(bktr, bktr->msp_addr, 0x12, 0x0005,0x3f28);
+ } else if (stereo > 0x8000) { /* bilingual mode */
+ if (bootverbose) printf ("%s: Bilingual mode detected\n",
+ bktr_name(bktr));
+ msp_dpl_write(bktr, bktr->msp_addr, 0x12, 0x0008,0x0000);/* Loudspeaker */
+ msp_dpl_write(bktr, bktr->msp_addr, 0x12, 0x0005,0x0000);/* all spatial effects off */
+ } else { /* must be mono */
+ msp_dpl_write(bktr, bktr->msp_addr, 0x12, 0x0008,0x0030);/* Loudspeaker */
+ /*
+ set spatial effect strength to 50% enlargement
+ set spatial effect mode a, stereo basewidth enlargment
+ and pseudo stereo effect with automatic high-pass filter
+ */
+ msp_dpl_write(bktr, bktr->msp_addr, 0x12, 0x0005,0x3f08);
+ }
+#if 0
+ /* The reset value for Channel matrix mode is FM/AM and SOUNDA/LEFT */
+ /* We would like STEREO instead val: 0x0020 */
+ msp_dpl_write(bktr, bktr->msp_addr, 0x12, 0x0008,0x0020);/* Loudspeaker */
+ msp_dpl_write(bktr, bktr->msp_addr, 0x12, 0x0009,0x0020);/* Headphone */
+ msp_dpl_write(bktr, bktr->msp_addr, 0x12, 0x000a,0x0020);/* SCART1 */
+ msp_dpl_write(bktr, bktr->msp_addr, 0x12, 0x0041,0x0020);/* SCART2 */
+ msp_dpl_write(bktr, bktr->msp_addr, 0x12, 0x000b,0x0020);/* I2S */
+ msp_dpl_write(bktr, bktr->msp_addr, 0x12, 0x000c,0x0020);/* Quasi-Peak Detector Source */
+ msp_dpl_write(bktr, bktr->msp_addr, 0x12, 0x000e,0x0001);
+#endif
+ break;
+ case 8: /* B/G FM NICAM */
+ msp_dpl_write(bktr, bktr->msp_addr, 0x10, 0x0021,0x0001);/* Auto selection of NICAM/MONO mode */
+ break;
+ case 9: /* L_AM NICAM or D/K*/
+ case 10: /* i-FM NICAM */
+ break;
+ default:
+ if (bootverbose) printf ("%s: Unknown autodetection result value: %d\n",
+ bktr_name(bktr), auto_detect);
+ }
+
+ }
+
+
+ /* uncomment the following line to enable the MSP34xx 1Khz Tone Generator */
+ /* turn your speaker volume down low before trying this */
+ /* msp_dpl_write(bktr, bktr->msp_addr, 0x12, 0x0014, 0x7f40); */
+}
+
+/* Read the DPL version string */
+void dpl_read_id( bktr_ptr_t bktr ){
+ int rev1=0, rev2=0;
+ rev1 = msp_dpl_read(bktr, bktr->dpl_addr, 0x12, 0x001e);
+ rev2 = msp_dpl_read(bktr, bktr->dpl_addr, 0x12, 0x001f);
+
+ sprintf(bktr->dpl_version_string, "34%02d%c-%c%d",
+ ((rev2>>8)&0xff)-1, (rev1&0xff)+'@', ((rev1>>8)&0xff)+'@', rev2&0x1f);
+}
+
+/* Configure the DPL chip to Auto-detect the audio format */
+void dpl_autodetect( bktr_ptr_t bktr ) {
+
+ /* The following are empiric values tried from the DPL35xx data sheet */
+ msp_dpl_write(bktr, bktr->dpl_addr, 0x12, 0x000c,0x0320); /* quasi peak detector source dolby
+ lr 0x03xx; quasi peak detector matrix
+ stereo 0xXX20 */
+ msp_dpl_write(bktr, bktr->dpl_addr, 0x12, 0x0040,0x0060); /* Surround decoder mode;
+ ADAPTIVE/3D-PANORAMA, that means two
+ speakers and no center speaker, all
+ channels L/R/C/S mixed to L and R */
+ msp_dpl_write(bktr, bktr->dpl_addr, 0x12, 0x0041,0x0620); /* surround source matrix;I2S2/STEREO*/
+ msp_dpl_write(bktr, bktr->dpl_addr, 0x12, 0x0042,0x1F00); /* surround delay 31ms max */
+ msp_dpl_write(bktr, bktr->dpl_addr, 0x12, 0x0043,0x0000); /* automatic surround input balance */
+ msp_dpl_write(bktr, bktr->dpl_addr, 0x12, 0x0044,0x4000); /* surround spatial effect 50%
+ recommended*/
+ msp_dpl_write(bktr, bktr->dpl_addr, 0x12, 0x0045,0x5400); /* surround panorama effect 66%
+ recommended with PANORAMA mode
+ in 0x0040 set to panorama */
+}
+
diff --git a/sys/dev/pci/bktr/bktr_audio.h b/sys/dev/pci/bktr/bktr_audio.h
new file mode 100644
index 00000000000..6ecae8ca919
--- /dev/null
+++ b/sys/dev/pci/bktr/bktr_audio.h
@@ -0,0 +1,85 @@
+/* $OpenBSD: bktr_audio.h,v 1.1 2001/03/28 03:27:09 fgsch Exp $ */
+/* $FreeBSD: src/sys/dev/bktr/bktr_audio.h,v 1.2 1999/10/28 13:58:14 roger Exp $ */
+
+/*
+ * This is part of the Driver for Video Capture Cards (Frame grabbers)
+ * and TV Tuner cards using the Brooktree Bt848, Bt848A, Bt849A, Bt878, Bt879
+ * chipset.
+ * Copyright Roger Hardiman and Amancio Hasty.
+ *
+ * bktr_audio : This deals with controlling the audio on TV cards,
+ * controlling the Audio Multiplexer (audio source selector).
+ * controlling any MSP34xx stereo audio decoders.
+ * controlling any DPL35xx dolby surroud sound audio decoders.
+ * initialising TDA98xx audio devices.
+ *
+ */
+
+/*
+ * 1. Redistributions of source code must retain the
+ * Copyright (c) 1997 Amancio Hasty, 1999 Roger Hardiman
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Amancio Hasty and
+ * Roger Hardiman
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Select Audio source, and allow muting
+ */
+int set_audio( bktr_ptr_t bktr, int mode );
+void temp_mute( bktr_ptr_t bktr, int flag );
+
+
+/*
+ * Initialise any MSP or TDA devices
+ */
+void init_audio_devices( bktr_ptr_t bktr );
+
+
+/*
+ * MSP34xx Audio Chip functions.
+ */
+void msp_autodetect( bktr_ptr_t bktr );
+void msp_read_id( bktr_ptr_t bktr );
+
+
+/*
+ * DPL35xx Audio Chip functions.
+ */
+void dpl_autodetect( bktr_ptr_t bktr );
+void dpl_read_id( bktr_ptr_t bktr );
+
+
+/*
+ * TDA98xx Audio Chip functions.
+ */
+void init_BTSC( bktr_ptr_t bktr );
+int set_BTSC( bktr_ptr_t bktr, int control );
+
+
+
diff --git a/sys/dev/pci/bktr/bktr_card.c b/sys/dev/pci/bktr/bktr_card.c
new file mode 100644
index 00000000000..843aaf49330
--- /dev/null
+++ b/sys/dev/pci/bktr/bktr_card.c
@@ -0,0 +1,1268 @@
+/* $OpenBSD: bktr_card.c,v 1.1 2001/03/28 03:27:09 fgsch Exp $ */
+/* $FreeBSD: src/sys/dev/bktr/bktr_card.c,v 1.16 2000/10/31 13:09:56 roger Exp $ */
+
+/*
+ * This is part of the Driver for Video Capture Cards (Frame grabbers)
+ * and TV Tuner cards using the Brooktree Bt848, Bt848A, Bt849A, Bt878, Bt879
+ * chipset.
+ * Copyright Roger Hardiman and Amancio Hasty.
+ *
+ * bktr_card : This deals with identifying TV cards.
+ * trying to find the card make and model of card.
+ * trying to find the type of tuner fitted.
+ * reading the configuration EEPROM.
+ * locating i2c devices.
+ *
+ */
+
+/*
+ * 1. Redistributions of source code must retain the
+ * Copyright (c) 1997 Amancio Hasty, 1999 Roger Hardiman
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Amancio Hasty and
+ * Roger Hardiman
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __OpenBSD__
+#include "opt_bktr.h" /* Include any kernel config options */
+#endif
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/vnode.h>
+
+#ifdef __FreeBSD__
+
+#if (__FreeBSD_version < 500000)
+#include <machine/clock.h> /* for DELAY */
+#endif
+
+#include <pci/pcivar.h>
+
+#if (__FreeBSD_version >=300000)
+#include <machine/bus_memio.h> /* for bus space */
+#include <machine/bus.h>
+#include <sys/bus.h>
+#endif
+#endif
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+#include <dev/ic/bt8xx.h> /* NetBSD location for .h files */
+#include <dev/pci/bktr/bktr_reg.h>
+#include <dev/pci/bktr/bktr_core.h>
+#include <dev/pci/bktr/bktr_tuner.h>
+#include <dev/pci/bktr/bktr_card.h>
+#include <dev/pci/bktr/bktr_audio.h>
+#else
+#include <machine/ioctl_meteor.h> /* Traditional location for .h files */
+#include <machine/ioctl_bt848.h> /* extensions to ioctl_meteor.h */
+#include <dev/bktr/bktr_reg.h>
+#include <dev/bktr/bktr_core.h>
+#include <dev/bktr/bktr_tuner.h>
+#include <dev/bktr/bktr_card.h>
+#include <dev/bktr/bktr_audio.h>
+#endif
+
+/* Include the PCI Vendor definitions */
+#ifdef __NetBSD__
+#include <dev/pci/pcidevs.h>
+#include <dev/pci/pcireg.h>
+#endif
+
+/* Various defines */
+#define HAUP_REMOTE_INT_WADDR 0x30
+#define HAUP_REMOTE_INT_RADDR 0x31
+
+#define HAUP_REMOTE_EXT_WADDR 0x34
+#define HAUP_REMOTE_EXT_RADDR 0x35
+
+/* address of BTSC/SAP decoder chip */
+#define TDA9850_WADDR 0xb6
+#define TDA9850_RADDR 0xb7
+
+/* address of MSP3400C chip */
+#define MSP3400C_WADDR 0x80
+#define MSP3400C_RADDR 0x81
+
+/* address of DPL3518A chip */
+#define DPL3518A_WADDR 0x84
+#define DPL3518A_RADDR 0x85
+
+/* EEProm (128 * 8) on an STB card */
+#define X24C01_WADDR 0xae
+#define X24C01_RADDR 0xaf
+
+
+/* EEProm (256 * 8) on a Hauppauge card */
+/* and on most BT878s cards to store the sub-system vendor id */
+#define PFC8582_WADDR 0xa0
+#define PFC8582_RADDR 0xa1
+
+#if BKTR_SYSTEM_DEFAULT == BROOKTREE_PAL
+#define DEFAULT_TUNER PHILIPS_PALI
+#else
+#define DEFAULT_TUNER PHILIPS_NTSC
+#endif
+
+
+
+
+/*
+ * the data for each type of card
+ *
+ * Note:
+ * these entried MUST be kept in the order defined by the CARD_XXX defines!
+ */
+static const struct CARDTYPE cards[] = {
+
+ { CARD_UNKNOWN, /* the card id */
+ "Unknown", /* the 'name' */
+ NULL, /* the tuner */
+ 0, /* the tuner i2c address */
+ 0, /* dbx unknown */
+ 0,
+ 0,
+ 0, /* EEProm unknown */
+ 0, /* EEProm unknown */
+ { 0, 0, 0, 0, 0 },
+ 0 }, /* GPIO mask */
+
+ { CARD_MIRO, /* the card id */
+ "Pinnacle/Miro TV", /* the 'name' */
+ NULL, /* the tuner */
+ 0, /* the tuner i2c address */
+ 0, /* dbx unknown */
+ 0,
+ 0,
+ 0, /* EEProm unknown */
+ 0, /* size unknown */
+ { 0x02, 0x01, 0x00, 0x0a, 1 }, /* audio MUX values */
+ 0x0f }, /* GPIO mask */
+
+ { CARD_HAUPPAUGE, /* the card id */
+ "Hauppauge WinCast/TV", /* the 'name' */
+ NULL, /* the tuner */
+ 0, /* the tuner i2c address */
+ 0, /* dbx is optional */
+ 0,
+ 0,
+ PFC8582_WADDR, /* EEProm type */
+ (u_char)(256 / EEPROMBLOCKSIZE), /* 256 bytes */
+ { 0x00, 0x02, 0x01, 0x04, 1 }, /* audio MUX values */
+ 0x0f }, /* GPIO mask */
+
+ { CARD_STB, /* the card id */
+ "STB TV/PCI", /* the 'name' */
+ NULL, /* the tuner */
+ 0, /* the tuner i2c address */
+ 0, /* dbx is optional */
+ 0,
+ 0,
+ X24C01_WADDR, /* EEProm type */
+ (u_char)(128 / EEPROMBLOCKSIZE), /* 128 bytes */
+ { 0x00, 0x01, 0x02, 0x02, 1 }, /* audio MUX values */
+ 0x0f }, /* GPIO mask */
+
+ { CARD_INTEL, /* the card id */
+ "Intel Smart Video III/VideoLogic Captivator PCI", /* the 'name' */
+ NULL, /* the tuner */
+ 0, /* the tuner i2c address */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ { 0, 0, 0, 0, 0 }, /* audio MUX values */
+ 0x00 }, /* GPIO mask */
+
+ { CARD_IMS_TURBO, /* the card id */
+ "IMS TV Turbo", /* the 'name' */
+ NULL, /* the tuner */
+ 0, /* the tuner i2c address */
+ 0, /* dbx is optional */
+ 0,
+ 0,
+ PFC8582_WADDR, /* EEProm type */
+ (u_char)(256 / EEPROMBLOCKSIZE), /* 256 bytes */
+ { 0x01, 0x02, 0x01, 0x00, 1 }, /* audio MUX values */
+ 0x0f }, /* GPIO mask */
+
+ { CARD_AVER_MEDIA, /* the card id */
+ "AVer Media TV/FM", /* the 'name' */
+ NULL, /* the tuner */
+ 0, /* the tuner i2c address */
+ 0, /* dbx is optional */
+ 0,
+ 0,
+ 0, /* EEProm type */
+ 0, /* EEProm size */
+ { 0x0c, 0x08, 0x04, 0x00, 1 }, /* audio MUX values */
+ 0x1f }, /* GPIO mask */
+
+ { CARD_OSPREY, /* the card id */
+ "MMAC Osprey", /* the 'name' */
+ NULL, /* the tuner */
+ 0, /* the tuner i2c address */
+ 0, /* dbx is optional */
+ 0,
+ 0,
+ PFC8582_WADDR, /* EEProm type */
+ (u_char)(256 / EEPROMBLOCKSIZE), /* 256 bytes */
+ { 0x00, 0x00, 0x00, 0x00, 0 }, /* audio MUX values */
+ 0 }, /* GPIO mask */
+
+ { CARD_NEC_PK, /* the card id */
+ "NEC PK-UG-X017", /* the 'name' */
+ NULL, /* the tuner */
+ 0, /* the tuner i2c address */
+ 0, /* dbx is optional */
+ 0,
+ 0,
+ 0, /* EEProm type */
+ 0, /* EEProm size */
+ { 0x01, 0x02, 0x01, 0x00, 1 }, /* audio MUX values */
+ 0x0f }, /* GPIO mask */
+
+ { CARD_IO_GV, /* the card id */
+ "I/O DATA GV-BCTV2/PCI", /* the 'name' */
+ NULL, /* the tuner */
+ 0, /* the tuner i2c address */
+ 0, /* dbx is optional */
+ 0,
+ 0,
+ 0, /* EEProm type */
+ 0, /* EEProm size */
+ { 0x00, 0x00, 0x00, 0x00, 1 }, /* Has special MUX handler */
+ 0x0f }, /* GPIO mask */
+
+ { CARD_FLYVIDEO, /* the card id */
+ "FlyVideo", /* the 'name' */
+ NULL, /* the tuner */
+ 0, /* the tuner i2c address */
+ 0, /* dbx is optional */
+ 0, /* msp34xx is optional */
+ 0, /* dpl3518a is optional */
+ 0xac, /* EEProm type */
+ (u_char)(256 / EEPROMBLOCKSIZE), /* 256 bytes */
+ { 0x000, 0x800, 0x400, 0x8dff00, 1 },/* audio MUX values */
+ 0x8dff00 }, /* GPIO mask */
+
+ { CARD_ZOLTRIX, /* the card id */
+ "Zoltrix", /* the 'name' */
+ NULL, /* the tuner */
+ 0, /* the tuner i2c address */
+ 0, /* dbx is optional */
+ 0, /* msp34xx is optional */
+ 0, /* dpl3518a is optional */
+ 0, /* EEProm type */
+ 0, /* EEProm size */
+ { 0x04, 0x01, 0x00, 0x0a, 1 }, /* audio MUX values */
+ 0x0f }, /* GPIO mask */
+
+ { CARD_KISS, /* the card id */
+ "KISS TV/FM PCI", /* the 'name' */
+ NULL, /* the tuner */
+ 0, /* the tuner i2c address */
+ 0, /* dbx is optional */
+ 0, /* msp34xx is optional */
+ 0, /* dpl3518a is optional */
+ 0, /* EEProm type */
+ 0, /* EEProm size */
+ { 0x0c, 0x00, 0x0b, 0x0b, 1 }, /* audio MUX values */
+ 0x0f }, /* GPIO mask */
+
+ { CARD_VIDEO_HIGHWAY_XTREME, /* the card id */
+ "Video Highway Xtreme", /* the 'name' */
+ NULL, /* the tuner */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0, /* EEProm type */
+ 0, /* EEProm size */
+ { 0x00, 0x02, 0x01, 0x04, 1 }, /* audio MUX values */
+ 0x0f }, /* GPIO mask */
+
+ { CARD_ASKEY_DYNALINK_MAGIC_TVIEW, /* the card id */
+ "Askey/Dynalink Magic TView", /* the 'name' */
+ NULL, /* the tuner */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0, /* EEProm type */
+ 0, /* EEProm size */
+ { 0x400, 0xE00, 0x400, 0xC00, 1 }, /* audio MUX values */
+ 0xE00 }, /* GPIO mask */
+
+ { CARD_LEADTEK, /* the card id */
+ "Leadtek Winfast TV 2000", /* the 'name' */
+ NULL, /* the tuner */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0, /* EEProm type */
+ 0, /* EEProm size */
+ /* Tuner, Extern, Intern, Mute, Enabled */
+ { 0x621000, 0x621000, 0x621000, 0xE21000, 1 }, /* audio MUX values */
+ 0xfff000 }, /* GPIO mask */
+
+ { CARD_TERRATVPLUS, /* the card id */
+ "TerraTVplus", /* the 'name' */
+ NULL, /* the tuner */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0, /* EEProm type */
+ 0, /* EEProm size */
+ { 0x20000, 0x00000, 0x30000, 0x40000, 1 }, /* audio MUX values*/
+ 0x70000 }, /* GPIO mask */
+
+};
+
+struct bt848_card_sig bt848_card_signature[1]= {
+ /* IMS TURBO TV : card 5 */
+ { 5,9, {00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 02, 00, 00, 00}}
+
+
+};
+
+
+/*
+ * Write to the configuration EEPROM on the card.
+ * This is dangerous and will mess up your card. Therefore it is not
+ * implemented.
+ */
+int
+writeEEProm( bktr_ptr_t bktr, int offset, int count, u_char *data )
+{
+ return( -1 );
+}
+
+/*
+ * Read the contents of the configuration EEPROM on the card.
+ * (This is not fitted to all makes of card. All Hauppauge cards have them
+ * and so do newer Bt878 based cards.
+ */
+int
+readEEProm( bktr_ptr_t bktr, int offset, int count, u_char *data )
+{
+ int x;
+ int addr;
+ int max;
+ int byte;
+
+ /* get the address of the EEProm */
+ addr = (int)(bktr->card.eepromAddr & 0xff);
+ if ( addr == 0 )
+ return( -1 );
+
+ max = (int)(bktr->card.eepromSize * EEPROMBLOCKSIZE);
+ if ( (offset + count) > max )
+ return( -1 );
+
+ /* set the start address */
+ if ( i2cWrite( bktr, addr, offset, -1 ) == -1 )
+ return( -1 );
+
+ /* the read cycle */
+ for ( x = 0; x < count; ++x ) {
+ if ( (byte = i2cRead( bktr, (addr | 1) )) == -1 )
+ return( -1 );
+ data[ x ] = byte;
+ }
+
+ return( 0 );
+}
+
+
+#define ABSENT (-1)
+
+/*
+ * get a signature of the card
+ * read all 128 possible i2c read addresses from 0x01 thru 0xff
+ * build a bit array with a 1 bit for each i2c device that responds
+ *
+ * XXX FIXME: use offset & count args
+ */
+int
+signCard( bktr_ptr_t bktr, int offset, int count, u_char* sig )
+{
+ int x;
+
+ for ( x = 0; x < 16; ++x )
+ sig[ x ] = 0;
+
+ for ( x = 0; x < count; ++x ) {
+ if ( i2cRead( bktr, (2 * x) + 1 ) != ABSENT ) {
+ sig[ x / 8 ] |= (1 << (x % 8) );
+ }
+ }
+
+ return( 0 );
+}
+
+
+/*
+ * check_for_i2c_devices.
+ * Some BT848 cards have no tuner and no additional i2c devices
+ * eg stereo decoder. These are used for video conferencing or capture from
+ * a video camera. (eg VideoLogic Captivator PCI, Intel SmartCapture card).
+ *
+ * Determine if there are any i2c devices present. There are none present if
+ * a) reading from all 128 devices returns ABSENT (-1) for each one
+ * (eg VideoLogic Captivator PCI with BT848)
+ * b) reading from all 128 devices returns 0 for each one
+ * (eg VideoLogic Captivator PCI rev. 2F with BT848A)
+ */
+static int check_for_i2c_devices( bktr_ptr_t bktr ){
+ int x, temp_read;
+ int i2c_all_0 = 1;
+ int i2c_all_absent = 1;
+ for ( x = 0; x < 128; ++x ) {
+ temp_read = i2cRead( bktr, (2 * x) + 1 );
+ if (temp_read != 0) i2c_all_0 = 0;
+ if (temp_read != ABSENT) i2c_all_absent = 0;
+ }
+
+ if ((i2c_all_0) || (i2c_all_absent)) return 0;
+ else return 1;
+}
+
+
+/*
+ * Temic/Philips datasheets say tuners can be at i2c addresses 0xc0, 0xc2,
+ * 0xc4 or 0xc6, settable by links on the tuner.
+ * Determine the actual address used on the TV card by probing read addresses.
+ */
+static int locate_tuner_address( bktr_ptr_t bktr) {
+ if (i2cRead( bktr, 0xc1) != ABSENT) return 0xc0;
+ if (i2cRead( bktr, 0xc3) != ABSENT) return 0xc2;
+ if (i2cRead( bktr, 0xc5) != ABSENT) return 0xc4;
+ if (i2cRead( bktr, 0xc7) != ABSENT) return 0xc6;
+ return -1; /* no tuner found */
+}
+
+
+/*
+ * Search for a configuration EEPROM on the i2c bus by looking at i2c addresses
+ * where EEPROMs are usually found.
+ * On some cards, the EEPROM appears in several locations, but all in the
+ * range 0xa0 to 0xae.
+ */
+static int locate_eeprom_address( bktr_ptr_t bktr) {
+ if (i2cRead( bktr, 0xa0) != ABSENT) return 0xa0;
+ if (i2cRead( bktr, 0xac) != ABSENT) return 0xac;
+ if (i2cRead( bktr, 0xae) != ABSENT) return 0xae;
+ return -1; /* no eeprom found */
+}
+
+
+/*
+ * determine the card brand/model
+ * BKTR_OVERRIDE_CARD, BKTR_OVERRIDE_TUNER, BKTR_OVERRIDE_DBX and
+ * BKTR_OVERRIDE_MSP can be used to select a specific device,
+ * regardless of the autodetection and i2c device checks.
+ *
+ * The scheme used for probing cards faces these problems:
+ * It is impossible to work out which type of tuner is actually fitted,
+ * (the driver cannot tell if the Tuner is PAL or NTSC, Temic or Philips)
+ * It is impossible to determine what audio-mux hardware is connected.
+ * It is impossible to determine if there is extra hardware connected to the
+ * GPIO pins (eg radio chips or MSP34xx reset logic)
+ *
+ * However some makes of card (eg Hauppauge) come with a configuration eeprom
+ * which tells us the make of the card. Most eeproms also tell us the
+ * tuner type and other features of the the cards.
+ *
+ * The current probe code works as follows
+ * A) If the card uses a Bt878/879:
+ * 1) Read the sub-system vendor id from the configuration EEPROM.
+ * Select the required tuner, audio mux arrangement and any other
+ * onboard features. If this fails, move to step B.
+ * B) If it card uses a Bt848, 848A, 849A or an unknown Bt878/879:
+ * 1) Look for I2C devices. If there are none fitted, it is an Intel or
+ * VideoLogic cards.
+ * 2) Look for a configuration EEPROM.
+ * 2a) If there is one at I2C address 0xa0 it may be
+ * a Hauppauge or an Osprey. Check the EEPROM contents to determine which
+ * one it is. For Hauppauge, select the tuner type and audio hardware.
+ * 2b) If there is an EEPROM at I2C address 0xa8 it will be an STB card.
+ * We still have to guess on the tuner type.
+ *
+ * C) If we do not know the card type from (A) or (B), guess at the tuner
+ * type based on the I2C address of the tuner.
+ *
+ * D) After determining the Tuner Type, we probe the i2c bus for other
+ * devices at known locations, eg IR-Remote Control, MSP34xx and TDA
+ * stereo chips.
+ */
+
+
+/*
+ * These are the sub-system vendor ID codes stored in the
+ * configuration EEPROM used on Bt878/879 cards. They should match the
+ * number assigned to the company by the PCI Special Interest Group
+ */
+#ifndef __NetBSD__
+#define PCI_VENDOR_HAUPPAUGE 0x0070
+#define PCI_VENDOR_AVERMEDIA 0x1461
+#define PCI_VENDOR_STB 0x10B4
+#define PCI_VENDOR_ASKEY 0x144F
+#endif
+/* Following not confirmed with http://members.hyperlink.net.au/~chart,
+ so not added to NetBSD's pcidevs */
+#define PCI_VENDOR_LEADTEK_ALT 0x6606
+#define PCI_VENDOR_FLYVIDEO 0x1851
+#define PCI_VENDOR_FLYVIDEO_2 0x1852
+#define PCI_VENDOR_PINNACLE_ALT 0xBD11
+
+
+void
+probeCard( bktr_ptr_t bktr, int verbose, int unit )
+{
+ int card, i,j, card_found;
+ int status;
+ u_char probe_signature[128], *probe_temp;
+ int any_i2c_devices;
+ u_char eeprom[256];
+ int tuner_i2c_address = -1;
+ int eeprom_i2c_address = -1;
+
+ /* Select all GPIO bits as inputs */
+ OUTL(bktr, BKTR_GPIO_OUT_EN, 0);
+ if (bootverbose)
+ printf("%s: GPIO is 0x%08x\n", bktr_name(bktr),
+ INL(bktr, BKTR_GPIO_DATA));
+
+#ifdef HAUPPAUGE_MSP_RESET
+ /* Reset the MSP34xx audio chip. This resolves bootup card
+ * detection problems with old Bt848 based Hauppauge cards with
+ * MSP34xx stereo audio chips. This must be user enabled because
+ * at this point the probe function does not know the card type. */
+ OUTL(bktr, BKTR_GPIO_OUT_EN, INL(bktr, BKTR_GPIO_OUT_EN) | (1<<5));
+ OUTL(bktr, BKTR_GPIO_DATA, INL(bktr, BKTR_GPIO_DATA) | (1<<5)); /* write '1' */
+ DELAY(2500); /* wait 2.5ms */
+ OUTL(bktr, BKTR_GPIO_DATA, INL(bktr, BKTR_GPIO_DATA) & ~(1<<5)); /* write '0' */
+ DELAY(2500); /* wait 2.5ms */
+ OUTL(bktr, BKTR_GPIO_DATA, INL(bktr, BKTR_GPIO_DATA) | (1<<5)); /* write '1' */
+ DELAY(2500); /* wait 2.5ms */
+#endif
+
+ /* Check for the presence of i2c devices */
+ any_i2c_devices = check_for_i2c_devices( bktr );
+
+
+ /* Check for a user specified override on the card selection */
+#if defined( BKTR_OVERRIDE_CARD )
+ bktr->card = cards[ (card = BKTR_OVERRIDE_CARD) ];
+ goto checkEEPROM;
+#endif
+ if (bktr->bt848_card != -1 ) {
+ bktr->card = cards[ (card = bktr->bt848_card) ];
+ goto checkEEPROM;
+ }
+
+
+ /* No override, so try and determine the make of the card */
+
+ /* On BT878/879 cards, read the sub-system vendor id */
+ /* This identifies the manufacturer of the card and the model */
+ /* In theory this can be read from PCI registers but this does not */
+ /* appear to work on the FlyVideo 98. Hauppauge also warned that */
+ /* the PCI registers are sometimes not loaded correctly. */
+ /* Therefore, I will read the sub-system vendor ID from the EEPROM */
+ /* (just like the Bt878 does during power up initialisation) */
+
+ if ((bktr->id==BROOKTREE_878) || (bktr->id==BROOKTREE_879)) {
+ /* Try and locate the EEPROM */
+ eeprom_i2c_address = locate_eeprom_address( bktr );
+ if (eeprom_i2c_address != -1) {
+
+ unsigned int subsystem_vendor_id; /* vendors PCI-SIG ID */
+ unsigned int subsystem_id; /* board model number */
+ unsigned int byte_252, byte_253, byte_254, byte_255;
+
+ bktr->card = cards[ (card = CARD_UNKNOWN) ];
+ bktr->card.eepromAddr = eeprom_i2c_address;
+ bktr->card.eepromSize = (u_char)(256 / EEPROMBLOCKSIZE);
+
+ readEEProm(bktr, 0, 256, (u_char *) &eeprom );
+ byte_252 = (unsigned int)eeprom[252];
+ byte_253 = (unsigned int)eeprom[253];
+ byte_254 = (unsigned int)eeprom[254];
+ byte_255 = (unsigned int)eeprom[255];
+
+ subsystem_id = (byte_252 << 8) | byte_253;
+ subsystem_vendor_id = (byte_254 << 8) | byte_255;
+
+ if ( bootverbose )
+ printf("%s: subsystem 0x%04x 0x%04x\n", bktr_name(bktr),
+ subsystem_vendor_id, subsystem_id);
+
+ if (subsystem_vendor_id == PCI_VENDOR_AVERMEDIA) {
+ bktr->card = cards[ (card = CARD_AVER_MEDIA) ];
+ bktr->card.eepromAddr = eeprom_i2c_address;
+ bktr->card.eepromSize = (u_char)(256 / EEPROMBLOCKSIZE);
+ goto checkTuner;
+ }
+
+ if (subsystem_vendor_id == PCI_VENDOR_HAUPPAUGE) {
+ bktr->card = cards[ (card = CARD_HAUPPAUGE) ];
+ bktr->card.eepromAddr = eeprom_i2c_address;
+ bktr->card.eepromSize = (u_char)(256 / EEPROMBLOCKSIZE);
+ goto checkTuner;
+ }
+
+ if ((subsystem_vendor_id == PCI_VENDOR_FLYVIDEO)
+ || (subsystem_vendor_id == PCI_VENDOR_FLYVIDEO_2) ) {
+ bktr->card = cards[ (card = CARD_FLYVIDEO) ];
+ bktr->card.eepromAddr = eeprom_i2c_address;
+ bktr->card.eepromSize = (u_char)(256 / EEPROMBLOCKSIZE);
+ goto checkTuner;
+ }
+
+ if (subsystem_vendor_id == PCI_VENDOR_STB) {
+ bktr->card = cards[ (card = CARD_STB) ];
+ bktr->card.eepromAddr = eeprom_i2c_address;
+ bktr->card.eepromSize = (u_char)(256 / EEPROMBLOCKSIZE);
+ goto checkTuner;
+ }
+
+ if (subsystem_vendor_id == PCI_VENDOR_ASKEY) {
+ bktr->card = cards[ (card = CARD_ASKEY_DYNALINK_MAGIC_TVIEW) ];
+ bktr->card.eepromAddr = eeprom_i2c_address;
+ bktr->card.eepromSize = (u_char)(256 / EEPROMBLOCKSIZE);
+ goto checkTuner;
+ }
+
+ if (subsystem_vendor_id == PCI_VENDOR_LEADTEK_ALT) {
+ bktr->card = cards[ (card = CARD_LEADTEK) ];
+ bktr->card.eepromAddr = eeprom_i2c_address;
+ bktr->card.eepromSize = (u_char)(256 / EEPROMBLOCKSIZE);
+ goto checkTuner;
+ }
+
+ if (subsystem_vendor_id == PCI_VENDOR_PINNACLE_ALT) {
+ bktr->card = cards[ (card = CARD_MIRO) ];
+ bktr->card.eepromAddr = eeprom_i2c_address;
+ bktr->card.eepromSize = (u_char)(256 / EEPROMBLOCKSIZE);
+ goto checkTuner;
+ }
+
+ /* Vendor is unknown. We will use the standard probe code */
+ /* which may not give best results */
+ printf("%s: Warning - card vendor 0x%04x (model 0x%04x) unknown.\n",
+ bktr_name(bktr), subsystem_vendor_id, subsystem_id);
+ }
+ else
+ {
+ printf("%s: Card has no configuration EEPROM. Cannot determine card make.\n",
+ bktr_name(bktr));
+ }
+ } /* end of bt878/bt879 card detection code */
+
+ /* If we get to this point, we must have a Bt848/848A/849A card */
+ /* or a Bt878/879 with an unknown subsystem vendor id */
+ /* Try and determine the make of card by clever i2c probing */
+
+ /* Check for i2c devices. If none, move on */
+ if (!any_i2c_devices) {
+ bktr->card = cards[ (card = CARD_INTEL) ];
+ bktr->card.eepromAddr = 0;
+ bktr->card.eepromSize = 0;
+ goto checkTuner;
+ }
+
+ /* Look for Hauppauge, STB and Osprey cards by the presence */
+ /* of an EEPROM */
+ /* Note: Bt878 based cards also use EEPROMs so we can only do this */
+ /* test on BT848/848A and 849A based cards. */
+ if ((bktr->id==BROOKTREE_848) ||
+ (bktr->id==BROOKTREE_848A) ||
+ (bktr->id==BROOKTREE_849A)) {
+
+ /* At i2c address 0xa0, look for Hauppauge and Osprey cards */
+ if ( (status = i2cRead( bktr, PFC8582_RADDR )) != ABSENT ) {
+
+ /* Read the eeprom contents */
+ bktr->card = cards[ (card = CARD_UNKNOWN) ];
+ bktr->card.eepromAddr = PFC8582_WADDR;
+ bktr->card.eepromSize = (u_char)(256 / EEPROMBLOCKSIZE);
+ readEEProm(bktr, 0, 128, (u_char *) &eeprom );
+
+ /* For Hauppauge, check the EEPROM begins with 0x84 */
+ if (eeprom[0] == 0x84) {
+ bktr->card = cards[ (card = CARD_HAUPPAUGE) ];
+ bktr->card.eepromAddr = PFC8582_WADDR;
+ bktr->card.eepromSize = (u_char)(256 / EEPROMBLOCKSIZE);
+ goto checkTuner;
+ }
+
+ /* For Osprey, check the EEPROM begins with "MMAC" */
+ if ( (eeprom[0] == 'M') &&(eeprom[1] == 'M')
+ &&(eeprom[2] == 'A') &&(eeprom[3] == 'C')) {
+ bktr->card = cards[ (card = CARD_OSPREY) ];
+ bktr->card.eepromAddr = PFC8582_WADDR;
+ bktr->card.eepromSize = (u_char)(256 / EEPROMBLOCKSIZE);
+ goto checkTuner;
+ }
+ printf("%s: Warning: Unknown card type. EEPROM data not recognised\n",
+ bktr_name(bktr));
+ printf("%s: %x %x %x %x\n", bktr_name(bktr),
+ eeprom[0],eeprom[1],eeprom[2],eeprom[3]);
+ }
+
+ /* look for an STB card */
+ if ( (status = i2cRead( bktr, X24C01_RADDR )) != ABSENT ) {
+ bktr->card = cards[ (card = CARD_STB) ];
+ bktr->card.eepromAddr = X24C01_WADDR;
+ bktr->card.eepromSize = (u_char)(128 / EEPROMBLOCKSIZE);
+ goto checkTuner;
+ }
+
+ }
+
+ signCard( bktr, 1, 128, (u_char *) &probe_signature );
+
+ if (bootverbose) {
+ printf("%s: card signature: ", bktr_name(bktr));
+ for (j = 0; j < Bt848_MAX_SIGN; j++) {
+ printf(" %02x ", probe_signature[j]);
+ }
+ printf("\n\n");
+ }
+ for (i = 0;
+ i < (sizeof bt848_card_signature)/ sizeof (struct bt848_card_sig);
+ i++ ) {
+
+ card_found = 1;
+ probe_temp = (u_char *) &bt848_card_signature[i].signature;
+
+ for (j = 0; j < Bt848_MAX_SIGN; j++) {
+ if ((probe_temp[j] & 0xf) != (probe_signature[j] & 0xf)) {
+ card_found = 0;
+ break;
+ }
+
+ }
+ if (card_found) {
+ bktr->card = cards[ card = bt848_card_signature[i].card];
+ eeprom_i2c_address = locate_eeprom_address( bktr );
+ if (eeprom_i2c_address != -1) {
+ bktr->card.eepromAddr = eeprom_i2c_address;
+ bktr->card.eepromSize = (u_char)(256 / EEPROMBLOCKSIZE);
+ } else {
+ bktr->card.eepromAddr = 0;
+ bktr->card.eepromSize = 0;
+ }
+ tuner_i2c_address = locate_tuner_address( bktr );
+ select_tuner( bktr, bt848_card_signature[i].tuner );
+ goto checkDBX;
+ }
+ }
+
+ /* We do not know the card type. Default to Miro */
+ bktr->card = cards[ (card = CARD_MIRO) ];
+
+
+checkEEPROM:
+ /* look for a configuration eeprom */
+ eeprom_i2c_address = locate_eeprom_address( bktr );
+ if (eeprom_i2c_address != -1) {
+ bktr->card.eepromAddr = eeprom_i2c_address;
+ bktr->card.eepromSize = (u_char)(256 / EEPROMBLOCKSIZE);
+ } else {
+ bktr->card.eepromAddr = 0;
+ bktr->card.eepromSize = 0;
+ }
+
+
+checkTuner:
+
+ /* look for a tuner */
+ tuner_i2c_address = locate_tuner_address( bktr );
+ if ( tuner_i2c_address == -1 ) {
+ select_tuner( bktr, NO_TUNER );
+ goto checkDBX;
+ }
+
+#if defined( BKTR_OVERRIDE_TUNER )
+ select_tuner( bktr, BKTR_OVERRIDE_TUNER );
+ goto checkDBX;
+#endif
+ if (bktr->bt848_tuner != -1 ) {
+ select_tuner( bktr, bktr->bt848_tuner & 0xff );
+ goto checkDBX;
+ }
+
+ /* Check for i2c devices */
+ if (!any_i2c_devices) {
+ select_tuner( bktr, NO_TUNER );
+ goto checkDBX;
+ }
+
+ /* differentiate type of tuner */
+
+ switch (card) {
+ case CARD_MIRO:
+ switch (((INL(bktr, BKTR_GPIO_DATA) >> 10)-1)&7) {
+ case 0: select_tuner( bktr, TEMIC_PAL ); break;
+ case 1: select_tuner( bktr, PHILIPS_PAL ); break;
+ case 2: select_tuner( bktr, PHILIPS_NTSC ); break;
+ case 3: select_tuner( bktr, PHILIPS_SECAM ); break;
+ case 4: select_tuner( bktr, NO_TUNER ); break;
+ case 5: select_tuner( bktr, PHILIPS_PALI ); break;
+ case 6: select_tuner( bktr, TEMIC_NTSC ); break;
+ case 7: select_tuner( bktr, TEMIC_PALI ); break;
+ }
+ goto checkDBX;
+ break;
+
+ case CARD_HAUPPAUGE:
+ /* Hauppauge kindly supplied the following Tuner Table */
+ /* FIXME: I think the tuners the driver selects for types */
+ /* 0x08 and 0x15 may be incorrect but no one has complained. */
+ /* Old Temic tuners had their own API, but newer Temic tuners */
+ /* have the same API as Philips tuners */
+ /*
+ ID Tuner Model Format We select Format
+ 0x00 NONE
+ 0x01 EXTERNAL
+ 0x02 OTHER
+ 0x03 Philips FI1216 BG
+ 0x04 Philips FI1216MF BGLL' PHILIPS_SECAM
+ 0x05 Philips FI1236 MN PHILIPS_NTSC
+ 0x06 Philips FI1246 I PHILIPS_PALI
+ 0x07 Philips FI1256 DK
+ 0x08 Philips FI1216 MK2 BG PHILIPS_PALI
+ 0x09 Philips FI1216MF MK2 BGLL' PHILIPS_SECAM
+ 0x0a Philips FI1236 MK2 MN PHILIPS_NTSC
+ 0x0b Philips FI1246 MK2 I PHILIPS_PALI
+ 0x0c Philips FI1256 MK2 DK
+ 0x0d Temic 4032FY5 NTSC TEMIC_NTSC
+ 0x0e Temic 4002FH5 BG TEMIC_PAL
+ 0x0f Temic 4062FY5 I TEMIC_PALI
+ 0x10 Philips FR1216 MK2 BG
+ 0x11 Philips FR1216MF MK2 BGLL' PHILIPS_FR1236_SECAM
+ 0x12 Philips FR1236 MK2 MN PHILIPS_FR1236_NTSC
+ 0x13 Philips FR1246 MK2 I
+ 0x14 Philips FR1256 MK2 DK
+ 0x15 Philips FM1216 BG PHILIPS_FR1216_PAL
+ 0x16 Philips FM1216MF BGLL' PHILIPS_FR1236_SECAM
+ 0x17 Philips FM1236 MN PHILIPS_FR1236_NTSC
+ 0x18 Philips FM1246 I
+ 0x19 Philips FM1256 DK
+ 0x1a Temic 4036FY5 MN (FI1236 MK2 clone) PHILIPS_NTSC
+ 0x1b Samsung TCPN9082D MN
+ 0x1c Samsung TCPM9092P Pal BG/I/DK
+ 0x1d Temic 4006FH5 BG PHILIPS_PALI
+ 0x1e Samsung TCPN9085D MN/Radio
+ 0x1f Samsung TCPB9085P Pal BG/I/DK / Radio
+ 0x20 Samsung TCPL9091P Pal BG & Secam L/L'
+ 0x21 Temic 4039FY5 NTSC Radio
+ 0x22 Philips FQ1216ME Pal BGIDK & Secam L/L'
+ 0x23 Temic 4066FY5 Pal I (FI1246 MK2 clone) PHILIPS_PALI
+ 0x24 Philips TD1536 MN/ATSCDigital
+ 0x25 Philips TD1536D MN/ATSCDigital DUAL INPUT
+ 0x26 Philips FMR1236 M/N FM(no demod)
+ 0x27 Philips FI1256MP B/G, D/K
+ 0x28 Samsung TCPQ9091P BG/I/DK, L/L'
+ 0x29 Temic 4006FN5 BG/I/DK
+ 0x2a Temic 4009FR5 BG FM PHILIPS_FR1216_PAL
+ 0x2b Temic 4046FM5 B/G, I, D/K, L/L'
+ 0x2c Temic 4009FN5 B/G, I, D/K, FM (no demod)
+ 0x2d Philips TD1536D_FH_44 MN/ATSCDigital DUAL INPUT
+ */
+
+
+ /* Determine the model number from the eeprom */
+ if (bktr->card.eepromAddr != 0) {
+ /* eeprom data block structure */
+ unsigned char *block_1, *block_2, *block_3, *block_4;
+ int block_1_data_size, block_2_data_size, block_3_data_size;
+ int block_1_total_size, block_2_total_size, block_3_total_size;
+ int block_4_header_size;
+
+ unsigned int model,revision;
+ unsigned char tuner_code;
+ unsigned char no_audio_mux;
+
+ readEEProm(bktr, 0, 128, (u_char *) &eeprom );
+
+ /* LOCATE THE EEPROM DATA BLOCKS */
+ block_1 = &eeprom[0];
+ block_1_data_size = (block_1[2] << 8 | block_1[1]);
+ block_1_total_size = block_1_data_size + 3; /* Header bytes */
+
+ block_2 = &eeprom[block_1_total_size];
+ block_2_data_size = (block_2[2] << 8 | block_2[1]);
+ block_2_total_size = block_2_data_size + 3; /* Header bytes */
+
+ block_3 = &eeprom[block_1_total_size + block_2_total_size];
+ block_3_data_size = (block_3[0] &0x07);
+ block_3_total_size = block_3_data_size + 1; /* Header size */
+
+ block_4 = &eeprom[block_1_total_size +block_2_total_size +block_3_total_size];
+ block_4_header_size = 1;
+
+ model = (block_1[12] << 8 | block_1[11]);
+ revision = (block_1[15] << 16 | block_1[14] << 8 | block_1[13]);
+
+ tuner_code = block_1[9];
+
+ no_audio_mux = ((block_3[3] >> 7) &0x01);
+
+ if (no_audio_mux) bktr->audio_mux_present = 0;
+
+ if (verbose)
+ printf("%s: Hauppauge Model %d %c%c%c%c\n",
+ bktr_name(bktr),
+ model,
+ ((revision >> 18) & 0x3f) + 32,
+ ((revision >> 12) & 0x3f) + 32,
+ ((revision >> 6) & 0x3f) + 32,
+ ((revision >> 0) & 0x3f) + 32 );
+
+ /* Determine the tuner type from the eeprom */
+
+ switch (tuner_code) {
+
+ case 0x5:
+ case 0x0a:
+ case 0x1a:
+ select_tuner( bktr, PHILIPS_NTSC );
+ goto checkDBX;
+
+ case 0x4:
+ case 0x9:
+ select_tuner( bktr, PHILIPS_SECAM );
+ goto checkDBX;
+
+ case 0x11:
+ case 0x16:
+ select_tuner( bktr, PHILIPS_FR1236_SECAM );
+ goto checkDBX;
+
+ case 0x12:
+ case 0x17:
+ select_tuner( bktr, PHILIPS_FR1236_NTSC );
+ goto checkDBX;
+
+ case 0x6:
+ case 0x8:
+ case 0xb:
+ case 0x1d:
+ case 0x23:
+ select_tuner( bktr, PHILIPS_PALI );
+ goto checkDBX;
+
+ case 0xd:
+ select_tuner( bktr, TEMIC_NTSC );
+ goto checkDBX;
+
+ case 0xe:
+ select_tuner( bktr, TEMIC_PAL );
+ goto checkDBX;
+
+ case 0xf:
+ select_tuner( bktr, TEMIC_PALI );
+ goto checkDBX;
+
+ case 0x15:
+ select_tuner( bktr, PHILIPS_FR1216_PAL );
+ goto checkDBX;
+
+ case 0x2a:
+ bktr->msp_use_mono_source = 1;
+ select_tuner( bktr, PHILIPS_FR1216_PAL );
+ goto checkDBX;
+
+ default :
+ printf("%s: Warning - Unknown Hauppauge Tuner 0x%x\n",
+ bktr_name(bktr), tuner_code);
+ }
+ }
+ break;
+
+
+ case CARD_AVER_MEDIA:
+ /* AVerMedia kindly supplied some details of their EEPROM contents
+ * which allow us to auto select the Tuner Type.
+ * Only the newer AVerMedia cards actually have an EEPROM.
+ */
+ if (bktr->card.eepromAddr != 0) {
+
+ u_char tuner_make; /* Eg Philips, Temic */
+ u_char tuner_tv_fm; /* TV or TV with FM Radio */
+ u_char tuner_format; /* Eg NTSC, PAL, SECAM */
+ int tuner;
+
+ int tuner_0_table[] = {
+ PHILIPS_NTSC, PHILIPS_PAL,
+ PHILIPS_PAL, PHILIPS_PAL,
+ PHILIPS_PAL, PHILIPS_PAL,
+ PHILIPS_SECAM, PHILIPS_SECAM,
+ PHILIPS_SECAM, PHILIPS_PAL};
+
+ int tuner_0_fm_table[] = {
+ PHILIPS_FR1236_NTSC, PHILIPS_FR1216_PAL,
+ PHILIPS_FR1216_PAL, PHILIPS_FR1216_PAL,
+ PHILIPS_FR1216_PAL, PHILIPS_FR1216_PAL,
+ PHILIPS_FR1236_SECAM, PHILIPS_FR1236_SECAM,
+ PHILIPS_FR1236_SECAM, PHILIPS_FR1216_PAL};
+
+ int tuner_1_table[] = {
+ TEMIC_NTSC, TEMIC_PAL, TEMIC_PAL,
+ TEMIC_PAL, TEMIC_PAL, TEMIC_PAL,
+ TEMIC_SECAM, TEMIC_SECAM, TEMIC_SECAM,
+ TEMIC_PAL};
+
+
+ /* Extract information from the EEPROM data */
+ readEEProm(bktr, 0, 128, (u_char *) &eeprom );
+
+ tuner_make = (eeprom[0x41] & 0x7);
+ tuner_tv_fm = (eeprom[0x41] & 0x18) >> 3;
+ tuner_format = (eeprom[0x42] & 0xf0) >> 4;
+
+ /* Treat tuner make 0 (Philips) and make 2 (LG) the same */
+ if ( ((tuner_make == 0) || (tuner_make == 2))
+ && (tuner_format <= 9) && (tuner_tv_fm == 0) ) {
+ tuner = tuner_0_table[tuner_format];
+ select_tuner( bktr, tuner );
+ goto checkDBX;
+ }
+
+ if ( ((tuner_make == 0) || (tuner_make == 2))
+ && (tuner_format <= 9) && (tuner_tv_fm == 1) ) {
+ tuner = tuner_0_fm_table[tuner_format];
+ select_tuner( bktr, tuner );
+ goto checkDBX;
+ }
+
+ if ( (tuner_make == 1) && (tuner_format <= 9) ) {
+ tuner = tuner_1_table[tuner_format];
+ select_tuner( bktr, tuner );
+ goto checkDBX;
+ }
+
+ printf("%s: Warning - Unknown AVerMedia Tuner Make %d Format %d\n",
+ bktr_name(bktr), tuner_make, tuner_format);
+ }
+ break;
+
+ case CARD_LEADTEK:
+#if BKTR_SYSTEM_DEFAULT == BROOKTREE_PAL
+ select_tuner( bktr, PHILIPS_FR1216_PAL );
+#else
+ select_tuner( bktr, PHILIPS_FR1236_NTSC );
+#endif
+ goto checkDBX;
+ break;
+
+ } /* end switch(card) */
+
+
+ /* At this point, a goto checkDBX has not occured */
+ /* We have not been able to select a Tuner */
+ /* Some cards make use of the tuner address to */
+ /* identify the make/model of tuner */
+
+ /* At address 0xc0/0xc1 we often find a TEMIC NTSC */
+ if ( i2cRead( bktr, 0xc1 ) != ABSENT ) {
+ select_tuner( bktr, TEMIC_NTSC );
+ goto checkDBX;
+ }
+
+ /* At address 0xc6/0xc7 we often find a PHILIPS NTSC Tuner */
+ if ( i2cRead( bktr, 0xc7 ) != ABSENT ) {
+ select_tuner( bktr, PHILIPS_NTSC );
+ goto checkDBX;
+ }
+
+ /* Address 0xc2/0xc3 is default (or common address) for several */
+ /* tuners and we cannot tell which is which. */
+ /* And for all other tuner i2c addresses, select the default */
+ select_tuner( bktr, DEFAULT_TUNER );
+
+
+checkDBX:
+#if defined( BKTR_OVERRIDE_DBX )
+ bktr->card.dbx = BKTR_OVERRIDE_DBX;
+ goto checkMSP;
+#endif
+ /* Check for i2c devices */
+ if (!any_i2c_devices) {
+ goto checkMSP;
+ }
+
+ /* probe for BTSC (dbx) chip */
+ if ( i2cRead( bktr, TDA9850_RADDR ) != ABSENT )
+ bktr->card.dbx = 1;
+
+checkMSP:
+ /* If this is a Hauppauge Bt878 card, we need to enable the
+ * MSP 34xx audio chip.
+ * If this is a Hauppauge Bt848 card, reset the MSP device.
+ * The MSP reset line is wired to GPIO pin 5. On Bt878 cards a pulldown
+ * resistor holds the device in reset until we set GPIO pin 5.
+ */
+
+ /* Optionally skip the MSP reset. This is handy if you initialise the
+ * MSP audio in another operating system (eg Windows) first and then
+ * do a soft reboot.
+ */
+
+#ifndef BKTR_NO_MSP_RESET
+ if (card == CARD_HAUPPAUGE) {
+ OUTL(bktr, BKTR_GPIO_OUT_EN, INL(bktr, BKTR_GPIO_OUT_EN) | (1<<5));
+ OUTL(bktr, BKTR_GPIO_DATA, INL(bktr, BKTR_GPIO_DATA) | (1<<5)); /* write '1' */
+ DELAY(2500); /* wait 2.5ms */
+ OUTL(bktr, BKTR_GPIO_DATA, INL(bktr, BKTR_GPIO_DATA) & ~(1<<5)); /* write '0' */
+ DELAY(2500); /* wait 2.5ms */
+ OUTL(bktr, BKTR_GPIO_DATA, INL(bktr, BKTR_GPIO_DATA) | (1<<5)); /* write '1' */
+ DELAY(2500); /* wait 2.5ms */
+ }
+#endif
+
+#if defined( BKTR_OVERRIDE_MSP )
+ bktr->card.msp3400c = BKTR_OVERRIDE_MSP;
+ goto checkMSPEnd;
+#endif
+
+ /* Check for i2c devices */
+ if (!any_i2c_devices) {
+ goto checkMSPEnd;
+ }
+
+ if ( i2cRead( bktr, MSP3400C_RADDR ) != ABSENT ) {
+ bktr->card.msp3400c = 1;
+ }
+
+checkMSPEnd:
+
+ if (bktr->card.msp3400c) {
+ bktr->msp_addr = MSP3400C_WADDR;
+ msp_read_id( bktr );
+ printf("%s: Detected a MSP%s at 0x%x\n", bktr_name(bktr),
+ bktr->msp_version_string,
+ bktr->msp_addr);
+
+ }
+
+/* Check for Dolby Surround Sound DPL3518A sound chip */
+ if ( i2cRead( bktr, DPL3518A_RADDR ) != ABSENT ) {
+ bktr->card.dpl3518a = 1;
+ }
+
+ if (bktr->card.dpl3518a) {
+ bktr->dpl_addr = DPL3518A_WADDR;
+ dpl_read_id( bktr );
+ printf("%s: Detected a DPL%s at 0x%x\n", bktr_name(bktr),
+ bktr->dpl_version_string,
+ bktr->dpl_addr);
+ }
+
+/* Start of Check Remote */
+ /* Check for the Hauppauge IR Remote Control */
+ /* If there is an external unit, the internal will be ignored */
+
+ bktr->remote_control = 0; /* initial value */
+
+ if (any_i2c_devices) {
+ if (i2cRead( bktr, HAUP_REMOTE_EXT_RADDR ) != ABSENT )
+ {
+ bktr->remote_control = 1;
+ bktr->remote_control_addr = HAUP_REMOTE_EXT_RADDR;
+ }
+ else if (i2cRead( bktr, HAUP_REMOTE_INT_RADDR ) != ABSENT )
+ {
+ bktr->remote_control = 1;
+ bktr->remote_control_addr = HAUP_REMOTE_INT_RADDR;
+ }
+
+ }
+ /* If a remote control is found, poll it 5 times to turn off the LED */
+ if (bktr->remote_control) {
+ int i;
+ for (i=0; i<5; i++)
+ i2cRead( bktr, bktr->remote_control_addr );
+ }
+/* End of Check Remote */
+
+#if defined( BKTR_USE_PLL )
+ bktr->xtal_pll_mode = BT848_USE_PLL;
+ goto checkPLLEnd;
+#endif
+ /* Default is to use XTALS and not PLL mode */
+ bktr->xtal_pll_mode = BT848_USE_XTALS;
+
+ /* Enable PLL mode for OSPREY users */
+ if (card == CARD_OSPREY)
+ bktr->xtal_pll_mode = BT848_USE_PLL;
+
+ /* Enable PLL mode for Video Highway Xtreme users */
+ if (card == CARD_VIDEO_HIGHWAY_XTREME)
+ bktr->xtal_pll_mode = BT848_USE_PLL;
+
+
+ /* Most (perhaps all) Bt878 cards need to be switched to PLL mode */
+ /* as they only fit the NTSC crystal to their cards */
+ /* Default to enabling PLL mode for all Bt878/879 cards */
+
+ if ((bktr->id==BROOKTREE_878 || bktr->id==BROOKTREE_879) )
+ bktr->xtal_pll_mode = BT848_USE_PLL;
+
+
+#if defined( BKTR_USE_PLL )
+checkPLLEnd:
+#endif
+
+
+ bktr->card.tuner_pllAddr = tuner_i2c_address;
+
+ if ( verbose ) {
+ printf( "%s: %s", bktr_name(bktr), bktr->card.name );
+ if ( bktr->card.tuner )
+ printf( ", %s tuner", bktr->card.tuner->name );
+ if ( bktr->card.dbx )
+ printf( ", dbx stereo" );
+ if ( bktr->card.msp3400c )
+ printf( ", msp3400c stereo" );
+ if ( bktr->card.dpl3518a )
+ printf( ", dpl3518a dolby" );
+ if ( bktr->remote_control )
+ printf( ", remote control" );
+ printf( ".\n" );
+ }
+}
+
+#undef ABSENT
diff --git a/sys/dev/pci/bktr/bktr_card.h b/sys/dev/pci/bktr/bktr_card.h
new file mode 100644
index 00000000000..5d948440c7d
--- /dev/null
+++ b/sys/dev/pci/bktr/bktr_card.h
@@ -0,0 +1,88 @@
+/* $OpenBSD: bktr_card.h,v 1.1 2001/03/28 03:27:09 fgsch Exp $ */
+/* $FreeBSD: src/sys/dev/bktr/bktr_card.h,v 1.4 2000/06/26 09:41:31 roger Exp $ */
+
+/*
+ * This is part of the Driver for Video Capture Cards (Frame grabbers)
+ * and TV Tuner cards using the Brooktree Bt848, Bt848A, Bt849A, Bt878, Bt879
+ * chipset.
+ * Copyright Roger Hardiman and Amancio Hasty.
+ *
+ * bktr_card : This deals with identifying TV cards.
+ * trying to find the card make and model of card.
+ * trying to find the type of tuner fitted.
+ * reading the configuration EEPROM.
+ * locating i2c devices.
+ *
+ */
+
+/*
+ * 1. Redistributions of source code must retain the
+ * Copyright (c) 1997 Amancio Hasty, 1999 Roger Hardiman
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Amancio Hasty and
+ * Roger Hardiman
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * If probeCard() fails to detect the correct card on boot you can
+ * override it by setting adding the following option to your kernel config
+ * options BKTR_OVERRIDE_CARD <card type>
+ * eg options BKTR_OVERRIDE CARD=1
+ *
+ * or using the sysclt hw.bt848.card
+ * eg sysctl -w hw.bt848.card=1
+ *
+ * where <card type> is one of the following card defines.
+ */
+
+#define CARD_UNKNOWN 0
+#define CARD_MIRO 1
+#define CARD_HAUPPAUGE 2
+#define CARD_STB 3
+#define CARD_INTEL 4 /* Also for VideoLogic Captivator PCI */
+#define CARD_IMS_TURBO 5
+#define CARD_AVER_MEDIA 6
+#define CARD_OSPREY 7
+#define CARD_NEC_PK 8
+#define CARD_IO_GV 9
+#define CARD_FLYVIDEO 10
+#define CARD_ZOLTRIX 11
+#define CARD_KISS 12
+#define CARD_VIDEO_HIGHWAY_XTREME 13
+#define CARD_ASKEY_DYNALINK_MAGIC_TVIEW 14
+#define CARD_LEADTEK 15
+#define CARD_TERRATVPLUS 16
+#define Bt848_MAX_CARD 17
+
+
+int signCard( bktr_ptr_t bktr, int offset, int count, u_char* sig );
+void probeCard( bktr_ptr_t bktr, int verbose, int unit);
+
+int writeEEProm( bktr_ptr_t bktr, int offset, int count, u_char *data );
+int readEEProm( bktr_ptr_t bktr, int offset, int count, u_char *data );
+
diff --git a/sys/dev/pci/bktr/bktr_core.c b/sys/dev/pci/bktr/bktr_core.c
new file mode 100644
index 00000000000..16f56150d44
--- /dev/null
+++ b/sys/dev/pci/bktr/bktr_core.c
@@ -0,0 +1,4264 @@
+/* $OpenBSD: bktr_core.c,v 1.1 2001/03/28 03:27:09 fgsch Exp $ */
+/* $FreeBSD: src/sys/dev/bktr/bktr_core.c,v 1.114 2000/10/31 13:09:56 roger Exp $ */
+
+/*
+ * This is part of the Driver for Video Capture Cards (Frame grabbers)
+ * and TV Tuner cards using the Brooktree Bt848, Bt848A, Bt849A, Bt878, Bt879
+ * chipset.
+ * Copyright Roger Hardiman and Amancio Hasty.
+ *
+ * bktr_core : This deals with the Bt848/849/878/879 PCI Frame Grabber,
+ * Handles all the open, close, ioctl and read userland calls.
+ * Sets the Bt848 registers and generates RISC pograms.
+ * Controls the i2c bus and GPIO interface.
+ * Contains the interface to the kernel.
+ * (eg probe/attach and open/close/ioctl)
+ *
+ */
+
+ /*
+ The Brooktree BT848 Driver driver is based upon Mark Tinguely and
+ Jim Lowe's driver for the Matrox Meteor PCI card . The
+ Philips SAA 7116 and SAA 7196 are very different chipsets than
+ the BT848.
+
+ The original copyright notice by Mark and Jim is included mostly
+ to honor their fantastic work in the Matrox Meteor driver!
+
+ */
+
+/*
+ * 1. Redistributions of source code must retain the
+ * Copyright (c) 1997 Amancio Hasty, 1999 Roger Hardiman
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Amancio Hasty and
+ * Roger Hardiman
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+
+
+/*
+ * 1. Redistributions of source code must retain the
+ * Copyright (c) 1995 Mark Tinguely and Jim Lowe
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Tinguely and Jim Lowe
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __OpenBSD__
+#include "opt_bktr.h" /* Include any kernel config options */
+#endif
+
+#ifdef __FreeBSD__
+#include "bktr.h"
+#endif /* __FreeBSD__ */
+
+#if ( \
+ (defined(__FreeBSD__) && (NBKTR > 0)) \
+ || (defined(__bsdi__)) \
+ || (defined(__OpenBSD__)) \
+ || (defined(__NetBSD__)) \
+ )
+
+
+/*******************/
+/* *** FreeBSD *** */
+/*******************/
+#ifdef __FreeBSD__
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/signalvar.h>
+#include <sys/vnode.h>
+
+#include <vm/vm.h>
+#include <vm/vm_kern.h>
+#include <vm/pmap.h>
+#include <vm/vm_extern.h>
+
+#if (__FreeBSD_version >=400000) || (NSMBUS > 0)
+#include <sys/bus.h> /* used by smbus and newbus */
+#endif
+
+#if (__FreeBSD_version < 500000)
+#include <machine/clock.h> /* for DELAY */
+#endif
+
+#include <pci/pcivar.h>
+
+#if (__FreeBSD_version >=300000)
+#include <machine/bus_memio.h> /* for bus space */
+#include <machine/bus.h>
+#include <sys/bus.h>
+#endif
+
+#include <machine/ioctl_meteor.h>
+#include <machine/ioctl_bt848.h> /* extensions to ioctl_meteor.h */
+#include <dev/bktr/bktr_reg.h>
+#include <dev/bktr/bktr_tuner.h>
+#include <dev/bktr/bktr_card.h>
+#include <dev/bktr/bktr_audio.h>
+#include <dev/bktr/bktr_os.h>
+#include <dev/bktr/bktr_core.h>
+#if defined(BKTR_FREEBSD_MODULE)
+#include <dev/bktr/bktr_mem.h>
+#endif
+
+#if defined(BKTR_USE_FREEBSD_SMBUS)
+#include <dev/bktr/bktr_i2c.h>
+#include <dev/smbus/smbconf.h>
+#include <dev/iicbus/iiconf.h>
+#include "smbus_if.h"
+#include "iicbus_if.h"
+#endif
+
+const char *
+bktr_name(bktr_ptr_t bktr)
+{
+ return bktr->bktr_xname;
+}
+
+
+#if (__FreeBSD__ == 2)
+typedef unsigned int uintptr_t;
+#endif
+#endif /* __FreeBSD__ */
+
+
+/****************/
+/* *** BSDI *** */
+/****************/
+#ifdef __bsdi__
+#endif /* __bsdi__ */
+
+
+/**************************/
+/* *** OpenBSD/NetBSD *** */
+/**************************/
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/signalvar.h>
+#include <sys/vnode.h>
+
+#ifdef __NetBSD__
+#include <uvm/uvm_extern.h>
+#else
+#include <vm/vm.h> /* for vtophys */
+#include <vm/pmap.h> /* for vtophys */
+#endif
+
+#ifdef __OpenBSD__
+typedef unsigned long uintptr_t;
+typedef int intrmask_t;
+#else
+#include <sys/inttypes.h> /* uintptr_t */
+#endif
+#include <dev/ic/bt8xx.h>
+#include <dev/pci/bktr/bktr_reg.h>
+#include <dev/pci/bktr/bktr_tuner.h>
+#include <dev/pci/bktr/bktr_card.h>
+#include <dev/pci/bktr/bktr_audio.h>
+#include <dev/pci/bktr/bktr_core.h>
+#include <dev/pci/bktr/bktr_os.h>
+
+static int bt848_format = -1;
+
+const char *
+bktr_name(bktr_ptr_t bktr)
+{
+ return (bktr->bktr_dev.dv_xname);
+}
+
+#endif /* __NetBSD__ || __OpenBSD__ */
+
+
+
+typedef u_char bool_t;
+
+#define BKTRPRI (PZERO+8)|PCATCH
+#define VBIPRI (PZERO-4)|PCATCH
+
+
+/*
+ * memory allocated for DMA programs
+ */
+#define DMA_PROG_ALLOC (8 * PAGE_SIZE)
+
+/* When to split a dma transfer , the bt848 has timing as well as
+ dma transfer size limitations so that we have to split dma
+ transfers into two dma requests
+ */
+#define DMA_BT848_SPLIT 319*2
+
+/*
+ * Allocate enough memory for:
+ * 768x576 RGB 16 or YUV (16 storage bits/pixel) = 884736 = 216 pages
+ *
+ * You may override this using the options "BROOKTREE_ALLOC_PAGES=value"
+ * in your kernel configuration file.
+ */
+
+#ifndef BROOKTREE_ALLOC_PAGES
+#define BROOKTREE_ALLOC_PAGES 217*4
+#endif
+#define BROOKTREE_ALLOC (BROOKTREE_ALLOC_PAGES * PAGE_SIZE)
+
+/* Definitions for VBI capture.
+ * There are 16 VBI lines in a PAL video field (32 in a frame),
+ * and we take 2044 samples from each line (placed in a 2048 byte buffer
+ * for alignment).
+ * VBI lines are held in a circular buffer before being read by a
+ * user program from /dev/vbi.
+ */
+
+#define MAX_VBI_LINES 16 /* Maximum for all vidoe formats */
+#define VBI_LINE_SIZE 2048 /* Store upto 2048 bytes per line */
+#define VBI_BUFFER_ITEMS 20 /* Number of frames we buffer */
+#define VBI_DATA_SIZE (VBI_LINE_SIZE * MAX_VBI_LINES * 2)
+#define VBI_BUFFER_SIZE (VBI_DATA_SIZE * VBI_BUFFER_ITEMS)
+
+
+/* Defines for fields */
+#define ODD_F 0x01
+#define EVEN_F 0x02
+
+
+/*
+ * Parameters describing size of transmitted image.
+ */
+
+static struct format_params format_params[] = {
+/* # define BT848_IFORM_F_AUTO (0x0) - don't matter. */
+ { 525, 26, 480, 910, 135, 754, 640, 780, 30, 0x68, 0x5d, BT848_IFORM_X_AUTO,
+ 12, 1600 },
+/* # define BT848_IFORM_F_NTSCM (0x1) */
+ { 525, 26, 480, 910, 135, 754, 640, 780, 30, 0x68, 0x5d, BT848_IFORM_X_XT0,
+ 12, 1600 },
+/* # define BT848_IFORM_F_NTSCJ (0x2) */
+ { 525, 22, 480, 910, 135, 754, 640, 780, 30, 0x68, 0x5d, BT848_IFORM_X_XT0,
+ 12, 1600 },
+/* # define BT848_IFORM_F_PALBDGHI (0x3) */
+ { 625, 32, 576, 1135, 186, 924, 768, 944, 25, 0x7f, 0x72, BT848_IFORM_X_XT1,
+ 16, 2044 },
+/* # define BT848_IFORM_F_PALM (0x4) */
+ { 525, 22, 480, 910, 135, 754, 640, 780, 30, 0x68, 0x5d, BT848_IFORM_X_XT0,
+ 12, 1600 },
+/* # define BT848_IFORM_F_PALN (0x5) */
+ { 625, 32, 576, 1135, 186, 924, 768, 944, 25, 0x7f, 0x72, BT848_IFORM_X_XT1,
+ 16, 2044 },
+/* # define BT848_IFORM_F_SECAM (0x6) */
+ { 625, 32, 576, 1135, 186, 924, 768, 944, 25, 0x7f, 0xa0, BT848_IFORM_X_XT1,
+ 16, 2044 },
+/* # define BT848_IFORM_F_RSVD (0x7) - ???? */
+ { 625, 32, 576, 1135, 186, 924, 768, 944, 25, 0x7f, 0x72, BT848_IFORM_X_XT0,
+ 16, 2044 },
+};
+
+/*
+ * Table of supported Pixel Formats
+ */
+
+static struct meteor_pixfmt_internal {
+ struct meteor_pixfmt public;
+ u_int color_fmt;
+} pixfmt_table[] = {
+
+{ { 0, METEOR_PIXTYPE_RGB, 2, { 0x7c00, 0x03e0, 0x001f }, 0,0 }, 0x33 },
+{ { 0, METEOR_PIXTYPE_RGB, 2, { 0x7c00, 0x03e0, 0x001f }, 1,0 }, 0x33 },
+
+{ { 0, METEOR_PIXTYPE_RGB, 2, { 0xf800, 0x07e0, 0x001f }, 0,0 }, 0x22 },
+{ { 0, METEOR_PIXTYPE_RGB, 2, { 0xf800, 0x07e0, 0x001f }, 1,0 }, 0x22 },
+
+{ { 0, METEOR_PIXTYPE_RGB, 3, { 0xff0000,0x00ff00,0x0000ff }, 1,0 }, 0x11 },
+
+{ { 0, METEOR_PIXTYPE_RGB, 4, { 0xff0000,0x00ff00,0x0000ff }, 0,0 }, 0x00 },
+{ { 0, METEOR_PIXTYPE_RGB, 4, { 0xff0000,0x00ff00,0x0000ff }, 0,1 }, 0x00 },
+{ { 0, METEOR_PIXTYPE_RGB, 4, { 0xff0000,0x00ff00,0x0000ff }, 1,0 }, 0x00 },
+{ { 0, METEOR_PIXTYPE_RGB, 4, { 0xff0000,0x00ff00,0x0000ff }, 1,1 }, 0x00 },
+{ { 0, METEOR_PIXTYPE_YUV, 2, { 0xff0000,0x00ff00,0x0000ff }, 1,1 }, 0x88 },
+{ { 0, METEOR_PIXTYPE_YUV_PACKED, 2, { 0xff0000,0x00ff00,0x0000ff }, 0,1 }, 0x44 },
+{ { 0, METEOR_PIXTYPE_YUV_12, 2, { 0xff0000,0x00ff00,0x0000ff }, 1,1 }, 0x88 },
+
+};
+#define PIXFMT_TABLE_SIZE ( sizeof(pixfmt_table) / sizeof(pixfmt_table[0]) )
+
+/*
+ * Table of Meteor-supported Pixel Formats (for SETGEO compatibility)
+ */
+
+/* FIXME: Also add YUV_422 and YUV_PACKED as well */
+static struct {
+ u_long meteor_format;
+ struct meteor_pixfmt public;
+} meteor_pixfmt_table[] = {
+ { METEOR_GEO_YUV_12,
+ { 0, METEOR_PIXTYPE_YUV_12, 2, { 0xff0000,0x00ff00,0x0000ff }, 1,1 }
+ },
+
+ /* FIXME: Should byte swap flag be on for this one; negative in drvr? */
+ { METEOR_GEO_YUV_422,
+ { 0, METEOR_PIXTYPE_YUV, 2, { 0xff0000,0x00ff00,0x0000ff }, 1,1 }
+ },
+ { METEOR_GEO_YUV_PACKED,
+ { 0, METEOR_PIXTYPE_YUV_PACKED, 2, { 0xff0000,0x00ff00,0x0000ff }, 0,1 }
+ },
+ { METEOR_GEO_RGB16,
+ { 0, METEOR_PIXTYPE_RGB, 2, { 0x7c00, 0x03e0, 0x001f }, 0, 0 }
+ },
+ { METEOR_GEO_RGB24,
+ { 0, METEOR_PIXTYPE_RGB, 4, { 0xff0000, 0x00ff00, 0x0000ff }, 0, 0 }
+ },
+
+};
+#define METEOR_PIXFMT_TABLE_SIZE ( sizeof(meteor_pixfmt_table) / \
+ sizeof(meteor_pixfmt_table[0]) )
+
+
+#define BSWAP (BT848_COLOR_CTL_BSWAP_ODD | BT848_COLOR_CTL_BSWAP_EVEN)
+#define WSWAP (BT848_COLOR_CTL_WSWAP_ODD | BT848_COLOR_CTL_WSWAP_EVEN)
+
+
+
+/* sync detect threshold */
+#if 0
+#define SYNC_LEVEL (BT848_ADC_RESERVED | \
+ BT848_ADC_CRUSH) /* threshold ~125 mV */
+#else
+#define SYNC_LEVEL (BT848_ADC_RESERVED | \
+ BT848_ADC_SYNC_T) /* threshold ~75 mV */
+#endif
+
+
+
+
+/* debug utility for holding previous INT_STAT contents */
+#define STATUS_SUM
+static u_long status_sum = 0;
+
+/*
+ * defines to make certain bit-fiddles understandable
+ */
+#define FIFO_ENABLED BT848_DMA_CTL_FIFO_EN
+#define RISC_ENABLED BT848_DMA_CTL_RISC_EN
+#define FIFO_RISC_ENABLED (BT848_DMA_CTL_FIFO_EN | BT848_DMA_CTL_RISC_EN)
+#define FIFO_RISC_DISABLED 0
+
+#define ALL_INTS_DISABLED 0
+#define ALL_INTS_CLEARED 0xffffffff
+#define CAPTURE_OFF 0
+
+#define BIT_SEVEN_HIGH (1<<7)
+#define BIT_EIGHT_HIGH (1<<8)
+
+#define I2C_BITS (BT848_INT_RACK | BT848_INT_I2CDONE)
+#define TDEC_BITS (BT848_INT_FDSR | BT848_INT_FBUS)
+
+
+
+static int oformat_meteor_to_bt( u_long format );
+
+static u_int pixfmt_swap_flags( int pixfmt );
+
+/*
+ * bt848 RISC programming routines.
+ */
+#ifdef BT848_DUMP
+static int dump_bt848( bktr_ptr_t bktr );
+#endif
+
+static void yuvpack_prog( bktr_ptr_t bktr, char i_flag, int cols,
+ int rows, int interlace );
+static void yuv422_prog( bktr_ptr_t bktr, char i_flag, int cols,
+ int rows, int interlace );
+static void yuv12_prog( bktr_ptr_t bktr, char i_flag, int cols,
+ int rows, int interlace );
+static void rgb_prog( bktr_ptr_t bktr, char i_flag, int cols,
+ int rows, int interlace );
+static void rgb_vbi_prog( bktr_ptr_t bktr, char i_flag, int cols,
+ int rows, int interlace );
+static void build_dma_prog( bktr_ptr_t bktr, char i_flag );
+
+static bool_t getline(bktr_reg_t *, int);
+static bool_t notclipped(bktr_reg_t * , int , int);
+static bool_t split(bktr_reg_t *, volatile u_long **, int, u_long, int,
+ volatile u_char ** , int );
+
+static void start_capture( bktr_ptr_t bktr, unsigned type );
+static void set_fps( bktr_ptr_t bktr, u_short fps );
+
+
+
+/*
+ * Remote Control Functions
+ */
+static void remote_read(bktr_ptr_t bktr, struct bktr_remote *remote);
+
+
+/*
+ * ioctls common to both video & tuner.
+ */
+static int common_ioctl( bktr_ptr_t bktr, ioctl_cmd_t cmd, caddr_t arg );
+
+
+#if !defined(BKTR_USE_FREEBSD_SMBUS)
+/*
+ * i2c primitives for low level control of i2c bus. Added for MSP34xx control
+ */
+static void i2c_start( bktr_ptr_t bktr);
+static void i2c_stop( bktr_ptr_t bktr);
+static int i2c_write_byte( bktr_ptr_t bktr, unsigned char data);
+static int i2c_read_byte( bktr_ptr_t bktr, unsigned char *data, int last );
+#endif
+
+
+
+/*
+ * the common attach code, used by all OS versions.
+ */
+void
+common_bktr_attach( bktr_ptr_t bktr, int unit, u_long pci_id, u_int rev )
+{
+ vm_offset_t buf = 0;
+
+/***************************************/
+/* *** OS Specific memory routines *** */
+/***************************************/
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+ /* allocate space for dma program */
+ bktr->dma_prog = get_bktr_mem(bktr, &bktr->dm_prog,
+ DMA_PROG_ALLOC);
+ bktr->odd_dma_prog = get_bktr_mem(bktr, &bktr->dm_oprog,
+ DMA_PROG_ALLOC);
+
+ /* allocate space for the VBI buffer */
+ bktr->vbidata = get_bktr_mem(bktr, &bktr->dm_vbidata,
+ VBI_DATA_SIZE);
+ bktr->vbibuffer = get_bktr_mem(bktr, &bktr->dm_vbibuffer,
+ VBI_BUFFER_SIZE);
+
+ /* allocate space for pixel buffer */
+ if ( BROOKTREE_ALLOC )
+ buf = get_bktr_mem(bktr, &bktr->dm_mem, BROOKTREE_ALLOC);
+ else
+ buf = 0;
+#endif
+
+#if defined(__FreeBSD__) || defined(__bsdi__)
+ int need_to_allocate_memory = 1;
+
+/* If this is a module, check if there is any currently saved contiguous memory */
+#if defined(BKTR_FREEBSD_MODULE)
+ if (bktr_has_stored_addresses(unit) == 1) {
+ /* recover the addresses */
+ bktr->dma_prog = bktr_retrieve_address(unit, BKTR_MEM_DMA_PROG);
+ bktr->odd_dma_prog = bktr_retrieve_address(unit, BKTR_MEM_ODD_DMA_PROG);
+ bktr->vbidata = bktr_retrieve_address(unit, BKTR_MEM_VBIDATA);
+ bktr->vbibuffer = bktr_retrieve_address(unit, BKTR_MEM_VBIBUFFER);
+ buf = bktr_retrieve_address(unit, BKTR_MEM_BUF);
+ need_to_allocate_memory = 0;
+ }
+#endif
+
+ if (need_to_allocate_memory == 1) {
+ /* allocate space for dma program */
+ bktr->dma_prog = get_bktr_mem(unit, DMA_PROG_ALLOC);
+ bktr->odd_dma_prog = get_bktr_mem(unit, DMA_PROG_ALLOC);
+
+ /* allocte space for the VBI buffer */
+ bktr->vbidata = get_bktr_mem(unit, VBI_DATA_SIZE);
+ bktr->vbibuffer = get_bktr_mem(unit, VBI_BUFFER_SIZE);
+
+ /* allocate space for pixel buffer */
+ if ( BROOKTREE_ALLOC )
+ buf = get_bktr_mem(unit, BROOKTREE_ALLOC);
+ else
+ buf = 0;
+ }
+#endif /* FreeBSD or BSDi */
+
+
+/* If this is a module, save the current contiguous memory */
+#if defined(BKTR_FREEBSD_MODULE)
+bktr_store_address(unit, BKTR_MEM_DMA_PROG, bktr->dma_prog);
+bktr_store_address(unit, BKTR_MEM_ODD_DMA_PROG, bktr->odd_dma_prog);
+bktr_store_address(unit, BKTR_MEM_VBIDATA, bktr->vbidata);
+bktr_store_address(unit, BKTR_MEM_VBIBUFFER, bktr->vbibuffer);
+bktr_store_address(unit, BKTR_MEM_BUF, buf);
+#endif
+
+
+ if ( bootverbose ) {
+ printf("%s: buffer size %d, addr 0x%x\n",
+ bktr_name(bktr), BROOKTREE_ALLOC, vtophys(buf));
+ }
+
+ if ( buf != 0 ) {
+ bktr->bigbuf = buf;
+ bktr->alloc_pages = BROOKTREE_ALLOC_PAGES;
+ bzero((caddr_t) bktr->bigbuf, BROOKTREE_ALLOC);
+ } else {
+ bktr->alloc_pages = 0;
+ }
+
+
+ bktr->flags = METEOR_INITALIZED | METEOR_AUTOMODE |
+ METEOR_DEV0 | METEOR_RGB16;
+ bktr->dma_prog_loaded = FALSE;
+ bktr->cols = 640;
+ bktr->rows = 480;
+ bktr->frames = 1; /* one frame */
+ bktr->format = METEOR_GEO_RGB16;
+ bktr->pixfmt = oformat_meteor_to_bt( bktr->format );
+ bktr->pixfmt_compat = TRUE;
+
+
+ bktr->vbiinsert = 0;
+ bktr->vbistart = 0;
+ bktr->vbisize = 0;
+ bktr->vbiflags = 0;
+
+
+ /* using the pci device id and revision id */
+ /* and determine the card type */
+ if (PCI_VENDOR(pci_id) == PCI_VENDOR_BROOKTREE)
+ {
+ switch (PCI_PRODUCT(pci_id)) {
+ case PCI_PRODUCT_BROOKTREE_BT848:
+ if (rev == 0x12)
+ bktr->id = BROOKTREE_848A;
+ else
+ bktr->id = BROOKTREE_848;
+ break;
+ case PCI_PRODUCT_BROOKTREE_BT849:
+ bktr->id = BROOKTREE_849A;
+ break;
+ case PCI_PRODUCT_BROOKTREE_BT878:
+ bktr->id = BROOKTREE_878;
+ break;
+ case PCI_PRODUCT_BROOKTREE_BT879:
+ bktr->id = BROOKTREE_879;
+ break;
+ }
+ };
+
+ bktr->clr_on_start = FALSE;
+
+ /* defaults for the tuner section of the card */
+ bktr->tflags = TUNER_INITALIZED;
+ bktr->tuner.frequency = 0;
+ bktr->tuner.channel = 0;
+ bktr->tuner.chnlset = DEFAULT_CHNLSET;
+ bktr->tuner.afc = 0;
+ bktr->tuner.radio_mode = 0;
+ bktr->audio_mux_select = 0;
+ bktr->audio_mute_state = FALSE;
+ bktr->bt848_card = -1;
+ bktr->bt848_tuner = -1;
+ bktr->reverse_mute = -1;
+ bktr->slow_msp_audio = 0;
+ bktr->msp_use_mono_source = 0;
+ bktr->msp_source_selected = -1;
+ bktr->audio_mux_present = 1;
+
+ probeCard( bktr, TRUE, unit );
+
+ /* Initialise any MSP34xx or TDA98xx audio chips */
+ init_audio_devices( bktr );
+
+}
+
+
+/* Copy the vbi lines from 'vbidata' into the circular buffer, 'vbibuffer'.
+ * The circular buffer holds 'n' fixed size data blocks.
+ * vbisize is the number of bytes in the circular buffer
+ * vbiread is the point we reading data out of the circular buffer
+ * vbiinsert is the point we insert data into the circular buffer
+ */
+static void vbidecode(bktr_ptr_t bktr) {
+ unsigned char *dest;
+ unsigned int *seq_dest;
+
+ /* Check if there is room in the buffer to insert the data. */
+ if (bktr->vbisize + VBI_DATA_SIZE > VBI_BUFFER_SIZE) return;
+
+ /* Copy the VBI data into the next free slot in the buffer. */
+ /* 'dest' is the point in vbibuffer where we want to insert new data */
+ dest = (unsigned char *)bktr->vbibuffer + bktr->vbiinsert;
+ memcpy(dest, (unsigned char*)bktr->vbidata, VBI_DATA_SIZE);
+
+ /* Write the VBI sequence number to the end of the vbi data */
+ /* This is used by the AleVT teletext program */
+ seq_dest = (unsigned int *)((unsigned char *)bktr->vbibuffer
+ + bktr->vbiinsert
+ + (VBI_DATA_SIZE - sizeof(bktr->vbi_sequence_number)));
+ *seq_dest = bktr->vbi_sequence_number;
+
+ /* And increase the VBI sequence number */
+ /* This can wrap around */
+ bktr->vbi_sequence_number++;
+
+
+ /* Increment the vbiinsert pointer */
+ /* This can wrap around */
+ bktr->vbiinsert += VBI_DATA_SIZE;
+ bktr->vbiinsert = (bktr->vbiinsert % VBI_BUFFER_SIZE);
+
+ /* And increase the amount of vbi data in the buffer */
+ bktr->vbisize = bktr->vbisize + VBI_DATA_SIZE;
+
+}
+
+
+/*
+ * the common interrupt handler.
+ * Returns a 0 or 1 depending on whether the interrupt has handled.
+ * In the OS specific section, bktr_intr() is defined which calls this
+ * common interrupt handler.
+ */
+int
+common_bktr_intr( void *arg )
+{
+ bktr_ptr_t bktr;
+ u_long bktr_status;
+ u_char dstatus;
+ u_long field;
+ u_long w_field;
+ u_long req_field;
+
+ bktr = (bktr_ptr_t) arg;
+
+ /*
+ * check to see if any interrupts are unmasked on this device. If
+ * none are, then we likely got here by way of being on a PCI shared
+ * interrupt dispatch list.
+ */
+ if (INL(bktr, BKTR_INT_MASK) == ALL_INTS_DISABLED)
+ return 0; /* bail out now, before we do something we
+ shouldn't */
+
+ if (!(bktr->flags & METEOR_OPEN)) {
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
+ OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
+ /* return; ?? */
+ }
+
+ /* record and clear the INTerrupt status bits */
+ bktr_status = INL(bktr, BKTR_INT_STAT);
+ OUTL(bktr, BKTR_INT_STAT, bktr_status & ~I2C_BITS); /* don't touch i2c */
+
+ /* record and clear the device status register */
+ dstatus = INB(bktr, BKTR_DSTATUS);
+ OUTB(bktr, BKTR_DSTATUS, 0x00);
+
+#if defined( STATUS_SUM )
+ /* add any new device status or INTerrupt status bits */
+ status_sum |= (bktr_status & ~(BT848_INT_RSV0|BT848_INT_RSV1));
+ status_sum |= ((dstatus & (BT848_DSTATUS_COF|BT848_DSTATUS_LOF)) << 6);
+#endif /* STATUS_SUM */
+ /* printf( "%s: STATUS %x %x %x \n", bktr_name(bktr),
+ dstatus, bktr_status, INL(bktr, BKTR_RISC_COUNT) );
+ */
+
+
+ /* if risc was disabled re-start process again */
+ /* if there was one of the following errors re-start again */
+ if ( !(bktr_status & BT848_INT_RISC_EN) ||
+ ((bktr_status &(/* BT848_INT_FBUS | */
+ /* BT848_INT_FTRGT | */
+ /* BT848_INT_FDSR | */
+ BT848_INT_PPERR |
+ BT848_INT_RIPERR | BT848_INT_PABORT |
+ BT848_INT_OCERR | BT848_INT_SCERR) ) != 0)
+ || ((INB(bktr, BKTR_TDEC) == 0) && (bktr_status & TDEC_BITS)) ) {
+
+ u_short tdec_save = INB(bktr, BKTR_TDEC);
+
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
+ OUTB(bktr, BKTR_CAP_CTL, CAPTURE_OFF);
+
+ OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
+
+ /* Reset temporal decimation counter */
+ OUTB(bktr, BKTR_TDEC, 0);
+ OUTB(bktr, BKTR_TDEC, tdec_save);
+
+ /* Reset to no-fields captured state */
+ if (bktr->flags & (METEOR_CONTIN | METEOR_SYNCAP)) {
+ switch(bktr->flags & METEOR_ONLY_FIELDS_MASK) {
+ case METEOR_ONLY_ODD_FIELDS:
+ bktr->flags |= METEOR_WANT_ODD;
+ break;
+ case METEOR_ONLY_EVEN_FIELDS:
+ bktr->flags |= METEOR_WANT_EVEN;
+ break;
+ default:
+ bktr->flags |= METEOR_WANT_MASK;
+ break;
+ }
+ }
+
+ OUTL(bktr, BKTR_RISC_STRT_ADD, vtophys(bktr->dma_prog));
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_ENABLED);
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, bktr->capcontrol);
+
+ OUTL(bktr, BKTR_INT_MASK, BT848_INT_MYSTERYBIT |
+ BT848_INT_RISCI |
+ BT848_INT_VSYNC |
+ BT848_INT_FMTCHG);
+
+ OUTB(bktr, BKTR_CAP_CTL, bktr->bktr_cap_ctl);
+ return 1;
+ }
+
+ /* If this is not a RISC program interrupt, return */
+ if (!(bktr_status & BT848_INT_RISCI))
+ return 0;
+
+/**
+ printf( "%s: intr status %x %x %x\n", bktr_name(bktr),
+ bktr_status, dstatus, INL(bktr, BKTR_RISC_COUNT) );
+ */
+
+
+ /*
+ * Disable future interrupts if a capture mode is not selected.
+ * This can happen when we are in the process of closing or
+ * changing capture modes, otherwise it shouldn't happen.
+ */
+ if (!(bktr->flags & METEOR_CAP_MASK))
+ OUTB(bktr, BKTR_CAP_CTL, CAPTURE_OFF);
+
+
+ /* Determine which field generated this interrupt */
+ field = ( bktr_status & BT848_INT_FIELD ) ? EVEN_F : ODD_F;
+
+
+ /*
+ * Process the VBI data if it is being captured. We do this once
+ * both Odd and Even VBI data is captured. Therefore we do this
+ * in the Even field interrupt handler.
+ */
+ if ( (bktr->vbiflags & VBI_CAPTURE)
+ &&(bktr->vbiflags & VBI_OPEN)
+ &&(field==EVEN_F)) {
+ /* Put VBI data into circular buffer */
+ vbidecode(bktr);
+
+ /* If someone is blocked on reading from /dev/vbi, wake them */
+ if (bktr->vbi_read_blocked) {
+ bktr->vbi_read_blocked = FALSE;
+ wakeup(VBI_SLEEP);
+ }
+
+ /* If someone has a select() on /dev/vbi, inform them */
+#ifndef __OpenBSD__
+ if (bktr->vbi_select.si_pid) {
+#else
+ if (bktr->vbi_select.si_selpid) {
+#endif
+ selwakeup(&bktr->vbi_select);
+ }
+
+
+ }
+
+
+ /*
+ * Register the completed field
+ * (For dual-field mode, require fields from the same frame)
+ */
+ switch ( bktr->flags & METEOR_WANT_MASK ) {
+ case METEOR_WANT_ODD : w_field = ODD_F ; break;
+ case METEOR_WANT_EVEN : w_field = EVEN_F ; break;
+ default : w_field = (ODD_F|EVEN_F); break;
+ }
+ switch ( bktr->flags & METEOR_ONLY_FIELDS_MASK ) {
+ case METEOR_ONLY_ODD_FIELDS : req_field = ODD_F ; break;
+ case METEOR_ONLY_EVEN_FIELDS : req_field = EVEN_F ; break;
+ default : req_field = (ODD_F|EVEN_F);
+ break;
+ }
+
+ if (( field == EVEN_F ) && ( w_field == EVEN_F ))
+ bktr->flags &= ~METEOR_WANT_EVEN;
+ else if (( field == ODD_F ) && ( req_field == ODD_F ) &&
+ ( w_field == ODD_F ))
+ bktr->flags &= ~METEOR_WANT_ODD;
+ else if (( field == ODD_F ) && ( req_field == (ODD_F|EVEN_F) ) &&
+ ( w_field == (ODD_F|EVEN_F) ))
+ bktr->flags &= ~METEOR_WANT_ODD;
+ else if (( field == ODD_F ) && ( req_field == (ODD_F|EVEN_F) ) &&
+ ( w_field == ODD_F )) {
+ bktr->flags &= ~METEOR_WANT_ODD;
+ bktr->flags |= METEOR_WANT_EVEN;
+ }
+ else {
+ /* We're out of sync. Start over. */
+ if (bktr->flags & (METEOR_CONTIN | METEOR_SYNCAP)) {
+ switch(bktr->flags & METEOR_ONLY_FIELDS_MASK) {
+ case METEOR_ONLY_ODD_FIELDS:
+ bktr->flags |= METEOR_WANT_ODD;
+ break;
+ case METEOR_ONLY_EVEN_FIELDS:
+ bktr->flags |= METEOR_WANT_EVEN;
+ break;
+ default:
+ bktr->flags |= METEOR_WANT_MASK;
+ break;
+ }
+ }
+ return 1;
+ }
+
+ /*
+ * If we have a complete frame.
+ */
+ if (!(bktr->flags & METEOR_WANT_MASK)) {
+ bktr->frames_captured++;
+ /*
+ * post the completion time.
+ */
+ if (bktr->flags & METEOR_WANT_TS) {
+ struct timeval *ts;
+
+ if ((u_int) bktr->alloc_pages * PAGE_SIZE
+ <= (bktr->frame_size + sizeof(struct timeval))) {
+ ts =(struct timeval *)bktr->bigbuf +
+ bktr->frame_size;
+ /* doesn't work in synch mode except
+ * for first frame */
+ /* XXX */
+ microtime(ts);
+ }
+ }
+
+
+ /*
+ * Wake up the user in single capture mode.
+ */
+ if (bktr->flags & METEOR_SINGLE) {
+
+ /* stop dma */
+ OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
+
+ /* disable risc, leave fifo running */
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_ENABLED);
+ wakeup(BKTR_SLEEP);
+ }
+
+ /*
+ * If the user requested to be notified via signal,
+ * let them know the frame is complete.
+ */
+
+ if (bktr->proc && !(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.
+ */
+/*
+* XXX NOTE (Luigi):
+* currently we only support 3 capture modes: odd only, even only,
+* odd+even interlaced (odd field first). A fourth mode (non interlaced,
+* either even OR odd) could provide 60 (50 for PAL) pictures per
+* second, but it would require this routine to toggle the desired frame
+* each time, and one more different DMA program for the Bt848.
+* As a consequence, this fourth mode is currently unsupported.
+*/
+
+ if (bktr->flags & (METEOR_CONTIN | METEOR_SYNCAP)) {
+ switch(bktr->flags & METEOR_ONLY_FIELDS_MASK) {
+ case METEOR_ONLY_ODD_FIELDS:
+ bktr->flags |= METEOR_WANT_ODD;
+ break;
+ case METEOR_ONLY_EVEN_FIELDS:
+ bktr->flags |= METEOR_WANT_EVEN;
+ break;
+ default:
+ bktr->flags |= METEOR_WANT_MASK;
+ break;
+ }
+ }
+ }
+
+ return 1;
+}
+
+
+
+
+/*
+ *
+ */
+extern int bt848_format; /* used to set the default format, PAL or NTSC */
+int
+video_open( bktr_ptr_t bktr )
+{
+ int frame_rate, video_format=0;
+
+ if (bktr->flags & METEOR_OPEN) /* device is busy */
+ return( EBUSY );
+
+ bktr->flags |= METEOR_OPEN;
+
+#ifdef BT848_DUMP
+ dump_bt848( bt848 );
+#endif
+
+ bktr->clr_on_start = FALSE;
+
+ OUTB(bktr, BKTR_DSTATUS, 0x00); /* clear device status reg. */
+
+ OUTB(bktr, BKTR_ADC, SYNC_LEVEL);
+
+#if BKTR_SYSTEM_DEFAULT == BROOKTREE_PAL
+ video_format = 0;
+#else
+ video_format = 1;
+#endif
+
+ if (bt848_format == 0 )
+ video_format = 0;
+
+ if (bt848_format == 1 )
+ video_format = 1;
+
+ if (video_format == 1 ) {
+ OUTB(bktr, BKTR_IFORM, BT848_IFORM_F_NTSCM);
+ bktr->format_params = BT848_IFORM_F_NTSCM;
+
+ } else {
+ OUTB(bktr, BKTR_IFORM, BT848_IFORM_F_PALBDGHI);
+ bktr->format_params = BT848_IFORM_F_PALBDGHI;
+
+ }
+
+ OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | format_params[bktr->format_params].iform_xtsel);
+
+ /* work around for new Hauppauge 878 cards */
+ if ((bktr->card.card_id == CARD_HAUPPAUGE) &&
+ (bktr->id==BROOKTREE_878 || bktr->id==BROOKTREE_879) )
+ OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX3);
+ else
+ OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX1);
+
+ OUTB(bktr, BKTR_ADELAY, format_params[bktr->format_params].adelay);
+ OUTB(bktr, BKTR_BDELAY, format_params[bktr->format_params].bdelay);
+ frame_rate = format_params[bktr->format_params].frame_rate;
+
+ /* enable PLL mode using 28Mhz crystal for PAL/SECAM users */
+ if (bktr->xtal_pll_mode == BT848_USE_PLL) {
+ OUTB(bktr, BKTR_TGCTRL, 0);
+ OUTB(bktr, BKTR_PLL_F_LO, 0xf9);
+ OUTB(bktr, BKTR_PLL_F_HI, 0xdc);
+ OUTB(bktr, BKTR_PLL_F_XCI, 0x8e);
+ }
+
+ bktr->flags = (bktr->flags & ~METEOR_DEV_MASK) | METEOR_DEV0;
+
+ bktr->max_clip_node = 0;
+
+ OUTB(bktr, BKTR_COLOR_CTL, BT848_COLOR_CTL_GAMMA | BT848_COLOR_CTL_RGB_DED);
+
+ OUTB(bktr, BKTR_E_HSCALE_LO, 170);
+ OUTB(bktr, BKTR_O_HSCALE_LO, 170);
+
+ OUTB(bktr, BKTR_E_DELAY_LO, 0x72);
+ OUTB(bktr, BKTR_O_DELAY_LO, 0x72);
+ OUTB(bktr, BKTR_E_SCLOOP, 0);
+ OUTB(bktr, BKTR_O_SCLOOP, 0);
+
+ OUTB(bktr, BKTR_VBI_PACK_SIZE, 0);
+ OUTB(bktr, BKTR_VBI_PACK_DEL, 0);
+
+ bktr->fifo_errors = 0;
+ bktr->dma_errors = 0;
+ bktr->frames_captured = 0;
+ bktr->even_fields_captured = 0;
+ bktr->odd_fields_captured = 0;
+ bktr->proc = (struct proc *)0;
+ set_fps(bktr, frame_rate);
+ bktr->video.addr = 0;
+ bktr->video.width = 0;
+ bktr->video.banksize = 0;
+ bktr->video.ramsize = 0;
+ bktr->pixfmt_compat = TRUE;
+ bktr->format = METEOR_GEO_RGB16;
+ bktr->pixfmt = oformat_meteor_to_bt( bktr->format );
+
+ bktr->capture_area_enabled = FALSE;
+
+ OUTL(bktr, BKTR_INT_MASK, BT848_INT_MYSTERYBIT); /* if you take this out triton
+ based motherboards will
+ operate unreliably */
+ return( 0 );
+}
+
+int
+vbi_open( bktr_ptr_t bktr )
+{
+ if (bktr->vbiflags & VBI_OPEN) /* device is busy */
+ return( EBUSY );
+
+ bktr->vbiflags |= VBI_OPEN;
+
+ /* reset the VBI circular buffer pointers and clear the buffers */
+ bktr->vbiinsert = 0;
+ bktr->vbistart = 0;
+ bktr->vbisize = 0;
+ bktr->vbi_sequence_number = 0;
+ bktr->vbi_read_blocked = FALSE;
+
+ bzero((caddr_t) bktr->vbibuffer, VBI_BUFFER_SIZE);
+ bzero((caddr_t) bktr->vbidata, VBI_DATA_SIZE);
+
+ return( 0 );
+}
+
+/*
+ *
+ */
+int
+tuner_open( bktr_ptr_t bktr )
+{
+ if ( !(bktr->tflags & TUNER_INITALIZED) ) /* device not found */
+ return( ENXIO );
+
+ if ( bktr->tflags & TUNER_OPEN ) /* already open */
+ return( 0 );
+
+ bktr->tflags |= TUNER_OPEN;
+ bktr->tuner.frequency = 0;
+ bktr->tuner.channel = 0;
+ bktr->tuner.chnlset = DEFAULT_CHNLSET;
+ bktr->tuner.afc = 0;
+ bktr->tuner.radio_mode = 0;
+
+ /* enable drivers on the GPIO port that control the MUXes */
+ OUTL(bktr, BKTR_GPIO_OUT_EN, INL(bktr, BKTR_GPIO_OUT_EN) | bktr->card.gpio_mux_bits);
+
+ /* unmute the audio stream */
+ set_audio( bktr, AUDIO_UNMUTE );
+
+ /* Initialise any audio chips, eg MSP34xx or TDA98xx */
+ init_audio_devices( bktr );
+
+ return( 0 );
+}
+
+
+
+
+/*
+ *
+ */
+int
+video_close( bktr_ptr_t bktr )
+{
+ bktr->flags &= ~(METEOR_OPEN |
+ METEOR_SINGLE |
+ METEOR_CAP_MASK |
+ METEOR_WANT_MASK);
+
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
+ OUTB(bktr, BKTR_CAP_CTL, CAPTURE_OFF);
+
+ bktr->dma_prog_loaded = FALSE;
+ OUTB(bktr, BKTR_TDEC, 0);
+ OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
+
+/** FIXME: is 0xf magic, wouldn't 0x00 work ??? */
+ OUTL(bktr, BKTR_SRESET, 0xf);
+ OUTL(bktr, BKTR_INT_STAT, ALL_INTS_CLEARED);
+
+ return( 0 );
+}
+
+
+/*
+ * tuner close handle,
+ * place holder for tuner specific operations on a close.
+ */
+int
+tuner_close( bktr_ptr_t bktr )
+{
+ bktr->tflags &= ~TUNER_OPEN;
+
+ /* mute the audio by switching the mux */
+ set_audio( bktr, AUDIO_MUTE );
+
+ /* disable drivers on the GPIO port that control the MUXes */
+ OUTL(bktr, BKTR_GPIO_OUT_EN, INL(bktr, BKTR_GPIO_OUT_EN) & ~bktr->card.gpio_mux_bits);
+
+ return( 0 );
+}
+
+int
+vbi_close( bktr_ptr_t bktr )
+{
+
+ bktr->vbiflags &= ~VBI_OPEN;
+
+ return( 0 );
+}
+
+/*
+ *
+ */
+int
+video_read(bktr_ptr_t bktr, int unit, dev_t dev, struct uio *uio)
+{
+ int status;
+ int count;
+
+
+ if (bktr->bigbuf == 0) /* no frame buffer allocated (ioctl failed) */
+ return( ENOMEM );
+
+ if (bktr->flags & METEOR_CAP_MASK)
+ return( EIO ); /* already capturing */
+
+ OUTB(bktr, BKTR_CAP_CTL, bktr->bktr_cap_ctl);
+
+
+ count = bktr->rows * bktr->cols *
+ pixfmt_table[ bktr->pixfmt ].public.Bpp;
+
+ if ((int) uio->uio_iov->iov_len < count)
+ return( EINVAL );
+
+ bktr->flags &= ~(METEOR_CAP_MASK | METEOR_WANT_MASK);
+
+ /* capture one frame */
+ start_capture(bktr, METEOR_SINGLE);
+ /* wait for capture to complete */
+ OUTL(bktr, BKTR_INT_STAT, ALL_INTS_CLEARED);
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_ENABLED);
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, bktr->capcontrol);
+ OUTL(bktr, BKTR_INT_MASK, BT848_INT_MYSTERYBIT |
+ BT848_INT_RISCI |
+ BT848_INT_VSYNC |
+ BT848_INT_FMTCHG);
+
+
+ status = tsleep(BKTR_SLEEP, BKTRPRI, "captur", 0);
+ if (!status) /* successful capture */
+ status = uiomove((caddr_t)bktr->bigbuf, count, uio);
+ else
+ printf ("%s: read: tsleep error %d\n",
+ bktr_name(bktr), status);
+
+ bktr->flags &= ~(METEOR_SINGLE | METEOR_WANT_MASK);
+
+ return( status );
+}
+
+/*
+ * Read VBI data from the vbi circular buffer
+ * The buffer holds vbi data blocks which are the same size
+ * vbiinsert is the position we will insert the next item into the buffer
+ * vbistart is the actual position in the buffer we want to read from
+ * vbisize is the exact number of bytes in the buffer left to read
+ */
+int
+vbi_read(bktr_ptr_t bktr, struct uio *uio, int ioflag)
+{
+ int readsize, readsize2;
+ int status;
+
+
+ while(bktr->vbisize == 0) {
+ if (ioflag & IO_NDELAY) {
+ return EWOULDBLOCK;
+ }
+
+ bktr->vbi_read_blocked = TRUE;
+ if ((status = tsleep(VBI_SLEEP, VBIPRI, "vbi", 0))) {
+ return status;
+ }
+ }
+
+ /* Now we have some data to give to the user */
+
+ /* We cannot read more bytes than there are in
+ * the circular buffer
+ */
+ readsize = (int)uio->uio_iov->iov_len;
+
+ if (readsize > bktr->vbisize) readsize = bktr->vbisize;
+
+ /* Check if we can read this number of bytes without having
+ * to wrap around the circular buffer */
+ if((bktr->vbistart + readsize) >= VBI_BUFFER_SIZE) {
+ /* We need to wrap around */
+
+ readsize2 = VBI_BUFFER_SIZE - bktr->vbistart;
+ status = uiomove((caddr_t)bktr->vbibuffer + bktr->vbistart, readsize2, uio);
+ status += uiomove((caddr_t)bktr->vbibuffer, (readsize - readsize2), uio);
+ } else {
+ /* We do not need to wrap around */
+ status = uiomove((caddr_t)bktr->vbibuffer + bktr->vbistart, readsize, uio);
+ }
+
+ /* Update the number of bytes left to read */
+ bktr->vbisize -= readsize;
+
+ /* Update vbistart */
+ bktr->vbistart += readsize;
+ bktr->vbistart = bktr->vbistart % VBI_BUFFER_SIZE; /* wrap around if needed */
+
+ return( status );
+
+}
+
+
+
+/*
+ * video ioctls
+ */
+int
+video_ioctl( bktr_ptr_t bktr, int unit, ioctl_cmd_t cmd, caddr_t arg, struct proc* pr )
+{
+ volatile u_char c_temp;
+ unsigned int temp;
+ unsigned int temp_iform;
+ unsigned int error;
+ struct meteor_geomet *geo;
+ struct meteor_counts *counts;
+ struct meteor_video *video;
+ struct bktr_capture_area *cap_area;
+ vm_offset_t buf;
+ int i;
+ char char_temp;
+
+ switch ( cmd ) {
+
+ case BT848SCLIP: /* set clip region */
+ bktr->max_clip_node = 0;
+ memcpy(&bktr->clip_list, arg, sizeof(bktr->clip_list));
+
+ for (i = 0; i < BT848_MAX_CLIP_NODE; i++) {
+ if (bktr->clip_list[i].y_min == 0 &&
+ bktr->clip_list[i].y_max == 0)
+ break;
+ }
+ bktr->max_clip_node = i;
+
+ /* make sure that the list contains a valid clip secquence */
+ /* the clip rectangles should be sorted by x then by y as the
+ second order sort key */
+
+ /* clip rectangle list is terminated by y_min and y_max set to 0 */
+
+ /* to disable clipping set y_min and y_max to 0 in the first
+ clip rectangle . The first clip rectangle is clip_list[0].
+ */
+
+
+
+ if (bktr->max_clip_node == 0 &&
+ (bktr->clip_list[0].y_min != 0 &&
+ bktr->clip_list[0].y_max != 0)) {
+ return EINVAL;
+ }
+
+ for (i = 0; i < BT848_MAX_CLIP_NODE - 1 ; i++) {
+ if (bktr->clip_list[i].y_min == 0 &&
+ bktr->clip_list[i].y_max == 0) {
+ break;
+ }
+ if ( bktr->clip_list[i+1].y_min != 0 &&
+ bktr->clip_list[i+1].y_max != 0 &&
+ bktr->clip_list[i].x_min > bktr->clip_list[i+1].x_min ) {
+
+ bktr->max_clip_node = 0;
+ return (EINVAL);
+
+ }
+
+ if (bktr->clip_list[i].x_min >= bktr->clip_list[i].x_max ||
+ bktr->clip_list[i].y_min >= bktr->clip_list[i].y_max ||
+ bktr->clip_list[i].x_min < 0 ||
+ bktr->clip_list[i].x_max < 0 ||
+ bktr->clip_list[i].y_min < 0 ||
+ bktr->clip_list[i].y_max < 0 ) {
+ bktr->max_clip_node = 0;
+ return (EINVAL);
+ }
+ }
+
+ bktr->dma_prog_loaded = FALSE;
+
+ break;
+
+ case METEORSTATUS: /* get Bt848 status */
+ c_temp = INB(bktr, BKTR_DSTATUS);
+ temp = 0;
+ if (!(c_temp & 0x40)) temp |= METEOR_STATUS_HCLK;
+ if (!(c_temp & 0x10)) temp |= METEOR_STATUS_FIDT;
+ *(u_short *)arg = temp;
+ break;
+
+ case BT848SFMT: /* set input format */
+ temp = *(unsigned long*)arg & BT848_IFORM_FORMAT;
+ temp_iform = INB(bktr, BKTR_IFORM);
+ temp_iform &= ~BT848_IFORM_FORMAT;
+ temp_iform &= ~BT848_IFORM_XTSEL;
+ OUTB(bktr, BKTR_IFORM, (temp_iform | temp | format_params[temp].iform_xtsel));
+ switch( temp ) {
+ case BT848_IFORM_F_AUTO:
+ bktr->flags = (bktr->flags & ~METEOR_FORM_MASK) |
+ METEOR_AUTOMODE;
+ break;
+
+ case BT848_IFORM_F_NTSCM:
+ case BT848_IFORM_F_NTSCJ:
+ bktr->flags = (bktr->flags & ~METEOR_FORM_MASK) |
+ METEOR_NTSC;
+ OUTB(bktr, BKTR_ADELAY, format_params[temp].adelay);
+ OUTB(bktr, BKTR_BDELAY, format_params[temp].bdelay);
+ bktr->format_params = temp;
+ break;
+
+ case BT848_IFORM_F_PALBDGHI:
+ case BT848_IFORM_F_PALN:
+ case BT848_IFORM_F_SECAM:
+ case BT848_IFORM_F_RSVD:
+ case BT848_IFORM_F_PALM:
+ bktr->flags = (bktr->flags & ~METEOR_FORM_MASK) |
+ METEOR_PAL;
+ OUTB(bktr, BKTR_ADELAY, format_params[temp].adelay);
+ OUTB(bktr, BKTR_BDELAY, format_params[temp].bdelay);
+ bktr->format_params = temp;
+ break;
+
+ }
+ bktr->dma_prog_loaded = FALSE;
+ break;
+
+ case METEORSFMT: /* set input format */
+ temp_iform = INB(bktr, BKTR_IFORM);
+ temp_iform &= ~BT848_IFORM_FORMAT;
+ temp_iform &= ~BT848_IFORM_XTSEL;
+ switch(*(unsigned long *)arg & METEOR_FORM_MASK ) {
+ case 0: /* default */
+ case METEOR_FMT_NTSC:
+ bktr->flags = (bktr->flags & ~METEOR_FORM_MASK) |
+ METEOR_NTSC;
+ OUTB(bktr, BKTR_IFORM, temp_iform | BT848_IFORM_F_NTSCM |
+ format_params[BT848_IFORM_F_NTSCM].iform_xtsel);
+ OUTB(bktr, BKTR_ADELAY, format_params[BT848_IFORM_F_NTSCM].adelay);
+ OUTB(bktr, BKTR_BDELAY, format_params[BT848_IFORM_F_NTSCM].bdelay);
+ bktr->format_params = BT848_IFORM_F_NTSCM;
+ break;
+
+ case METEOR_FMT_PAL:
+ bktr->flags = (bktr->flags & ~METEOR_FORM_MASK) |
+ METEOR_PAL;
+ OUTB(bktr, BKTR_IFORM, temp_iform | BT848_IFORM_F_PALBDGHI |
+ format_params[BT848_IFORM_F_PALBDGHI].iform_xtsel);
+ OUTB(bktr, BKTR_ADELAY, format_params[BT848_IFORM_F_PALBDGHI].adelay);
+ OUTB(bktr, BKTR_BDELAY, format_params[BT848_IFORM_F_PALBDGHI].bdelay);
+ bktr->format_params = BT848_IFORM_F_PALBDGHI;
+ break;
+
+ case METEOR_FMT_AUTOMODE:
+ bktr->flags = (bktr->flags & ~METEOR_FORM_MASK) |
+ METEOR_AUTOMODE;
+ OUTB(bktr, BKTR_IFORM, temp_iform | BT848_IFORM_F_AUTO |
+ format_params[BT848_IFORM_F_AUTO].iform_xtsel);
+ break;
+
+ default:
+ return( EINVAL );
+ }
+ bktr->dma_prog_loaded = FALSE;
+ break;
+
+ case METEORGFMT: /* get input format */
+ *(u_long *)arg = bktr->flags & METEOR_FORM_MASK;
+ break;
+
+
+ case BT848GFMT: /* get input format */
+ *(u_long *)arg = INB(bktr, BKTR_IFORM) & BT848_IFORM_FORMAT;
+ break;
+
+ case METEORSCOUNT: /* (re)set error counts */
+ counts = (struct meteor_counts *) arg;
+ bktr->fifo_errors = counts->fifo_errors;
+ bktr->dma_errors = counts->dma_errors;
+ bktr->frames_captured = counts->frames_captured;
+ bktr->even_fields_captured = counts->even_fields_captured;
+ bktr->odd_fields_captured = counts->odd_fields_captured;
+ break;
+
+ case METEORGCOUNT: /* get error counts */
+ counts = (struct meteor_counts *) arg;
+ counts->fifo_errors = bktr->fifo_errors;
+ counts->dma_errors = bktr->dma_errors;
+ counts->frames_captured = bktr->frames_captured;
+ counts->even_fields_captured = bktr->even_fields_captured;
+ counts->odd_fields_captured = bktr->odd_fields_captured;
+ break;
+
+ case METEORGVIDEO:
+ video = (struct meteor_video *)arg;
+ video->addr = bktr->video.addr;
+ video->width = bktr->video.width;
+ video->banksize = bktr->video.banksize;
+ video->ramsize = bktr->video.ramsize;
+ break;
+
+ case METEORSVIDEO:
+ video = (struct meteor_video *)arg;
+ bktr->video.addr = video->addr;
+ bktr->video.width = video->width;
+ bktr->video.banksize = video->banksize;
+ bktr->video.ramsize = video->ramsize;
+ break;
+
+ case METEORSFPS:
+ set_fps(bktr, *(u_short *)arg);
+ break;
+
+ case METEORGFPS:
+ *(u_short *)arg = bktr->fps;
+ break;
+
+ case METEORSHUE: /* set hue */
+ OUTB(bktr, BKTR_HUE, (*(u_char *) arg) & 0xff);
+ break;
+
+ case METEORGHUE: /* get hue */
+ *(u_char *)arg = INB(bktr, BKTR_HUE);
+ break;
+
+ case METEORSBRIG: /* set brightness */
+ char_temp = ( *(u_char *)arg & 0xff) - 128;
+ OUTB(bktr, BKTR_BRIGHT, char_temp);
+
+ break;
+
+ case METEORGBRIG: /* get brightness */
+ *(u_char *)arg = INB(bktr, BKTR_BRIGHT);
+ break;
+
+ case METEORSCSAT: /* set chroma saturation */
+ temp = (int)*(u_char *)arg;
+
+ OUTB(bktr, BKTR_SAT_U_LO, (temp << 1) & 0xff);
+ OUTB(bktr, BKTR_SAT_V_LO, (temp << 1) & 0xff);
+ OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL)
+ & ~(BT848_E_CONTROL_SAT_U_MSB
+ | BT848_E_CONTROL_SAT_V_MSB));
+ OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL)
+ & ~(BT848_O_CONTROL_SAT_U_MSB |
+ BT848_O_CONTROL_SAT_V_MSB));
+
+ if ( temp & BIT_SEVEN_HIGH ) {
+ OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL)
+ | (BT848_E_CONTROL_SAT_U_MSB
+ | BT848_E_CONTROL_SAT_V_MSB));
+ OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL)
+ | (BT848_O_CONTROL_SAT_U_MSB
+ | BT848_O_CONTROL_SAT_V_MSB));
+ }
+ break;
+
+ case METEORGCSAT: /* get chroma saturation */
+ temp = (INB(bktr, BKTR_SAT_V_LO) >> 1) & 0xff;
+ if ( INB(bktr, BKTR_E_CONTROL) & BT848_E_CONTROL_SAT_V_MSB )
+ temp |= BIT_SEVEN_HIGH;
+ *(u_char *)arg = (u_char)temp;
+ break;
+
+ case METEORSCONT: /* set contrast */
+ temp = (int)*(u_char *)arg & 0xff;
+ temp <<= 1;
+ OUTB(bktr, BKTR_CONTRAST_LO, temp & 0xff);
+ OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) & ~BT848_E_CONTROL_CON_MSB);
+ OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) & ~BT848_O_CONTROL_CON_MSB);
+ OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) |
+ (((temp & 0x100) >> 6 ) & BT848_E_CONTROL_CON_MSB));
+ OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) |
+ (((temp & 0x100) >> 6 ) & BT848_O_CONTROL_CON_MSB));
+ break;
+
+ case METEORGCONT: /* get contrast */
+ temp = (int)INB(bktr, BKTR_CONTRAST_LO) & 0xff;
+ temp |= ((int)INB(bktr, BKTR_O_CONTROL) & 0x04) << 6;
+ *(u_char *)arg = (u_char)((temp >> 1) & 0xff);
+ break;
+
+ case BT848SCBUF: /* set Clear-Buffer-on-start flag */
+ bktr->clr_on_start = (*(int *)arg != 0);
+ break;
+
+ case BT848GCBUF: /* get Clear-Buffer-on-start flag */
+ *(int *)arg = (int) bktr->clr_on_start;
+ break;
+
+ case METEORSSIGNAL:
+ if(*(int *)arg == 0 || *(int *)arg >= NSIG) {
+ return( EINVAL );
+ break;
+ }
+ 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 );
+ /* already capturing */
+ if (temp & METEOR_CAP_MASK)
+ return( EIO );
+
+
+
+ start_capture(bktr, METEOR_SINGLE);
+
+ /* wait for capture to complete */
+ OUTL(bktr, BKTR_INT_STAT, ALL_INTS_CLEARED);
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_ENABLED);
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, bktr->capcontrol);
+
+ OUTL(bktr, BKTR_INT_MASK, BT848_INT_MYSTERYBIT |
+ BT848_INT_RISCI |
+ BT848_INT_VSYNC |
+ BT848_INT_FMTCHG);
+
+ OUTB(bktr, BKTR_CAP_CTL, bktr->bktr_cap_ctl);
+ error = tsleep(BKTR_SLEEP, BKTRPRI, "captur", hz);
+ if (error && (error != ERESTART)) {
+ /* Here if we didn't get complete frame */
+#ifdef DIAGNOSTIC
+ printf( "%s: ioctl: tsleep error %d %x\n",
+ bktr_name(bktr), error,
+ INL(bktr, BKTR_RISC_COUNT));
+#endif
+
+ /* stop dma */
+ OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
+
+ /* disable risc, leave fifo running */
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_ENABLED);
+ }
+
+ bktr->flags &= ~(METEOR_SINGLE|METEOR_WANT_MASK);
+ /* FIXME: should we set bt848->int_stat ??? */
+ break;
+
+ case METEOR_CAP_CONTINOUS:
+ if (bktr->bigbuf==0) /* no frame buffer allocated */
+ return( ENOMEM );
+ /* already capturing */
+ if (temp & METEOR_CAP_MASK)
+ return( EIO );
+
+
+ start_capture(bktr, METEOR_CONTIN);
+
+ /* Clear the interrypt status register */
+ OUTL(bktr, BKTR_INT_STAT, INL(bktr, BKTR_INT_STAT));
+
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_ENABLED);
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, bktr->capcontrol);
+ OUTB(bktr, BKTR_CAP_CTL, bktr->bktr_cap_ctl);
+
+ OUTL(bktr, BKTR_INT_MASK, BT848_INT_MYSTERYBIT |
+ BT848_INT_RISCI |
+ BT848_INT_VSYNC |
+ BT848_INT_FMTCHG);
+#ifdef BT848_DUMP
+ dump_bt848( bt848 );
+#endif
+ break;
+
+ case METEOR_CAP_STOP_CONT:
+ if (bktr->flags & METEOR_CONTIN) {
+ /* turn off capture */
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
+ OUTB(bktr, BKTR_CAP_CTL, CAPTURE_OFF);
+ OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
+ bktr->flags &=
+ ~(METEOR_CONTIN | METEOR_WANT_MASK);
+
+ }
+ }
+ break;
+
+ case METEORSETGEO:
+ /* can't change parameters while capturing */
+ if (bktr->flags & METEOR_CAP_MASK)
+ return( EBUSY );
+
+
+ geo = (struct meteor_geomet *) arg;
+
+ error = 0;
+ /* Either even or odd, if even & odd, then these a zero */
+ if ((geo->oformat & METEOR_GEO_ODD_ONLY) &&
+ (geo->oformat & METEOR_GEO_EVEN_ONLY)) {
+ printf( "%s: ioctl: Geometry odd or even only.\n",
+ bktr_name(bktr));
+ return( EINVAL );
+ }
+
+ /* set/clear even/odd flags */
+ if (geo->oformat & METEOR_GEO_ODD_ONLY)
+ bktr->flags |= METEOR_ONLY_ODD_FIELDS;
+ else
+ bktr->flags &= ~METEOR_ONLY_ODD_FIELDS;
+ if (geo->oformat & METEOR_GEO_EVEN_ONLY)
+ bktr->flags |= METEOR_ONLY_EVEN_FIELDS;
+ else
+ bktr->flags &= ~METEOR_ONLY_EVEN_FIELDS;
+
+ if (geo->columns <= 0) {
+ printf(
+ "%s: ioctl: %d: columns must be greater than zero.\n",
+ bktr_name(bktr), geo->columns);
+ error = EINVAL;
+ }
+ else if ((geo->columns & 0x3fe) != geo->columns) {
+ printf(
+ "%s: ioctl: %d: columns too large or not even.\n",
+ bktr_name(bktr), geo->columns);
+ error = EINVAL;
+ }
+
+ if (geo->rows <= 0) {
+ printf(
+ "%s: ioctl: %d: rows must be greater than zero.\n",
+ bktr_name(bktr), geo->rows);
+ error = EINVAL;
+ }
+ else if (((geo->rows & 0x7fe) != geo->rows) ||
+ ((geo->oformat & METEOR_GEO_FIELD_MASK) &&
+ ((geo->rows & 0x3fe) != geo->rows)) ) {
+ printf(
+ "%s: ioctl: %d: rows too large or not even.\n",
+ bktr_name(bktr), geo->rows);
+ error = EINVAL;
+ }
+
+ if (geo->frames > 32) {
+ printf("%s: ioctl: too many frames.\n",
+ bktr_name(bktr));
+
+ error = EINVAL;
+ }
+
+ if (error)
+ return( error );
+
+ bktr->dma_prog_loaded = FALSE;
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
+
+ OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
+
+ if ((temp=(geo->rows * geo->columns * geo->frames * 2))) {
+ if (geo->oformat & METEOR_GEO_RGB24) temp = temp * 2;
+
+ /* meteor_mem structure for SYNC Capture */
+ if (geo->frames > 1) temp += PAGE_SIZE;
+
+ temp = btoc(temp);
+ if ((int) temp > bktr->alloc_pages
+ && bktr->video.addr == 0) {
+
+/*****************************/
+/* *** OS Dependant code *** */
+/*****************************/
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+ bus_dmamap_t dmamap;
+
+ buf = get_bktr_mem(bktr, &dmamap,
+ temp * PAGE_SIZE);
+ if (buf != 0) {
+ free_bktr_mem(bktr, bktr->dm_mem,
+ bktr->bigbuf);
+ bktr->dm_mem = dmamap;
+
+#else
+ buf = get_bktr_mem(unit, temp*PAGE_SIZE);
+ if (buf != 0) {
+ kmem_free(kernel_map, bktr->bigbuf,
+ (bktr->alloc_pages * PAGE_SIZE));
+#endif
+
+ bktr->bigbuf = buf;
+ bktr->alloc_pages = temp;
+ if (bootverbose)
+ printf(
+ "%s: ioctl: Allocating %d bytes\n",
+ bktr_name(bktr), temp*PAGE_SIZE);
+ }
+ else
+ error = ENOMEM;
+ }
+ }
+
+ if (error)
+ return error;
+
+ bktr->rows = geo->rows;
+ bktr->cols = geo->columns;
+ bktr->frames = geo->frames;
+
+ /* Pixel format (if in meteor pixfmt compatibility mode) */
+ if ( bktr->pixfmt_compat ) {
+ bktr->format = METEOR_GEO_YUV_422;
+ switch (geo->oformat & METEOR_GEO_OUTPUT_MASK) {
+ case 0: /* default */
+ case METEOR_GEO_RGB16:
+ bktr->format = METEOR_GEO_RGB16;
+ break;
+ case METEOR_GEO_RGB24:
+ bktr->format = METEOR_GEO_RGB24;
+ break;
+ case METEOR_GEO_YUV_422:
+ bktr->format = METEOR_GEO_YUV_422;
+ if (geo->oformat & METEOR_GEO_YUV_12)
+ bktr->format = METEOR_GEO_YUV_12;
+ break;
+ case METEOR_GEO_YUV_PACKED:
+ bktr->format = METEOR_GEO_YUV_PACKED;
+ break;
+ }
+ bktr->pixfmt = oformat_meteor_to_bt( bktr->format );
+ }
+
+ if (bktr->flags & METEOR_CAP_MASK) {
+
+ if (bktr->flags & (METEOR_CONTIN|METEOR_SYNCAP)) {
+ switch(bktr->flags & METEOR_ONLY_FIELDS_MASK) {
+ case METEOR_ONLY_ODD_FIELDS:
+ bktr->flags |= METEOR_WANT_ODD;
+ break;
+ case METEOR_ONLY_EVEN_FIELDS:
+ bktr->flags |= METEOR_WANT_EVEN;
+ break;
+ default:
+ bktr->flags |= METEOR_WANT_MASK;
+ break;
+ }
+
+ start_capture(bktr, METEOR_CONTIN);
+ OUTL(bktr, BKTR_INT_STAT, INL(bktr, BKTR_INT_STAT));
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_ENABLED);
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, bktr->capcontrol);
+ OUTL(bktr, BKTR_INT_MASK, BT848_INT_MYSTERYBIT |
+ BT848_INT_VSYNC |
+ BT848_INT_FMTCHG);
+ }
+ }
+ break;
+ /* end of METEORSETGEO */
+
+ /* FIXME. The Capture Area currently has the following restrictions:
+ GENERAL
+ y_offset may need to be even in interlaced modes
+ RGB24 - Interlaced mode
+ x_size must be greater than or equal to 1.666*METEORSETGEO width (cols)
+ y_size must be greater than or equal to METEORSETGEO height (rows)
+ RGB24 - Even Only (or Odd Only) mode
+ x_size must be greater than or equal to 1.666*METEORSETGEO width (cols)
+ y_size must be greater than or equal to 2*METEORSETGEO height (rows)
+ YUV12 - Interlaced mode
+ x_size must be greater than or equal to METEORSETGEO width (cols)
+ y_size must be greater than or equal to METEORSETGEO height (rows)
+ YUV12 - Even Only (or Odd Only) mode
+ x_size must be greater than or equal to METEORSETGEO width (cols)
+ y_size must be greater than or equal to 2*METEORSETGEO height (rows)
+ */
+
+ case BT848_SCAPAREA: /* set capture area of each video frame */
+ /* can't change parameters while capturing */
+ if (bktr->flags & METEOR_CAP_MASK)
+ return( EBUSY );
+
+ cap_area = (struct bktr_capture_area *) arg;
+ bktr->capture_area_x_offset = cap_area->x_offset;
+ bktr->capture_area_y_offset = cap_area->y_offset;
+ bktr->capture_area_x_size = cap_area->x_size;
+ bktr->capture_area_y_size = cap_area->y_size;
+ bktr->capture_area_enabled = TRUE;
+
+ bktr->dma_prog_loaded = FALSE;
+ break;
+
+ case BT848_GCAPAREA: /* get capture area of each video frame */
+ cap_area = (struct bktr_capture_area *) arg;
+ if (bktr->capture_area_enabled == FALSE) {
+ cap_area->x_offset = 0;
+ cap_area->y_offset = 0;
+ cap_area->x_size = format_params[
+ bktr->format_params].scaled_hactive;
+ cap_area->y_size = format_params[
+ bktr->format_params].vactive;
+ } else {
+ cap_area->x_offset = bktr->capture_area_x_offset;
+ cap_area->y_offset = bktr->capture_area_y_offset;
+ cap_area->x_size = bktr->capture_area_x_size;
+ cap_area->y_size = bktr->capture_area_y_size;
+ }
+ break;
+
+ default:
+ return common_ioctl( bktr, cmd, arg );
+ }
+
+ return( 0 );
+}
+
+/*
+ * tuner ioctls
+ */
+int
+tuner_ioctl( bktr_ptr_t bktr, int unit, ioctl_cmd_t cmd, caddr_t arg, struct proc* pr )
+{
+ int tmp_int;
+ unsigned int temp, temp1;
+ int offset;
+ int count;
+ u_char *buf;
+ u_long par;
+ u_char write;
+ int i2c_addr;
+ int i2c_port;
+ u_long data;
+
+ switch ( cmd ) {
+
+ case REMOTE_GETKEY:
+ /* Read the last key pressed by the Remote Control */
+ if (bktr->remote_control == 0) return (EINVAL);
+ remote_read(bktr, (struct bktr_remote *)arg);
+ break;
+
+#if defined( TUNER_AFC )
+ case TVTUNER_SETAFC:
+ bktr->tuner.afc = (*(int *)arg != 0);
+ break;
+
+ case TVTUNER_GETAFC:
+ *(int *)arg = bktr->tuner.afc;
+ /* XXX Perhaps use another bit to indicate AFC success? */
+ break;
+#endif /* TUNER_AFC */
+
+ case TVTUNER_SETCHNL:
+ temp_mute( bktr, TRUE );
+ temp = tv_channel( bktr, (int)*(unsigned long *)arg );
+ if ( temp < 0 ) {
+ temp_mute( bktr, FALSE );
+ return( EINVAL );
+ }
+ *(unsigned long *)arg = temp;
+
+ /* after every channel change, we must restart the MSP34xx */
+ /* audio chip to reselect NICAM STEREO or MONO audio */
+ if ( bktr->card.msp3400c )
+ msp_autodetect( bktr );
+
+ /* after every channel change, we must restart the DPL35xx */
+ if ( bktr->card.dpl3518a )
+ dpl_autodetect( bktr );
+
+ temp_mute( bktr, FALSE );
+ break;
+
+ case TVTUNER_GETCHNL:
+ *(unsigned long *)arg = bktr->tuner.channel;
+ break;
+
+ case TVTUNER_SETTYPE:
+ temp = *(unsigned long *)arg;
+ if ( (temp < CHNLSET_MIN) || (temp > CHNLSET_MAX) )
+ return( EINVAL );
+ bktr->tuner.chnlset = temp;
+ break;
+
+ case TVTUNER_GETTYPE:
+ *(unsigned long *)arg = bktr->tuner.chnlset;
+ break;
+
+ case TVTUNER_GETSTATUS:
+ temp = get_tuner_status( bktr );
+ *(unsigned long *)arg = temp & 0xff;
+ break;
+
+ case TVTUNER_SETFREQ:
+ temp_mute( bktr, TRUE );
+ temp = tv_freq( bktr, (int)*(unsigned long *)arg, TV_FREQUENCY);
+ temp_mute( bktr, FALSE );
+ if ( temp < 0 ) {
+ temp_mute( bktr, FALSE );
+ return( EINVAL );
+ }
+ *(unsigned long *)arg = temp;
+
+ /* after every channel change, we must restart the MSP34xx */
+ /* audio chip to reselect NICAM STEREO or MONO audio */
+ if ( bktr->card.msp3400c )
+ msp_autodetect( bktr );
+
+ /* after every channel change, we must restart the DPL35xx */
+ if ( bktr->card.dpl3518a )
+ dpl_autodetect( bktr );
+
+ temp_mute( bktr, FALSE );
+ break;
+
+ case TVTUNER_GETFREQ:
+ *(unsigned long *)arg = bktr->tuner.frequency;
+ break;
+
+ case TVTUNER_GETCHNLSET:
+ return tuner_getchnlset((struct bktr_chnlset *)arg);
+
+ case BT848_SAUDIO: /* set audio channel */
+ if ( set_audio( bktr, *(int*)arg ) < 0 )
+ return( EIO );
+ break;
+
+ /* hue is a 2's compliment number, -90' to +89.3' in 0.7' steps */
+ case BT848_SHUE: /* set hue */
+ OUTB(bktr, BKTR_HUE, (u_char)(*(int*)arg & 0xff));
+ break;
+
+ case BT848_GHUE: /* get hue */
+ *(int*)arg = (signed char)(INB(bktr, BKTR_HUE) & 0xff);
+ break;
+
+ /* brightness is a 2's compliment #, -50 to +%49.6% in 0.39% steps */
+ case BT848_SBRIG: /* set brightness */
+ OUTB(bktr, BKTR_BRIGHT, (u_char)(*(int *)arg & 0xff));
+ break;
+
+ case BT848_GBRIG: /* get brightness */
+ *(int *)arg = (signed char)(INB(bktr, BKTR_BRIGHT) & 0xff);
+ break;
+
+ /* */
+ case BT848_SCSAT: /* set chroma saturation */
+ tmp_int = *(int*)arg;
+
+ temp = INB(bktr, BKTR_E_CONTROL);
+ temp1 = INB(bktr, BKTR_O_CONTROL);
+ if ( tmp_int & BIT_EIGHT_HIGH ) {
+ temp |= (BT848_E_CONTROL_SAT_U_MSB |
+ BT848_E_CONTROL_SAT_V_MSB);
+ temp1 |= (BT848_O_CONTROL_SAT_U_MSB |
+ BT848_O_CONTROL_SAT_V_MSB);
+ }
+ else {
+ temp &= ~(BT848_E_CONTROL_SAT_U_MSB |
+ BT848_E_CONTROL_SAT_V_MSB);
+ temp1 &= ~(BT848_O_CONTROL_SAT_U_MSB |
+ BT848_O_CONTROL_SAT_V_MSB);
+ }
+
+ OUTB(bktr, BKTR_SAT_U_LO, (u_char)(tmp_int & 0xff));
+ OUTB(bktr, BKTR_SAT_V_LO, (u_char)(tmp_int & 0xff));
+ OUTB(bktr, BKTR_E_CONTROL, temp);
+ OUTB(bktr, BKTR_O_CONTROL, temp1);
+ break;
+
+ case BT848_GCSAT: /* get chroma saturation */
+ tmp_int = (int)(INB(bktr, BKTR_SAT_V_LO) & 0xff);
+ if ( INB(bktr, BKTR_E_CONTROL) & BT848_E_CONTROL_SAT_V_MSB )
+ tmp_int |= BIT_EIGHT_HIGH;
+ *(int*)arg = tmp_int;
+ break;
+
+ /* */
+ case BT848_SVSAT: /* set chroma V saturation */
+ tmp_int = *(int*)arg;
+
+ temp = INB(bktr, BKTR_E_CONTROL);
+ temp1 = INB(bktr, BKTR_O_CONTROL);
+ if ( tmp_int & BIT_EIGHT_HIGH) {
+ temp |= BT848_E_CONTROL_SAT_V_MSB;
+ temp1 |= BT848_O_CONTROL_SAT_V_MSB;
+ }
+ else {
+ temp &= ~BT848_E_CONTROL_SAT_V_MSB;
+ temp1 &= ~BT848_O_CONTROL_SAT_V_MSB;
+ }
+
+ OUTB(bktr, BKTR_SAT_V_LO, (u_char)(tmp_int & 0xff));
+ OUTB(bktr, BKTR_E_CONTROL, temp);
+ OUTB(bktr, BKTR_O_CONTROL, temp1);
+ break;
+
+ case BT848_GVSAT: /* get chroma V saturation */
+ tmp_int = (int)INB(bktr, BKTR_SAT_V_LO) & 0xff;
+ if ( INB(bktr, BKTR_E_CONTROL) & BT848_E_CONTROL_SAT_V_MSB )
+ tmp_int |= BIT_EIGHT_HIGH;
+ *(int*)arg = tmp_int;
+ break;
+
+ /* */
+ case BT848_SUSAT: /* set chroma U saturation */
+ tmp_int = *(int*)arg;
+
+ temp = INB(bktr, BKTR_E_CONTROL);
+ temp1 = INB(bktr, BKTR_O_CONTROL);
+ if ( tmp_int & BIT_EIGHT_HIGH ) {
+ temp |= BT848_E_CONTROL_SAT_U_MSB;
+ temp1 |= BT848_O_CONTROL_SAT_U_MSB;
+ }
+ else {
+ temp &= ~BT848_E_CONTROL_SAT_U_MSB;
+ temp1 &= ~BT848_O_CONTROL_SAT_U_MSB;
+ }
+
+ OUTB(bktr, BKTR_SAT_U_LO, (u_char)(tmp_int & 0xff));
+ OUTB(bktr, BKTR_E_CONTROL, temp);
+ OUTB(bktr, BKTR_O_CONTROL, temp1);
+ break;
+
+ case BT848_GUSAT: /* get chroma U saturation */
+ tmp_int = (int)INB(bktr, BKTR_SAT_U_LO) & 0xff;
+ if ( INB(bktr, BKTR_E_CONTROL) & BT848_E_CONTROL_SAT_U_MSB )
+ tmp_int |= BIT_EIGHT_HIGH;
+ *(int*)arg = tmp_int;
+ break;
+
+/* lr 970528 luma notch etc - 3 high bits of e_control/o_control */
+
+ case BT848_SLNOTCH: /* set luma notch */
+ tmp_int = (*(int *)arg & 0x7) << 5 ;
+ OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) & ~0xe0);
+ OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) & ~0xe0);
+ OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) | tmp_int);
+ OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) | tmp_int);
+ break;
+
+ case BT848_GLNOTCH: /* get luma notch */
+ *(int *)arg = (int) ( (INB(bktr, BKTR_E_CONTROL) & 0xe0) >> 5) ;
+ break;
+
+
+ /* */
+ case BT848_SCONT: /* set contrast */
+ tmp_int = *(int*)arg;
+
+ temp = INB(bktr, BKTR_E_CONTROL);
+ temp1 = INB(bktr, BKTR_O_CONTROL);
+ if ( tmp_int & BIT_EIGHT_HIGH ) {
+ temp |= BT848_E_CONTROL_CON_MSB;
+ temp1 |= BT848_O_CONTROL_CON_MSB;
+ }
+ else {
+ temp &= ~BT848_E_CONTROL_CON_MSB;
+ temp1 &= ~BT848_O_CONTROL_CON_MSB;
+ }
+
+ OUTB(bktr, BKTR_CONTRAST_LO, (u_char)(tmp_int & 0xff));
+ OUTB(bktr, BKTR_E_CONTROL, temp);
+ OUTB(bktr, BKTR_O_CONTROL, temp1);
+ break;
+
+ case BT848_GCONT: /* get contrast */
+ tmp_int = (int)INB(bktr, BKTR_CONTRAST_LO) & 0xff;
+ if ( INB(bktr, BKTR_E_CONTROL) & BT848_E_CONTROL_CON_MSB )
+ tmp_int |= BIT_EIGHT_HIGH;
+ *(int*)arg = tmp_int;
+ break;
+
+ /* FIXME: SCBARS and CCBARS require a valid int * */
+ /* argument to succeed, but its not used; consider */
+ /* using the arg to store the on/off state so */
+ /* there's only one ioctl() needed to turn cbars on/off */
+ case BT848_SCBARS: /* set colorbar output */
+ OUTB(bktr, BKTR_COLOR_CTL, INB(bktr, BKTR_COLOR_CTL) | BT848_COLOR_CTL_COLOR_BARS);
+ break;
+
+ case BT848_CCBARS: /* clear colorbar output */
+ OUTB(bktr, BKTR_COLOR_CTL, INB(bktr, BKTR_COLOR_CTL) & ~(BT848_COLOR_CTL_COLOR_BARS));
+ break;
+
+ case BT848_GAUDIO: /* get audio channel */
+ temp = bktr->audio_mux_select;
+ if ( bktr->audio_mute_state == TRUE )
+ temp |= AUDIO_MUTE;
+ *(int*)arg = temp;
+ break;
+
+ case BT848_SBTSC: /* set audio channel */
+ if ( set_BTSC( bktr, *(int*)arg ) < 0 )
+ return( EIO );
+ break;
+
+ case BT848_WEEPROM: /* write eeprom */
+ offset = (((struct eeProm *)arg)->offset);
+ count = (((struct eeProm *)arg)->count);
+ buf = &(((struct eeProm *)arg)->bytes[ 0 ]);
+ if ( writeEEProm( bktr, offset, count, buf ) < 0 )
+ return( EIO );
+ break;
+
+ case BT848_REEPROM: /* read eeprom */
+ offset = (((struct eeProm *)arg)->offset);
+ count = (((struct eeProm *)arg)->count);
+ buf = &(((struct eeProm *)arg)->bytes[ 0 ]);
+ if ( readEEProm( bktr, offset, count, buf ) < 0 )
+ return( EIO );
+ break;
+
+ case BT848_SIGNATURE:
+ offset = (((struct eeProm *)arg)->offset);
+ count = (((struct eeProm *)arg)->count);
+ buf = &(((struct eeProm *)arg)->bytes[ 0 ]);
+ if ( signCard( bktr, offset, count, buf ) < 0 )
+ return( EIO );
+ break;
+
+ /* Ioctl's for direct gpio access */
+#ifdef BKTR_GPIO_ACCESS
+ case BT848_GPIO_GET_EN:
+ *(int*)arg = INL(bktr, BKTR_GPIO_OUT_EN);
+ break;
+
+ case BT848_GPIO_SET_EN:
+ OUTL(bktr, BKTR_GPIO_OUT_EN, *(int*)arg);
+ break;
+
+ case BT848_GPIO_GET_DATA:
+ *(int*)arg = INL(bktr, BKTR_GPIO_DATA);
+ break;
+
+ case BT848_GPIO_SET_DATA:
+ OUTL(bktr, BKTR_GPIO_DATA, *(int*)arg);
+ break;
+#endif /* BKTR_GPIO_ACCESS */
+
+ /* Ioctl's for running the tuner device in radio mode */
+
+ case RADIO_GETMODE:
+ *(unsigned char *)arg = bktr->tuner.radio_mode;
+ break;
+
+ case RADIO_SETMODE:
+ bktr->tuner.radio_mode = *(unsigned char *)arg;
+ break;
+
+ case RADIO_GETFREQ:
+ *(unsigned long *)arg = bktr->tuner.frequency;
+ break;
+
+ case RADIO_SETFREQ:
+ /* The argument to this ioctl is NOT freq*16. It is
+ ** freq*100.
+ */
+
+ temp=(int)*(unsigned long *)arg;
+
+#ifdef BKTR_RADIO_DEBUG
+ printf("%s: arg=%d temp=%d\n", bktr_name(bktr),
+ (int)*(unsigned long *)arg, temp);
+#endif
+
+#ifndef BKTR_RADIO_NOFREQCHECK
+ /* According to the spec. sheet the band: 87.5MHz-108MHz */
+ /* is supported. */
+ if(temp<8750 || temp>10800) {
+ printf("%s: Radio frequency out of range\n", bktr_name(bktr));
+ return(EINVAL);
+ }
+#endif
+ temp_mute( bktr, TRUE );
+ temp = tv_freq( bktr, temp, FM_RADIO_FREQUENCY );
+ temp_mute( bktr, FALSE );
+#ifdef BKTR_RADIO_DEBUG
+ if(temp)
+ printf("%s: tv_freq returned: %d\n", bktr_name(bktr), temp);
+#endif
+ if ( temp < 0 )
+ return( EINVAL );
+ *(unsigned long *)arg = temp;
+ break;
+
+ /* Luigi's I2CWR ioctl */
+ case BT848_I2CWR:
+ par = *(u_long *)arg;
+ write = (par >> 24) & 0xff ;
+ i2c_addr = (par >> 16) & 0xff ;
+ i2c_port = (par >> 8) & 0xff ;
+ data = (par) & 0xff ;
+
+ if (write) {
+ i2cWrite( bktr, i2c_addr, i2c_port, data);
+ } else {
+ data = i2cRead( bktr, i2c_addr);
+ }
+ *(u_long *)arg = (par & 0xffffff00) | ( data & 0xff );
+ break;
+
+
+#ifdef BT848_MSP_READ
+ /* I2C ioctls to allow userland access to the MSP chip */
+ case BT848_MSP_READ:
+ {
+ struct bktr_msp_control *msp;
+ msp = (struct bktr_msp_control *) arg;
+ msp->data = msp_dpl_read(bktr, bktr->msp_addr,
+ msp->function, msp->address);
+ break;
+ }
+
+ case BT848_MSP_WRITE:
+ {
+ struct bktr_msp_control *msp;
+ msp = (struct bktr_msp_control *) arg;
+ msp_dpl_write(bktr, bktr->msp_addr, msp->function,
+ msp->address, msp->data );
+ break;
+ }
+
+ case BT848_MSP_RESET:
+ msp_dpl_reset(bktr, bktr->msp_addr);
+ break;
+#endif
+
+ default:
+ return common_ioctl( bktr, cmd, arg );
+ }
+
+ return( 0 );
+}
+
+
+/*
+ * common ioctls
+ */
+int
+common_ioctl( bktr_ptr_t bktr, ioctl_cmd_t cmd, caddr_t arg )
+{
+ int pixfmt;
+ unsigned int temp;
+ struct meteor_pixfmt *pf_pub;
+
+ switch (cmd) {
+
+ case METEORSINPUT: /* set input device */
+ /*Bt848 has 3 MUX Inputs. Bt848A/849A/878/879 has 4 MUX Inputs*/
+ /* On the original bt848 boards, */
+ /* Tuner is MUX0, RCA is MUX1, S-Video is MUX2 */
+ /* On the Hauppauge bt878 boards, */
+ /* Tuner is MUX0, RCA is MUX3 */
+ /* Unfortunatly Meteor driver codes DEV_RCA as DEV_0, so we */
+ /* stick with this system in our Meteor Emulation */
+
+ switch(*(unsigned long *)arg & METEOR_DEV_MASK) {
+
+ /* this is the RCA video input */
+ case 0: /* default */
+ case METEOR_INPUT_DEV0:
+ /* METEOR_INPUT_DEV_RCA: */
+ bktr->flags = (bktr->flags & ~METEOR_DEV_MASK)
+ | METEOR_DEV0;
+ OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM)
+ & ~BT848_IFORM_MUXSEL);
+
+ /* work around for new Hauppauge 878 cards */
+ if ((bktr->card.card_id == CARD_HAUPPAUGE) &&
+ (bktr->id==BROOKTREE_878 ||
+ bktr->id==BROOKTREE_879) )
+ OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX3);
+ else
+ OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX1);
+
+ OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) & ~BT848_E_CONTROL_COMP);
+ OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) & ~BT848_O_CONTROL_COMP);
+ set_audio( bktr, AUDIO_EXTERN );
+ break;
+
+ /* this is the tuner input */
+ case METEOR_INPUT_DEV1:
+ bktr->flags = (bktr->flags & ~METEOR_DEV_MASK)
+ | METEOR_DEV1;
+ OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) & ~BT848_IFORM_MUXSEL);
+ OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX0);
+ OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) & ~BT848_E_CONTROL_COMP);
+ OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) & ~BT848_O_CONTROL_COMP);
+ set_audio( bktr, AUDIO_TUNER );
+ break;
+
+ /* this is the S-VHS input, but with a composite camera */
+ case METEOR_INPUT_DEV2:
+ bktr->flags = (bktr->flags & ~METEOR_DEV_MASK)
+ | METEOR_DEV2;
+ OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) & ~BT848_IFORM_MUXSEL);
+ OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX2);
+ OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) & ~BT848_E_CONTROL_COMP);
+ OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_E_CONTROL) & ~BT848_O_CONTROL_COMP);
+ set_audio( bktr, AUDIO_EXTERN );
+ break;
+
+ /* this is the S-VHS input */
+ case METEOR_INPUT_DEV_SVIDEO:
+ bktr->flags = (bktr->flags & ~METEOR_DEV_MASK)
+ | METEOR_DEV_SVIDEO;
+ OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) & ~BT848_IFORM_MUXSEL);
+ OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX2);
+ OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) | BT848_E_CONTROL_COMP);
+ OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) | BT848_O_CONTROL_COMP);
+ set_audio( bktr, AUDIO_EXTERN );
+ break;
+
+ case METEOR_INPUT_DEV3:
+ if ((bktr->id == BROOKTREE_848A) ||
+ (bktr->id == BROOKTREE_849A) ||
+ (bktr->id == BROOKTREE_878) ||
+ (bktr->id == BROOKTREE_879) ) {
+ bktr->flags = (bktr->flags & ~METEOR_DEV_MASK)
+ | METEOR_DEV3;
+ OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) & ~BT848_IFORM_MUXSEL);
+
+ /* work around for new Hauppauge 878 cards */
+ if ((bktr->card.card_id == CARD_HAUPPAUGE) &&
+ (bktr->id==BROOKTREE_878 ||
+ bktr->id==BROOKTREE_879) )
+ OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX1);
+ else
+ OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX3);
+
+ OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) & ~BT848_E_CONTROL_COMP);
+ OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) & ~BT848_O_CONTROL_COMP);
+ set_audio( bktr, AUDIO_EXTERN );
+
+ break;
+ }
+
+ default:
+ return( EINVAL );
+ }
+ break;
+
+ case METEORGINPUT: /* get input device */
+ *(u_long *)arg = bktr->flags & METEOR_DEV_MASK;
+ break;
+
+ case METEORSACTPIXFMT:
+ if (( *(int *)arg < 0 ) ||
+ ( *(int *)arg >= PIXFMT_TABLE_SIZE ))
+ return( EINVAL );
+
+ bktr->pixfmt = *(int *)arg;
+ OUTB(bktr, BKTR_COLOR_CTL, (INB(bktr, BKTR_COLOR_CTL) & 0xf0)
+ | pixfmt_swap_flags( bktr->pixfmt ));
+ bktr->pixfmt_compat = FALSE;
+ break;
+
+ case METEORGACTPIXFMT:
+ *(int *)arg = bktr->pixfmt;
+ break;
+
+ case METEORGSUPPIXFMT :
+ pf_pub = (struct meteor_pixfmt *)arg;
+ pixfmt = pf_pub->index;
+
+ if (( pixfmt < 0 ) || ( pixfmt >= PIXFMT_TABLE_SIZE ))
+ return( EINVAL );
+
+ memcpy( pf_pub, &pixfmt_table[ pixfmt ].public,
+ sizeof( *pf_pub ) );
+
+ /* Patch in our format index */
+ pf_pub->index = pixfmt;
+ break;
+
+#if defined( STATUS_SUM )
+ case BT848_GSTATUS: /* reap status */
+ {
+ DECLARE_INTR_MASK(s);
+ DISABLE_INTR(s);
+ temp = status_sum;
+ status_sum = 0;
+ ENABLE_INTR(s);
+ *(u_int*)arg = temp;
+ break;
+ }
+#endif /* STATUS_SUM */
+
+ default:
+ return( ENOTTY );
+ }
+
+ return( 0 );
+}
+
+
+
+
+/******************************************************************************
+ * bt848 RISC programming routines:
+ */
+
+
+/*
+ *
+ */
+#ifdef BT848_DEBUG
+static int
+dump_bt848( bktr_ptr_t bktr )
+{
+ int r[60]={
+ 4, 8, 0xc, 0x8c, 0x10, 0x90, 0x14, 0x94,
+ 0x18, 0x98, 0x1c, 0x9c, 0x20, 0xa0, 0x24, 0xa4,
+ 0x28, 0x2c, 0xac, 0x30, 0x34, 0x38, 0x3c, 0x40,
+ 0xc0, 0x48, 0x4c, 0xcc, 0x50, 0xd0, 0xd4, 0x60,
+ 0x64, 0x68, 0x6c, 0xec, 0xd8, 0xdc, 0xe0, 0xe4,
+ 0, 0, 0, 0
+ };
+ int i;
+
+ for (i = 0; i < 40; i+=4) {
+ printf("%s: Reg:value : \t%x:%x \t%x:%x \t %x:%x \t %x:%x\n",
+ bktr_name(bktr),
+ r[i], INL(bktr, r[i]),
+ r[i+1], INL(bktr, r[i+1]),
+ r[i+2], INL(bktr, r[i+2]),
+ r[i+3], INL(bktr, r[i+3]]));
+ }
+
+ printf("%s: INT STAT %x \n", bktr_name(bktr),
+ INL(bktr, BKTR_INT_STAT));
+ printf("%s: Reg INT_MASK %x \n", bktr_name(bktr),
+ INL(bktr, BKTR_INT_MASK));
+ printf("%s: Reg GPIO_DMA_CTL %x \n", bktr_name(bktr),
+ INW(bktr, BKTR_GPIO_DMA_CTL));
+
+ return( 0 );
+}
+
+#endif
+
+/*
+ * build write instruction
+ */
+#define BKTR_FM1 0x6 /* packed data to follow */
+#define BKTR_FM3 0xe /* planar data to follow */
+#define BKTR_VRE 0x4 /* Marks the end of the even field */
+#define BKTR_VRO 0xC /* Marks the end of the odd field */
+#define BKTR_PXV 0x0 /* valid word (never used) */
+#define BKTR_EOL 0x1 /* last dword, 4 bytes */
+#define BKTR_SOL 0x2 /* first dword */
+
+#define OP_WRITE (0x1 << 28)
+#define OP_SKIP (0x2 << 28)
+#define OP_WRITEC (0x5 << 28)
+#define OP_JUMP (0x7 << 28)
+#define OP_SYNC (0x8 << 28)
+#define OP_WRITE123 (0x9 << 28)
+#define OP_WRITES123 (0xb << 28)
+#define OP_SOL (1 << 27) /* first instr for scanline */
+#define OP_EOL (1 << 26)
+
+#define BKTR_RESYNC (1 << 15)
+#define BKTR_GEN_IRQ (1 << 24)
+
+/*
+ * The RISC status bits can be set/cleared in the RISC programs
+ * and tested in the Interrupt Handler
+ */
+#define BKTR_SET_RISC_STATUS_BIT0 (1 << 16)
+#define BKTR_SET_RISC_STATUS_BIT1 (1 << 17)
+#define BKTR_SET_RISC_STATUS_BIT2 (1 << 18)
+#define BKTR_SET_RISC_STATUS_BIT3 (1 << 19)
+
+#define BKTR_CLEAR_RISC_STATUS_BIT0 (1 << 20)
+#define BKTR_CLEAR_RISC_STATUS_BIT1 (1 << 21)
+#define BKTR_CLEAR_RISC_STATUS_BIT2 (1 << 22)
+#define BKTR_CLEAR_RISC_STATUS_BIT3 (1 << 23)
+
+#define BKTR_TEST_RISC_STATUS_BIT0 (1 << 28)
+#define BKTR_TEST_RISC_STATUS_BIT1 (1 << 29)
+#define BKTR_TEST_RISC_STATUS_BIT2 (1 << 30)
+#define BKTR_TEST_RISC_STATUS_BIT3 (1 << 31)
+
+bool_t notclipped (bktr_reg_t * bktr, int x, int width) {
+ int i;
+ bktr_clip_t * clip_node;
+ bktr->clip_start = -1;
+ bktr->last_y = 0;
+ bktr->y = 0;
+ bktr->y2 = width;
+ bktr->line_length = width;
+ bktr->yclip = -1;
+ bktr->yclip2 = -1;
+ bktr->current_col = 0;
+
+ if (bktr->max_clip_node == 0 ) return TRUE;
+ clip_node = (bktr_clip_t *) &bktr->clip_list[0];
+
+
+ for (i = 0; i < bktr->max_clip_node; i++ ) {
+ clip_node = (bktr_clip_t *) &bktr->clip_list[i];
+ if (x >= clip_node->x_min && x <= clip_node->x_max ) {
+ bktr->clip_start = i;
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+bool_t getline(bktr_reg_t *bktr, int x ) {
+ int i, j;
+ bktr_clip_t * clip_node ;
+
+ if (bktr->line_length == 0 ||
+ bktr->current_col >= bktr->line_length) return FALSE;
+
+ bktr->y = min(bktr->last_y, bktr->line_length);
+ bktr->y2 = bktr->line_length;
+
+ bktr->yclip = bktr->yclip2 = -1;
+ for (i = bktr->clip_start; i < bktr->max_clip_node; i++ ) {
+ clip_node = (bktr_clip_t *) &bktr->clip_list[i];
+ if (x >= clip_node->x_min && x <= clip_node->x_max) {
+ if (bktr->last_y <= clip_node->y_min) {
+ bktr->y = min(bktr->last_y, bktr->line_length);
+ bktr->y2 = min(clip_node->y_min, bktr->line_length);
+ bktr->yclip = min(clip_node->y_min, bktr->line_length);
+ bktr->yclip2 = min(clip_node->y_max, bktr->line_length);
+ bktr->last_y = bktr->yclip2;
+ bktr->clip_start = i;
+
+ for (j = i+1; j < bktr->max_clip_node; j++ ) {
+ clip_node = (bktr_clip_t *) &bktr->clip_list[j];
+ if (x >= clip_node->x_min && x <= clip_node->x_max) {
+ if (bktr->last_y >= clip_node->y_min) {
+ bktr->yclip2 = min(clip_node->y_max, bktr->line_length);
+ bktr->last_y = bktr->yclip2;
+ bktr->clip_start = j;
+ }
+ } else break ;
+ }
+ return TRUE;
+ }
+ }
+ }
+
+ if (bktr->current_col <= bktr->line_length) {
+ bktr->current_col = bktr->line_length;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static bool_t split(bktr_reg_t * bktr, volatile u_long **dma_prog, int width ,
+ u_long operation, int pixel_width,
+ volatile u_char ** target_buffer, int cols ) {
+
+ u_long flag, flag2;
+ struct meteor_pixfmt *pf = &pixfmt_table[ bktr->pixfmt ].public;
+ u_int skip, start_skip;
+
+ /* For RGB24, we need to align the component in FIFO Byte Lane 0 */
+ /* to the 1st byte in the mem dword containing our start addr. */
+ /* BTW, we know this pixfmt's 1st byte is Blue; thus the start addr */
+ /* must be Blue. */
+ start_skip = 0;
+ if (( pf->type == METEOR_PIXTYPE_RGB ) && ( pf->Bpp == 3 ))
+ switch ( ((uintptr_t) (volatile void *) *target_buffer) % 4 ) {
+ case 2 : start_skip = 4 ; break;
+ case 1 : start_skip = 8 ; break;
+ }
+
+ if ((width * pixel_width) < DMA_BT848_SPLIT ) {
+ if ( width == cols) {
+ flag = OP_SOL | OP_EOL;
+ } else if (bktr->current_col == 0 ) {
+ flag = OP_SOL;
+ } else if (bktr->current_col == cols) {
+ flag = OP_EOL;
+ } else flag = 0;
+
+ skip = 0;
+ if (( flag & OP_SOL ) && ( start_skip > 0 )) {
+ *(*dma_prog)++ = OP_SKIP | OP_SOL | start_skip;
+ flag &= ~OP_SOL;
+ skip = start_skip;
+ }
+
+ *(*dma_prog)++ = operation | flag | (width * pixel_width - skip);
+ if (operation != OP_SKIP )
+ *(*dma_prog)++ = (uintptr_t) (volatile void *) *target_buffer;
+
+ *target_buffer += width * pixel_width;
+ bktr->current_col += width;
+
+ } else {
+
+ if (bktr->current_col == 0 && width == cols) {
+ flag = OP_SOL ;
+ flag2 = OP_EOL;
+ } else if (bktr->current_col == 0 ) {
+ flag = OP_SOL;
+ flag2 = 0;
+ } else if (bktr->current_col >= cols) {
+ flag = 0;
+ flag2 = OP_EOL;
+ } else {
+ flag = 0;
+ flag2 = 0;
+ }
+
+ skip = 0;
+ if (( flag & OP_SOL ) && ( start_skip > 0 )) {
+ *(*dma_prog)++ = OP_SKIP | OP_SOL | start_skip;
+ flag &= ~OP_SOL;
+ skip = start_skip;
+ }
+
+ *(*dma_prog)++ = operation | flag |
+ (width * pixel_width / 2 - skip);
+ if (operation != OP_SKIP )
+ *(*dma_prog)++ = (uintptr_t) (volatile void *) *target_buffer ;
+ *target_buffer += (width * pixel_width / 2) ;
+
+ if ( operation == OP_WRITE )
+ operation = OP_WRITEC;
+ *(*dma_prog)++ = operation | flag2 |
+ (width * pixel_width / 2);
+ *target_buffer += (width * pixel_width / 2) ;
+ bktr->current_col += width;
+
+ }
+ return TRUE;
+}
+
+
+/*
+ * Generate the RISC instructions to capture both VBI and video images
+ */
+static void
+rgb_vbi_prog( bktr_ptr_t bktr, char i_flag, int cols, int rows, int interlace )
+{
+ int i;
+ volatile u_long target_buffer, buffer, target,width;
+ volatile u_long pitch;
+ volatile u_long *dma_prog; /* DMA prog is an array of
+ 32 bit RISC instructions */
+ volatile u_long *loop_point;
+ struct meteor_pixfmt_internal *pf_int = &pixfmt_table[ bktr->pixfmt ];
+ u_int Bpp = pf_int->public.Bpp;
+ unsigned int vbisamples; /* VBI samples per line */
+ unsigned int vbilines; /* VBI lines per field */
+ unsigned int num_dwords; /* DWORDS per line */
+
+ vbisamples = format_params[bktr->format_params].vbi_num_samples;
+ vbilines = format_params[bktr->format_params].vbi_num_lines;
+ num_dwords = vbisamples/4;
+
+ OUTB(bktr, BKTR_COLOR_FMT, pf_int->color_fmt);
+ OUTB(bktr, BKTR_ADC, SYNC_LEVEL);
+ OUTB(bktr, BKTR_VBI_PACK_SIZE, ((num_dwords)) & 0xff);
+ OUTB(bktr, BKTR_VBI_PACK_DEL, ((num_dwords)>> 8) & 0x01); /* no hdelay */
+ /* no ext frame */
+
+ OUTB(bktr, BKTR_OFORM, 0x00);
+
+ OUTB(bktr, BKTR_E_VSCALE_HI, INB(bktr, BKTR_E_VSCALE_HI) | 0x40); /* set chroma comb */
+ OUTB(bktr, BKTR_O_VSCALE_HI, INB(bktr, BKTR_O_VSCALE_HI) | 0x40);
+ OUTB(bktr, BKTR_E_VSCALE_HI, INB(bktr, BKTR_E_VSCALE_HI) & ~0x80); /* clear Ycomb */
+ OUTB(bktr, BKTR_O_VSCALE_HI, INB(bktr, BKTR_O_VSCALE_HI) & ~0x80);
+
+ /* disable gamma correction removal */
+ OUTB(bktr, BKTR_COLOR_CTL, INB(bktr, BKTR_COLOR_CTL) | BT848_COLOR_CTL_GAMMA);
+
+ if (cols > 385 ) {
+ OUTB(bktr, BKTR_E_VTC, 0);
+ OUTB(bktr, BKTR_O_VTC, 0);
+ } else {
+ OUTB(bktr, BKTR_E_VTC, 1);
+ OUTB(bktr, BKTR_O_VTC, 1);
+ }
+ bktr->capcontrol = 3 << 2 | 3;
+
+ dma_prog = (u_long *) bktr->dma_prog;
+
+ /* Construct Write */
+
+ if (bktr->video.addr) {
+ target_buffer = (u_long) bktr->video.addr;
+ pitch = bktr->video.width;
+ }
+ else {
+ target_buffer = (u_long) vtophys(bktr->bigbuf);
+ pitch = cols*Bpp;
+ }
+
+ buffer = target_buffer;
+
+ /* Wait for the VRE sync marking the end of the Even and
+ * the start of the Odd field. Resync here.
+ */
+ *dma_prog++ = OP_SYNC | BKTR_RESYNC |BKTR_VRE;
+ *dma_prog++ = 0;
+
+ loop_point = dma_prog;
+
+ /* store the VBI data */
+ /* look for sync with packed data */
+ *dma_prog++ = OP_SYNC | BKTR_FM1;
+ *dma_prog++ = 0;
+ for(i = 0; i < vbilines; i++) {
+ *dma_prog++ = OP_WRITE | OP_SOL | OP_EOL | vbisamples;
+ *dma_prog++ = (u_long) vtophys((caddr_t)bktr->vbidata +
+ (i * VBI_LINE_SIZE));
+ }
+
+ if ( (i_flag == 2/*Odd*/) || (i_flag==3) /*interlaced*/ ) {
+ /* store the Odd field video image */
+ /* look for sync with packed data */
+ *dma_prog++ = OP_SYNC | BKTR_FM1;
+ *dma_prog++ = 0; /* NULL WORD */
+ width = cols;
+ for (i = 0; i < (rows/interlace); i++) {
+ target = target_buffer;
+ if ( notclipped(bktr, i, width)) {
+ split(bktr, (volatile u_long **) &dma_prog,
+ bktr->y2 - bktr->y, OP_WRITE,
+ Bpp, (volatile u_char **) &target, cols);
+
+ } else {
+ while(getline(bktr, i)) {
+ if (bktr->y != bktr->y2 ) {
+ split(bktr, (volatile u_long **) &dma_prog,
+ bktr->y2 - bktr->y, OP_WRITE,
+ Bpp, (volatile u_char **) &target, cols);
+ }
+ if (bktr->yclip != bktr->yclip2 ) {
+ split(bktr,(volatile u_long **) &dma_prog,
+ bktr->yclip2 - bktr->yclip,
+ OP_SKIP,
+ Bpp, (volatile u_char **) &target, cols);
+ }
+ }
+
+ }
+
+ target_buffer += interlace * pitch;
+
+ }
+
+ } /* end if */
+
+ /* Grab the Even field */
+ /* Look for the VRO, end of Odd field, marker */
+ *dma_prog++ = OP_SYNC | BKTR_GEN_IRQ | BKTR_RESYNC | BKTR_VRO;
+ *dma_prog++ = 0; /* NULL WORD */
+
+ /* store the VBI data */
+ /* look for sync with packed data */
+ *dma_prog++ = OP_SYNC | BKTR_FM1;
+ *dma_prog++ = 0;
+ for(i = 0; i < vbilines; i++) {
+ *dma_prog++ = OP_WRITE | OP_SOL | OP_EOL | vbisamples;
+ *dma_prog++ = (u_long) vtophys((caddr_t)bktr->vbidata +
+ ((i+MAX_VBI_LINES) * VBI_LINE_SIZE));
+ }
+
+ /* store the video image */
+ if (i_flag == 1) /*Even Only*/
+ target_buffer = buffer;
+ if (i_flag == 3) /*interlaced*/
+ target_buffer = buffer+pitch;
+
+
+ if ((i_flag == 1) /*Even Only*/ || (i_flag==3) /*interlaced*/) {
+ /* look for sync with packed data */
+ *dma_prog++ = OP_SYNC | BKTR_FM1;
+ *dma_prog++ = 0; /* NULL WORD */
+ width = cols;
+ for (i = 0; i < (rows/interlace); i++) {
+ target = target_buffer;
+ if ( notclipped(bktr, i, width)) {
+ split(bktr, (volatile u_long **) &dma_prog,
+ bktr->y2 - bktr->y, OP_WRITE,
+ Bpp, (volatile u_char **) &target, cols);
+ } else {
+ while(getline(bktr, i)) {
+ if (bktr->y != bktr->y2 ) {
+ split(bktr, (volatile u_long **) &dma_prog,
+ bktr->y2 - bktr->y, OP_WRITE,
+ Bpp, (volatile u_char **) &target,
+ cols);
+ }
+ if (bktr->yclip != bktr->yclip2 ) {
+ split(bktr, (volatile u_long **) &dma_prog,
+ bktr->yclip2 - bktr->yclip, OP_SKIP,
+ Bpp, (volatile u_char **) &target, cols);
+ }
+
+ }
+
+ }
+
+ target_buffer += interlace * pitch;
+
+ }
+ }
+
+ /* Look for end of 'Even Field' */
+ *dma_prog++ = OP_SYNC | BKTR_GEN_IRQ | BKTR_RESYNC | BKTR_VRE;
+ *dma_prog++ = 0; /* NULL WORD */
+
+ *dma_prog++ = OP_JUMP ;
+ *dma_prog++ = (u_long ) vtophys(loop_point) ;
+ *dma_prog++ = 0; /* NULL WORD */
+
+}
+
+
+
+
+static void
+rgb_prog( bktr_ptr_t bktr, char i_flag, int cols, int rows, int interlace )
+{
+ int i;
+ volatile u_long target_buffer, buffer, target,width;
+ volatile u_long pitch;
+ volatile u_long *dma_prog;
+ struct meteor_pixfmt_internal *pf_int = &pixfmt_table[ bktr->pixfmt ];
+ u_int Bpp = pf_int->public.Bpp;
+
+ OUTB(bktr, BKTR_COLOR_FMT, pf_int->color_fmt);
+ OUTB(bktr, BKTR_VBI_PACK_SIZE, 0);
+ OUTB(bktr, BKTR_VBI_PACK_DEL, 0);
+ OUTB(bktr, BKTR_ADC, SYNC_LEVEL);
+
+ OUTB(bktr, BKTR_OFORM, 0x00);
+
+ OUTB(bktr, BKTR_E_VSCALE_HI, INB(bktr, BKTR_E_VSCALE_HI) | 0x40); /* set chroma comb */
+ OUTB(bktr, BKTR_O_VSCALE_HI, INB(bktr, BKTR_O_VSCALE_HI) | 0x40);
+ OUTB(bktr, BKTR_E_VSCALE_HI, INB(bktr, BKTR_E_VSCALE_HI) & ~0x80); /* clear Ycomb */
+ OUTB(bktr, BKTR_O_VSCALE_HI, INB(bktr, BKTR_O_VSCALE_HI) & ~0x80);
+
+ /* disable gamma correction removal */
+ OUTB(bktr, BKTR_COLOR_CTL, INB(bktr, BKTR_COLOR_CTL) | BT848_COLOR_CTL_GAMMA);
+
+ if (cols > 385 ) {
+ OUTB(bktr, BKTR_E_VTC, 0);
+ OUTB(bktr, BKTR_O_VTC, 0);
+ } else {
+ OUTB(bktr, BKTR_E_VTC, 1);
+ OUTB(bktr, BKTR_O_VTC, 1);
+ }
+ bktr->capcontrol = 3 << 2 | 3;
+
+ dma_prog = (u_long *) bktr->dma_prog;
+
+ /* Construct Write */
+
+ if (bktr->video.addr) {
+ target_buffer = (u_long) bktr->video.addr;
+ pitch = bktr->video.width;
+ }
+ else {
+ target_buffer = (u_long) vtophys(bktr->bigbuf);
+ pitch = cols*Bpp;
+ }
+
+ buffer = target_buffer;
+
+ /* contruct sync : for video packet format */
+ *dma_prog++ = OP_SYNC | BKTR_RESYNC | BKTR_FM1;
+
+ /* sync, mode indicator packed data */
+ *dma_prog++ = 0; /* NULL WORD */
+ width = cols;
+ for (i = 0; i < (rows/interlace); i++) {
+ target = target_buffer;
+ if ( notclipped(bktr, i, width)) {
+ split(bktr, (volatile u_long **) &dma_prog,
+ bktr->y2 - bktr->y, OP_WRITE,
+ Bpp, (volatile u_char **) &target, cols);
+
+ } else {
+ while(getline(bktr, i)) {
+ if (bktr->y != bktr->y2 ) {
+ split(bktr, (volatile u_long **) &dma_prog,
+ bktr->y2 - bktr->y, OP_WRITE,
+ Bpp, (volatile u_char **) &target, cols);
+ }
+ if (bktr->yclip != bktr->yclip2 ) {
+ split(bktr,(volatile u_long **) &dma_prog,
+ bktr->yclip2 - bktr->yclip,
+ OP_SKIP,
+ Bpp, (volatile u_char **) &target, cols);
+ }
+ }
+
+ }
+
+ target_buffer += interlace * pitch;
+
+ }
+
+ switch (i_flag) {
+ case 1:
+ /* sync vre */
+ *dma_prog++ = OP_SYNC | BKTR_GEN_IRQ | BKTR_VRO;
+ *dma_prog++ = 0; /* NULL WORD */
+
+ *dma_prog++ = OP_JUMP;
+ *dma_prog++ = (u_long ) vtophys(bktr->dma_prog);
+ return;
+
+ case 2:
+ /* sync vro */
+ *dma_prog++ = OP_SYNC | BKTR_GEN_IRQ | BKTR_VRE;
+ *dma_prog++ = 0; /* NULL WORD */
+
+ *dma_prog++ = OP_JUMP;
+ *dma_prog++ = (u_long ) vtophys(bktr->dma_prog);
+ return;
+
+ case 3:
+ /* sync vro */
+ *dma_prog++ = OP_SYNC | BKTR_GEN_IRQ | BKTR_RESYNC | BKTR_VRO;
+ *dma_prog++ = 0; /* NULL WORD */
+ *dma_prog++ = OP_JUMP; ;
+ *dma_prog = (u_long ) vtophys(bktr->odd_dma_prog);
+ break;
+ }
+
+ if (interlace == 2) {
+
+ target_buffer = buffer + pitch;
+
+ dma_prog = (u_long *) bktr->odd_dma_prog;
+
+ /* sync vre IRQ bit */
+ *dma_prog++ = OP_SYNC | BKTR_RESYNC | BKTR_FM1;
+ *dma_prog++ = 0; /* NULL WORD */
+ width = cols;
+ for (i = 0; i < (rows/interlace); i++) {
+ target = target_buffer;
+ if ( notclipped(bktr, i, width)) {
+ split(bktr, (volatile u_long **) &dma_prog,
+ bktr->y2 - bktr->y, OP_WRITE,
+ Bpp, (volatile u_char **) &target, cols);
+ } else {
+ while(getline(bktr, i)) {
+ if (bktr->y != bktr->y2 ) {
+ split(bktr, (volatile u_long **) &dma_prog,
+ bktr->y2 - bktr->y, OP_WRITE,
+ Bpp, (volatile u_char **) &target,
+ cols);
+ }
+ if (bktr->yclip != bktr->yclip2 ) {
+ split(bktr, (volatile u_long **) &dma_prog,
+ bktr->yclip2 - bktr->yclip, OP_SKIP,
+ Bpp, (volatile u_char **) &target, cols);
+ }
+
+ }
+
+ }
+
+ target_buffer += interlace * pitch;
+
+ }
+ }
+
+ /* sync vre IRQ bit */
+ *dma_prog++ = OP_SYNC | BKTR_GEN_IRQ | BKTR_RESYNC | BKTR_VRE;
+ *dma_prog++ = 0; /* NULL WORD */
+ *dma_prog++ = OP_JUMP ;
+ *dma_prog++ = (u_long ) vtophys(bktr->dma_prog) ;
+ *dma_prog++ = 0; /* NULL WORD */
+}
+
+
+/*
+ *
+ */
+static void
+yuvpack_prog( bktr_ptr_t bktr, char i_flag,
+ int cols, int rows, int interlace )
+{
+ int i;
+ volatile unsigned int inst;
+ volatile unsigned int inst3;
+ volatile u_long target_buffer, buffer;
+ volatile u_long *dma_prog;
+ struct meteor_pixfmt_internal *pf_int = &pixfmt_table[ bktr->pixfmt ];
+ int b;
+
+ OUTB(bktr, BKTR_COLOR_FMT, pf_int->color_fmt);
+
+ OUTB(bktr, BKTR_E_SCLOOP, INB(bktr, BKTR_E_SCLOOP) | BT848_E_SCLOOP_CAGC); /* enable chroma comb */
+ OUTB(bktr, BKTR_O_SCLOOP, INB(bktr, BKTR_O_SCLOOP) | BT848_O_SCLOOP_CAGC);
+
+ OUTB(bktr, BKTR_COLOR_CTL, INB(bktr, BKTR_COLOR_CTL) | BT848_COLOR_CTL_RGB_DED | BT848_COLOR_CTL_GAMMA);
+ OUTB(bktr, BKTR_ADC, SYNC_LEVEL);
+
+ bktr->capcontrol = 1 << 6 | 1 << 4 | 1 << 2 | 3;
+ bktr->capcontrol = 3 << 2 | 3;
+
+ dma_prog = (u_long *) bktr->dma_prog;
+
+ /* Construct Write */
+
+ /* write , sol, eol */
+ inst = OP_WRITE | OP_SOL | (cols);
+ /* write , sol, eol */
+ inst3 = OP_WRITE | OP_EOL | (cols);
+
+ if (bktr->video.addr)
+ target_buffer = (u_long) bktr->video.addr;
+ else
+ target_buffer = (u_long) vtophys(bktr->bigbuf);
+
+ buffer = target_buffer;
+
+ /* contruct sync : for video packet format */
+ /* sync, mode indicator packed data */
+ *dma_prog++ = OP_SYNC | 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 vro */
+ *dma_prog++ = OP_SYNC | 1 << 24 | BKTR_VRO;
+ *dma_prog++ = 0; /* NULL WORD */
+ *dma_prog++ = OP_JUMP;
+ *dma_prog++ = (u_long ) vtophys(bktr->dma_prog);
+ return;
+
+ case 3:
+ /* sync vro */
+ *dma_prog++ = OP_SYNC | 1 << 24 | 1 << 15 | BKTR_VRO;
+ *dma_prog++ = 0; /* NULL WORD */
+ *dma_prog++ = OP_JUMP ;
+ *dma_prog = (u_long ) vtophys(bktr->odd_dma_prog);
+ break;
+ }
+
+ if (interlace == 2) {
+
+ target_buffer = (u_long) buffer + cols*2;
+
+ dma_prog = (u_long * ) bktr->odd_dma_prog;
+
+ /* sync vre */
+ *dma_prog++ = OP_SYNC | 1 << 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 * ( cols*2);
+ }
+ }
+
+ /* sync vro IRQ bit */
+ *dma_prog++ = OP_SYNC | 1 << 24 | 1 << 15 | BKTR_VRE;
+ *dma_prog++ = 0; /* NULL WORD */
+ *dma_prog++ = OP_JUMP ;
+ *dma_prog++ = (u_long ) vtophys(bktr->dma_prog);
+
+ *dma_prog++ = OP_JUMP;
+ *dma_prog++ = (u_long ) vtophys(bktr->dma_prog);
+ *dma_prog++ = 0; /* NULL WORD */
+}
+
+
+/*
+ *
+ */
+static void
+yuv422_prog( bktr_ptr_t bktr, char i_flag,
+ int cols, int rows, int interlace ){
+
+ int i;
+ volatile unsigned int inst;
+ volatile u_long target_buffer, t1, buffer;
+ volatile u_long *dma_prog;
+ struct meteor_pixfmt_internal *pf_int = &pixfmt_table[ bktr->pixfmt ];
+
+ OUTB(bktr, BKTR_COLOR_FMT, pf_int->color_fmt);
+
+ dma_prog = (u_long *) bktr->dma_prog;
+
+ bktr->capcontrol = 1 << 6 | 1 << 4 | 3;
+
+ OUTB(bktr, BKTR_ADC, SYNC_LEVEL);
+ OUTB(bktr, BKTR_OFORM, 0x00);
+
+ OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) | BT848_E_CONTROL_LDEC); /* disable luma decimation */
+ OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) | BT848_O_CONTROL_LDEC);
+
+ OUTB(bktr, BKTR_E_SCLOOP, INB(bktr, BKTR_E_SCLOOP) | BT848_E_SCLOOP_CAGC); /* chroma agc enable */
+ OUTB(bktr, BKTR_O_SCLOOP, INB(bktr, BKTR_O_SCLOOP) | BT848_O_SCLOOP_CAGC);
+
+ OUTB(bktr, BKTR_E_VSCALE_HI, INB(bktr, BKTR_E_VSCALE_HI) & ~0x80); /* clear Ycomb */
+ OUTB(bktr, BKTR_O_VSCALE_HI, INB(bktr, BKTR_O_VSCALE_HI) & ~0x80);
+ OUTB(bktr, BKTR_E_VSCALE_HI, INB(bktr, BKTR_E_VSCALE_HI) | ~0x40); /* set chroma comb */
+ OUTB(bktr, BKTR_O_VSCALE_HI, INB(bktr, BKTR_O_VSCALE_HI) | ~0x40);
+
+ /* disable gamma correction removal */
+ OUTB(bktr, BKTR_COLOR_CTL, INB(bktr, BKTR_COLOR_CTL) | BT848_COLOR_CTL_GAMMA);
+
+ /* Construct Write */
+ inst = OP_WRITE123 | OP_SOL | OP_EOL | (cols);
+ if (bktr->video.addr)
+ target_buffer = (u_long) bktr->video.addr;
+ else
+ target_buffer = (u_long) vtophys(bktr->bigbuf);
+
+ buffer = target_buffer;
+
+ t1 = buffer;
+
+ /* contruct sync : for video packet format */
+ *dma_prog++ = OP_SYNC | 1 << 15 | BKTR_FM3; /*sync, mode indicator packed data*/
+ *dma_prog++ = 0; /* NULL WORD */
+
+ for (i = 0; i < (rows/interlace ) ; i++) {
+ *dma_prog++ = inst;
+ *dma_prog++ = cols/2 | cols/2 << 16;
+ *dma_prog++ = target_buffer;
+ *dma_prog++ = t1 + (cols*rows) + i*cols/2 * interlace;
+ *dma_prog++ = t1 + (cols*rows) + (cols*rows/2) + i*cols/2 * interlace;
+ target_buffer += interlace*cols;
+ }
+
+ switch (i_flag) {
+ case 1:
+ *dma_prog++ = OP_SYNC | 1 << 24 | BKTR_VRE; /*sync vre*/
+ *dma_prog++ = 0; /* NULL WORD */
+
+ *dma_prog++ = OP_JUMP ;
+ *dma_prog++ = (u_long ) vtophys(bktr->dma_prog);
+ return;
+
+ case 2:
+ *dma_prog++ = OP_SYNC | 1 << 24 | BKTR_VRO; /*sync vre*/
+ *dma_prog++ = 0; /* NULL WORD */
+
+ *dma_prog++ = OP_JUMP;
+ *dma_prog++ = (u_long ) vtophys(bktr->dma_prog);
+ return;
+
+ case 3:
+ *dma_prog++ = OP_SYNC | 1 << 24 | 1 << 15 | BKTR_VRO;
+ *dma_prog++ = 0; /* NULL WORD */
+
+ *dma_prog++ = OP_JUMP ;
+ *dma_prog = (u_long ) vtophys(bktr->odd_dma_prog);
+ break;
+ }
+
+ if (interlace == 2) {
+
+ dma_prog = (u_long * ) bktr->odd_dma_prog;
+
+ target_buffer = (u_long) buffer + cols;
+ t1 = buffer + cols/2;
+ *dma_prog++ = OP_SYNC | 1 << 15 | BKTR_FM3;
+ *dma_prog++ = 0; /* NULL WORD */
+
+ for (i = 0; i < (rows/interlace ) ; i++) {
+ *dma_prog++ = inst;
+ *dma_prog++ = cols/2 | cols/2 << 16;
+ *dma_prog++ = target_buffer;
+ *dma_prog++ = t1 + (cols*rows) + i*cols/2 * interlace;
+ *dma_prog++ = t1 + (cols*rows) + (cols*rows/2) + i*cols/2 * interlace;
+ target_buffer += interlace*cols;
+ }
+ }
+
+ *dma_prog++ = OP_SYNC | 1 << 24 | 1 << 15 | BKTR_VRE;
+ *dma_prog++ = 0; /* NULL WORD */
+ *dma_prog++ = OP_JUMP ;
+ *dma_prog++ = (u_long ) vtophys(bktr->dma_prog) ;
+ *dma_prog++ = 0; /* NULL WORD */
+}
+
+
+/*
+ *
+ */
+static void
+yuv12_prog( bktr_ptr_t bktr, char i_flag,
+ int cols, int rows, int interlace ){
+
+ int i;
+ volatile unsigned int inst;
+ volatile unsigned int inst1;
+ volatile u_long target_buffer, t1, buffer;
+ volatile u_long *dma_prog;
+ struct meteor_pixfmt_internal *pf_int = &pixfmt_table[ bktr->pixfmt ];
+
+ OUTB(bktr, BKTR_COLOR_FMT, pf_int->color_fmt);
+
+ dma_prog = (u_long *) bktr->dma_prog;
+
+ bktr->capcontrol = 1 << 6 | 1 << 4 | 3;
+
+ OUTB(bktr, BKTR_ADC, SYNC_LEVEL);
+ OUTB(bktr, BKTR_OFORM, 0x0);
+
+ /* Construct Write */
+ inst = OP_WRITE123 | OP_SOL | OP_EOL | (cols);
+ inst1 = OP_WRITES123 | OP_SOL | OP_EOL | (cols);
+ if (bktr->video.addr)
+ target_buffer = (u_long) bktr->video.addr;
+ else
+ target_buffer = (u_long) vtophys(bktr->bigbuf);
+
+ buffer = target_buffer;
+ t1 = buffer;
+
+ *dma_prog++ = OP_SYNC | 1 << 15 | BKTR_FM3; /*sync, mode indicator packed data*/
+ *dma_prog++ = 0; /* NULL WORD */
+
+ for (i = 0; i < (rows/interlace )/2 ; i++) {
+ *dma_prog++ = inst;
+ *dma_prog++ = cols/2 | (cols/2 << 16);
+ *dma_prog++ = target_buffer;
+ *dma_prog++ = t1 + (cols*rows) + i*cols/2 * interlace;
+ *dma_prog++ = t1 + (cols*rows) + (cols*rows/4) + i*cols/2 * interlace;
+ target_buffer += interlace*cols;
+ *dma_prog++ = inst1;
+ *dma_prog++ = cols/2 | (cols/2 << 16);
+ *dma_prog++ = target_buffer;
+ target_buffer += interlace*cols;
+
+ }
+
+ switch (i_flag) {
+ case 1:
+ *dma_prog++ = OP_SYNC | 1 << 24 | BKTR_VRE; /*sync vre*/
+ *dma_prog++ = 0; /* NULL WORD */
+
+ *dma_prog++ = OP_JUMP;
+ *dma_prog++ = (u_long ) vtophys(bktr->dma_prog);
+ return;
+
+ case 2:
+ *dma_prog++ = OP_SYNC | 1 << 24 | BKTR_VRO; /*sync vro*/
+ *dma_prog++ = 0; /* NULL WORD */
+
+ *dma_prog++ = OP_JUMP;
+ *dma_prog++ = (u_long ) vtophys(bktr->dma_prog);
+ return;
+
+ case 3:
+ *dma_prog++ = OP_SYNC | 1 << 24 | 1 << 15 | BKTR_VRO;
+ *dma_prog++ = 0; /* NULL WORD */
+ *dma_prog++ = OP_JUMP ;
+ *dma_prog = (u_long ) vtophys(bktr->odd_dma_prog);
+ break;
+ }
+
+ if (interlace == 2) {
+
+ dma_prog = (u_long * ) bktr->odd_dma_prog;
+
+ target_buffer = (u_long) buffer + cols;
+ t1 = buffer + cols/2;
+ *dma_prog++ = OP_SYNC | 1 << 15 | BKTR_FM3;
+ *dma_prog++ = 0; /* NULL WORD */
+
+ for (i = 0; i < ((rows/interlace )/2 ) ; i++) {
+ *dma_prog++ = inst;
+ *dma_prog++ = cols/2 | (cols/2 << 16);
+ *dma_prog++ = target_buffer;
+ *dma_prog++ = t1 + (cols*rows) + i*cols/2 * interlace;
+ *dma_prog++ = t1 + (cols*rows) + (cols*rows/4) + i*cols/2 * interlace;
+ target_buffer += interlace*cols;
+ *dma_prog++ = inst1;
+ *dma_prog++ = cols/2 | (cols/2 << 16);
+ *dma_prog++ = target_buffer;
+ target_buffer += interlace*cols;
+
+ }
+
+
+ }
+
+ *dma_prog++ = OP_SYNC | 1 << 24 | 1 << 15 | BKTR_VRE;
+ *dma_prog++ = 0; /* NULL WORD */
+ *dma_prog++ = OP_JUMP;
+ *dma_prog++ = (u_long ) vtophys(bktr->dma_prog);
+ *dma_prog++ = 0; /* NULL WORD */
+}
+
+
+
+/*
+ *
+ */
+static void
+build_dma_prog( bktr_ptr_t bktr, char i_flag )
+{
+ int rows, cols, interlace;
+ int tmp_int;
+ unsigned int temp;
+ struct format_params *fp;
+ struct meteor_pixfmt_internal *pf_int = &pixfmt_table[ bktr->pixfmt ];
+
+
+ fp = &format_params[bktr->format_params];
+
+ OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
+
+ /* disable FIFO & RISC, leave other bits alone */
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, INW(bktr, BKTR_GPIO_DMA_CTL) & ~FIFO_RISC_ENABLED);
+
+ /* set video parameters */
+ if (bktr->capture_area_enabled)
+ temp = ((quad_t ) fp->htotal* (quad_t) bktr->capture_area_x_size * 4096
+ / fp->scaled_htotal / bktr->cols) - 4096;
+ else
+ temp = ((quad_t ) fp->htotal* (quad_t) fp->scaled_hactive * 4096
+ / fp->scaled_htotal / bktr->cols) - 4096;
+
+ /* printf("%s: HSCALE value is %d\n", bktr_name(bktr), temp); */
+ OUTB(bktr, BKTR_E_HSCALE_LO, temp & 0xff);
+ OUTB(bktr, BKTR_O_HSCALE_LO, temp & 0xff);
+ OUTB(bktr, BKTR_E_HSCALE_HI, (temp >> 8) & 0xff);
+ OUTB(bktr, BKTR_O_HSCALE_HI, (temp >> 8) & 0xff);
+
+ /* horizontal active */
+ temp = bktr->cols;
+ /* printf("%s: HACTIVE value is %d\n", bktr_name(bktr), temp); */
+ OUTB(bktr, BKTR_E_HACTIVE_LO, temp & 0xff);
+ OUTB(bktr, BKTR_O_HACTIVE_LO, temp & 0xff);
+ OUTB(bktr, BKTR_E_CROP, INB(bktr, BKTR_E_CROP) & ~0x3);
+ OUTB(bktr, BKTR_O_CROP, INB(bktr, BKTR_O_CROP) & ~0x3);
+ OUTB(bktr, BKTR_E_CROP, INB(bktr, BKTR_E_CROP) | ((temp >> 8) & 0x3));
+ OUTB(bktr, BKTR_O_CROP, INB(bktr, BKTR_O_CROP) | ((temp >> 8) & 0x3));
+
+ /* horizontal delay */
+ if (bktr->capture_area_enabled)
+ temp = ( (fp->hdelay* fp->scaled_hactive + bktr->capture_area_x_offset* fp->scaled_htotal)
+ * bktr->cols) / (bktr->capture_area_x_size * fp->hactive);
+ else
+ temp = (fp->hdelay * bktr->cols) / fp->hactive;
+
+ temp = temp & 0x3fe;
+
+ /* printf("%s: HDELAY value is %d\n", bktr_name(bktr), temp); */
+ OUTB(bktr, BKTR_E_DELAY_LO, temp & 0xff);
+ OUTB(bktr, BKTR_O_DELAY_LO, temp & 0xff);
+ OUTB(bktr, BKTR_E_CROP, INB(bktr, BKTR_E_CROP) & ~0xc);
+ OUTB(bktr, BKTR_O_CROP, INB(bktr, BKTR_O_CROP) & ~0xc);
+ OUTB(bktr, BKTR_E_CROP, INB(bktr, BKTR_E_CROP) | ((temp >> 6) & 0xc));
+ OUTB(bktr, BKTR_O_CROP, INB(bktr, BKTR_O_CROP) | ((temp >> 6) & 0xc));
+
+ /* vertical scale */
+
+ if (bktr->capture_area_enabled) {
+ if (bktr->flags & METEOR_ONLY_ODD_FIELDS ||
+ bktr->flags & METEOR_ONLY_EVEN_FIELDS)
+ tmp_int = 65536 -
+ (((bktr->capture_area_y_size * 256 + (bktr->rows/2)) / bktr->rows) - 512);
+ else {
+ tmp_int = 65536 -
+ (((bktr->capture_area_y_size * 512 + (bktr->rows / 2)) / bktr->rows) - 512);
+ }
+ } else {
+ if (bktr->flags & METEOR_ONLY_ODD_FIELDS ||
+ bktr->flags & METEOR_ONLY_EVEN_FIELDS)
+ tmp_int = 65536 -
+ (((fp->vactive * 256 + (bktr->rows/2)) / bktr->rows) - 512);
+ else {
+ tmp_int = 65536 -
+ (((fp->vactive * 512 + (bktr->rows / 2)) / bktr->rows) - 512);
+ }
+ }
+
+ tmp_int &= 0x1fff;
+ /* printf("%s: VSCALE value is %d\n", bktr_name(bktr), tmp_int); */
+ OUTB(bktr, BKTR_E_VSCALE_LO, tmp_int & 0xff);
+ OUTB(bktr, BKTR_O_VSCALE_LO, tmp_int & 0xff);
+ OUTB(bktr, BKTR_E_VSCALE_HI, INB(bktr, BKTR_E_VSCALE_HI) & ~0x1f);
+ OUTB(bktr, BKTR_O_VSCALE_HI, INB(bktr, BKTR_O_VSCALE_HI) & ~0x1f);
+ OUTB(bktr, BKTR_E_VSCALE_HI, INB(bktr, BKTR_E_VSCALE_HI) | ((tmp_int >> 8) & 0x1f));
+ OUTB(bktr, BKTR_O_VSCALE_HI, INB(bktr, BKTR_O_VSCALE_HI) | ((tmp_int >> 8) & 0x1f));
+
+
+ /* vertical active */
+ if (bktr->capture_area_enabled)
+ temp = bktr->capture_area_y_size;
+ else
+ temp = fp->vactive;
+ /* printf("%s: VACTIVE is %d\n", bktr_name(bktr), temp); */
+ OUTB(bktr, BKTR_E_CROP, INB(bktr, BKTR_E_CROP) & ~0x30);
+ OUTB(bktr, BKTR_E_CROP, INB(bktr, BKTR_E_CROP) | ((temp >> 4) & 0x30));
+ OUTB(bktr, BKTR_E_VACTIVE_LO, temp & 0xff);
+ OUTB(bktr, BKTR_O_CROP, INB(bktr, BKTR_O_CROP) & ~0x30);
+ OUTB(bktr, BKTR_O_CROP, INB(bktr, BKTR_O_CROP) | ((temp >> 4) & 0x30));
+ OUTB(bktr, BKTR_O_VACTIVE_LO, temp & 0xff);
+
+ /* vertical delay */
+ if (bktr->capture_area_enabled)
+ temp = fp->vdelay + (bktr->capture_area_y_offset);
+ else
+ temp = fp->vdelay;
+ /* printf("%s: VDELAY is %d\n", bktr_name(bktr), temp); */
+ OUTB(bktr, BKTR_E_CROP, INB(bktr, BKTR_E_CROP) & ~0xC0);
+ OUTB(bktr, BKTR_E_CROP, INB(bktr, BKTR_E_CROP) | ((temp >> 2) & 0xC0));
+ OUTB(bktr, BKTR_E_VDELAY_LO, temp & 0xff);
+ OUTB(bktr, BKTR_O_CROP, INB(bktr, BKTR_O_CROP) & ~0xC0);
+ OUTB(bktr, BKTR_O_CROP, INB(bktr, BKTR_O_CROP) | ((temp >> 2) & 0xC0));
+ OUTB(bktr, BKTR_O_VDELAY_LO, temp & 0xff);
+
+ /* end of video params */
+
+ if ((bktr->xtal_pll_mode == BT848_USE_PLL)
+ && (fp->iform_xtsel==BT848_IFORM_X_XT1)) {
+ OUTB(bktr, BKTR_TGCTRL, BT848_TGCTRL_TGCKI_PLL); /* Select PLL mode */
+ } else {
+ OUTB(bktr, BKTR_TGCTRL, BT848_TGCTRL_TGCKI_XTAL); /* Select Normal xtal 0/xtal 1 mode */
+ }
+
+ /* capture control */
+ switch (i_flag) {
+ case 1:
+ bktr->bktr_cap_ctl =
+ (BT848_CAP_CTL_DITH_FRAME | BT848_CAP_CTL_EVEN);
+ OUTB(bktr, BKTR_E_VSCALE_HI, INB(bktr, BKTR_E_VSCALE_HI) & ~0x20);
+ OUTB(bktr, BKTR_O_VSCALE_HI, INB(bktr, BKTR_O_VSCALE_HI) & ~0x20);
+ interlace = 1;
+ break;
+ case 2:
+ bktr->bktr_cap_ctl =
+ (BT848_CAP_CTL_DITH_FRAME | BT848_CAP_CTL_ODD);
+ OUTB(bktr, BKTR_E_VSCALE_HI, INB(bktr, BKTR_E_VSCALE_HI) & ~0x20);
+ OUTB(bktr, BKTR_O_VSCALE_HI, INB(bktr, BKTR_O_VSCALE_HI) & ~0x20);
+ interlace = 1;
+ break;
+ default:
+ bktr->bktr_cap_ctl =
+ (BT848_CAP_CTL_DITH_FRAME |
+ BT848_CAP_CTL_EVEN | BT848_CAP_CTL_ODD);
+ OUTB(bktr, BKTR_E_VSCALE_HI, INB(bktr, BKTR_E_VSCALE_HI) | 0x20);
+ OUTB(bktr, BKTR_O_VSCALE_HI, INB(bktr, BKTR_O_VSCALE_HI) | 0x20);
+ interlace = 2;
+ break;
+ }
+
+ OUTL(bktr, BKTR_RISC_STRT_ADD, vtophys(bktr->dma_prog));
+
+ rows = bktr->rows;
+ cols = bktr->cols;
+
+ bktr->vbiflags &= ~VBI_CAPTURE; /* default - no vbi capture */
+
+ /* RGB Grabs. If /dev/vbi is already open, or we are a PAL/SECAM */
+ /* user, then use the rgb_vbi RISC program. */
+ /* Otherwise, use the normal rgb RISC program */
+ if (pf_int->public.type == METEOR_PIXTYPE_RGB) {
+ if ( (bktr->vbiflags & VBI_OPEN)
+ ||(bktr->format_params == BT848_IFORM_F_PALBDGHI)
+ ||(bktr->format_params == BT848_IFORM_F_SECAM)
+ ){
+ bktr->bktr_cap_ctl |=
+ BT848_CAP_CTL_VBI_EVEN | BT848_CAP_CTL_VBI_ODD;
+ bktr->vbiflags |= VBI_CAPTURE;
+ rgb_vbi_prog(bktr, i_flag, cols, rows, interlace);
+ return;
+ } else {
+ rgb_prog(bktr, i_flag, cols, rows, interlace);
+ return;
+ }
+ }
+
+ if ( pf_int->public.type == METEOR_PIXTYPE_YUV ) {
+ yuv422_prog(bktr, i_flag, cols, rows, interlace);
+ OUTB(bktr, BKTR_COLOR_CTL, (INB(bktr, BKTR_COLOR_CTL) & 0xf0)
+ | pixfmt_swap_flags( bktr->pixfmt ));
+ return;
+ }
+
+ if ( pf_int->public.type == METEOR_PIXTYPE_YUV_PACKED ) {
+ yuvpack_prog(bktr, i_flag, cols, rows, interlace);
+ OUTB(bktr, BKTR_COLOR_CTL, (INB(bktr, BKTR_COLOR_CTL) & 0xf0)
+ | pixfmt_swap_flags( bktr->pixfmt ));
+ return;
+ }
+
+ if ( pf_int->public.type == METEOR_PIXTYPE_YUV_12 ) {
+ yuv12_prog(bktr, i_flag, cols, rows, interlace);
+ OUTB(bktr, BKTR_COLOR_CTL, (INB(bktr, BKTR_COLOR_CTL) & 0xf0)
+ | pixfmt_swap_flags( bktr->pixfmt ));
+ return;
+ }
+ return;
+}
+
+
+/******************************************************************************
+ * video & video capture specific routines:
+ */
+
+
+/*
+ *
+ */
+static void
+start_capture( bktr_ptr_t bktr, unsigned type )
+{
+ u_char i_flag;
+ struct format_params *fp;
+
+ fp = &format_params[bktr->format_params];
+
+ /* If requested, clear out capture buf first */
+ if (bktr->clr_on_start && (bktr->video.addr == 0)) {
+ bzero((caddr_t)bktr->bigbuf,
+ (size_t)bktr->rows * bktr->cols * bktr->frames *
+ pixfmt_table[ bktr->pixfmt ].public.Bpp);
+ }
+
+ OUTB(bktr, BKTR_DSTATUS, 0);
+ OUTL(bktr, BKTR_INT_STAT, INL(bktr, BKTR_INT_STAT));
+
+ bktr->flags |= type;
+ bktr->flags &= ~METEOR_WANT_MASK;
+ switch(bktr->flags & METEOR_ONLY_FIELDS_MASK) {
+ case METEOR_ONLY_EVEN_FIELDS:
+ bktr->flags |= METEOR_WANT_EVEN;
+ i_flag = 1;
+ break;
+ case METEOR_ONLY_ODD_FIELDS:
+ bktr->flags |= METEOR_WANT_ODD;
+ i_flag = 2;
+ break;
+ default:
+ bktr->flags |= METEOR_WANT_MASK;
+ i_flag = 3;
+ break;
+ }
+
+ /* TDEC is only valid for continuous captures */
+ if ( type == METEOR_SINGLE ) {
+ u_short fps_save = bktr->fps;
+
+ set_fps(bktr, fp->frame_rate);
+ bktr->fps = fps_save;
+ }
+ else
+ set_fps(bktr, bktr->fps);
+
+ if (bktr->dma_prog_loaded == FALSE) {
+ build_dma_prog(bktr, i_flag);
+ bktr->dma_prog_loaded = TRUE;
+ }
+
+
+ OUTL(bktr, BKTR_RISC_STRT_ADD, vtophys(bktr->dma_prog));
+
+}
+
+
+/*
+ *
+ */
+static void
+set_fps( bktr_ptr_t bktr, u_short fps )
+{
+ struct format_params *fp;
+ int i_flag;
+
+ fp = &format_params[bktr->format_params];
+
+ switch(bktr->flags & METEOR_ONLY_FIELDS_MASK) {
+ case METEOR_ONLY_EVEN_FIELDS:
+ bktr->flags |= METEOR_WANT_EVEN;
+ i_flag = 1;
+ break;
+ case METEOR_ONLY_ODD_FIELDS:
+ bktr->flags |= METEOR_WANT_ODD;
+ i_flag = 1;
+ break;
+ default:
+ bktr->flags |= METEOR_WANT_MASK;
+ i_flag = 2;
+ break;
+ }
+
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
+ OUTL(bktr, BKTR_INT_STAT, ALL_INTS_CLEARED);
+
+ bktr->fps = fps;
+ OUTB(bktr, BKTR_TDEC, 0);
+
+ if (fps < fp->frame_rate)
+ OUTB(bktr, BKTR_TDEC, i_flag*(fp->frame_rate - fps) & 0x3f);
+ else
+ OUTB(bktr, BKTR_TDEC, 0);
+ return;
+
+}
+
+
+
+
+
+/*
+ * Given a pixfmt index, compute the bt848 swap_flags necessary to
+ * achieve the specified swapping.
+ * Note that without bt swapping, 2Bpp and 3Bpp modes are written
+ * byte-swapped, and 4Bpp modes are byte and word swapped (see Table 6
+ * and read R->L).
+ * Note also that for 3Bpp, we may additionally need to do some creative
+ * SKIPing to align the FIFO bytelines with the target buffer (see split()).
+ * This is abstracted here: e.g. no swaps = RGBA; byte & short swap = ABGR
+ * as one would expect.
+ */
+
+static u_int pixfmt_swap_flags( int pixfmt )
+{
+ struct meteor_pixfmt *pf = &pixfmt_table[ pixfmt ].public;
+ u_int swapf = 0;
+
+ switch ( pf->Bpp ) {
+ case 2 : swapf = ( pf->swap_bytes ? 0 : BSWAP );
+ break;
+
+ case 3 : /* no swaps supported for 3bpp - makes no sense w/ bt848 */
+ break;
+
+ case 4 : if ( pf->swap_bytes )
+ swapf = pf->swap_shorts ? 0 : WSWAP;
+ else
+ swapf = pf->swap_shorts ? BSWAP : (BSWAP | WSWAP);
+ break;
+ }
+ return swapf;
+}
+
+
+
+/*
+ * Converts meteor-defined pixel formats (e.g. METEOR_GEO_RGB16) into
+ * our pixfmt_table indices.
+ */
+
+static int oformat_meteor_to_bt( u_long format )
+{
+ int i;
+ struct meteor_pixfmt *pf1, *pf2;
+
+ /* Find format in compatibility table */
+ for ( i = 0; i < METEOR_PIXFMT_TABLE_SIZE; i++ )
+ if ( meteor_pixfmt_table[i].meteor_format == format )
+ break;
+
+ if ( i >= METEOR_PIXFMT_TABLE_SIZE )
+ return -1;
+ pf1 = &meteor_pixfmt_table[i].public;
+
+ /* Match it with an entry in master pixel format table */
+ for ( i = 0; i < PIXFMT_TABLE_SIZE; i++ ) {
+ pf2 = &pixfmt_table[i].public;
+
+ if (( pf1->type == pf2->type ) &&
+ ( pf1->Bpp == pf2->Bpp ) &&
+ !bcmp( pf1->masks, pf2->masks, sizeof( pf1->masks )) &&
+ ( pf1->swap_bytes == pf2->swap_bytes ) &&
+ ( pf1->swap_shorts == pf2->swap_shorts ))
+ break;
+ }
+ if ( i >= PIXFMT_TABLE_SIZE )
+ return -1;
+
+ return i;
+}
+
+/******************************************************************************
+ * i2c primitives:
+ */
+
+/* */
+#define I2CBITTIME (0x5<<4) /* 5 * 0.48uS */
+#define I2CBITTIME_878 (1 << 7)
+#define I2C_READ 0x01
+#define I2C_COMMAND (I2CBITTIME | \
+ BT848_DATA_CTL_I2CSCL | \
+ BT848_DATA_CTL_I2CSDA)
+
+#define I2C_COMMAND_878 (I2CBITTIME_878 | \
+ BT848_DATA_CTL_I2CSCL | \
+ BT848_DATA_CTL_I2CSDA)
+
+/* Select between old i2c code and new iicbus / smbus code */
+#if defined(BKTR_USE_FREEBSD_SMBUS)
+
+/*
+ * The hardware interface is actually SMB commands
+ */
+int
+i2cWrite( bktr_ptr_t bktr, int addr, int byte1, int byte2 )
+{
+ char cmd;
+
+ if (bktr->id == BROOKTREE_848 ||
+ bktr->id == BROOKTREE_848A ||
+ bktr->id == BROOKTREE_849A)
+ cmd = I2C_COMMAND;
+ else
+ cmd = I2C_COMMAND_878;
+
+ if (byte2 != -1) {
+ if (smbus_writew(bktr->i2c_sc.smbus, addr, cmd,
+ (short)(((byte2 & 0xff) << 8) | (byte1 & 0xff))))
+ return (-1);
+ } else {
+ if (smbus_writeb(bktr->i2c_sc.smbus, addr, cmd,
+ (char)(byte1 & 0xff)))
+ return (-1);
+ }
+
+ /* return OK */
+ return( 0 );
+}
+
+int
+i2cRead( bktr_ptr_t bktr, int addr )
+{
+ char result;
+ char cmd;
+
+ if (bktr->id == BROOKTREE_848 ||
+ bktr->id == BROOKTREE_848A ||
+ bktr->id == BROOKTREE_849A)
+ cmd = I2C_COMMAND;
+ else
+ cmd = I2C_COMMAND_878;
+
+ if (smbus_readb(bktr->i2c_sc.smbus, addr, cmd, &result))
+ return (-1);
+
+ return ((int)((unsigned char)result));
+}
+
+#define IICBUS(bktr) ((bktr)->i2c_sc.iicbus)
+
+/* The MSP34xx and DPL35xx Audio chip require i2c bus writes of up */
+/* to 5 bytes which the bt848 automated i2c bus controller cannot handle */
+/* Therefore we need low level control of the i2c bus hardware */
+
+/* Write to the MSP or DPL registers */
+void
+msp_dpl_write(bktr_ptr_t bktr, int i2c_addr, unsigned char dev, unsigned int addr, unsigned int data)
+{
+ unsigned char addr_l, addr_h, data_h, data_l ;
+
+ addr_h = (addr >>8) & 0xff;
+ addr_l = addr & 0xff;
+ data_h = (data >>8) & 0xff;
+ data_l = data & 0xff;
+
+ iicbus_start(IICBUS(bktr), i2c_addr, 0 /* no timeout? */);
+
+ iicbus_write_byte(IICBUS(bktr), dev, 0);
+ iicbus_write_byte(IICBUS(bktr), addr_h, 0);
+ iicbus_write_byte(IICBUS(bktr), addr_l, 0);
+ iicbus_write_byte(IICBUS(bktr), data_h, 0);
+ iicbus_write_byte(IICBUS(bktr), data_l, 0);
+
+ iicbus_stop(IICBUS(bktr));
+
+ return;
+}
+
+/* Read from the MSP or DPL registers */
+unsigned int
+msp_dpl_read(bktr_ptr_t bktr, int i2c_addr, unsigned char dev, unsigned int addr)
+{
+ unsigned int data;
+ unsigned char addr_l, addr_h, dev_r;
+ int read;
+ u_char data_read[2];
+
+ addr_h = (addr >>8) & 0xff;
+ addr_l = addr & 0xff;
+ dev_r = dev+1;
+
+ /* XXX errors ignored */
+ iicbus_start(IICBUS(bktr), i2c_addr, 0 /* no timeout? */);
+
+ iicbus_write_byte(IICBUS(bktr), dev_r, 0);
+ iicbus_write_byte(IICBUS(bktr), addr_h, 0);
+ iicbus_write_byte(IICBUS(bktr), addr_l, 0);
+
+ iicbus_repeated_start(IICBUS(bktr), i2c_addr +1, 0 /* no timeout? */);
+ iicbus_read(IICBUS(bktr), data_read, 2, &read, IIC_LAST_READ, 0);
+ iicbus_stop(IICBUS(bktr));
+
+ data = (data_read[0]<<8) | data_read[1];
+
+ return (data);
+}
+
+/* Reset the MSP or DPL chip */
+/* The user can block the reset (which is handy if you initialise the
+ * MSP and/or DPL audio in another operating system first (eg in Windows)
+ */
+void
+msp_dpl_reset( bktr_ptr_t bktr, int i2c_addr )
+{
+
+#ifndef BKTR_NO_MSP_RESET
+ /* put into reset mode */
+ iicbus_start(IICBUS(bktr), i2c_addr, 0 /* no timeout? */);
+ iicbus_write_byte(IICBUS(bktr), 0x00, 0);
+ iicbus_write_byte(IICBUS(bktr), 0x80, 0);
+ iicbus_write_byte(IICBUS(bktr), 0x00, 0);
+ iicbus_stop(IICBUS(bktr));
+
+ /* put back to operational mode */
+ iicbus_start(IICBUS(bktr), i2c_addr, 0 /* no timeout? */);
+ iicbus_write_byte(IICBUS(bktr), 0x00, 0);
+ iicbus_write_byte(IICBUS(bktr), 0x00, 0);
+ iicbus_write_byte(IICBUS(bktr), 0x00, 0);
+ iicbus_stop(IICBUS(bktr));
+#endif
+ return;
+}
+
+static void remote_read(bktr_ptr_t bktr, struct bktr_remote *remote) {
+ int read;
+
+ /* XXX errors ignored */
+ iicbus_start(IICBUS(bktr), bktr->remote_control_addr, 0 /* no timeout? */);
+ iicbus_read(IICBUS(bktr), remote->data, 3, &read, IIC_LAST_READ, 0);
+ iicbus_stop(IICBUS(bktr));
+
+ return;
+}
+
+#else /* defined(BKTR_USE_FREEBSD_SMBUS) */
+
+/*
+ * Program the i2c bus directly
+ */
+int
+i2cWrite( bktr_ptr_t bktr, int addr, int byte1, int byte2 )
+{
+ u_long x;
+ u_long data;
+
+ /* clear status bits */
+ OUTL(bktr, BKTR_INT_STAT, BT848_INT_RACK | BT848_INT_I2CDONE);
+
+ /* build the command datum */
+ if (bktr->id == BROOKTREE_848 ||
+ bktr->id == BROOKTREE_848A ||
+ bktr->id == BROOKTREE_849A) {
+ data = ((addr & 0xff) << 24) | ((byte1 & 0xff) << 16) | I2C_COMMAND;
+ } else {
+ data = ((addr & 0xff) << 24) | ((byte1 & 0xff) << 16) | I2C_COMMAND_878;
+ }
+ if ( byte2 != -1 ) {
+ data |= ((byte2 & 0xff) << 8);
+ data |= BT848_DATA_CTL_I2CW3B;
+ }
+
+ /* write the address and data */
+ OUTL(bktr, BKTR_I2C_DATA_CTL, data);
+
+ /* wait for completion */
+ for ( x = 0x7fffffff; x; --x ) { /* safety valve */
+ if ( INL(bktr, BKTR_INT_STAT) & BT848_INT_I2CDONE )
+ break;
+ }
+
+ /* check for ACK */
+ if ( !x || !(INL(bktr, BKTR_INT_STAT) & BT848_INT_RACK) )
+ return( -1 );
+
+ /* return OK */
+ return( 0 );
+}
+
+
+/*
+ *
+ */
+int
+i2cRead( bktr_ptr_t bktr, int addr )
+{
+ u_long x;
+
+ /* clear status bits */
+ OUTL(bktr, BKTR_INT_STAT, BT848_INT_RACK | BT848_INT_I2CDONE);
+
+ /* write the READ address */
+ /* The Bt878 and Bt879 differed on the treatment of i2c commands */
+
+ if (bktr->id == BROOKTREE_848 ||
+ bktr->id == BROOKTREE_848A ||
+ bktr->id == BROOKTREE_849A) {
+ OUTL(bktr, BKTR_I2C_DATA_CTL, ((addr & 0xff) << 24) | I2C_COMMAND);
+ } else {
+ OUTL(bktr, BKTR_I2C_DATA_CTL, ((addr & 0xff) << 24) | I2C_COMMAND_878);
+ }
+
+ /* wait for completion */
+ for ( x = 0x7fffffff; x; --x ) { /* safety valve */
+ if ( INL(bktr, BKTR_INT_STAT) & BT848_INT_I2CDONE )
+ break;
+ }
+
+ /* check for ACK */
+ if ( !x || !(INL(bktr, BKTR_INT_STAT) & BT848_INT_RACK) )
+ return( -1 );
+
+ /* it was a read */
+ return( (INL(bktr, BKTR_I2C_DATA_CTL) >> 8) & 0xff );
+}
+
+/* The MSP34xx Audio chip require i2c bus writes of up to 5 bytes which the */
+/* bt848 automated i2c bus controller cannot handle */
+/* Therefore we need low level control of the i2c bus hardware */
+/* Idea for the following functions are from elsewhere in this driver and */
+/* from the Linux BTTV i2c driver by Gerd Knorr <kraxel@cs.tu-berlin.de> */
+
+#define BITD 40
+static void i2c_start( bktr_ptr_t bktr) {
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 1); DELAY( BITD ); /* release data */
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 3); DELAY( BITD ); /* release clock */
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 2); DELAY( BITD ); /* lower data */
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 0); DELAY( BITD ); /* lower clock */
+}
+
+static void i2c_stop( bktr_ptr_t bktr) {
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 0); DELAY( BITD ); /* lower clock & data */
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 2); DELAY( BITD ); /* release clock */
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 3); DELAY( BITD ); /* release data */
+}
+
+static int i2c_write_byte( bktr_ptr_t bktr, unsigned char data) {
+ int x;
+ int status;
+
+ /* write out the byte */
+ for ( x = 7; x >= 0; --x ) {
+ if ( data & (1<<x) ) {
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 1);
+ DELAY( BITD ); /* assert HI data */
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 3);
+ DELAY( BITD ); /* strobe clock */
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 1);
+ DELAY( BITD ); /* release clock */
+ }
+ else {
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 0);
+ DELAY( BITD ); /* assert LO data */
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 2);
+ DELAY( BITD ); /* strobe clock */
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 0);
+ DELAY( BITD ); /* release clock */
+ }
+ }
+
+ /* look for an ACK */
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 1); DELAY( BITD ); /* float data */
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 3); DELAY( BITD ); /* strobe clock */
+ status = INL(bktr, BKTR_I2C_DATA_CTL) & 1; /* read the ACK bit */
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 1); DELAY( BITD ); /* release clock */
+
+ return( status );
+}
+
+static int i2c_read_byte( bktr_ptr_t bktr, unsigned char *data, int last ) {
+ int x;
+ int bit;
+ int byte = 0;
+
+ /* read in the byte */
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 1);
+ DELAY( BITD ); /* float data */
+ for ( x = 7; x >= 0; --x ) {
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 3);
+ DELAY( BITD ); /* strobe clock */
+ bit = INL(bktr, BKTR_I2C_DATA_CTL) & 1; /* read the data bit */
+ if ( bit ) byte |= (1<<x);
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 1);
+ DELAY( BITD ); /* release clock */
+ }
+ /* After reading the byte, send an ACK */
+ /* (unless that was the last byte, for which we send a NAK */
+ if (last) { /* send NAK - same a writing a 1 */
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 1);
+ DELAY( BITD ); /* set data bit */
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 3);
+ DELAY( BITD ); /* strobe clock */
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 1);
+ DELAY( BITD ); /* release clock */
+ } else { /* send ACK - same as writing a 0 */
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 0);
+ DELAY( BITD ); /* set data bit */
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 2);
+ DELAY( BITD ); /* strobe clock */
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 0);
+ DELAY( BITD ); /* release clock */
+ }
+
+ *data=byte;
+ return 0;
+}
+#undef BITD
+
+/* Write to the MSP or DPL registers */
+void msp_dpl_write( bktr_ptr_t bktr, int i2c_addr, unsigned char dev, unsigned int addr,
+ unsigned int data){
+ unsigned int msp_w_addr = i2c_addr;
+ unsigned char addr_l, addr_h, data_h, data_l ;
+ addr_h = (addr >>8) & 0xff;
+ addr_l = addr & 0xff;
+ data_h = (data >>8) & 0xff;
+ data_l = data & 0xff;
+
+ i2c_start(bktr);
+ i2c_write_byte(bktr, msp_w_addr);
+ i2c_write_byte(bktr, dev);
+ i2c_write_byte(bktr, addr_h);
+ i2c_write_byte(bktr, addr_l);
+ i2c_write_byte(bktr, data_h);
+ i2c_write_byte(bktr, data_l);
+ i2c_stop(bktr);
+}
+
+/* Read from the MSP or DPL registers */
+unsigned int msp_dpl_read(bktr_ptr_t bktr, int i2c_addr, unsigned char dev, unsigned int addr){
+ unsigned int data;
+ unsigned char addr_l, addr_h, data_1, data_2, dev_r ;
+ addr_h = (addr >>8) & 0xff;
+ addr_l = addr & 0xff;
+ dev_r = dev+1;
+
+ i2c_start(bktr);
+ i2c_write_byte(bktr,i2c_addr);
+ i2c_write_byte(bktr,dev_r);
+ i2c_write_byte(bktr,addr_h);
+ i2c_write_byte(bktr,addr_l);
+
+ i2c_start(bktr);
+ i2c_write_byte(bktr,i2c_addr+1);
+ i2c_read_byte(bktr,&data_1, 0);
+ i2c_read_byte(bktr,&data_2, 1);
+ i2c_stop(bktr);
+ data = (data_1<<8) | data_2;
+ return data;
+}
+
+/* Reset the MSP or DPL chip */
+/* The user can block the reset (which is handy if you initialise the
+ * MSP audio in another operating system first (eg in Windows)
+ */
+void msp_dpl_reset( bktr_ptr_t bktr, int i2c_addr ) {
+
+#ifndef BKTR_NO_MSP_RESET
+ /* put into reset mode */
+ i2c_start(bktr);
+ i2c_write_byte(bktr, i2c_addr);
+ i2c_write_byte(bktr, 0x00);
+ i2c_write_byte(bktr, 0x80);
+ i2c_write_byte(bktr, 0x00);
+ i2c_stop(bktr);
+
+ /* put back to operational mode */
+ i2c_start(bktr);
+ i2c_write_byte(bktr, i2c_addr);
+ i2c_write_byte(bktr, 0x00);
+ i2c_write_byte(bktr, 0x00);
+ i2c_write_byte(bktr, 0x00);
+ i2c_stop(bktr);
+#endif
+ return;
+
+}
+
+static void remote_read(bktr_ptr_t bktr, struct bktr_remote *remote) {
+
+ /* XXX errors ignored */
+ i2c_start(bktr);
+ i2c_write_byte(bktr,bktr->remote_control_addr);
+ i2c_read_byte(bktr,&(remote->data[0]), 0);
+ i2c_read_byte(bktr,&(remote->data[1]), 0);
+ i2c_read_byte(bktr,&(remote->data[2]), 0);
+ i2c_stop(bktr);
+
+ return;
+}
+
+#endif /* defined(BKTR_USE_FREEBSD_SMBUS) */
+
+
+#if defined( I2C_SOFTWARE_PROBE )
+
+/*
+ * we are keeping this around for any parts that we need to probe
+ * but that CANNOT be probed via an i2c read.
+ * this is necessary because the hardware i2c mechanism
+ * cannot be programmed for 1 byte writes.
+ * currently there are no known i2c parts that we need to probe
+ * and that cannot be safely read.
+ */
+static int i2cProbe( bktr_ptr_t bktr, int addr );
+#define BITD 40
+#define EXTRA_START
+
+/*
+ * probe for an I2C device at addr.
+ */
+static int
+i2cProbe( bktr_ptr_t bktr, int addr )
+{
+ int x, status;
+
+ /* the START */
+#if defined( EXTRA_START )
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 1); DELAY( BITD ); /* release data */
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 3); DELAY( BITD ); /* release clock */
+#endif /* EXTRA_START */
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 2); DELAY( BITD ); /* lower data */
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 0); DELAY( BITD ); /* lower clock */
+
+ /* write addr */
+ for ( x = 7; x >= 0; --x ) {
+ if ( addr & (1<<x) ) {
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 1);
+ DELAY( BITD ); /* assert HI data */
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 3);
+ DELAY( BITD ); /* strobe clock */
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 1);
+ DELAY( BITD ); /* release clock */
+ }
+ else {
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 0);
+ DELAY( BITD ); /* assert LO data */
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 2);
+ DELAY( BITD ); /* strobe clock */
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 0);
+ DELAY( BITD ); /* release clock */
+ }
+ }
+
+ /* look for an ACK */
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 1); DELAY( BITD ); /* float data */
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 3); DELAY( BITD ); /* strobe clock */
+ status = INL(bktr, BKTR_I2C_DATA_CTL) & 1; /* read the ACK bit */
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 1); DELAY( BITD ); /* release clock */
+
+ /* the STOP */
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 0); DELAY( BITD ); /* lower clock & data */
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 2); DELAY( BITD ); /* release clock */
+ OUTL(bktr, BKTR_I2C_DATA_CTL, 3); DELAY( BITD ); /* release data */
+
+ return( status );
+}
+#undef EXTRA_START
+#undef BITD
+
+#endif /* I2C_SOFTWARE_PROBE */
+
+
+#define ABSENT (-1)
+
+#endif /* FreeBSD, BSDI, NetBSD, OpenBSD */
diff --git a/sys/dev/pci/bktr/bktr_core.h b/sys/dev/pci/bktr/bktr_core.h
new file mode 100644
index 00000000000..2fd3c5bf42c
--- /dev/null
+++ b/sys/dev/pci/bktr/bktr_core.h
@@ -0,0 +1,97 @@
+/* $OpenBSD: bktr_core.h,v 1.1 2001/03/28 03:27:09 fgsch Exp $ */
+/* $FreeBSD: src/sys/dev/bktr/bktr_core.h,v 1.4 2000/06/26 09:41:32 roger Exp $ */
+
+/*
+ * This is part of the Driver for Video Capture Cards (Frame grabbers)
+ * and TV Tuner cards using the Brooktree Bt848, Bt848A, Bt849A, Bt878, Bt879
+ * chipset.
+ * Copyright Roger Hardiman and Amancio Hasty.
+ *
+ * bktr_core : This deals with the Bt848/849/878/879 PCI Frame Grabber,
+ * Handles all the open, close, ioctl and read userland calls.
+ * Sets the Bt848 registers and generates RISC pograms.
+ * Controls the i2c bus and GPIO interface.
+ * Contains the interface to the kernel.
+ * (eg probe/attach and open/close/ioctl)
+ *
+ */
+
+/*
+ * 1. Redistributions of source code must retain the
+ * Copyright (c) 1997 Amancio Hasty, 1999 Roger Hardiman
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Amancio Hasty and
+ * Roger Hardiman
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+int i2cWrite( bktr_ptr_t bktr, int addr, int byte1, int byte2 );
+int i2cRead( bktr_ptr_t bktr, int addr );
+
+void msp_dpl_reset( bktr_ptr_t bktr, int i2d_addr );
+unsigned int msp_dpl_read( bktr_ptr_t bktr, int i2c_addr, unsigned char dev, unsigned int addr );
+void msp_dpl_write( bktr_ptr_t bktr, int i2c_addr, unsigned char dev,
+ unsigned int addr, unsigned int data );
+
+
+/*
+ * Defines for userland processes blocked in this driver
+ * For /dev/bktr[n] use memory address of bktr structure
+ * For /dev/vbi[n] use memory address of bktr structure + 1
+ * this is ok as the bktr structure is > 1 byte
+ */
+#define BKTR_SLEEP ((caddr_t)bktr )
+#define VBI_SLEEP ((caddr_t)bktr + 1)
+
+
+/* device name for printf */
+const char *bktr_name(bktr_ptr_t bktr);
+
+/* Prototypes for attatch and interrupt functions */
+void common_bktr_attach( bktr_ptr_t bktr, int unit,
+ u_long pci_id, u_int rev );
+int common_bktr_intr( void *arg );
+
+
+/* Prototypes for open, close, read, mmap and ioctl calls */
+int video_open( bktr_ptr_t bktr );
+int video_close( bktr_ptr_t bktr );
+int video_read( bktr_ptr_t bktr, int unit, dev_t dev, struct uio *uio );
+int video_ioctl( bktr_ptr_t bktr, int unit,
+ ioctl_cmd_t cmd, caddr_t arg, struct proc* pr );
+
+
+int tuner_open( bktr_ptr_t bktr );
+int tuner_close( bktr_ptr_t bktr );
+int tuner_ioctl( bktr_ptr_t bktr, int unit,
+ ioctl_cmd_t cmd, caddr_t arg, struct proc* pr );
+
+int vbi_open( bktr_ptr_t bktr );
+int vbi_close( bktr_ptr_t bktr );
+int vbi_read( bktr_ptr_t bktr, struct uio *uio, int ioflag );
+
diff --git a/sys/dev/pci/bktr/bktr_os.c b/sys/dev/pci/bktr/bktr_os.c
new file mode 100644
index 00000000000..0a758773159
--- /dev/null
+++ b/sys/dev/pci/bktr/bktr_os.c
@@ -0,0 +1,1703 @@
+/* $OpenBSD: bktr_os.c,v 1.1 2001/03/28 03:27:09 fgsch Exp $ */
+/* $FreeBSD: src/sys/dev/bktr/bktr_os.c,v 1.20 2000/10/20 08:16:53 roger Exp $ */
+
+/*
+ * This is part of the Driver for Video Capture Cards (Frame grabbers)
+ * and TV Tuner cards using the Brooktree Bt848, Bt848A, Bt849A, Bt878, Bt879
+ * chipset.
+ * Copyright Roger Hardiman and Amancio Hasty.
+ *
+ * bktr_os : This has all the Operating System dependant code,
+ * probe/attach and open/close/ioctl/read/mmap
+ * memory allocation
+ * PCI bus interfacing
+ *
+ *
+ */
+
+/*
+ * 1. Redistributions of source code must retain the
+ * Copyright (c) 1997 Amancio Hasty, 1999 Roger Hardiman
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Amancio Hasty and
+ * Roger Hardiman
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifdef __FreeBSD__
+#include "bktr.h"
+#endif /* __FreeBSD__ */
+
+#ifndef __OpenBSD__
+#include "opt_bktr.h" /* include any kernel config options */
+#endif
+
+#define FIFO_RISC_DISABLED 0
+#define ALL_INTS_DISABLED 0
+
+
+/*******************/
+/* *** FreeBSD *** */
+/*******************/
+#ifdef __FreeBSD__
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/uio.h>
+#include <sys/kernel.h>
+#include <sys/signalvar.h>
+#include <sys/mman.h>
+#include <sys/poll.h>
+#include <sys/select.h>
+#include <sys/vnode.h>
+
+#include <vm/vm.h>
+#include <vm/vm_kern.h>
+#include <vm/pmap.h>
+#include <vm/vm_extern.h>
+
+#if (__FreeBSD_version >=400000) || (NSMBUS > 0)
+#include <sys/bus.h> /* used by smbus and newbus */
+#endif
+
+#if (__FreeBSD_version >=300000)
+#include <machine/bus_memio.h> /* used by bus space */
+#include <machine/bus.h> /* used by bus space and newbus */
+#include <sys/bus.h>
+#endif
+
+#if (__FreeBSD_version >=400000)
+#include <sys/rman.h> /* used by newbus */
+#include <machine/resource.h> /* used by newbus */
+#endif
+
+#if (__FreeBSD_version < 500000)
+#include <machine/clock.h> /* for DELAY */
+#endif
+
+#include <pci/pcivar.h>
+#include <pci/pcireg.h>
+
+#include <sys/sysctl.h>
+int bt848_card = -1;
+int bt848_tuner = -1;
+int bt848_reverse_mute = -1;
+int bt848_format = -1;
+int bt848_slow_msp_audio = -1;
+
+SYSCTL_NODE(_hw, OID_AUTO, bt848, CTLFLAG_RW, 0, "Bt848 Driver mgmt");
+SYSCTL_INT(_hw_bt848, OID_AUTO, card, CTLFLAG_RW, &bt848_card, -1, "");
+SYSCTL_INT(_hw_bt848, OID_AUTO, tuner, CTLFLAG_RW, &bt848_tuner, -1, "");
+SYSCTL_INT(_hw_bt848, OID_AUTO, reverse_mute, CTLFLAG_RW, &bt848_reverse_mute, -1, "");
+SYSCTL_INT(_hw_bt848, OID_AUTO, format, CTLFLAG_RW, &bt848_format, -1, "");
+SYSCTL_INT(_hw_bt848, OID_AUTO, slow_msp_audio, CTLFLAG_RW, &bt848_slow_msp_audio, -1, "");
+
+#if (__FreeBSD__ == 2)
+#define PCIR_REVID PCI_CLASS_REG
+#endif
+
+#endif /* end freebsd section */
+
+
+
+/****************/
+/* *** BSDI *** */
+/****************/
+#ifdef __bsdi__
+#endif /* __bsdi__ */
+
+
+/**************************/
+/* *** OpenBSD/NetBSD *** */
+/**************************/
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/uio.h>
+#include <sys/kernel.h>
+#include <sys/signalvar.h>
+#include <sys/mman.h>
+#include <sys/poll.h>
+#include <sys/select.h>
+#include <sys/vnode.h>
+
+#include <vm/vm.h>
+
+#include <sys/device.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcidevs.h>
+
+#define BKTR_DEBUG
+#ifdef BKTR_DEBUG
+int bktr_debug = 0;
+#define DPR(x) (bktr_debug ? printf x : 0)
+#else
+#define DPR(x)
+#endif
+#endif /* __NetBSD__ || __OpenBSD__ */
+
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+#include <dev/ic/bt8xx.h> /* NetBSD location for .h files */
+#include <dev/pci/bktr/bktr_reg.h>
+#include <dev/pci/bktr/bktr_tuner.h>
+#include <dev/pci/bktr/bktr_card.h>
+#include <dev/pci/bktr/bktr_audio.h>
+#include <dev/pci/bktr/bktr_core.h>
+#include <dev/pci/bktr/bktr_os.h>
+#else /* Traditional location for .h files */
+#include <machine/ioctl_meteor.h>
+#include <machine/ioctl_bt848.h> /* extensions to ioctl_meteor.h */
+#include <dev/bktr/bktr_reg.h>
+#include <dev/bktr/bktr_tuner.h>
+#include <dev/bktr/bktr_card.h>
+#include <dev/bktr/bktr_audio.h>
+#include <dev/bktr/bktr_core.h>
+#include <dev/bktr/bktr_os.h>
+#if defined(BKTR_USE_FREEBSD_SMBUS)
+#include <dev/bktr/bktr_i2c.h>
+#endif
+#endif
+
+
+
+/****************************/
+/* *** FreeBSD 4.x code *** */
+/****************************/
+#if (__FreeBSD_version >= 400000)
+
+static int bktr_probe( device_t dev );
+static int bktr_attach( device_t dev );
+static int bktr_detach( device_t dev );
+static int bktr_shutdown( device_t dev );
+static void bktr_intr(void *arg) { common_bktr_intr(arg); }
+
+static device_method_t bktr_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, bktr_probe),
+ DEVMETHOD(device_attach, bktr_attach),
+ DEVMETHOD(device_detach, bktr_detach),
+ DEVMETHOD(device_shutdown, bktr_shutdown),
+
+ { 0, 0 }
+};
+
+static driver_t bktr_driver = {
+ "bktr",
+ bktr_methods,
+ sizeof(struct bktr_softc),
+};
+
+static devclass_t bktr_devclass;
+
+static d_open_t bktr_open;
+static d_close_t bktr_close;
+static d_read_t bktr_read;
+static d_write_t bktr_write;
+static d_ioctl_t bktr_ioctl;
+static d_mmap_t bktr_mmap;
+static d_poll_t bktr_poll;
+
+#define CDEV_MAJOR 92
+static struct cdevsw bktr_cdevsw = {
+ /* open */ bktr_open,
+ /* close */ bktr_close,
+ /* read */ bktr_read,
+ /* write */ bktr_write,
+ /* ioctl */ bktr_ioctl,
+ /* poll */ bktr_poll,
+ /* mmap */ bktr_mmap,
+ /* strategy */ nostrategy,
+ /* name */ "bktr",
+ /* maj */ CDEV_MAJOR,
+ /* dump */ nodump,
+ /* psize */ nopsize,
+ /* flags */ 0,
+ /* bmaj */ -1
+};
+
+DRIVER_MODULE(bktr, pci, bktr_driver, bktr_devclass, 0, 0);
+#if (__FreeBSD_version > 410000)
+MODULE_DEPEND(bktr, bktr_mem, 1,1,1);
+MODULE_VERSION(bktr, 1);
+#endif
+
+
+/*
+ * the boot time probe routine.
+ */
+static int
+bktr_probe( device_t dev )
+{
+ unsigned int type = pci_get_devid(dev);
+ unsigned int rev = pci_get_revid(dev);
+
+ if (PCI_VENDOR(type) == PCI_VENDOR_BROOKTREE)
+ {
+ switch (PCI_PRODUCT(type)) {
+ case PCI_PRODUCT_BROOKTREE_BT848:
+ if (rev == 0x12)
+ device_set_desc(dev, "BrookTree 848A");
+ else
+ device_set_desc(dev, "BrookTree 848");
+ return 0;
+ case PCI_PRODUCT_BROOKTREE_BT849:
+ device_set_desc(dev, "BrookTree 849A");
+ return 0;
+ case PCI_PRODUCT_BROOKTREE_BT878:
+ device_set_desc(dev, "BrookTree 878");
+ return 0;
+ case PCI_PRODUCT_BROOKTREE_BT879:
+ device_set_desc(dev, "BrookTree 879");
+ return 0;
+ }
+ };
+
+ return ENXIO;
+}
+
+
+/*
+ * the attach routine.
+ */
+static int
+bktr_attach( device_t dev )
+{
+ u_long latency;
+ u_long fun;
+ u_long val;
+ unsigned int rev;
+ unsigned int unit;
+ int error = 0;
+#ifdef BROOKTREE_IRQ
+ u_long old_irq, new_irq;
+#endif
+
+ struct bktr_softc *bktr = device_get_softc(dev);
+
+ unit = device_get_unit(dev);
+
+ /* build the device name for bktr_name() */
+ snprintf(bktr->bktr_xname, sizeof(bktr->bktr_xname), "bktr%d",unit);
+
+ /*
+ * Enable bus mastering and Memory Mapped device
+ */
+ val = pci_read_config(dev, PCIR_COMMAND, 4);
+ val |= (PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
+ pci_write_config(dev, PCIR_COMMAND, val, 4);
+
+ /*
+ * Map control/status registers.
+ */
+ bktr->mem_rid = PCIR_MAPS;
+ bktr->res_mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &bktr->mem_rid,
+ 0, ~0, 1, RF_ACTIVE);
+
+
+ if (!bktr->res_mem) {
+ device_printf(dev, "could not map memory\n");
+ error = ENXIO;
+ goto fail;
+ }
+ bktr->memt = rman_get_bustag(bktr->res_mem);
+ bktr->memh = rman_get_bushandle(bktr->res_mem);
+
+
+ /*
+ * Disable the brooktree device
+ */
+ OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
+
+
+#ifdef BROOKTREE_IRQ /* from the configuration file */
+ old_irq = pci_conf_read(tag, PCI_INTERRUPT_REG);
+ pci_conf_write(tag, PCI_INTERRUPT_REG, BROOKTREE_IRQ);
+ new_irq = pci_conf_read(tag, PCI_INTERRUPT_REG);
+ printf("bktr%d: attach: irq changed from %d to %d\n",
+ unit, (old_irq & 0xff), (new_irq & 0xff));
+#endif
+
+ /*
+ * Allocate our interrupt.
+ */
+ bktr->irq_rid = 0;
+ bktr->res_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &bktr->irq_rid,
+ 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE);
+ if (bktr->res_irq == NULL) {
+ device_printf(dev, "could not map interrupt\n");
+ error = ENXIO;
+ goto fail;
+ }
+
+ error = bus_setup_intr(dev, bktr->res_irq, INTR_TYPE_TTY,
+ bktr_intr, bktr, &bktr->res_ih);
+ if (error) {
+ device_printf(dev, "could not setup irq\n");
+ goto fail;
+
+ }
+
+
+ /* Update the Device Control Register */
+ /* on Bt878 and Bt879 cards */
+ fun = pci_read_config( dev, 0x40, 2);
+ fun = fun | 1; /* Enable writes to the sub-system vendor ID */
+
+#if defined( BKTR_430_FX_MODE )
+ if (bootverbose) printf("Using 430 FX chipset compatibilty mode\n");
+ fun = fun | 2; /* Enable Intel 430 FX compatibility mode */
+#endif
+
+#if defined( BKTR_SIS_VIA_MODE )
+ if (bootverbose) printf("Using SiS/VIA chipset compatibilty mode\n");
+ fun = fun | 4; /* Enable SiS/VIA compatibility mode (usefull for
+ OPTi chipset motherboards too */
+#endif
+ pci_write_config(dev, 0x40, fun, 2);
+
+
+ /* XXX call bt848_i2c dependent attach() routine */
+#if defined(BKTR_USE_FREEBSD_SMBUS)
+ if (bt848_i2c_attach(unit, bktr, &bktr->i2c_sc))
+ printf("bktr%d: i2c_attach: can't attach\n", unit);
+#endif
+
+
+/*
+ * PCI latency timer. 32 is a good value for 4 bus mastering slots, if
+ * you have more than four, then 16 would probably be a better value.
+ */
+#ifndef BROOKTREE_DEF_LATENCY_VALUE
+#define BROOKTREE_DEF_LATENCY_VALUE 10
+#endif
+ latency = pci_read_config(dev, PCI_LATENCY_TIMER, 4);
+ latency = (latency >> 8) & 0xff;
+ if ( bootverbose ) {
+ if (latency)
+ printf("brooktree%d: PCI bus latency is", unit);
+ else
+ printf("brooktree%d: PCI bus latency was 0 changing to",
+ unit);
+ }
+ if ( !latency ) {
+ latency = BROOKTREE_DEF_LATENCY_VALUE;
+ pci_write_config(dev, PCI_LATENCY_TIMER, latency<<8, 4);
+ }
+ if ( bootverbose ) {
+ printf(" %d.\n", (int) latency);
+ }
+
+ /* read the pci device id and revision id */
+ fun = pci_get_devid(dev);
+ rev = pci_get_revid(dev);
+
+ /* call the common attach code */
+ common_bktr_attach( bktr, unit, fun, rev );
+
+ /* make the device entries */
+ bktr->bktrdev = make_dev(&bktr_cdevsw, unit,
+ 0, 0, 0444, "bktr%d", unit);
+ bktr->tunerdev= make_dev(&bktr_cdevsw, unit+16,
+ 0, 0, 0444, "tuner%d", unit);
+ bktr->vbidev = make_dev(&bktr_cdevsw, unit+32,
+ 0, 0, 0444, "vbi%d" , unit);
+
+
+ /* if this is unit 0 (/dev/bktr0, /dev/tuner0, /dev/vbi0) then make */
+ /* alias entries to /dev/bktr /dev/tuner and /dev/vbi */
+#if (__FreeBSD_version >=500000)
+ if (unit == 0) {
+ bktr->bktrdev_alias = make_dev_alias(bktr->bktrdev, "bktr");
+ bktr->tunerdev_alias= make_dev_alias(bktr->tunerdev, "tuner");
+ bktr->vbidev_alias = make_dev_alias(bktr->vbidev, "vbi");
+ }
+#endif
+
+ return 0;
+
+fail:
+ if (bktr->res_irq)
+ bus_release_resource(dev, SYS_RES_IRQ, bktr->irq_rid, bktr->res_irq);
+ if (bktr->res_mem)
+ bus_release_resource(dev, SYS_RES_IRQ, bktr->mem_rid, bktr->res_mem);
+ return error;
+
+}
+
+/*
+ * the detach routine.
+ */
+static int
+bktr_detach( device_t dev )
+{
+ unsigned int unit;
+
+ struct bktr_softc *bktr = device_get_softc(dev);
+
+ unit = device_get_unit(dev);
+
+ /* Disable the brooktree device */
+ OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
+
+ /* Note: We do not free memory for RISC programs, grab buffer, vbi buffers */
+ /* The memory is retained by the bktr_mem module so we can unload and */
+ /* then reload the main bktr driver module */
+
+ /* Unregister the /dev/bktrN, tunerN and vbiN devices */
+ destroy_dev(bktr->vbidev);
+ destroy_dev(bktr->tunerdev);
+ destroy_dev(bktr->bktrdev);
+
+ /* If this is unit 0, then destroy the alias entries too */
+#if (__FreeBSD_version >=500000)
+ if (unit == 0) {
+ destroy_dev(bktr->vbidev_alias);
+ destroy_dev(bktr->tunerdev_alias);
+ destroy_dev(bktr->bktrdev_alias);
+ }
+#endif
+
+ /*
+ * Deallocate resources.
+ */
+ bus_teardown_intr(dev, bktr->res_irq, bktr->res_ih);
+ bus_release_resource(dev, SYS_RES_IRQ, bktr->irq_rid, bktr->res_irq);
+ bus_release_resource(dev, SYS_RES_MEMORY, bktr->mem_rid, bktr->res_mem);
+
+ return 0;
+}
+
+/*
+ * the shutdown routine.
+ */
+static int
+bktr_shutdown( device_t dev )
+{
+ struct bktr_softc *bktr = device_get_softc(dev);
+
+ /* Disable the brooktree device */
+ OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
+
+ return 0;
+}
+
+
+/*
+ * Special Memory Allocation
+ */
+vm_offset_t
+get_bktr_mem( int unit, unsigned size )
+{
+ vm_offset_t addr = 0;
+
+ addr = vm_page_alloc_contig(size, 0, 0xffffffff, 1<<24);
+ if (addr == 0)
+ addr = vm_page_alloc_contig(size, 0, 0xffffffff, PAGE_SIZE);
+ if (addr == 0) {
+ printf("bktr%d: Unable to allocate %d bytes of memory.\n",
+ unit, size);
+ }
+
+ return( addr );
+}
+
+
+/*---------------------------------------------------------
+**
+** BrookTree 848 character device driver routines
+**
+**---------------------------------------------------------
+*/
+
+#define VIDEO_DEV 0x00
+#define TUNER_DEV 0x01
+#define VBI_DEV 0x02
+
+#define UNIT(x) ((x) & 0x0f)
+#define FUNCTION(x) (x >> 4)
+
+/*
+ *
+ */
+int
+bktr_open( dev_t dev, int flags, int fmt, struct proc *p )
+{
+ bktr_ptr_t bktr;
+ int unit;
+ int result;
+
+ unit = UNIT( minor(dev) );
+
+ /* Get the device data */
+ bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
+ if (bktr == NULL) {
+ /* the device is no longer valid/functioning */
+ return (ENXIO);
+ }
+
+ if (!(bktr->flags & METEOR_INITALIZED)) /* device not found */
+ return( ENXIO );
+
+ /* Record that the device is now busy */
+ device_busy(devclass_get_device(bktr_devclass, unit));
+
+
+ if (bt848_card != -1) {
+ if ((bt848_card >> 8 == unit ) &&
+ ( (bt848_card & 0xff) < Bt848_MAX_CARD )) {
+ if ( bktr->bt848_card != (bt848_card & 0xff) ) {
+ bktr->bt848_card = (bt848_card & 0xff);
+ probeCard(bktr, FALSE, unit);
+ }
+ }
+ }
+
+ if (bt848_tuner != -1) {
+ if ((bt848_tuner >> 8 == unit ) &&
+ ( (bt848_tuner & 0xff) < Bt848_MAX_TUNER )) {
+ if ( bktr->bt848_tuner != (bt848_tuner & 0xff) ) {
+ bktr->bt848_tuner = (bt848_tuner & 0xff);
+ probeCard(bktr, FALSE, unit);
+ }
+ }
+ }
+
+ if (bt848_reverse_mute != -1) {
+ if ((bt848_reverse_mute >> 8) == unit ) {
+ bktr->reverse_mute = bt848_reverse_mute & 0xff;
+ }
+ }
+
+ if (bt848_slow_msp_audio != -1) {
+ if ((bt848_slow_msp_audio >> 8) == unit ) {
+ bktr->slow_msp_audio = (bt848_slow_msp_audio & 0xff);
+ }
+ }
+
+ switch ( FUNCTION( minor(dev) ) ) {
+ case VIDEO_DEV:
+ result = video_open( bktr );
+ break;
+ case TUNER_DEV:
+ result = tuner_open( bktr );
+ break;
+ case VBI_DEV:
+ result = vbi_open( bktr );
+ break;
+ default:
+ result = ENXIO;
+ break;
+ }
+
+ /* If there was an error opening the device, undo the busy status */
+ if (result != 0)
+ device_unbusy(devclass_get_device(bktr_devclass, unit));
+ return( result );
+}
+
+
+/*
+ *
+ */
+int
+bktr_close( dev_t dev, int flags, int fmt, struct proc *p )
+{
+ bktr_ptr_t bktr;
+ int unit;
+ int result;
+
+ unit = UNIT( minor(dev) );
+
+ /* Get the device data */
+ bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
+ if (bktr == NULL) {
+ /* the device is no longer valid/functioning */
+ return (ENXIO);
+ }
+
+ switch ( FUNCTION( minor(dev) ) ) {
+ case VIDEO_DEV:
+ result = video_close( bktr );
+ break;
+ case TUNER_DEV:
+ result = tuner_close( bktr );
+ break;
+ case VBI_DEV:
+ result = vbi_close( bktr );
+ break;
+ default:
+ return (ENXIO);
+ break;
+ }
+
+ device_unbusy(devclass_get_device(bktr_devclass, unit));
+ return( result );
+}
+
+
+/*
+ *
+ */
+int
+bktr_read( dev_t dev, struct uio *uio, int ioflag )
+{
+ bktr_ptr_t bktr;
+ int unit;
+
+ unit = UNIT(minor(dev));
+
+ /* Get the device data */
+ bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
+ if (bktr == NULL) {
+ /* the device is no longer valid/functioning */
+ return (ENXIO);
+ }
+
+ switch ( FUNCTION( minor(dev) ) ) {
+ case VIDEO_DEV:
+ return( video_read( bktr, unit, dev, uio ) );
+ case VBI_DEV:
+ return( vbi_read( bktr, uio, ioflag ) );
+ }
+ return( ENXIO );
+}
+
+
+/*
+ *
+ */
+int
+bktr_write( dev_t dev, struct uio *uio, int ioflag )
+{
+ return( EINVAL ); /* XXX or ENXIO ? */
+}
+
+
+/*
+ *
+ */
+int
+bktr_ioctl( dev_t dev, ioctl_cmd_t cmd, caddr_t arg, int flag, struct proc* pr )
+{
+ bktr_ptr_t bktr;
+ int unit;
+
+ unit = UNIT(minor(dev));
+
+ /* Get the device data */
+ bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
+ if (bktr == NULL) {
+ /* the device is no longer valid/functioning */
+ return (ENXIO);
+ }
+
+ if (bktr->bigbuf == 0) /* no frame buffer allocated (ioctl failed) */
+ return( ENOMEM );
+
+ switch ( FUNCTION( minor(dev) ) ) {
+ case VIDEO_DEV:
+ return( video_ioctl( bktr, unit, cmd, arg, pr ) );
+ case TUNER_DEV:
+ return( tuner_ioctl( bktr, unit, cmd, arg, pr ) );
+ }
+
+ return( ENXIO );
+}
+
+
+/*
+ *
+ */
+int
+bktr_mmap( dev_t dev, vm_offset_t offset, int nprot )
+{
+ int unit;
+ bktr_ptr_t bktr;
+
+ unit = UNIT(minor(dev));
+
+ if (FUNCTION(minor(dev)) > 0) /* only allow mmap on /dev/bktr[n] */
+ return( -1 );
+
+ /* Get the device data */
+ bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
+ if (bktr == NULL) {
+ /* the device is no longer valid/functioning */
+ return (ENXIO);
+ }
+
+ if (nprot & PROT_EXEC)
+ return( -1 );
+
+ if (offset < 0)
+ return( -1 );
+
+ if (offset >= bktr->alloc_pages * PAGE_SIZE)
+ return( -1 );
+
+ return( atop(vtophys(bktr->bigbuf) + offset) );
+}
+
+int bktr_poll( dev_t dev, int events, struct proc *p)
+{
+ int unit;
+ bktr_ptr_t bktr;
+ int revents = 0;
+ DECLARE_INTR_MASK(s);
+
+ unit = UNIT(minor(dev));
+
+ /* Get the device data */
+ bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit);
+ if (bktr == NULL) {
+ /* the device is no longer valid/functioning */
+ return (ENXIO);
+ }
+
+ DISABLE_INTR(s);
+
+ if (events & (POLLIN | POLLRDNORM)) {
+
+ switch ( FUNCTION( minor(dev) ) ) {
+ case VBI_DEV:
+ if(bktr->vbisize == 0)
+ selrecord(p, &bktr->vbi_select);
+ else
+ revents |= events & (POLLIN | POLLRDNORM);
+ break;
+ }
+ }
+
+ ENABLE_INTR(s);
+
+ return (revents);
+}
+
+#endif /* FreeBSD 4.x specific kernel interface routines */
+
+/**********************************/
+/* *** FreeBSD 2.2.x and 3.x *** */
+/**********************************/
+
+#if ((__FreeBSD__ == 2) || (__FreeBSD__ == 3))
+
+static bktr_reg_t brooktree[ NBKTR ];
+
+static const char* bktr_probe( pcici_t tag, pcidi_t type );
+static void bktr_attach( pcici_t tag, int unit );
+static void bktr_intr(void *arg) { common_bktr_intr(arg); }
+
+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;
+static d_poll_t bktr_poll;
+
+#define CDEV_MAJOR 92
+static struct cdevsw bktr_cdevsw =
+{
+ bktr_open, bktr_close, bktr_read, bktr_write,
+ bktr_ioctl, nostop, nullreset, nodevtotty,
+ bktr_poll, bktr_mmap, NULL, "bktr",
+ NULL, -1
+};
+
+static int bktr_devsw_installed;
+
+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)
+
+/*
+ * the boot time probe routine.
+ */
+static const char*
+bktr_probe( pcici_t tag, pcidi_t type )
+{
+ unsigned int rev = pci_conf_read( tag, PCIR_REVID) & 0x000000ff;
+
+ if (PCI_VENDOR(type) == PCI_VENDOR_BROOKTREE)
+ {
+ switch (PCI_PRODUCT(type)) {
+ case PCI_PRODUCT_BROOKTREE_BT848:
+ if (rev == 0x12) return("BrookTree 848A");
+ else return("BrookTree 848");
+ case PCI_PRODUCT_BROOKTREE_BT849:
+ return("BrookTree 849A");
+ case PCI_PRODUCT_BROOKTREE_BT878:
+ return("BrookTree 878");
+ case PCI_PRODUCT_BROOKTREE_BT879:
+ return("BrookTree 879");
+ }
+ };
+
+ return ((char *)0);
+}
+
+/*
+ * the attach routine.
+ */
+static void
+bktr_attach( pcici_t tag, int unit )
+{
+ bktr_ptr_t bktr;
+ u_long latency;
+ u_long fun;
+ unsigned int rev;
+ unsigned long base;
+#ifdef BROOKTREE_IRQ
+ u_long old_irq, new_irq;
+#endif
+
+ 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;
+ }
+
+ /* build the device name for bktr_name() */
+ snprintf(bktr->bktr_xname, sizeof(bktr->bktr_xname), "bktr%d",unit);
+
+ /* Enable Memory Mapping */
+ fun = pci_conf_read(tag, PCI_COMMAND_STATUS_REG);
+ pci_conf_write(tag, PCI_COMMAND_STATUS_REG, fun | 2);
+
+ /* Enable Bus Mastering */
+ fun = pci_conf_read(tag, PCI_COMMAND_STATUS_REG);
+ pci_conf_write(tag, PCI_COMMAND_STATUS_REG, fun | 4);
+
+ bktr->tag = tag;
+
+
+ /*
+ * Map control/status registers
+ */
+ pci_map_mem( tag, PCI_MAP_REG_START, (vm_offset_t *) &base,
+ &bktr->phys_base );
+#if (__FreeBSD_version >= 300000)
+ bktr->memt = I386_BUS_SPACE_MEM; /* XXX should use proper bus space */
+ bktr->memh = (bus_space_handle_t)base; /* XXX functions here */
+#endif
+
+ /*
+ * Disable the brooktree device
+ */
+ OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
+
+#ifdef BROOKTREE_IRQ /* from the configuration file */
+ old_irq = pci_conf_read(tag, PCI_INTERRUPT_REG);
+ pci_conf_write(tag, PCI_INTERRUPT_REG, BROOKTREE_IRQ);
+ new_irq = pci_conf_read(tag, PCI_INTERRUPT_REG);
+ printf("bktr%d: attach: irq changed from %d to %d\n",
+ unit, (old_irq & 0xff), (new_irq & 0xff));
+#endif
+
+ /*
+ * setup the interrupt handling routine
+ */
+ pci_map_int(tag, bktr_intr, (void*) bktr, &tty_imask);
+
+
+ /* Update the Device Control Register */
+ /* on Bt878 and Bt879 cards */
+ fun = pci_conf_read(tag, 0x40);
+ fun = fun | 1; /* Enable writes to the sub-system vendor ID */
+
+#if defined( BKTR_430_FX_MODE )
+ if (bootverbose) printf("Using 430 FX chipset compatibilty mode\n");
+ fun = fun | 2; /* Enable Intel 430 FX compatibility mode */
+#endif
+
+#if defined( BKTR_SIS_VIA_MODE )
+ if (bootverbose) printf("Using SiS/VIA chipset compatibilty mode\n");
+ fun = fun | 4; /* Enable SiS/VIA compatibility mode (usefull for
+ OPTi chipset motherboards too */
+#endif
+ pci_conf_write(tag, 0x40, fun);
+
+
+ /* XXX call bt848_i2c dependent attach() routine */
+#if defined(BKTR_USE_FREEBSD_SMBUS)
+ if (bt848_i2c_attach(unit, bktr, &bktr->i2c_sc))
+ printf("bktr%d: i2c_attach: can't attach\n", unit);
+#endif
+
+
+/*
+ * PCI latency timer. 32 is a good value for 4 bus mastering slots, if
+ * you have more than four, then 16 would probably be a better value.
+ */
+#ifndef BROOKTREE_DEF_LATENCY_VALUE
+#define BROOKTREE_DEF_LATENCY_VALUE 10
+#endif
+ latency = pci_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", (int) latency);
+ }
+
+
+ /* read the pci device id and revision id */
+ fun = pci_conf_read(tag, PCI_ID_REG);
+ rev = pci_conf_read(tag, PCIR_REVID) & 0x000000ff;
+
+ /* call the common attach code */
+ common_bktr_attach( bktr, unit, fun, rev );
+
+}
+
+
+/*
+ * Special Memory Allocation
+ */
+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("bktr%d: Unable to allocate %d bytes of memory.\n",
+ unit, size);
+ }
+
+ return( addr );
+}
+
+/*---------------------------------------------------------
+**
+** BrookTree 848 character device driver routines
+**
+**---------------------------------------------------------
+*/
+
+
+#define VIDEO_DEV 0x00
+#define TUNER_DEV 0x01
+#define VBI_DEV 0x02
+
+#define UNIT(x) ((x) & 0x0f)
+#define FUNCTION(x) ((x >> 4) & 0x0f)
+
+
+/*
+ *
+ */
+int
+bktr_open( dev_t dev, int flags, int fmt, struct proc *p )
+{
+ bktr_ptr_t bktr;
+ int unit;
+
+ 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 (bt848_card != -1) {
+ if ((bt848_card >> 8 == unit ) &&
+ ( (bt848_card & 0xff) < Bt848_MAX_CARD )) {
+ if ( bktr->bt848_card != (bt848_card & 0xff) ) {
+ bktr->bt848_card = (bt848_card & 0xff);
+ probeCard(bktr, FALSE, unit);
+ }
+ }
+ }
+
+ if (bt848_tuner != -1) {
+ if ((bt848_tuner >> 8 == unit ) &&
+ ( (bt848_tuner & 0xff) < Bt848_MAX_TUNER )) {
+ if ( bktr->bt848_tuner != (bt848_tuner & 0xff) ) {
+ bktr->bt848_tuner = (bt848_tuner & 0xff);
+ probeCard(bktr, FALSE, unit);
+ }
+ }
+ }
+
+ if (bt848_reverse_mute != -1) {
+ if ((bt848_reverse_mute >> 8) == unit ) {
+ bktr->reverse_mute = bt848_reverse_mute & 0xff;
+ }
+ }
+
+ if (bt848_slow_msp_audio != -1) {
+ if ((bt848_slow_msp_audio >> 8) == unit ) {
+ bktr->slow_msp_audio = (bt848_slow_msp_audio & 0xff);
+ }
+ }
+
+ switch ( FUNCTION( minor(dev) ) ) {
+ case VIDEO_DEV:
+ return( video_open( bktr ) );
+ case TUNER_DEV:
+ return( tuner_open( bktr ) );
+ case VBI_DEV:
+ return( vbi_open( bktr ) );
+ }
+ return( ENXIO );
+}
+
+
+/*
+ *
+ */
+int
+bktr_close( dev_t dev, int flags, int fmt, struct proc *p )
+{
+ bktr_ptr_t bktr;
+ int unit;
+
+ unit = UNIT( minor(dev) );
+ if (unit >= NBKTR) /* unit out of range */
+ return( ENXIO );
+
+ bktr = &(brooktree[ unit ]);
+
+ switch ( FUNCTION( minor(dev) ) ) {
+ case VIDEO_DEV:
+ return( video_close( bktr ) );
+ case TUNER_DEV:
+ return( tuner_close( bktr ) );
+ case VBI_DEV:
+ return( vbi_close( bktr ) );
+ }
+
+ return( ENXIO );
+}
+
+/*
+ *
+ */
+int
+bktr_read( dev_t dev, struct uio *uio, int ioflag )
+{
+ bktr_ptr_t bktr;
+ int unit;
+
+ unit = UNIT(minor(dev));
+ if (unit >= NBKTR) /* unit out of range */
+ return( ENXIO );
+
+ bktr = &(brooktree[unit]);
+
+ switch ( FUNCTION( minor(dev) ) ) {
+ case VIDEO_DEV:
+ return( video_read( bktr, unit, dev, uio ) );
+ case VBI_DEV:
+ return( vbi_read( bktr, uio, ioflag ) );
+ }
+ return( ENXIO );
+}
+
+
+/*
+ *
+ */
+int
+bktr_write( dev_t dev, struct uio *uio, int ioflag )
+{
+ return( EINVAL ); /* XXX or ENXIO ? */
+}
+
+/*
+ *
+ */
+int
+bktr_ioctl( dev_t dev, ioctl_cmd_t cmd, caddr_t arg, int flag, struct proc* pr )
+{
+ bktr_ptr_t bktr;
+ int unit;
+
+ 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 );
+
+ switch ( FUNCTION( minor(dev) ) ) {
+ case VIDEO_DEV:
+ return( video_ioctl( bktr, unit, cmd, arg, pr ) );
+ case TUNER_DEV:
+ return( tuner_ioctl( bktr, unit, cmd, arg, pr ) );
+ }
+
+ return( ENXIO );
+}
+
+/*
+ * bktr_mmap.
+ * Note: 2.2.5/2.2.6/2.2.7/3.0 users must manually
+ * edit the line below and change "vm_offset_t" to "int"
+ */
+int bktr_mmap( dev_t dev, vm_offset_t offset, int nprot )
+
+{
+ int unit;
+ bktr_ptr_t bktr;
+
+ unit = UNIT(minor(dev));
+
+ if (unit >= NBKTR || FUNCTION(minor(dev)) > 0)
+ return( -1 );
+
+ bktr = &(brooktree[ unit ]);
+
+ if (nprot & PROT_EXEC)
+ return( -1 );
+
+ if (offset < 0)
+ return( -1 );
+
+ if (offset >= bktr->alloc_pages * PAGE_SIZE)
+ return( -1 );
+
+ return( i386_btop(vtophys(bktr->bigbuf) + offset) );
+}
+
+int bktr_poll( dev_t dev, int events, struct proc *p)
+{
+ int unit;
+ bktr_ptr_t bktr;
+ int revents = 0;
+
+ unit = UNIT(minor(dev));
+
+ if (unit >= NBKTR)
+ return( -1 );
+
+ bktr = &(brooktree[ unit ]);
+
+ disable_intr();
+
+ if (events & (POLLIN | POLLRDNORM)) {
+
+ switch ( FUNCTION( minor(dev) ) ) {
+ case VBI_DEV:
+ if(bktr->vbisize == 0)
+ selrecord(p, &bktr->vbi_select);
+ else
+ revents |= events & (POLLIN | POLLRDNORM);
+ break;
+ }
+ }
+
+ enable_intr();
+
+ return (revents);
+}
+
+
+#endif /* FreeBSD 2.2.x and 3.x specific kernel interface routines */
+
+
+/*****************/
+/* *** BSDI *** */
+/*****************/
+
+#if defined(__bsdi__)
+#endif /* __bsdi__ BSDI specific kernel interface routines */
+
+
+/*****************************/
+/* *** OpenBSD / NetBSD *** */
+/*****************************/
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+
+#define IPL_VIDEO IPL_BIO /* XXX */
+
+static int bktr_intr(void *arg) { return common_bktr_intr(arg); }
+
+#define bktr_open bktropen
+#define bktr_close bktrclose
+#define bktr_read bktrread
+#define bktr_write bktrwrite
+#define bktr_ioctl bktrioctl
+#define bktr_mmap bktrmmap
+
+#ifdef __OpenBSD__
+int bktr_open __P((dev_t, int, int, struct proc *));
+int bktr_close __P((dev_t, int, int, struct proc *));
+int bktr_read __P((dev_t, struct uio *, int));
+int bktr_write __P((dev_t, struct uio *, int));
+int bktr_ioctl __P((dev_t, ioctl_cmd_t, caddr_t, int, struct proc *));
+paddr_t bktr_mmap __P((dev_t, off_t, int));
+#endif
+
+vm_offset_t vm_page_alloc_contig(vm_offset_t, vm_offset_t,
+ vm_offset_t, vm_offset_t);
+
+#if defined(__OpenBSD__)
+static int bktr_probe __P((struct device *, void *, void *));
+#else
+static int bktr_probe __P((struct device *, struct cfdata *, void *));
+#endif
+static void bktr_attach __P((struct device *, struct device *, void *));
+
+struct cfattach bktr_ca = {
+ sizeof(struct bktr_softc), bktr_probe, bktr_attach
+};
+
+#if defined(__NetBSD__)
+extern struct cfdriver bktr_cd;
+#else
+struct cfdriver bktr_cd = {
+ NULL, "bktr", DV_DULL
+};
+#endif
+
+int
+bktr_probe(parent, match, aux)
+ struct device *parent;
+#if defined(__OpenBSD__)
+ void *match;
+#else
+ struct cfdata *match;
+#endif
+ void *aux;
+{
+ struct pci_attach_args *pa = aux;
+
+ if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_BROOKTREE &&
+ (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROOKTREE_BT848 ||
+ PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROOKTREE_BT849 ||
+ PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROOKTREE_BT878 ||
+ PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROOKTREE_BT879))
+ return 1;
+
+ return 0;
+}
+
+
+/*
+ * the attach routine.
+ */
+static void
+bktr_attach(struct device *parent, struct device *self, void *aux)
+{
+ bktr_ptr_t bktr;
+ u_long latency;
+ u_long fun;
+ unsigned int rev;
+ struct pci_attach_args *pa = aux;
+ pci_intr_handle_t ih;
+ const char *intrstr;
+ int retval;
+ int unit;
+
+ bktr = (bktr_ptr_t)self;
+ unit = bktr->bktr_dev.dv_unit;
+ bktr->dmat = pa->pa_dmat;
+
+#ifndef __OpenBSD__
+ printf("\n");
+#endif
+
+ /*
+ * map memory
+ */
+ retval = pci_mapreg_map(pa, PCI_MAPREG_START,
+ PCI_MAPREG_TYPE_MEM
+ | PCI_MAPREG_MEM_TYPE_32BIT, 0,
+ &bktr->memt, &bktr->memh, NULL,
+ &bktr->obmemsz);
+ DPR(("pci_mapreg_map: memt %x, memh %x, size %x\n",
+ bktr->memt, (u_int)bktr->memh, (u_int)bktr->obmemsz));
+ if (retval) {
+ printf("%s: couldn't map memory\n", bktr_name(bktr));
+ return;
+ }
+
+ /*
+ * Disable the brooktree device
+ */
+ OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
+
+ /*
+ * map interrupt
+ */
+ if (pci_intr_map(pa->pa_pc, pa->pa_intrtag, pa->pa_intrpin,
+ pa->pa_intrline, &ih)) {
+ printf("%s: couldn't map interrupt\n",
+ bktr_name(bktr));
+ return;
+ }
+ intrstr = pci_intr_string(pa->pa_pc, ih);
+ bktr->ih = pci_intr_establish(pa->pa_pc, ih, IPL_VIDEO,
+ bktr_intr, bktr
+#ifdef __OpenBSD__
+ , bktr->bktr_dev.dv_xname
+#endif
+ );
+ if (bktr->ih == NULL) {
+ printf("%s: couldn't establish interrupt",
+ bktr_name(bktr));
+ if (intrstr != NULL)
+ printf(" at %s", intrstr);
+ printf("\n");
+ return;
+ }
+ if (intrstr != NULL)
+#ifdef __NetBSD__
+ printf("%s: interrupting at %s\n", bktr_name(bktr),
+ intrstr);
+#else
+ printf(": %s\n", intrstr);
+#endif
+
+/*
+ * PCI latency timer. 32 is a good value for 4 bus mastering slots, if
+ * you have more than four, then 16 would probably be a better value.
+ */
+#ifndef BROOKTREE_DEF_LATENCY_VALUE
+#define BROOKTREE_DEF_LATENCY_VALUE 10
+#endif
+ latency = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_LATENCY_TIMER);
+ latency = (latency >> 8) & 0xff;
+
+ if (!latency) {
+ if (bootverbose) {
+ printf("%s: PCI bus latency was 0 changing to %d",
+ bktr_name(bktr), BROOKTREE_DEF_LATENCY_VALUE);
+ }
+ latency = BROOKTREE_DEF_LATENCY_VALUE;
+ pci_conf_write(pa->pa_pc, pa->pa_tag,
+ PCI_LATENCY_TIMER, latency<<8);
+ }
+
+
+ /* Enabled Bus Master
+ XXX: check if all old DMA is stopped first (e.g. after warm
+ boot) */
+ fun = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
+ pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
+ fun | PCI_COMMAND_MASTER_ENABLE);
+
+ /* read the pci id and determine the card type */
+ fun = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ID_REG);
+ rev = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_CLASS_REG) & 0x000000ff;
+
+ common_bktr_attach(bktr, unit, fun, rev);
+}
+
+
+/*
+ * Special Memory Allocation
+ */
+vm_offset_t
+get_bktr_mem(bktr, dmapp, size)
+ bktr_ptr_t bktr;
+ bus_dmamap_t *dmapp;
+ unsigned int size;
+{
+ bus_dma_tag_t dmat = bktr->dmat;
+ bus_dma_segment_t seg;
+ bus_size_t align;
+ int rseg;
+ caddr_t kva;
+
+ /*
+ * Allocate a DMA area
+ */
+ align = 1 << 24;
+ if (bus_dmamem_alloc(dmat, size, align, 0, &seg, 1,
+ &rseg, BUS_DMA_NOWAIT)) {
+ align = PAGE_SIZE;
+ if (bus_dmamem_alloc(dmat, size, align, 0, &seg, 1,
+ &rseg, BUS_DMA_NOWAIT)) {
+ printf("%s: Unable to dmamem_alloc of %d bytes\n",
+ bktr_name(bktr), size);
+ return 0;
+ }
+ }
+ if (bus_dmamem_map(dmat, &seg, rseg, size,
+ &kva, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) {
+ printf("%s: Unable to dmamem_map of %d bytes\n",
+ bktr_name(bktr), size);
+ bus_dmamem_free(dmat, &seg, rseg);
+ return 0;
+ }
+#ifdef __OpenBSD__
+ bktr->dm_mapsize = size;
+#endif
+ /*
+ * Create and locd the DMA map for the DMA area
+ */
+ if (bus_dmamap_create(dmat, size, 1, size, 0, BUS_DMA_NOWAIT, dmapp)) {
+ printf("%s: Unable to dmamap_create of %d bytes\n",
+ bktr_name(bktr), size);
+ bus_dmamem_unmap(dmat, kva, size);
+ bus_dmamem_free(dmat, &seg, rseg);
+ return 0;
+ }
+ if (bus_dmamap_load(dmat, *dmapp, kva, size, NULL, BUS_DMA_NOWAIT)) {
+ printf("%s: Unable to dmamap_load of %d bytes\n",
+ bktr_name(bktr), size);
+ bus_dmamem_unmap(dmat, kva, size);
+ bus_dmamem_free(dmat, &seg, rseg);
+ bus_dmamap_destroy(dmat, *dmapp);
+ return 0;
+ }
+ return (vm_offset_t)kva;
+}
+
+void
+free_bktr_mem(bktr, dmap, kva)
+ bktr_ptr_t bktr;
+ bus_dmamap_t dmap;
+ vm_offset_t kva;
+{
+ bus_dma_tag_t dmat = bktr->dmat;
+
+#ifdef __NetBSD__
+ bus_dmamem_unmap(dmat, (caddr_t)kva, dmap->dm_mapsize);
+#else
+ bus_dmamem_unmap(dmat, (caddr_t)kva, bktr->dm_mapsize);
+#endif
+ bus_dmamem_free(dmat, dmap->dm_segs, 1);
+ bus_dmamap_destroy(dmat, dmap);
+}
+
+
+/*---------------------------------------------------------
+**
+** BrookTree 848 character device driver routines
+**
+**---------------------------------------------------------
+*/
+
+
+#define VIDEO_DEV 0x00
+#define TUNER_DEV 0x01
+#define VBI_DEV 0x02
+
+#define UNIT(x) (minor((x) & 0x0f))
+#define FUNCTION(x) (minor((x >> 4) & 0x0f))
+
+/*
+ *
+ */
+int
+bktr_open(dev_t dev, int flags, int fmt, struct proc *p)
+{
+ bktr_ptr_t bktr;
+ int unit;
+
+ unit = UNIT(dev);
+
+ /* unit out of range */
+ if ((unit > bktr_cd.cd_ndevs) || (bktr_cd.cd_devs[unit] == NULL))
+ return(ENXIO);
+
+ bktr = bktr_cd.cd_devs[unit];
+
+ if (!(bktr->flags & METEOR_INITALIZED)) /* device not found */
+ return(ENXIO);
+
+ switch (FUNCTION(dev)) {
+ case VIDEO_DEV:
+ return(video_open(bktr));
+ case TUNER_DEV:
+ return(tuner_open(bktr));
+ case VBI_DEV:
+ return(vbi_open(bktr));
+ }
+
+ return(ENXIO);
+}
+
+
+/*
+ *
+ */
+int
+bktr_close(dev_t dev, int flags, int fmt, struct proc *p)
+{
+ bktr_ptr_t bktr;
+ int unit;
+
+ unit = UNIT(dev);
+
+ bktr = bktr_cd.cd_devs[unit];
+
+ switch (FUNCTION(dev)) {
+ case VIDEO_DEV:
+ return(video_close(bktr));
+ case TUNER_DEV:
+ return(tuner_close(bktr));
+ case VBI_DEV:
+ return(vbi_close(bktr));
+ }
+
+ return(ENXIO);
+}
+
+/*
+ *
+ */
+int
+bktr_read(dev_t dev, struct uio *uio, int ioflag)
+{
+ bktr_ptr_t bktr;
+ int unit;
+
+ unit = UNIT(dev);
+
+ bktr = bktr_cd.cd_devs[unit];
+
+ switch (FUNCTION(dev)) {
+ case VIDEO_DEV:
+ return(video_read(bktr, unit, dev, uio));
+ case VBI_DEV:
+ return(vbi_read(bktr, uio, ioflag));
+ }
+
+ return(ENXIO);
+}
+
+
+/*
+ *
+ */
+int
+bktr_write(dev_t dev, struct uio *uio, int ioflag)
+{
+ /* operation not supported */
+ return(EOPNOTSUPP);
+}
+
+/*
+ *
+ */
+int
+bktr_ioctl(dev_t dev, ioctl_cmd_t cmd, caddr_t arg, int flag, struct proc* pr)
+{
+ bktr_ptr_t bktr;
+ int unit;
+
+ unit = UNIT(dev);
+
+ bktr = bktr_cd.cd_devs[unit];
+
+ if (bktr->bigbuf == 0) /* no frame buffer allocated (ioctl failed) */
+ return(ENOMEM);
+
+ switch (FUNCTION(dev)) {
+ case VIDEO_DEV:
+ return(video_ioctl(bktr, unit, cmd, arg, pr));
+ case TUNER_DEV:
+ return(tuner_ioctl(bktr, unit, cmd, arg, pr));
+ }
+
+ return(ENXIO);
+}
+
+/*
+ *
+ */
+paddr_t
+bktr_mmap(dev_t dev, off_t offset, int nprot)
+{
+ int unit;
+ bktr_ptr_t bktr;
+
+ unit = UNIT(dev);
+
+ if (FUNCTION(dev) > 0) /* only allow mmap on /dev/bktr[n] */
+ return(-1);
+
+ bktr = bktr_cd.cd_devs[unit];
+
+ if ((vaddr_t)offset < 0)
+ return(-1);
+
+ if ((vaddr_t)offset >= bktr->alloc_pages * PAGE_SIZE)
+ return(-1);
+
+ return (bus_dmamem_mmap(bktr->dmat, bktr->dm_mem->dm_segs, 1,
+ (vaddr_t)offset, nprot, BUS_DMA_WAITOK));
+}
+
+#endif /* __NetBSD__ || __OpenBSD__ */
diff --git a/sys/dev/pci/bktr/bktr_os.h b/sys/dev/pci/bktr/bktr_os.h
new file mode 100644
index 00000000000..a20a4a35cfb
--- /dev/null
+++ b/sys/dev/pci/bktr/bktr_os.h
@@ -0,0 +1,73 @@
+/* $OpenBSD: bktr_os.h,v 1.1 2001/03/28 03:27:09 fgsch Exp $ */
+/* $FreeBSD: src/sys/dev/bktr/bktr_os.h,v 1.4 2000/04/16 07:56:58 roger Exp $ */
+
+/*
+ * This is part of the Driver for Video Capture Cards (Frame grabbers)
+ * and TV Tuner cards using the Brooktree Bt848, Bt848A, Bt849A, Bt878, Bt879
+ * chipset.
+ * Copyright Roger Hardiman and Amancio Hasty.
+ *
+ * bktr_os : This has all the Operating System dependant code.
+ *
+ */
+
+/*
+ * 1. Redistributions of source code must retain the
+ * Copyright (c) 1997 Amancio Hasty, 1999 Roger Hardiman
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Amancio Hasty and
+ * Roger Hardiman
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+/******************************/
+/* *** Memory Allocation *** */
+/******************************/
+#if (defined(__FreeBSD__) || defined(__bsdi__))
+vm_offset_t get_bktr_mem( int unit, unsigned size );
+#endif
+
+#if (defined(__NetBSD__) || defined(__OpenBSD__))
+vm_offset_t get_bktr_mem(bktr_ptr_t, bus_dmamap_t *, unsigned size);
+void free_bktr_mem(bktr_ptr_t, bus_dmamap_t, vm_offset_t);
+#endif
+
+/************************************/
+/* *** Interrupt Enable/Disable *** */
+/************************************/
+#if defined(__FreeBSD__) || defined(__OpenBSD__)
+#define DECLARE_INTR_MASK(s) intrmask_t s
+#define DISABLE_INTR(s) s=spltty()
+#define ENABLE_INTR(s) splx(s)
+#else
+#define DECLARE_INTR_MASK(s) /* no need to declare 's' */
+#define DISABLE_INTR(s) disable_intr()
+#define ENABLE_INTR(s) enable_intr()
+#endif
+
+
diff --git a/sys/dev/pci/bktr/bktr_reg.h b/sys/dev/pci/bktr/bktr_reg.h
new file mode 100644
index 00000000000..f6e43ca60c5
--- /dev/null
+++ b/sys/dev/pci/bktr/bktr_reg.h
@@ -0,0 +1,729 @@
+/* $OpenBSD: bktr_reg.h,v 1.1 2001/03/28 03:27:10 fgsch Exp $ */
+/*
+ * $FreeBSD: src/sys/dev/bktr/bktr_reg.h,v 1.42 2000/10/31 13:09:56 roger Exp $
+ *
+ * Copyright (c) 1999 Roger Hardiman
+ * Copyright (c) 1998 Amancio Hasty
+ * Copyright (c) 1995 Mark Tinguely and Jim Lowe
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Tinguely and Jim Lowe
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifdef __FreeBSD__
+# if (__FreeBSD_version >= 310000)
+# include "smbus.h"
+# else
+# define NSMBUS 0 /* FreeBSD before 3.1 does not have SMBUS */
+# endif
+# if (NSMBUS > 0)
+# define BKTR_USE_FREEBSD_SMBUS
+# endif
+#endif
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+#include <machine/bus.h> /* struct device */
+#include <sys/device.h>
+#include <sys/select.h> /* struct selinfo */
+# ifdef DEBUG
+# define bootverbose 1
+# else
+# define bootverbose 0
+# endif
+#endif
+
+/*
+ * The kernel options for the driver now all begin with BKTR.
+ * Support the older kernel options on FreeBSD and OpenBSD.
+ *
+ */
+#if defined(__FreeBSD__) || defined(__OpenBSD__)
+#if defined(BROOKTREE_ALLOC_PAGES)
+#define BKTR_ALLOC_PAGES BROOKTREE_ALLOC_PAGES
+#endif
+
+#if defined(BROOKTREE_SYSTEM_DEFAULT)
+#define BKTR_SYSTEM_DEFAULT BROOKTREE_SYSTEM_DEFAULT
+#endif
+
+#if defined(OVERRIDE_CARD)
+#define BKTR_OVERRIDE_CARD OVERRIDE_CARD
+#endif
+
+#if defined(OVERRIDE_TUNER)
+#define BKTR_OVERRIDE_TUNER OVERRIDE_TUNER
+#endif
+
+#if defined(OVERRIDE_DBX)
+#define BKTR_OVERRIDE_DBX OVERRIDE_DBX
+#endif
+
+#if defined(OVERRIDE_MSP)
+#define BKTR_OVERRIDE_MSP OVERRIDE_MSP
+#endif
+
+#endif
+
+
+#ifndef PCI_LATENCY_TIMER
+#define PCI_LATENCY_TIMER 0x0c /* pci timer register */
+#endif
+
+/*
+ * Definitions for the Brooktree 848/878 video capture to pci interface.
+ */
+#ifndef __NetBSD__
+#ifdef __OpenBSD__
+#include <dev/pci/pcivar.h>
+#else
+#define PCI_VENDOR_SHIFT 0
+#define PCI_VENDOR_MASK 0xffff
+#define PCI_VENDOR(id) \
+ (((id) >> PCI_VENDOR_SHIFT) & PCI_VENDOR_MASK)
+
+#define PCI_PRODUCT_SHIFT 16
+#define PCI_PRODUCT_MASK 0xffff
+#define PCI_PRODUCT(id) \
+ (((id) >> PCI_PRODUCT_SHIFT) & PCI_PRODUCT_MASK)
+#endif
+
+/* PCI vendor ID */
+#define PCI_VENDOR_BROOKTREE 0x109e /* Brooktree */
+/* Brooktree products */
+#define PCI_PRODUCT_BROOKTREE_BT848 0x0350 /* Bt848 Video Capture */
+#define PCI_PRODUCT_BROOKTREE_BT849 0x0351 /* Bt849 Video Capture */
+#define PCI_PRODUCT_BROOKTREE_BT878 0x036e /* Bt878 Video Capture */
+#define PCI_PRODUCT_BROOKTREE_BT879 0x036f /* Bt879 Video Capture */
+#endif
+
+#define BROOKTREE_848 1
+#define BROOKTREE_848A 2
+#define BROOKTREE_849A 3
+#define BROOKTREE_878 4
+#define BROOKTREE_879 5
+
+typedef volatile u_int bregister_t;
+/*
+ * if other persuasion endian, then compiler will probably require that
+ * these next
+ * macros be reversed
+ */
+#define BTBYTE(what) bregister_t what:8; int :24
+#define BTWORD(what) bregister_t what:16; int: 16
+#define BTLONG(what) bregister_t what:32
+
+struct bt848_registers {
+ BTBYTE (dstatus); /* 0, 1,2,3 */
+#define BT848_DSTATUS_PRES (1<<7)
+#define BT848_DSTATUS_HLOC (1<<6)
+#define BT848_DSTATUS_FIELD (1<<5)
+#define BT848_DSTATUS_NUML (1<<4)
+#define BT848_DSTATUS_CSEL (1<<3)
+#define BT848_DSTATUS_PLOCK (1<<2)
+#define BT848_DSTATUS_LOF (1<<1)
+#define BT848_DSTATUS_COF (1<<0)
+ BTBYTE (iform); /* 4, 5,6,7 */
+#define BT848_IFORM_MUXSEL (0x3<<5)
+# define BT848_IFORM_M_MUX1 (0x03<<5)
+# define BT848_IFORM_M_MUX0 (0x02<<5)
+# define BT848_IFORM_M_MUX2 (0x01<<5)
+# define BT848_IFORM_M_MUX3 (0x0)
+# define BT848_IFORM_M_RSVD (0x00<<5)
+#define BT848_IFORM_XTSEL (0x3<<3)
+# define BT848_IFORM_X_AUTO (0x03<<3)
+# define BT848_IFORM_X_XT1 (0x02<<3)
+# define BT848_IFORM_X_XT0 (0x01<<3)
+# define BT848_IFORM_X_RSVD (0x00<<3)
+ BTBYTE (tdec); /* 8, 9,a,b */
+ BTBYTE (e_crop); /* c, d,e,f */
+ BTBYTE (e_vdelay_lo); /* 10, 11,12,13 */
+ BTBYTE (e_vactive_lo); /* 14, 15,16,17 */
+ BTBYTE (e_delay_lo); /* 18, 19,1a,1b */
+ BTBYTE (e_hactive_lo); /* 1c, 1d,1e,1f */
+ BTBYTE (e_hscale_hi); /* 20, 21,22,23 */
+ BTBYTE (e_hscale_lo); /* 24, 25,26,27 */
+ BTBYTE (bright); /* 28, 29,2a,2b */
+ BTBYTE (e_control); /* 2c, 2d,2e,2f */
+#define BT848_E_CONTROL_LNOTCH (1<<7)
+#define BT848_E_CONTROL_COMP (1<<6)
+#define BT848_E_CONTROL_LDEC (1<<5)
+#define BT848_E_CONTROL_CBSENSE (1<<4)
+#define BT848_E_CONTROL_RSVD (1<<3)
+#define BT848_E_CONTROL_CON_MSB (1<<2)
+#define BT848_E_CONTROL_SAT_U_MSB (1<<1)
+#define BT848_E_CONTROL_SAT_V_MSB (1<<0)
+ BTBYTE (contrast_lo); /* 30, 31,32,33 */
+ BTBYTE (sat_u_lo); /* 34, 35,36,37 */
+ BTBYTE (sat_v_lo); /* 38, 39,3a,3b */
+ BTBYTE (hue); /* 3c, 3d,3e,3f */
+ BTBYTE (e_scloop); /* 40, 41,42,43 */
+#define BT848_E_SCLOOP_RSVD1 (1<<7)
+#define BT848_E_SCLOOP_CAGC (1<<6)
+#define BT848_E_SCLOOP_CKILL (1<<5)
+#define BT848_E_SCLOOP_HFILT (0x3<<3)
+# define BT848_E_SCLOOP_HFILT_ICON (0x3<<3)
+# define BT848_E_SCLOOP_HFILT_QCIF (0x2<<3)
+# define BT848_E_SCLOOP_HFILT_CIF (0x1<<3)
+# define BT848_E_SCLOOP_HFILT_AUTO (0x0<<3)
+#define BT848_E_SCLOOP_RSVD0 (0x7<<0)
+ int :32; /* 44, 45,46,47 */
+ BTBYTE (oform); /* 48, 49,4a,4b */
+ BTBYTE (e_vscale_hi); /* 4c, 4d,4e,4f */
+ BTBYTE (e_vscale_lo); /* 50, 51,52,53 */
+ BTBYTE (test); /* 54, 55,56,57 */
+ int :32; /* 58, 59,5a,5b */
+ int :32; /* 5c, 5d,5e,5f */
+ BTLONG (adelay); /* 60, 61,62,63 */
+ BTBYTE (bdelay); /* 64, 65,66,67 */
+ BTBYTE (adc); /* 68, 69,6a,6b */
+#define BT848_ADC_RESERVED (0x80) /* required pattern */
+#define BT848_ADC_SYNC_T (1<<5)
+#define BT848_ADC_AGC_EN (1<<4)
+#define BT848_ADC_CLK_SLEEP (1<<3)
+#define BT848_ADC_Y_SLEEP (1<<2)
+#define BT848_ADC_C_SLEEP (1<<1)
+#define BT848_ADC_CRUSH (1<<0)
+ BTBYTE (e_vtc); /* 6c, 6d,6e,6f */
+ int :32; /* 70, 71,72,73 */
+ int :32; /* 74, 75,76,77 */
+ int :32; /* 78, 79,7a,7b */
+ BTLONG (sreset); /* 7c, 7d,7e,7f */
+ u_char filler1[0x84-0x80];
+ BTBYTE (tgctrl); /* 84, 85,86,87 */
+#define BT848_TGCTRL_TGCKI (3<<3)
+#define BT848_TGCTRL_TGCKI_XTAL (0<<3)
+#define BT848_TGCTRL_TGCKI_PLL (1<<3)
+#define BT848_TGCTRL_TGCKI_GPCLK (2<<3)
+#define BT848_TGCTRL_TGCKI_GPCLK_I (3<<3)
+ u_char filler[0x8c-0x88];
+ BTBYTE (o_crop); /* 8c, 8d,8e,8f */
+ BTBYTE (o_vdelay_lo); /* 90, 91,92,93 */
+ BTBYTE (o_vactive_lo); /* 94, 95,96,97 */
+ BTBYTE (o_delay_lo); /* 98, 99,9a,9b */
+ BTBYTE (o_hactive_lo); /* 9c, 9d,9e,9f */
+ BTBYTE (o_hscale_hi); /* a0, a1,a2,a3 */
+ BTBYTE (o_hscale_lo); /* a4, a5,a6,a7 */
+ int :32; /* a8, a9,aa,ab */
+ BTBYTE (o_control); /* ac, ad,ae,af */
+#define BT848_O_CONTROL_LNOTCH (1<<7)
+#define BT848_O_CONTROL_COMP (1<<6)
+#define BT848_O_CONTROL_LDEC (1<<5)
+#define BT848_O_CONTROL_CBSENSE (1<<4)
+#define BT848_O_CONTROL_RSVD (1<<3)
+#define BT848_O_CONTROL_CON_MSB (1<<2)
+#define BT848_O_CONTROL_SAT_U_MSB (1<<1)
+#define BT848_O_CONTROL_SAT_V_MSB (1<<0)
+ u_char fillter4[16];
+ BTBYTE (o_scloop); /* c0, c1,c2,c3 */
+#define BT848_O_SCLOOP_RSVD1 (1<<7)
+#define BT848_O_SCLOOP_CAGC (1<<6)
+#define BT848_O_SCLOOP_CKILL (1<<5)
+#define BT848_O_SCLOOP_HFILT (0x3<<3)
+#define BT848_O_SCLOOP_HFILT_ICON (0x3<<3)
+#define BT848_O_SCLOOP_HFILT_QCIF (0x2<<3)
+#define BT848_O_SCLOOP_HFILT_CIF (0x1<<3)
+#define BT848_O_SCLOOP_HFILT_AUTO (0x0<<3)
+#define BT848_O_SCLOOP_RSVD0 (0x7<<0)
+ int :32; /* c4, c5,c6,c7 */
+ int :32; /* c8, c9,ca,cb */
+ BTBYTE (o_vscale_hi); /* cc, cd,ce,cf */
+ BTBYTE (o_vscale_lo); /* d0, d1,d2,d3 */
+ BTBYTE (color_fmt); /* d4, d5,d6,d7 */
+ bregister_t color_ctl_swap :4; /* d8 */
+#define BT848_COLOR_CTL_WSWAP_ODD (1<<3)
+#define BT848_COLOR_CTL_WSWAP_EVEN (1<<2)
+#define BT848_COLOR_CTL_BSWAP_ODD (1<<1)
+#define BT848_COLOR_CTL_BSWAP_EVEN (1<<0)
+ bregister_t color_ctl_gamma :1;
+ bregister_t color_ctl_rgb_ded :1;
+ bregister_t color_ctl_color_bars :1;
+ bregister_t color_ctl_ext_frmrate :1;
+#define BT848_COLOR_CTL_GAMMA (1<<4)
+#define BT848_COLOR_CTL_RGB_DED (1<<5)
+#define BT848_COLOR_CTL_COLOR_BARS (1<<6)
+#define BT848_COLOR_CTL_EXT_FRMRATE (1<<7)
+ int :24; /* d9,da,db */
+ BTBYTE (cap_ctl); /* dc, dd,de,df */
+#define BT848_CAP_CTL_DITH_FRAME (1<<4)
+#define BT848_CAP_CTL_VBI_ODD (1<<3)
+#define BT848_CAP_CTL_VBI_EVEN (1<<2)
+#define BT848_CAP_CTL_ODD (1<<1)
+#define BT848_CAP_CTL_EVEN (1<<0)
+ BTBYTE (vbi_pack_size); /* e0, e1,e2,e3 */
+ BTBYTE (vbi_pack_del); /* e4, e5,e6,e7 */
+ int :32; /* e8, e9,ea,eb */
+ BTBYTE (o_vtc); /* ec, ed,ee,ef */
+ BTBYTE (pll_f_lo); /* f0, f1,f2,f3 */
+ BTBYTE (pll_f_hi); /* f4, f5,f6,f7 */
+ BTBYTE (pll_f_xci); /* f8, f9,fa,fb */
+#define BT848_PLL_F_C (1<<6)
+#define BT848_PLL_F_X (1<<7)
+ u_char filler2[0x100-0xfc];
+ BTLONG (int_stat); /* 100, 101,102,103 */
+ BTLONG (int_mask); /* 104, 105,106,107 */
+#define BT848_INT_RISCS (0xf<<28)
+#define BT848_INT_RISC_EN (1<<27)
+#define BT848_INT_RACK (1<<25)
+#define BT848_INT_FIELD (1<<24)
+#define BT848_INT_MYSTERYBIT (1<<23)
+#define BT848_INT_SCERR (1<<19)
+#define BT848_INT_OCERR (1<<18)
+#define BT848_INT_PABORT (1<<17)
+#define BT848_INT_RIPERR (1<<16)
+#define BT848_INT_PPERR (1<<15)
+#define BT848_INT_FDSR (1<<14)
+#define BT848_INT_FTRGT (1<<13)
+#define BT848_INT_FBUS (1<<12)
+#define BT848_INT_RISCI (1<<11)
+#define BT848_INT_GPINT (1<<9)
+#define BT848_INT_I2CDONE (1<<8)
+#define BT848_INT_RSV1 (1<<7)
+#define BT848_INT_RSV0 (1<<6)
+#define BT848_INT_VPRES (1<<5)
+#define BT848_INT_HLOCK (1<<4)
+#define BT848_INT_OFLOW (1<<3)
+#define BT848_INT_HSYNC (1<<2)
+#define BT848_INT_VSYNC (1<<1)
+#define BT848_INT_FMTCHG (1<<0)
+ int :32; /* 108, 109,10a,10b */
+ BTWORD (gpio_dma_ctl); /* 10c, 10d,10e,10f */
+#define BT848_DMA_CTL_PL23TP4 (0<<6) /* planar1 trigger 4 */
+#define BT848_DMA_CTL_PL23TP8 (1<<6) /* planar1 trigger 8 */
+#define BT848_DMA_CTL_PL23TP16 (2<<6) /* planar1 trigger 16 */
+#define BT848_DMA_CTL_PL23TP32 (3<<6) /* planar1 trigger 32 */
+#define BT848_DMA_CTL_PL1TP4 (0<<4) /* planar1 trigger 4 */
+#define BT848_DMA_CTL_PL1TP8 (1<<4) /* planar1 trigger 8 */
+#define BT848_DMA_CTL_PL1TP16 (2<<4) /* planar1 trigger 16 */
+#define BT848_DMA_CTL_PL1TP32 (3<<4) /* planar1 trigger 32 */
+#define BT848_DMA_CTL_PKTP4 (0<<2) /* packed trigger 4 */
+#define BT848_DMA_CTL_PKTP8 (1<<2) /* packed trigger 8 */
+#define BT848_DMA_CTL_PKTP16 (2<<2) /* packed trigger 16 */
+#define BT848_DMA_CTL_PKTP32 (3<<2) /* packed trigger 32 */
+#define BT848_DMA_CTL_RISC_EN (1<<1)
+#define BT848_DMA_CTL_FIFO_EN (1<<0)
+ BTLONG (i2c_data_ctl); /* 110, 111,112,113 */
+#define BT848_DATA_CTL_I2CDIV (0xf<<4)
+#define BT848_DATA_CTL_I2CSYNC (1<<3)
+#define BT848_DATA_CTL_I2CW3B (1<<2)
+#define BT848_DATA_CTL_I2CSCL (1<<1)
+#define BT848_DATA_CTL_I2CSDA (1<<0)
+ BTLONG (risc_strt_add); /* 114, 115,116,117 */
+ BTLONG (gpio_out_en); /* 118, 119,11a,11b */ /* really 24 bits */
+ BTLONG (gpio_reg_inp); /* 11c, 11d,11e,11f */ /* really 24 bits */
+ BTLONG (risc_count); /* 120, 121,122,123 */
+ u_char filler3[0x200-0x124];
+ BTLONG (gpio_data); /* 200, 201,202,203 */ /* really 24 bits */
+};
+
+
+#define BKTR_DSTATUS 0x000
+#define BKTR_IFORM 0x004
+#define BKTR_TDEC 0x008
+#define BKTR_E_CROP 0x00C
+#define BKTR_O_CROP 0x08C
+#define BKTR_E_VDELAY_LO 0x010
+#define BKTR_O_VDELAY_LO 0x090
+#define BKTR_E_VACTIVE_LO 0x014
+#define BKTR_O_VACTIVE_LO 0x094
+#define BKTR_E_DELAY_LO 0x018
+#define BKTR_O_DELAY_LO 0x098
+#define BKTR_E_HACTIVE_LO 0x01C
+#define BKTR_O_HACTIVE_LO 0x09C
+#define BKTR_E_HSCALE_HI 0x020
+#define BKTR_O_HSCALE_HI 0x0A0
+#define BKTR_E_HSCALE_LO 0x024
+#define BKTR_O_HSCALE_LO 0x0A4
+#define BKTR_BRIGHT 0x028
+#define BKTR_E_CONTROL 0x02C
+#define BKTR_O_CONTROL 0x0AC
+#define BKTR_CONTRAST_LO 0x030
+#define BKTR_SAT_U_LO 0x034
+#define BKTR_SAT_V_LO 0x038
+#define BKTR_HUE 0x03C
+#define BKTR_E_SCLOOP 0x040
+#define BKTR_O_SCLOOP 0x0C0
+#define BKTR_OFORM 0x048
+#define BKTR_E_VSCALE_HI 0x04C
+#define BKTR_O_VSCALE_HI 0x0CC
+#define BKTR_E_VSCALE_LO 0x050
+#define BKTR_O_VSCALE_LO 0x0D0
+#define BKTR_TEST 0x054
+#define BKTR_ADELAY 0x060
+#define BKTR_BDELAY 0x064
+#define BKTR_ADC 0x068
+#define BKTR_E_VTC 0x06C
+#define BKTR_O_VTC 0x0EC
+#define BKTR_SRESET 0x07C
+#define BKTR_COLOR_FMT 0x0D4
+#define BKTR_COLOR_CTL 0x0D8
+#define BKTR_CAP_CTL 0x0DC
+#define BKTR_VBI_PACK_SIZE 0x0E0
+#define BKTR_VBI_PACK_DEL 0x0E4
+#define BKTR_INT_STAT 0x100
+#define BKTR_INT_MASK 0x104
+#define BKTR_RISC_COUNT 0x120
+#define BKTR_RISC_STRT_ADD 0x114
+#define BKTR_GPIO_DMA_CTL 0x10C
+#define BKTR_GPIO_OUT_EN 0x118
+#define BKTR_GPIO_REG_INP 0x11C
+#define BKTR_GPIO_DATA 0x200
+#define BKTR_I2C_DATA_CTL 0x110
+#define BKTR_TGCTRL 0x084
+#define BKTR_PLL_F_LO 0x0F0
+#define BKTR_PLL_F_HI 0x0F4
+#define BKTR_PLL_F_XCI 0x0F8
+
+/*
+ * device support for onboard tv tuners
+ */
+
+/* description of the LOGICAL tuner */
+struct TVTUNER {
+ int frequency;
+ u_char chnlset;
+ u_char channel;
+ u_char band;
+ u_char afc;
+ u_char radio_mode; /* current mode of the radio mode */
+};
+
+/* description of the PHYSICAL tuner */
+struct TUNER {
+ char* name;
+ u_char type;
+ u_char pllControl[4];
+ u_char bandLimits[ 2 ];
+ u_char bandAddrs[ 4 ]; /* 3 first for the 3 TV
+ ** bands. Last for radio
+ ** band (0x00=NoRadio).
+ */
+
+};
+
+/* description of the card */
+#define EEPROMBLOCKSIZE 32
+struct CARDTYPE {
+ unsigned int card_id; /* card id (from #define's) */
+ char* name;
+ const struct TUNER* tuner; /* Tuner details */
+ u_char tuner_pllAddr; /* Tuner i2c address */
+ u_char dbx; /* Has DBX chip? */
+ u_char msp3400c; /* Has msp3400c chip? */
+ u_char dpl3518a; /* Has dpl3518a chip? */
+ u_char eepromAddr;
+ u_char eepromSize; /* bytes / EEPROMBLOCKSIZE */
+ u_int audiomuxs[ 5 ]; /* tuner, ext (line-in) */
+ /* int/unused (radio) */
+ /* mute, present */
+ u_int gpio_mux_bits; /* GPIO mask for audio mux */
+};
+
+struct format_params {
+ /* Total lines, lines before image, image lines */
+ int vtotal, vdelay, vactive;
+ /* Total unscaled horizontal pixels, pixels before image, image pixels */
+ int htotal, hdelay, hactive;
+ /* Scaled horizontal image pixels, Total Scaled horizontal pixels */
+ int scaled_hactive, scaled_htotal;
+ /* frame rate . for ntsc is 30 frames per second */
+ int frame_rate;
+ /* A-delay and B-delay */
+ u_char adelay, bdelay;
+ /* Iform XTSEL value */
+ int iform_xtsel;
+ /* VBI number of lines per field, and number of samples per line */
+ int vbi_num_lines, vbi_num_samples;
+};
+
+#if defined(BKTR_USE_FREEBSD_SMBUS)
+struct bktr_i2c_softc {
+ device_t iicbus;
+ device_t smbus;
+};
+#endif
+
+
+/* Bt848/878 register access
+ * The registers can either be access via a memory mapped structure
+ * or accessed via bus_space.
+ * bus_0pace access allows cross platform support, where as the
+ * memory mapped structure method only works on 32 bit processors
+ * with the right type of endianness.
+ */
+#if defined(__NetBSD__) || ( defined(__FreeBSD__) && (__FreeBSD_version >=300000) )
+#define INB(bktr,offset) bus_space_read_1((bktr)->memt,(bktr)->memh,(offset))
+#define INW(bktr,offset) bus_space_read_2((bktr)->memt,(bktr)->memh,(offset))
+#define INL(bktr,offset) bus_space_read_4((bktr)->memt,(bktr)->memh,(offset))
+#define OUTB(bktr,offset,value) bus_space_write_1((bktr)->memt,(bktr)->memh,(offset),(value))
+#define OUTW(bktr,offset,value) bus_space_write_2((bktr)->memt,(bktr)->memh,(offset),(value))
+#define OUTL(bktr,offset,value) bus_space_write_4((bktr)->memt,(bktr)->memh,(offset),(value))
+#else
+#define INB(bktr,offset) *(volatile unsigned char*) ((int)((bktr)->memh)+(offset))
+#define INW(bktr,offset) *(volatile unsigned short*)((int)((bktr)->memh)+(offset))
+#define INL(bktr,offset) *(volatile unsigned int*) ((int)((bktr)->memh)+(offset))
+#define OUTB(bktr,offset,value) *(volatile unsigned char*) ((int)((bktr)->memh)+(offset)) = (value)
+#define OUTW(bktr,offset,value) *(volatile unsigned short*)((int)((bktr)->memh)+(offset)) = (value)
+#define OUTL(bktr,offset,value) *(volatile unsigned int*) ((int)((bktr)->memh)+(offset)) = (value)
+#endif
+
+
+typedef struct bktr_clip bktr_clip_t;
+
+/*
+ * BrookTree 848 info structure, one per bt848 card installed.
+ */
+struct bktr_softc {
+
+#if defined (__bsdi__)
+ struct device bktr_dev; /* base device */
+ struct isadev bktr_id; /* ISA device */
+ struct intrhand bktr_ih; /* interrupt vectoring */
+ #define pcici_t pci_devaddr_t
+#endif
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+ struct device bktr_dev; /* base device */
+ bus_dma_tag_t dmat; /* DMA tag */
+ bus_space_tag_t memt;
+ bus_space_handle_t memh;
+ bus_size_t obmemsz; /* size of en card (bytes) */
+ void *ih;
+ bus_dmamap_t dm_prog;
+ bus_dmamap_t dm_oprog;
+ bus_dmamap_t dm_mem;
+ bus_dmamap_t dm_vbidata;
+ bus_dmamap_t dm_vbibuffer;
+#ifdef __OpenBSD__
+ size_t dm_mapsize;
+#endif
+#endif
+
+#if defined (__FreeBSD__)
+ #if (__FreeBSD_version < 400000)
+ vm_offset_t phys_base; /* 2.x Bt848 register physical address */
+ pcici_t tag; /* 2.x PCI tag, for doing PCI commands */
+ #endif
+ #if (__FreeBSD_version >= 400000)
+ int mem_rid; /* 4.x resource id */
+ struct resource *res_mem; /* 4.x resource descriptor for registers */
+ int irq_rid; /* 4.x resource id */
+ struct resource *res_irq; /* 4.x resource descriptor for interrupt */
+ void *res_ih; /* 4.x newbus interrupt handler cookie */
+ dev_t bktrdev; /* 4.x device entry for /dev/bktrN */
+ dev_t tunerdev; /* 4.x device entry for /dev/tunerN */
+ dev_t vbidev; /* 4.x device entry for /dev/vbiN */
+ dev_t bktrdev_alias; /* alias /dev/bktr to /dev/bktr0 */
+ dev_t tunerdev_alias; /* alias /dev/tuner to /dev/tuner0 */
+ dev_t vbidev_alias; /* alias /dev/vbi to /dev/vbi0 */
+ #endif
+ #if (__FreeBSD_version >= 310000)
+ bus_space_tag_t memt; /* Bus space register access functions */
+ bus_space_handle_t memh; /* Bus space register access functions */
+ bus_size_t obmemsz;/* Size of card (bytes) */
+ #endif
+ #if (NSMBUS > 0)
+ struct bktr_i2c_softc i2c_sc; /* bt848_i2c device */
+ #endif
+ char bktr_xname[7]; /* device name and unit number */
+#endif
+
+
+ /* The following definitions are for the contiguous memory */
+#ifdef __NetBSD__
+ vaddr_t bigbuf; /* buffer that holds the captured image */
+ vaddr_t vbidata; /* RISC program puts VBI data from the current frame here */
+ vaddr_t vbibuffer; /* Circular buffer holding VBI data for the user */
+ vaddr_t dma_prog; /* RISC prog for single and/or even field capture*/
+ vaddr_t odd_dma_prog; /* RISC program for Odd field capture */
+#else
+ vm_offset_t bigbuf; /* buffer that holds the captured image */
+ vm_offset_t vbidata; /* RISC program puts VBI data from the current frame here */
+ vm_offset_t vbibuffer; /* Circular buffer holding VBI data for the user */
+ vm_offset_t dma_prog; /* RISC prog for single and/or even field capture*/
+ vm_offset_t odd_dma_prog;/* RISC program for Odd field capture */
+#endif
+
+
+ /* the following definitions are common over all platforms */
+ int alloc_pages; /* number of pages in bigbuf */
+ int vbiinsert; /* Position for next write into circular buffer */
+ int vbistart; /* Position of last read from circular buffer */
+ int vbisize; /* Number of bytes in the circular buffer */
+ u_long vbi_sequence_number; /* sequence number for VBI */
+ int vbi_read_blocked; /* user process blocked on read() from /dev/vbi */
+ struct selinfo vbi_select; /* Data used by select() on /dev/vbi */
+
+
+ struct proc *proc; /* process to receive raised signal */
+ int signal; /* signal to send to process */
+ int clr_on_start; /* clear cap buf on capture start? */
+#define METEOR_SIG_MODE_MASK 0xffff0000
+#define METEOR_SIG_FIELD_MODE 0x00010000
+#define METEOR_SIG_FRAME_MODE 0x00000000
+ char dma_prog_loaded;
+ struct meteor_mem *mem; /* used to control sync. multi-frame output */
+ u_long synch_wait; /* wait for free buffer before continuing */
+ short current; /* frame number in buffer (1-frames) */
+ short rows; /* number of rows in a frame */
+ short cols; /* number of columns in a frame */
+ int capture_area_x_offset; /* Usually the full 640x480(NTSC) image is */
+ int capture_area_y_offset; /* captured. The capture area allows for */
+ int capture_area_x_size; /* example 320x200 pixels from the centre */
+ int capture_area_y_size; /* of the video image to be captured. */
+ char capture_area_enabled; /* When TRUE use user's capture area. */
+ int pixfmt; /* active pixel format (idx into fmt tbl) */
+ int pixfmt_compat; /* Y/N - in meteor pix fmt compat mode */
+ u_long format; /* frame format rgb, yuv, etc.. */
+ short frames; /* number of frames allocated */
+ int frame_size; /* number of bytes in a frame */
+ u_long fifo_errors; /* number of fifo capture errors since open */
+ u_long dma_errors; /* number of DMA capture errors since open */
+ u_long frames_captured;/* number of frames captured since open */
+ u_long even_fields_captured; /* number of even fields captured */
+ u_long odd_fields_captured; /* number of odd fields captured */
+ u_long range_enable; /* enable range checking ?? */
+ u_short capcontrol; /* reg 0xdc capture control */
+ u_short bktr_cap_ctl;
+ volatile u_int flags;
+#define METEOR_INITALIZED 0x00000001
+#define METEOR_OPEN 0x00000002
+#define METEOR_MMAP 0x00000004
+#define METEOR_INTR 0x00000008
+#define METEOR_READ 0x00000010 /* XXX never gets referenced */
+#define METEOR_SINGLE 0x00000020 /* get single frame */
+#define METEOR_CONTIN 0x00000040 /* continuously get frames */
+#define METEOR_SYNCAP 0x00000080 /* synchronously get frames */
+#define METEOR_CAP_MASK 0x000000f0
+#define METEOR_NTSC 0x00000100
+#define METEOR_PAL 0x00000200
+#define METEOR_SECAM 0x00000400
+#define BROOKTREE_NTSC 0x00000100 /* used in video open() and */
+#define BROOKTREE_PAL 0x00000200 /* in the kernel config */
+#define BROOKTREE_SECAM 0x00000400 /* file */
+#define METEOR_AUTOMODE 0x00000800
+#define METEOR_FORM_MASK 0x00000f00
+#define METEOR_DEV0 0x00001000
+#define METEOR_DEV1 0x00002000
+#define METEOR_DEV2 0x00004000
+#define METEOR_DEV3 0x00008000
+#define METEOR_DEV_SVIDEO 0x00006000
+#define METEOR_DEV_RGB 0x0000a000
+#define METEOR_DEV_MASK 0x0000f000
+#define METEOR_RGB16 0x00010000
+#define METEOR_RGB24 0x00020000
+#define METEOR_YUV_PACKED 0x00040000
+#define METEOR_YUV_PLANAR 0x00080000
+#define METEOR_WANT_EVEN 0x00100000 /* want even frame */
+#define METEOR_WANT_ODD 0x00200000 /* want odd frame */
+#define METEOR_WANT_MASK 0x00300000
+#define METEOR_ONLY_EVEN_FIELDS 0x01000000
+#define METEOR_ONLY_ODD_FIELDS 0x02000000
+#define METEOR_ONLY_FIELDS_MASK 0x03000000
+#define METEOR_YUV_422 0x04000000
+#define METEOR_OUTPUT_FMT_MASK 0x040f0000
+#define METEOR_WANT_TS 0x08000000 /* time-stamp a frame */
+#define METEOR_RGB 0x20000000 /* meteor rgb unit */
+#define METEOR_FIELD_MODE 0x80000000
+ u_char tflags; /* Tuner flags (/dev/tuner) */
+#define TUNER_INITALIZED 0x00000001
+#define TUNER_OPEN 0x00000002
+ u_char vbiflags; /* VBI flags (/dev/vbi) */
+#define VBI_INITALIZED 0x00000001
+#define VBI_OPEN 0x00000002
+#define VBI_CAPTURE 0x00000004
+ u_short fps; /* frames per second */
+ struct meteor_video video;
+ struct TVTUNER tuner;
+ struct CARDTYPE card;
+ u_char audio_mux_select; /* current mode of the audio */
+ u_char audio_mute_state; /* mute state of the audio */
+ u_char format_params;
+ u_long current_sol;
+ u_long current_col;
+ int clip_start;
+ int line_length;
+ int last_y;
+ int y;
+ int y2;
+ int yclip;
+ int yclip2;
+ int max_clip_node;
+ bktr_clip_t clip_list[100];
+ int reverse_mute; /* Swap the GPIO values for Mute and TV Audio */
+ int bt848_tuner;
+ int bt848_card;
+ u_long id;
+#define BT848_USE_XTALS 0
+#define BT848_USE_PLL 1
+ int xtal_pll_mode; /* Use XTAL or PLL mode for PAL/SECAM */
+ int remote_control; /* remote control detected */
+ int remote_control_addr; /* remote control i2c address */
+ char msp_version_string[9]; /* MSP version string 34xxx-xx */
+ int msp_addr; /* MSP i2c address */
+ char dpl_version_string[9]; /* DPL version string 35xxx-xx */
+ int dpl_addr; /* DPL i2c address */
+ int slow_msp_audio; /* 0 = use fast MSP3410/3415 programming sequence */
+ /* 1 = use slow MSP3410/3415 programming sequence */
+ /* 2 = use Tuner's Mono audio output via the MSP chip */
+ int msp_use_mono_source; /* use Tuner's Mono audio output via the MSP chip */
+ int audio_mux_present; /* 1 = has audio mux on GPIO lines, 0 = no audio mux */
+ int msp_source_selected; /* 0 = TV source, 1 = Line In source, 2 = FM Radio Source */
+
+};
+
+typedef struct bktr_softc bktr_reg_t;
+typedef struct bktr_softc* bktr_ptr_t;
+
+#define Bt848_MAX_SIGN 16
+
+struct bt848_card_sig {
+ int card;
+ int tuner;
+ u_char signature[Bt848_MAX_SIGN];
+};
+
+
+/***********************************************************/
+/* ioctl_cmd_t int on old versions, u_long on new versions */
+/***********************************************************/
+
+#if (__FreeBSD__ == 2)
+typedef int ioctl_cmd_t;
+#endif
+
+#if defined(__FreeBSD__)
+#if (__FreeBSD_version >= 300000)
+typedef u_long ioctl_cmd_t;
+#endif
+#endif
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+typedef u_long ioctl_cmd_t;
+#endif
+
+
diff --git a/sys/dev/pci/bktr/bktr_tuner.c b/sys/dev/pci/bktr/bktr_tuner.c
new file mode 100644
index 00000000000..e4b2fd3c998
--- /dev/null
+++ b/sys/dev/pci/bktr/bktr_tuner.c
@@ -0,0 +1,1017 @@
+/* $OpenBSD: bktr_tuner.c,v 1.1 2001/03/28 03:27:10 fgsch Exp $ */
+/* $FreeBSD: src/sys/dev/bktr/bktr_tuner.c,v 1.9 2000/10/19 07:33:28 roger Exp $ */
+
+/*
+ * This is part of the Driver for Video Capture Cards (Frame grabbers)
+ * and TV Tuner cards using the Brooktree Bt848, Bt848A, Bt849A, Bt878, Bt879
+ * chipset.
+ * Copyright Roger Hardiman and Amancio Hasty.
+ *
+ * bktr_tuner : This deals with controlling the tuner fitted to TV cards.
+ *
+ */
+
+/*
+ * 1. Redistributions of source code must retain the
+ * Copyright (c) 1997 Amancio Hasty, 1999 Roger Hardiman
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Amancio Hasty and
+ * Roger Hardiman
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/vnode.h>
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+#include <sys/proc.h>
+#endif
+
+#ifdef __FreeBSD__
+#include <pci/pcivar.h>
+
+#if (__FreeBSD_version < 500000)
+#include <machine/clock.h> /* for DELAY */
+#endif
+
+#if (__FreeBSD_version >=300000)
+#include <machine/bus_memio.h> /* for bus space */
+#include <machine/bus.h>
+#include <sys/bus.h>
+#endif
+#endif
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+#include <dev/ic/bt8xx.h> /* NetBSD .h file location */
+#include <dev/pci/bktr/bktr_reg.h>
+#include <dev/pci/bktr/bktr_tuner.h>
+#include <dev/pci/bktr/bktr_card.h>
+#include <dev/pci/bktr/bktr_core.h>
+#else
+#include <machine/ioctl_meteor.h> /* Traditional .h file location */
+#include <machine/ioctl_bt848.h> /* extensions to ioctl_meteor.h */
+#include <dev/bktr/bktr_reg.h>
+#include <dev/bktr/bktr_tuner.h>
+#include <dev/bktr/bktr_card.h>
+#include <dev/bktr/bktr_core.h>
+#endif
+
+
+
+#if defined( TUNER_AFC )
+#define AFC_DELAY 10000 /* 10 millisend delay */
+#define AFC_BITS 0x07
+#define AFC_FREQ_MINUS_125 0x00
+#define AFC_FREQ_MINUS_62 0x01
+#define AFC_FREQ_CENTERED 0x02
+#define AFC_FREQ_PLUS_62 0x03
+#define AFC_FREQ_PLUS_125 0x04
+#define AFC_MAX_STEP (5 * FREQFACTOR) /* no more than 5 MHz */
+#endif /* TUNER_AFC */
+
+
+#define TTYPE_XXX 0
+#define TTYPE_NTSC 1
+#define TTYPE_NTSC_J 2
+#define TTYPE_PAL 3
+#define TTYPE_PAL_M 4
+#define TTYPE_PAL_N 5
+#define TTYPE_SECAM 6
+
+#define TSA552x_CB_MSB (0x80)
+#define TSA552x_CB_CP (1<<6) /* set this for fast tuning */
+#define TSA552x_CB_T2 (1<<5) /* test mode - Normally set to 0 */
+#define TSA552x_CB_T1 (1<<4) /* test mode - Normally set to 0 */
+#define TSA552x_CB_T0 (1<<3) /* test mode - Normally set to 1 */
+#define TSA552x_CB_RSA (1<<2) /* 0 for 31.25 khz, 1 for 62.5 kHz */
+#define TSA552x_CB_RSB (1<<1) /* 0 for FM 50kHz steps, 1 = Use RSA*/
+#define TSA552x_CB_OS (1<<0) /* Set to 0 for normal operation */
+
+#define TSA552x_RADIO (TSA552x_CB_MSB | \
+ TSA552x_CB_T0)
+
+/* raise the charge pump voltage for fast tuning */
+#define TSA552x_FCONTROL (TSA552x_CB_MSB | \
+ TSA552x_CB_CP | \
+ TSA552x_CB_T0 | \
+ TSA552x_CB_RSA | \
+ TSA552x_CB_RSB)
+
+/* lower the charge pump voltage for better residual oscillator FM */
+#define TSA552x_SCONTROL (TSA552x_CB_MSB | \
+ TSA552x_CB_T0 | \
+ TSA552x_CB_RSA | \
+ TSA552x_CB_RSB)
+
+/* The control value for the ALPS TSCH5 Tuner */
+#define TSCH5_FCONTROL 0x82
+#define TSCH5_RADIO 0x86
+
+/* The control value for the ALPS TSBH1 Tuner */
+#define TSBH1_FCONTROL 0xce
+
+
+static const struct TUNER tuners[] = {
+/* XXX FIXME: fill in the band-switch crosspoints */
+ /* NO_TUNER */
+ { "<no>", /* the 'name' */
+ TTYPE_XXX, /* input type */
+ { 0x00, /* control byte for Tuner PLL */
+ 0x00,
+ 0x00,
+ 0x00 },
+ { 0x00, 0x00 }, /* band-switch crosspoints */
+ { 0x00, 0x00, 0x00,0x00} }, /* the band-switch values */
+
+ /* TEMIC_NTSC */
+ { "Temic NTSC", /* the 'name' */
+ TTYPE_NTSC, /* input type */
+ { TSA552x_SCONTROL, /* control byte for Tuner PLL */
+ TSA552x_SCONTROL,
+ TSA552x_SCONTROL,
+ 0x00 },
+ { 0x00, 0x00}, /* band-switch crosspoints */
+ { 0x02, 0x04, 0x01, 0x00 } }, /* the band-switch values */
+
+ /* TEMIC_PAL */
+ { "Temic PAL", /* the 'name' */
+ TTYPE_PAL, /* input type */
+ { TSA552x_SCONTROL, /* control byte for Tuner PLL */
+ TSA552x_SCONTROL,
+ TSA552x_SCONTROL,
+ 0x00 },
+ { 0x00, 0x00 }, /* band-switch crosspoints */
+ { 0x02, 0x04, 0x01, 0x00 } }, /* the band-switch values */
+
+ /* TEMIC_SECAM */
+ { "Temic SECAM", /* the 'name' */
+ TTYPE_SECAM, /* input type */
+ { TSA552x_SCONTROL, /* control byte for Tuner PLL */
+ TSA552x_SCONTROL,
+ TSA552x_SCONTROL,
+ 0x00 },
+ { 0x00, 0x00 }, /* band-switch crosspoints */
+ { 0x02, 0x04, 0x01,0x00 } }, /* the band-switch values */
+
+ /* PHILIPS_NTSC */
+ { "Philips NTSC", /* the 'name' */
+ TTYPE_NTSC, /* input type */
+ { TSA552x_SCONTROL, /* control byte for Tuner PLL */
+ TSA552x_SCONTROL,
+ TSA552x_SCONTROL,
+ 0x00 },
+ { 0x00, 0x00 }, /* band-switch crosspoints */
+ { 0xa0, 0x90, 0x30, 0x00 } }, /* the band-switch values */
+
+ /* PHILIPS_PAL */
+ { "Philips PAL", /* the 'name' */
+ TTYPE_PAL, /* input type */
+ { TSA552x_SCONTROL, /* control byte for Tuner PLL */
+ TSA552x_SCONTROL,
+ TSA552x_SCONTROL,
+ 0x00 },
+ { 0x00, 0x00 }, /* band-switch crosspoints */
+ { 0xa0, 0x90, 0x30, 0x00 } }, /* the band-switch values */
+
+ /* PHILIPS_SECAM */
+ { "Philips SECAM", /* the 'name' */
+ TTYPE_SECAM, /* input type */
+ { TSA552x_SCONTROL, /* control byte for Tuner PLL */
+ TSA552x_SCONTROL,
+ TSA552x_SCONTROL,
+ 0x00 },
+ { 0x00, 0x00 }, /* band-switch crosspoints */
+ { 0xa7, 0x97, 0x37, 0x00 } }, /* the band-switch values */
+
+ /* TEMIC_PAL I */
+ { "Temic PAL I", /* the 'name' */
+ TTYPE_PAL, /* input type */
+ { TSA552x_SCONTROL, /* control byte for Tuner PLL */
+ TSA552x_SCONTROL,
+ TSA552x_SCONTROL,
+ 0x00 },
+ { 0x00, 0x00 }, /* band-switch crosspoints */
+ { 0x02, 0x04, 0x01,0x00 } }, /* the band-switch values */
+
+ /* PHILIPS_PALI */
+ { "Philips PAL I", /* the 'name' */
+ TTYPE_PAL, /* input type */
+ { TSA552x_SCONTROL, /* control byte for Tuner PLL */
+ TSA552x_SCONTROL,
+ TSA552x_SCONTROL,
+ 0x00 },
+ { 0x00, 0x00 }, /* band-switch crosspoints */
+ { 0xa0, 0x90, 0x30,0x00 } }, /* the band-switch values */
+
+ /* PHILIPS_FR1236_NTSC */
+ { "Philips FR1236 NTSC FM", /* the 'name' */
+ TTYPE_NTSC, /* input type */
+ { TSA552x_FCONTROL, /* control byte for Tuner PLL */
+ TSA552x_FCONTROL,
+ TSA552x_FCONTROL,
+ TSA552x_RADIO },
+ { 0x00, 0x00 }, /* band-switch crosspoints */
+ { 0xa0, 0x90, 0x30,0xa4 } }, /* the band-switch values */
+
+ /* PHILIPS_FR1216_PAL */
+ { "Philips FR1216 PAL FM" , /* the 'name' */
+ TTYPE_PAL, /* input type */
+ { TSA552x_FCONTROL, /* control byte for Tuner PLL */
+ TSA552x_FCONTROL,
+ TSA552x_FCONTROL,
+ TSA552x_RADIO },
+ { 0x00, 0x00 }, /* band-switch crosspoints */
+ { 0xa0, 0x90, 0x30, 0xa4 } }, /* the band-switch values */
+
+ /* PHILIPS_FR1236_SECAM */
+ { "Philips FR1236 SECAM FM", /* the 'name' */
+ TTYPE_SECAM, /* input type */
+ { TSA552x_FCONTROL, /* control byte for Tuner PLL */
+ TSA552x_FCONTROL,
+ TSA552x_FCONTROL,
+ TSA552x_RADIO },
+ { 0x00, 0x00 }, /* band-switch crosspoints */
+ { 0xa7, 0x97, 0x37, 0xa4 } }, /* the band-switch values */
+
+ /* ALPS TSCH5 NTSC */
+ { "ALPS TSCH5 NTSC FM", /* the 'name' */
+ TTYPE_NTSC, /* input type */
+ { TSCH5_FCONTROL, /* control byte for Tuner PLL */
+ TSCH5_FCONTROL,
+ TSCH5_FCONTROL,
+ TSCH5_RADIO },
+ { 0x00, 0x00 }, /* band-switch crosspoints */
+ { 0x14, 0x12, 0x11, 0x04 } }, /* the band-switch values */
+
+ /* ALPS TSBH1 NTSC */
+ { "ALPS TSBH1 NTSC", /* the 'name' */
+ TTYPE_NTSC, /* input type */
+ { TSBH1_FCONTROL, /* control byte for Tuner PLL */
+ TSBH1_FCONTROL,
+ TSBH1_FCONTROL,
+ 0x00 },
+ { 0x00, 0x00 }, /* band-switch crosspoints */
+ { 0x01, 0x02, 0x08, 0x00 } } /* the band-switch values */
+};
+
+
+/* scaling factor for frequencies expressed as ints */
+#define FREQFACTOR 16
+
+/*
+ * Format:
+ * entry 0: MAX legal channel
+ * entry 1: IF frequency
+ * expressed as fi{mHz} * 16,
+ * eg 45.75mHz == 45.75 * 16 = 732
+ * entry 2: [place holder/future]
+ * entry 3: base of channel record 0
+ * entry 3 + (x*3): base of channel record 'x'
+ * entry LAST: NULL channel entry marking end of records
+ *
+ * Record:
+ * int 0: base channel
+ * int 1: frequency of base channel,
+ * expressed as fb{mHz} * 16,
+ * int 2: offset frequency between channels,
+ * expressed as fo{mHz} * 16,
+ */
+
+/*
+ * North American Broadcast Channels:
+ *
+ * 2: 55.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
+ *
+ * IF freq: 45.75 mHz
+ */
+#define OFFSET 6.00
+static int nabcst[] = {
+ 83, (int)( 45.75 * FREQFACTOR), 0,
+ 14, (int)(471.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
+ 7, (int)(175.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
+ 5, (int)( 77.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
+ 2, (int)( 55.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
+ 0
+};
+#undef OFFSET
+
+/*
+ * North American Cable Channels, IRC:
+ *
+ * 2: 55.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
+ *
+ * IF freq: 45.75 mHz
+ */
+#define OFFSET 6.00
+static int irccable[] = {
+ 116, (int)( 45.75 * FREQFACTOR), 0,
+ 100, (int)(649.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
+ 95, (int)( 91.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
+ 23, (int)(217.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
+ 14, (int)(121.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
+ 7, (int)(175.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
+ 5, (int)( 77.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
+ 2, (int)( 55.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
+ 0
+};
+#undef OFFSET
+
+/*
+ * North American Cable Channels, HRC:
+ *
+ * 2: 54 mHz - 4: 66 mHz
+ * 5: 78 mHz - 6: 84 mHz
+ * 7: 174 mHz - 13: 210 mHz
+ * 14: 120 mHz - 22: 168 mHz
+ * 23: 216 mHz - 94: 642 mHz
+ * 95: 90 mHz - 99: 114 mHz
+ *
+ * IF freq: 45.75 mHz
+ */
+#define OFFSET 6.00
+static int hrccable[] = {
+ 116, (int)( 45.75 * FREQFACTOR), 0,
+ 100, (int)(648.00 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
+ 95, (int)( 90.00 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
+ 23, (int)(216.00 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
+ 14, (int)(120.00 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
+ 7, (int)(174.00 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
+ 5, (int)( 78.00 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
+ 2, (int)( 54.00 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
+ 0
+};
+#undef OFFSET
+
+/*
+ * Western European broadcast channels:
+ *
+ * (there are others that appear to vary between countries - rmt)
+ *
+ * here's the table Philips provides:
+ * caution, some of the offsets don't compute...
+ *
+ * 1 4525 700 N21
+ *
+ * 2 4825 700 E2
+ * 3 5525 700 E3
+ * 4 6225 700 E4
+ *
+ * 5 17525 700 E5
+ * 6 18225 700 E6
+ * 7 18925 700 E7
+ * 8 19625 700 E8
+ * 9 20325 700 E9
+ * 10 21025 700 E10
+ * 11 21725 700 E11
+ * 12 22425 700 E12
+ *
+ * 13 5375 700 ITA
+ * 14 6225 700 ITB
+ *
+ * 15 8225 700 ITC
+ *
+ * 16 17525 700 ITD
+ * 17 18325 700 ITE
+ *
+ * 18 19225 700 ITF
+ * 19 20125 700 ITG
+ * 20 21025 700 ITH
+ *
+ * 21 47125 800 E21
+ * 22 47925 800 E22
+ * 23 48725 800 E23
+ * 24 49525 800 E24
+ * 25 50325 800 E25
+ * 26 51125 800 E26
+ * 27 51925 800 E27
+ * 28 52725 800 E28
+ * 29 53525 800 E29
+ * 30 54325 800 E30
+ * 31 55125 800 E31
+ * 32 55925 800 E32
+ * 33 56725 800 E33
+ * 34 57525 800 E34
+ * 35 58325 800 E35
+ * 36 59125 800 E36
+ * 37 59925 800 E37
+ * 38 60725 800 E38
+ * 39 61525 800 E39
+ * 40 62325 800 E40
+ * 41 63125 800 E41
+ * 42 63925 800 E42
+ * 43 64725 800 E43
+ * 44 65525 800 E44
+ * 45 66325 800 E45
+ * 46 67125 800 E46
+ * 47 67925 800 E47
+ * 48 68725 800 E48
+ * 49 69525 800 E49
+ * 50 70325 800 E50
+ * 51 71125 800 E51
+ * 52 71925 800 E52
+ * 53 72725 800 E53
+ * 54 73525 800 E54
+ * 55 74325 800 E55
+ * 56 75125 800 E56
+ * 57 75925 800 E57
+ * 58 76725 800 E58
+ * 59 77525 800 E59
+ * 60 78325 800 E60
+ * 61 79125 800 E61
+ * 62 79925 800 E62
+ * 63 80725 800 E63
+ * 64 81525 800 E64
+ * 65 82325 800 E65
+ * 66 83125 800 E66
+ * 67 83925 800 E67
+ * 68 84725 800 E68
+ * 69 85525 800 E69
+ *
+ * 70 4575 800 IA
+ * 71 5375 800 IB
+ * 72 6175 800 IC
+ *
+ * 74 6925 700 S01
+ * 75 7625 700 S02
+ * 76 8325 700 S03
+ *
+ * 80 10525 700 S1
+ * 81 11225 700 S2
+ * 82 11925 700 S3
+ * 83 12625 700 S4
+ * 84 13325 700 S5
+ * 85 14025 700 S6
+ * 86 14725 700 S7
+ * 87 15425 700 S8
+ * 88 16125 700 S9
+ * 89 16825 700 S10
+ * 90 23125 700 S11
+ * 91 23825 700 S12
+ * 92 24525 700 S13
+ * 93 25225 700 S14
+ * 94 25925 700 S15
+ * 95 26625 700 S16
+ * 96 27325 700 S17
+ * 97 28025 700 S18
+ * 98 28725 700 S19
+ * 99 29425 700 S20
+ *
+ *
+ * Channels S21 - S41 are taken from
+ * http://gemma.apple.com:80/dev/technotes/tn/tn1012.html
+ *
+ * 100 30325 800 S21
+ * 101 31125 800 S22
+ * 102 31925 800 S23
+ * 103 32725 800 S24
+ * 104 33525 800 S25
+ * 105 34325 800 S26
+ * 106 35125 800 S27
+ * 107 35925 800 S28
+ * 108 36725 800 S29
+ * 109 37525 800 S30
+ * 110 38325 800 S31
+ * 111 39125 800 S32
+ * 112 39925 800 S33
+ * 113 40725 800 S34
+ * 114 41525 800 S35
+ * 115 42325 800 S36
+ * 116 43125 800 S37
+ * 117 43925 800 S38
+ * 118 44725 800 S39
+ * 119 45525 800 S40
+ * 120 46325 800 S41
+ *
+ * 121 3890 000 IFFREQ
+ *
+ */
+static int weurope[] = {
+ 121, (int)( 38.90 * FREQFACTOR), 0,
+ 100, (int)(303.25 * FREQFACTOR), (int)(8.00 * FREQFACTOR),
+ 90, (int)(231.25 * FREQFACTOR), (int)(7.00 * FREQFACTOR),
+ 80, (int)(105.25 * FREQFACTOR), (int)(7.00 * FREQFACTOR),
+ 74, (int)( 69.25 * FREQFACTOR), (int)(7.00 * FREQFACTOR),
+ 21, (int)(471.25 * FREQFACTOR), (int)(8.00 * FREQFACTOR),
+ 17, (int)(183.25 * FREQFACTOR), (int)(9.00 * FREQFACTOR),
+ 16, (int)(175.25 * FREQFACTOR), (int)(9.00 * FREQFACTOR),
+ 15, (int)(82.25 * FREQFACTOR), (int)(8.50 * FREQFACTOR),
+ 13, (int)(53.75 * FREQFACTOR), (int)(8.50 * FREQFACTOR),
+ 5, (int)(175.25 * FREQFACTOR), (int)(7.00 * FREQFACTOR),
+ 2, (int)(48.25 * FREQFACTOR), (int)(7.00 * FREQFACTOR),
+ 0
+};
+
+/*
+ * Japanese Broadcast Channels:
+ *
+ * 1: 91.25MHz - 3: 103.25MHz
+ * 4: 171.25MHz - 7: 189.25MHz
+ * 8: 193.25MHz - 12: 217.25MHz (VHF)
+ * 13: 471.25MHz - 62: 765.25MHz (UHF)
+ *
+ * IF freq: 45.75 mHz
+ * OR
+ * IF freq: 58.75 mHz
+ */
+#define OFFSET 6.00
+#define IF_FREQ 45.75
+static int jpnbcst[] = {
+ 62, (int)(IF_FREQ * FREQFACTOR), 0,
+ 13, (int)(471.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
+ 8, (int)(193.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
+ 4, (int)(171.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
+ 1, (int)( 91.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
+ 0
+};
+#undef IF_FREQ
+#undef OFFSET
+
+/*
+ * Japanese Cable Channels:
+ *
+ * 1: 91.25MHz - 3: 103.25MHz
+ * 4: 171.25MHz - 7: 189.25MHz
+ * 8: 193.25MHz - 12: 217.25MHz
+ * 13: 109.25MHz - 21: 157.25MHz
+ * 22: 165.25MHz
+ * 23: 223.25MHz - 63: 463.25MHz
+ *
+ * IF freq: 45.75 mHz
+ */
+#define OFFSET 6.00
+#define IF_FREQ 45.75
+static int jpncable[] = {
+ 63, (int)(IF_FREQ * FREQFACTOR), 0,
+ 23, (int)(223.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
+ 22, (int)(165.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
+ 13, (int)(109.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
+ 8, (int)(193.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
+ 4, (int)(171.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
+ 1, (int)( 91.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
+ 0
+};
+#undef IF_FREQ
+#undef OFFSET
+
+/*
+ * xUSSR Broadcast Channels:
+ *
+ * 1: 49.75MHz - 2: 59.25MHz
+ * 3: 77.25MHz - 5: 93.25MHz
+ * 6: 175.25MHz - 12: 223.25MHz
+ * 13-20 - not exist
+ * 21: 471.25MHz - 34: 575.25MHz
+ * 35: 583.25MHz - 69: 855.25MHz
+ *
+ * Cable channels
+ *
+ * 70: 111.25MHz - 77: 167.25MHz
+ * 78: 231.25MHz -107: 463.25MHz
+ *
+ * IF freq: 38.90 MHz
+ */
+#define IF_FREQ 38.90
+static int xussr[] = {
+ 107, (int)(IF_FREQ * FREQFACTOR), 0,
+ 78, (int)(231.25 * FREQFACTOR), (int)(8.00 * FREQFACTOR),
+ 70, (int)(111.25 * FREQFACTOR), (int)(8.00 * FREQFACTOR),
+ 35, (int)(583.25 * FREQFACTOR), (int)(8.00 * FREQFACTOR),
+ 21, (int)(471.25 * FREQFACTOR), (int)(8.00 * FREQFACTOR),
+ 6, (int)(175.25 * FREQFACTOR), (int)(8.00 * FREQFACTOR),
+ 3, (int)( 77.25 * FREQFACTOR), (int)(8.00 * FREQFACTOR),
+ 1, (int)( 49.75 * FREQFACTOR), (int)(9.50 * FREQFACTOR),
+ 0
+};
+#undef IF_FREQ
+
+/*
+ * Australian broadcast channels
+ */
+#define OFFSET 7.00
+#define IF_FREQ 38.90
+static int australia[] = {
+ 83, (int)(IF_FREQ * FREQFACTOR), 0,
+ 28, (int)(527.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
+ 10, (int)(209.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
+ 6, (int)(175.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
+ 4, (int)( 95.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
+ 3, (int)( 86.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
+ 1, (int)( 57.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
+ 0
+};
+#undef OFFSET
+#undef IF_FREQ
+
+/*
+ * France broadcast channels
+ */
+#define OFFSET 8.00
+#define IF_FREQ 38.90
+static int france[] = {
+ 69, (int)(IF_FREQ * FREQFACTOR), 0,
+ 21, (int)(471.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), /* 21 -> 69 */
+ 5, (int)(176.00 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), /* 5 -> 10 */
+ 4, (int)( 63.75 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), /* 4 */
+ 3, (int)( 60.50 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), /* 3 */
+ 1, (int)( 47.75 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), /* 1 2 */
+ 0
+};
+#undef OFFSET
+#undef IF_FREQ
+
+static struct {
+ int *ptr;
+ char name[BT848_MAX_CHNLSET_NAME_LEN];
+} freqTable[] = {
+ {NULL, ""},
+ {nabcst, "nabcst"},
+ {irccable, "cableirc"},
+ {hrccable, "cablehrc"},
+ {weurope, "weurope"},
+ {jpnbcst, "jpnbcst"},
+ {jpncable, "jpncable"},
+ {xussr, "xussr"},
+ {australia, "australia"},
+ {france, "france"},
+
+};
+
+#define TBL_CHNL freqTable[ bktr->tuner.chnlset ].ptr[ x ]
+#define TBL_BASE_FREQ freqTable[ bktr->tuner.chnlset ].ptr[ x + 1 ]
+#define TBL_OFFSET freqTable[ bktr->tuner.chnlset ].ptr[ x + 2 ]
+static int
+frequency_lookup( bktr_ptr_t bktr, int channel )
+{
+ int x;
+
+ /* check for "> MAX channel" */
+ x = 0;
+ if ( channel > TBL_CHNL )
+ return( -1 );
+
+ /* search the table for data */
+ for ( x = 3; TBL_CHNL; x += 3 ) {
+ if ( channel >= TBL_CHNL ) {
+ return( TBL_BASE_FREQ +
+ ((channel - TBL_CHNL) * TBL_OFFSET) );
+ }
+ }
+
+ /* not found, must be below the MIN channel */
+ return( -1 );
+}
+#undef TBL_OFFSET
+#undef TBL_BASE_FREQ
+#undef TBL_CHNL
+
+
+#define TBL_IF freqTable[ bktr->tuner.chnlset ].ptr[ 1 ]
+
+
+/* Initialise the tuner structures in the bktr_softc */
+/* This is needed as the tuner details are no longer globally declared */
+
+void select_tuner( bktr_ptr_t bktr, int tuner_type ) {
+ if (tuner_type < Bt848_MAX_TUNER) {
+ bktr->card.tuner = &tuners[ tuner_type ];
+ } else {
+ bktr->card.tuner = NULL;
+ }
+}
+
+/*
+ * Tuner Notes:
+ * Programming the tuner properly is quite complicated.
+ * Here are some notes, based on a FM1246 data sheet for a PAL-I tuner.
+ * The tuner (front end) covers 45.75 Mhz - 855.25 Mhz and an FM band of
+ * 87.5 Mhz to 108.0 Mhz.
+ *
+ * RF and IF. RF = radio frequencies, it is the transmitted signal.
+ * IF is the Intermediate Frequency (the offset from the base
+ * signal where the video, color, audio and NICAM signals are.
+ *
+ * Eg, Picture at 38.9 Mhz, Colour at 34.47 MHz, sound at 32.9 MHz
+ * NICAM at 32.348 Mhz.
+ * Strangely enough, there is an IF (intermediate frequency) for
+ * FM Radio which is 10.7 Mhz.
+ *
+ * The tuner also works in Bands. Philips bands are
+ * FM radio band 87.50 to 108.00 MHz
+ * Low band 45.75 to 170.00 MHz
+ * Mid band 170.00 to 450.00 MHz
+ * High band 450.00 to 855.25 MHz
+ *
+ *
+ * Now we need to set the PLL on the tuner to the required freuqncy.
+ * It has a programmable divisor.
+ * For TV we want
+ * N = 16 (freq RF(pc) + freq IF(pc)) pc is picture carrier and RF and IF
+ * are in MHz.
+
+ * For RADIO we want a different equation.
+ * freq IF is 10.70 MHz (so the data sheet tells me)
+ * N = (freq RF + freq IF) / step size
+ * The step size must be set to 50 khz (so the data sheet tells me)
+ * (note this is 50 kHz, the other things are in MHz)
+ * so we end up with N = 20x(freq RF + 10.7)
+ *
+ */
+
+#define LOW_BAND 0
+#define MID_BAND 1
+#define HIGH_BAND 2
+#define FM_RADIO_BAND 3
+
+
+/* Check if these are correct for other than Philips PAL */
+#define STATUSBIT_COLD 0x80
+#define STATUSBIT_LOCK 0x40
+#define STATUSBIT_TV 0x20
+#define STATUSBIT_STEREO 0x10 /* valid if FM (aka not TV) */
+#define STATUSBIT_ADC 0x07
+
+/*
+ * set the frequency of the tuner
+ * If 'type' is TV_FREQUENCY, the frequency is freq MHz*16
+ * If 'type' is FM_RADIO_FREQUENCY, the frequency is freq MHz * 100
+ * (note *16 gives is 4 bits of fraction, eg steps of nnn.0625)
+ *
+ */
+int
+tv_freq( bktr_ptr_t bktr, int frequency, int type )
+{
+ const struct TUNER* tuner;
+ u_char addr;
+ u_char control;
+ u_char band;
+ int N;
+ int band_select = 0;
+#if defined( TEST_TUNER_AFC )
+ int oldFrequency, afcDelta;
+#endif
+
+ tuner = bktr->card.tuner;
+ if ( tuner == NULL )
+ return( -1 );
+
+ if (type == TV_FREQUENCY) {
+ /*
+ * select the band based on frequency
+ * XXX FIXME: get the cross-over points from the tuner struct
+ */
+ if ( frequency < (160 * FREQFACTOR ) )
+ band_select = LOW_BAND;
+ else if ( frequency < (454 * FREQFACTOR ) )
+ band_select = MID_BAND;
+ else
+ band_select = HIGH_BAND;
+
+#if defined( TEST_TUNER_AFC )
+ if ( bktr->tuner.afc )
+ frequency -= 4;
+#endif
+ /*
+ * N = 16 * { fRF(pc) + fIF(pc) }
+ * or N = 16* fRF(pc) + 16*fIF(pc) }
+ * where:
+ * pc is picture carrier, fRF & fIF are in MHz
+ *
+ * fortunatly, frequency is passed in as MHz * 16
+ * and the TBL_IF frequency is also stored in MHz * 16
+ */
+ N = frequency + TBL_IF;
+
+ /* set the address of the PLL */
+ addr = bktr->card.tuner_pllAddr;
+ control = tuner->pllControl[ band_select ];
+ band = tuner->bandAddrs[ band_select ];
+
+ if(!(band && control)) /* Don't try to set un- */
+ return(-1); /* supported modes. */
+
+ if ( frequency > bktr->tuner.frequency ) {
+ i2cWrite( bktr, addr, (N>>8) & 0x7f, N & 0xff );
+ i2cWrite( bktr, addr, control, band );
+ }
+ else {
+ i2cWrite( bktr, addr, control, band );
+ i2cWrite( bktr, addr, (N>>8) & 0x7f, N & 0xff );
+ }
+
+#if defined( TUNER_AFC )
+ if ( bktr->tuner.afc == TRUE ) {
+#if defined( TEST_TUNER_AFC )
+ oldFrequency = frequency;
+#endif
+ if ( (N = do_afc( bktr, addr, N )) < 0 ) {
+ /* AFC failed, restore requested frequency */
+ N = frequency + TBL_IF;
+#if defined( TEST_TUNER_AFC )
+ printf("%s: do_afc: failed to lock\n",
+ bktr_name(bktr));
+#endif
+ i2cWrite( bktr, addr, (N>>8) & 0x7f, N & 0xff );
+ }
+ else
+ frequency = N - TBL_IF;
+#if defined( TEST_TUNER_AFC )
+ printf("%s: do_afc: returned freq %d (%d %% %d)\n", bktr_name(bktr), frequency, frequency / 16, frequency % 16);
+ afcDelta = frequency - oldFrequency;
+ printf("%s: changed by: %d clicks (%d mod %d)\n", bktr_name(bktr), afcDelta, afcDelta / 16, afcDelta % 16);
+#endif
+ }
+#endif /* TUNER_AFC */
+
+ bktr->tuner.frequency = frequency;
+ }
+
+ if ( type == FM_RADIO_FREQUENCY ) {
+ band_select = FM_RADIO_BAND;
+
+ /*
+ * N = { fRF(pc) + fIF(pc) }/step_size
+ * The step size is 50kHz for FM radio.
+ * (eg after 102.35MHz comes 102.40 MHz)
+ * fIF is 10.7 MHz (as detailed in the specs)
+ *
+ * frequency is passed in as MHz * 100
+ *
+ * So, we have N = (frequency/100 + 10.70) /(50/1000)
+ */
+ N = (frequency + 1070)/5;
+
+ /* set the address of the PLL */
+ addr = bktr->card.tuner_pllAddr;
+ control = tuner->pllControl[ band_select ];
+ band = tuner->bandAddrs[ band_select ];
+
+ if(!(band && control)) /* Don't try to set un- */
+ return(-1); /* supported modes. */
+
+ band |= bktr->tuner.radio_mode; /* tuner.radio_mode is set in
+ * the ioctls RADIO_SETMODE
+ * and RADIO_GETMODE */
+
+ i2cWrite( bktr, addr, control, band );
+ i2cWrite( bktr, addr, (N>>8) & 0x7f, N & 0xff );
+
+ bktr->tuner.frequency = (N * 5) - 1070;
+
+
+ }
+
+
+ return( 0 );
+}
+
+
+
+#if defined( TUNER_AFC )
+/*
+ *
+ */
+int
+do_afc( bktr_ptr_t bktr, int addr, int frequency )
+{
+ int step;
+ int status;
+ int origFrequency;
+
+ origFrequency = frequency;
+
+ /* wait for first setting to take effect */
+ tsleep( BKTR_SLEEP, PZERO, "tuning", hz/8 );
+
+ if ( (status = i2cRead( bktr, addr + 1 )) < 0 )
+ return( -1 );
+
+#if defined( TEST_TUNER_AFC )
+ printf( "%s: Original freq: %d, status: 0x%02x\n", bktr_name(bktr), frequency, status );
+#endif
+ for ( step = 0; step < AFC_MAX_STEP; ++step ) {
+ if ( (status = i2cRead( bktr, addr + 1 )) < 0 )
+ goto fubar;
+ if ( !(status & 0x40) ) {
+#if defined( TEST_TUNER_AFC )
+ printf( "%s: no lock!\n", bktr_name(bktr) );
+#endif
+ goto fubar;
+ }
+
+ switch( status & AFC_BITS ) {
+ case AFC_FREQ_CENTERED:
+#if defined( TEST_TUNER_AFC )
+ printf( "%s: Centered, freq: %d, status: 0x%02x\n", bktr_name(bktr), frequency, status );
+#endif
+ return( frequency );
+
+ case AFC_FREQ_MINUS_125:
+ case AFC_FREQ_MINUS_62:
+#if defined( TEST_TUNER_AFC )
+ printf( "%s: Low, freq: %d, status: 0x%02x\n", bktr_name(bktr), frequency, status );
+#endif
+ --frequency;
+ break;
+
+ case AFC_FREQ_PLUS_62:
+ case AFC_FREQ_PLUS_125:
+#if defined( TEST_TUNER_AFC )
+ printf( "%s: Hi, freq: %d, status: 0x%02x\n", bktr_name(bktr), frequency, status );
+#endif
+ ++frequency;
+ break;
+ }
+
+ i2cWrite( bktr, addr,
+ (frequency>>8) & 0x7f, frequency & 0xff );
+ DELAY( AFC_DELAY );
+ }
+
+ fubar:
+ i2cWrite( bktr, addr,
+ (origFrequency>>8) & 0x7f, origFrequency & 0xff );
+
+ return( -1 );
+}
+#endif /* TUNER_AFC */
+#undef TBL_IF
+
+
+/*
+ * Get the Tuner status and signal strength
+ */
+int get_tuner_status( bktr_ptr_t bktr ) {
+ return i2cRead( bktr, bktr->card.tuner_pllAddr + 1 );
+}
+
+/*
+ * set the channel of the tuner
+ */
+int
+tv_channel( bktr_ptr_t bktr, int channel )
+{
+ int frequency;
+
+ /* calculate the frequency according to tuner type */
+ if ( (frequency = frequency_lookup( bktr, channel )) < 0 )
+ return( -1 );
+
+ /* set the new frequency */
+ if ( tv_freq( bktr, frequency, TV_FREQUENCY ) < 0 )
+ return( -1 );
+
+ /* OK to update records */
+ return( (bktr->tuner.channel = channel) );
+}
+
+/*
+ * get channelset name
+ */
+int
+tuner_getchnlset(struct bktr_chnlset *chnlset)
+{
+ if (( chnlset->index < CHNLSET_MIN ) ||
+ ( chnlset->index > CHNLSET_MAX ))
+ return( EINVAL );
+
+ memcpy(&chnlset->name, &freqTable[chnlset->index].name,
+ BT848_MAX_CHNLSET_NAME_LEN);
+
+ chnlset->max_channel=freqTable[chnlset->index].ptr[0];
+ return( 0 );
+}
diff --git a/sys/dev/pci/bktr/bktr_tuner.h b/sys/dev/pci/bktr/bktr_tuner.h
new file mode 100644
index 00000000000..5ca817d26e7
--- /dev/null
+++ b/sys/dev/pci/bktr/bktr_tuner.h
@@ -0,0 +1,104 @@
+/* $OpenBSD: bktr_tuner.h,v 1.1 2001/03/28 03:27:10 fgsch Exp $ */
+/* $FreeBSD: src/sys/dev/bktr/bktr_tuner.h,v 1.1 1999/09/26 22:06:20 roger Exp $ */
+
+/*
+ * This is part of the Driver for Video Capture Cards (Frame grabbers)
+ * and TV Tuner cards using the Brooktree Bt848, Bt848A, Bt849A, Bt878, Bt879
+ * chipset.
+ * Copyright Roger Hardiman and Amancio Hasty.
+ *
+ * bktr_tuner : This deals with controlling the tuner fitted to TV cards.
+ *
+ */
+
+/*
+ * 1. Redistributions of source code must retain the
+ * Copyright (c) 1997 Amancio Hasty, 1999 Roger Hardiman
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Amancio Hasty and
+ * Roger Hardiman
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Definitions for Tuners */
+
+#define NO_TUNER 0
+#define TEMIC_NTSC 1
+#define TEMIC_PAL 2
+#define TEMIC_SECAM 3
+#define PHILIPS_NTSC 4
+#define PHILIPS_PAL 5
+#define PHILIPS_SECAM 6
+#define TEMIC_PALI 7
+#define PHILIPS_PALI 8
+#define PHILIPS_FR1236_NTSC 9 /* These have FM radio support */
+#define PHILIPS_FR1216_PAL 10 /* These have FM radio support */
+#define PHILIPS_FR1236_SECAM 11 /* These have FM radio support */
+#define ALPS_TSCH5 12
+#define ALPS_TSBH1 13
+#define Bt848_MAX_TUNER 14
+
+/* experimental code for Automatic Frequency Control */
+#define TUNER_AFC
+
+/*
+ * Fill in the tuner entries in the bktr_softc based on the selected tuner
+ * type (from the list of tuners above)
+ */
+void select_tuner( bktr_ptr_t bktr, int tuner_type );
+
+
+/*
+ * The Channel Set maps TV channels eg Ch 36, Ch 51, onto frequencies
+ * and is country specific.
+ */
+int tuner_getchnlset( struct bktr_chnlset *chnlset );
+
+/*
+ * tv_channel sets the tuner to channel 'n' using the current Channel Set
+ * tv_freq sets the tuner to a specific frequency for TV or for FM Radio
+ * get_tuner_status can be used to get the signal strength.
+ */
+#define TV_FREQUENCY 0
+#define FM_RADIO_FREQUENCY 1
+int tv_channel( bktr_ptr_t bktr, int channel );
+int tv_freq( bktr_ptr_t bktr, int frequency, int type );
+int get_tuner_status( bktr_ptr_t bktr );
+
+#if defined( TUNER_AFC )
+int do_afc( bktr_ptr_t bktr, int addr, int frequency );
+#endif /* TUNER_AFC */
+
+
+/*
+ * This is for start-up convenience only, NOT mandatory.
+ */
+#if !defined( DEFAULT_CHNLSET )
+#define DEFAULT_CHNLSET CHNLSET_WEUROPE
+#endif
+
+