summaryrefslogtreecommitdiff
path: root/sys/dev/bktr/bktr_core.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/bktr/bktr_core.c')
-rw-r--r--sys/dev/bktr/bktr_core.c4316
1 files changed, 4316 insertions, 0 deletions
diff --git a/sys/dev/bktr/bktr_core.c b/sys/dev/bktr/bktr_core.c
new file mode 100644
index 000000000000..41f0b09ad6ea
--- /dev/null
+++ b/sys/dev/bktr/bktr_core.c
@@ -0,0 +1,4316 @@
+/*-
+ * 1. Redistributions of source code must retain the
+ * Copyright (c) 1997 Amancio Hasty, 1999 Roger Hardiman
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Amancio Hasty and
+ * Roger Hardiman
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*-
+ * 1. Redistributions of source code must retain the
+ * Copyright (c) 1995 Mark Tinguely and Jim Lowe
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Tinguely and Jim Lowe
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * This is part of the Driver for Video Capture Cards (Frame grabbers)
+ * and TV Tuner cards using the Brooktree Bt848, Bt848A, Bt849A, Bt878, Bt879
+ * chipset.
+ * Copyright Roger Hardiman and Amancio Hasty.
+ *
+ * bktr_core : This deals with the Bt848/849/878/879 PCI Frame Grabber,
+ * Handles all the open, close, ioctl and read userland calls.
+ * Sets the Bt848 registers and generates RISC pograms.
+ * Controls the i2c bus and GPIO interface.
+ * Contains the interface to the kernel.
+ * (eg probe/attach and open/close/ioctl)
+ */
+
+ /*
+ The Brooktree BT848 Driver driver is based upon Mark Tinguely and
+ Jim Lowe's driver for the Matrox Meteor PCI card . The
+ Philips SAA 7116 and SAA 7196 are very different chipsets than
+ the BT848.
+
+ The original copyright notice by Mark and Jim is included mostly
+ to honor their fantastic work in the Matrox Meteor driver!
+ */
+
+#include "opt_bktr.h" /* Include any kernel config options */
+
+#if ( \
+ (defined(__FreeBSD__)) \
+ || (defined(__bsdi__)) \
+ || (defined(__OpenBSD__)) \
+ || (defined(__NetBSD__)) \
+ )
+
+
+/*******************/
+/* *** FreeBSD *** */
+/*******************/
+#ifdef __FreeBSD__
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/fcntl.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/signalvar.h>
+#include <sys/selinfo.h>
+#include <sys/uio.h>
+
+#include <vm/vm.h>
+#include <vm/vm_kern.h>
+#include <vm/pmap.h>
+#include <vm/vm_extern.h>
+
+#include <sys/bus.h> /* used by smbus and newbus */
+
+#if (__FreeBSD_version < 500000)
+#include <machine/clock.h> /* for DELAY */
+#define PROC_LOCK(p)
+#define PROC_UNLOCK(p)
+#include <pci/pcivar.h>
+#else
+#include <dev/pci/pcivar.h>
+#endif
+
+#include <machine/bus.h>
+#include <sys/bus.h>
+
+#include <dev/bktr/ioctl_meteor.h>
+#include <dev/bktr/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;
+}
+
+
+#endif /* __FreeBSD__ */
+
+
+/****************/
+/* *** BSDI *** */
+/****************/
+#ifdef __bsdi__
+#define PROC_LOCK(p)
+#define PROC_UNLOCK(p)
+#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>
+#include <vm/vm_kern.h>
+#include <vm/pmap.h>
+#include <vm/vm_extern.h>
+#endif
+
+#include <sys/inttypes.h> /* uintptr_t */
+#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);
+}
+
+#define PROC_LOCK(p)
+#define PROC_UNLOCK(p)
+
+#endif /* __NetBSD__ || __OpenBSD__ */
+
+
+typedef u_char bool_t;
+
+#define BKTRPRI (PZERO+8)|PCATCH
+#define VBIPRI (PZERO-4)|PCATCH
+
+
+/*
+ * memory allocated for DMA programs
+ */
+#define DMA_PROG_ALLOC (8 * PAGE_SIZE)
+
+/* When to split a dma transfer , the bt848 has timing as well as
+ dma transfer size limitations so that we have to split dma
+ transfers into two dma requests
+ */
+#define DMA_BT848_SPLIT 319*2
+
+/*
+ * Allocate enough memory for:
+ * 768x576 RGB 16 or YUV (16 storage bits/pixel) = 884736 = 216 pages
+ *
+ * You may override this using the options "BROOKTREE_ALLOC_PAGES=value"
+ * in your kernel configuration file.
+ */
+
+#ifndef BROOKTREE_ALLOC_PAGES
+#define BROOKTREE_ALLOC_PAGES 217*4
+#endif
+#define BROOKTREE_ALLOC (BROOKTREE_ALLOC_PAGES * PAGE_SIZE)
+
+/* Definitions for VBI capture.
+ * There are 16 VBI lines in a PAL video field (32 in a frame),
+ * and we take 2044 samples from each line (placed in a 2048 byte buffer
+ * for alignment).
+ * VBI lines are held in a circular buffer before being read by a
+ * user program from /dev/vbi.
+ */
+
+#define MAX_VBI_LINES 16 /* Maximum for all vidoe formats */
+#define VBI_LINE_SIZE 2048 /* Store upto 2048 bytes per line */
+#define VBI_BUFFER_ITEMS 20 /* Number of frames we buffer */
+#define VBI_DATA_SIZE (VBI_LINE_SIZE * MAX_VBI_LINES * 2)
+#define VBI_BUFFER_SIZE (VBI_DATA_SIZE * VBI_BUFFER_ITEMS)
+
+
+/* Defines for fields */
+#define ODD_F 0x01
+#define EVEN_F 0x02
+
+
+/*
+ * Parameters describing size of transmitted image.
+ */
+
+static struct format_params format_params[] = {
+/* # define BT848_IFORM_F_AUTO (0x0) - don't matter. */
+ { 525, 26, 480, 910, 135, 754, 640, 780, 30, 0x68, 0x5d, BT848_IFORM_X_AUTO,
+ 12, 1600 },
+/* # define BT848_IFORM_F_NTSCM (0x1) */
+ { 525, 26, 480, 910, 135, 754, 640, 780, 30, 0x68, 0x5d, BT848_IFORM_X_XT0,
+ 12, 1600 },
+/* # define BT848_IFORM_F_NTSCJ (0x2) */
+ { 525, 22, 480, 910, 135, 754, 640, 780, 30, 0x68, 0x5d, BT848_IFORM_X_XT0,
+ 12, 1600 },
+/* # define BT848_IFORM_F_PALBDGHI (0x3) */
+ { 625, 32, 576, 1135, 186, 924, 768, 944, 25, 0x7f, 0x72, BT848_IFORM_X_XT1,
+ 16, 2044 },
+/* # define BT848_IFORM_F_PALM (0x4) */
+ { 525, 22, 480, 910, 135, 754, 640, 780, 30, 0x68, 0x5d, BT848_IFORM_X_XT0,
+ 12, 1600 },
+/* # define BT848_IFORM_F_PALN (0x5) */
+ { 625, 32, 576, 1135, 186, 924, 768, 944, 25, 0x7f, 0x72, BT848_IFORM_X_XT1,
+ 16, 2044 },
+/* # define BT848_IFORM_F_SECAM (0x6) */
+ { 625, 32, 576, 1135, 186, 924, 768, 944, 25, 0x7f, 0xa0, BT848_IFORM_X_XT1,
+ 16, 2044 },
+/* # define BT848_IFORM_F_RSVD (0x7) - ???? */
+ { 625, 32, 576, 1135, 186, 924, 768, 944, 25, 0x7f, 0x72, BT848_IFORM_X_XT0,
+ 16, 2044 },
+};
+
+/*
+ * Table of supported Pixel Formats
+ */
+
+static struct meteor_pixfmt_internal {
+ struct meteor_pixfmt public;
+ u_int color_fmt;
+} pixfmt_table[] = {
+
+{ { 0, METEOR_PIXTYPE_RGB, 2, { 0x7c00, 0x03e0, 0x001f }, 0,0 }, 0x33 },
+{ { 0, METEOR_PIXTYPE_RGB, 2, { 0x7c00, 0x03e0, 0x001f }, 1,0 }, 0x33 },
+
+{ { 0, METEOR_PIXTYPE_RGB, 2, { 0xf800, 0x07e0, 0x001f }, 0,0 }, 0x22 },
+{ { 0, METEOR_PIXTYPE_RGB, 2, { 0xf800, 0x07e0, 0x001f }, 1,0 }, 0x22 },
+
+{ { 0, METEOR_PIXTYPE_RGB, 3, { 0xff0000,0x00ff00,0x0000ff }, 1,0 }, 0x11 },
+
+{ { 0, METEOR_PIXTYPE_RGB, 4, { 0xff0000,0x00ff00,0x0000ff }, 0,0 }, 0x00 },
+{ { 0, METEOR_PIXTYPE_RGB, 4, { 0xff0000,0x00ff00,0x0000ff }, 0,1 }, 0x00 },
+{ { 0, METEOR_PIXTYPE_RGB, 4, { 0xff0000,0x00ff00,0x0000ff }, 1,0 }, 0x00 },
+{ { 0, METEOR_PIXTYPE_RGB, 4, { 0xff0000,0x00ff00,0x0000ff }, 1,1 }, 0x00 },
+{ { 0, METEOR_PIXTYPE_YUV, 2, { 0xff0000,0x00ff00,0x0000ff }, 1,1 }, 0x88 },
+{ { 0, METEOR_PIXTYPE_YUV_PACKED, 2, { 0xff0000,0x00ff00,0x0000ff }, 0,1 }, 0x44 },
+{ { 0, METEOR_PIXTYPE_YUV_12, 2, { 0xff0000,0x00ff00,0x0000ff }, 1,1 }, 0x88 },
+
+};
+#define PIXFMT_TABLE_SIZE ( sizeof(pixfmt_table) / sizeof(pixfmt_table[0]) )
+
+/*
+ * Table of Meteor-supported Pixel Formats (for SETGEO compatibility)
+ */
+
+/* FIXME: Also add YUV_422 and YUV_PACKED as well */
+static struct {
+ u_long meteor_format;
+ struct meteor_pixfmt public;
+} meteor_pixfmt_table[] = {
+ { METEOR_GEO_YUV_12,
+ { 0, METEOR_PIXTYPE_YUV_12, 2, { 0xff0000,0x00ff00,0x0000ff }, 1,1 }
+ },
+
+ /* FIXME: Should byte swap flag be on for this one; negative in drvr? */
+ { METEOR_GEO_YUV_422,
+ { 0, METEOR_PIXTYPE_YUV, 2, { 0xff0000,0x00ff00,0x0000ff }, 1,1 }
+ },
+ { METEOR_GEO_YUV_PACKED,
+ { 0, METEOR_PIXTYPE_YUV_PACKED, 2, { 0xff0000,0x00ff00,0x0000ff }, 0,1 }
+ },
+ { METEOR_GEO_RGB16,
+ { 0, METEOR_PIXTYPE_RGB, 2, { 0x7c00, 0x03e0, 0x001f }, 0, 0 }
+ },
+ { METEOR_GEO_RGB24,
+ { 0, METEOR_PIXTYPE_RGB, 4, { 0xff0000, 0x00ff00, 0x0000ff }, 0, 0 }
+ },
+
+};
+#define METEOR_PIXFMT_TABLE_SIZE ( sizeof(meteor_pixfmt_table) / \
+ sizeof(meteor_pixfmt_table[0]) )
+
+
+#define BSWAP (BT848_COLOR_CTL_BSWAP_ODD | BT848_COLOR_CTL_BSWAP_EVEN)
+#define WSWAP (BT848_COLOR_CTL_WSWAP_ODD | BT848_COLOR_CTL_WSWAP_EVEN)
+
+
+
+/* sync detect threshold */
+#if 0
+#define SYNC_LEVEL (BT848_ADC_RESERVED | \
+ BT848_ADC_CRUSH) /* threshold ~125 mV */
+#else
+#define SYNC_LEVEL (BT848_ADC_RESERVED | \
+ BT848_ADC_SYNC_T) /* threshold ~75 mV */
+#endif
+
+
+
+
+/* debug utility for holding previous INT_STAT contents */
+#define STATUS_SUM
+static u_long status_sum = 0;
+
+/*
+ * defines to make certain bit-fiddles understandable
+ */
+#define FIFO_ENABLED BT848_DMA_CTL_FIFO_EN
+#define RISC_ENABLED BT848_DMA_CTL_RISC_EN
+#define FIFO_RISC_ENABLED (BT848_DMA_CTL_FIFO_EN | BT848_DMA_CTL_RISC_EN)
+#define FIFO_RISC_DISABLED 0
+
+#define ALL_INTS_DISABLED 0
+#define ALL_INTS_CLEARED 0xffffffff
+#define CAPTURE_OFF 0
+
+#define BIT_SEVEN_HIGH (1<<7)
+#define BIT_EIGHT_HIGH (1<<8)
+
+#define I2C_BITS (BT848_INT_RACK | BT848_INT_I2CDONE)
+#define TDEC_BITS (BT848_INT_FDSR | BT848_INT_FBUS)
+
+
+
+static int oformat_meteor_to_bt( u_long format );
+
+static u_int pixfmt_swap_flags( int pixfmt );
+
+/*
+ * bt848 RISC programming routines.
+ */
+#ifdef BT848_DUMP
+static int dump_bt848( bktr_ptr_t bktr );
+#endif
+
+static void yuvpack_prog( bktr_ptr_t bktr, char i_flag, int cols,
+ int rows, int interlace );
+static void yuv422_prog( bktr_ptr_t bktr, char i_flag, int cols,
+ int rows, int interlace );
+static void yuv12_prog( bktr_ptr_t bktr, char i_flag, int cols,
+ int rows, int interlace );
+static void rgb_prog( bktr_ptr_t bktr, char i_flag, int cols,
+ int rows, int interlace );
+static void rgb_vbi_prog( bktr_ptr_t bktr, char i_flag, int cols,
+ int rows, int interlace );
+static void build_dma_prog( bktr_ptr_t bktr, char i_flag );
+
+static bool_t getline(bktr_reg_t *, int);
+static bool_t notclipped(bktr_reg_t * , int , int);
+static bool_t split(bktr_reg_t *, volatile uint32_t **, int, u_long, int,
+ volatile u_char ** , int );
+
+static void start_capture( bktr_ptr_t bktr, unsigned type );
+static void set_fps( bktr_ptr_t bktr, u_short fps );
+
+
+
+/*
+ * Remote Control Functions
+ */
+static void remote_read(bktr_ptr_t bktr, struct bktr_remote *remote);
+
+
+/*
+ * ioctls common to both video & tuner.
+ */
+static int common_ioctl( bktr_ptr_t bktr, ioctl_cmd_t cmd, caddr_t arg );
+
+
+#if !defined(BKTR_USE_FREEBSD_SMBUS)
+/*
+ * i2c primitives for low level control of i2c bus. Added for MSP34xx control
+ */
+static void i2c_start( bktr_ptr_t bktr);
+static void i2c_stop( bktr_ptr_t bktr);
+static int i2c_write_byte( bktr_ptr_t bktr, unsigned char data);
+static int i2c_read_byte( bktr_ptr_t bktr, unsigned char *data, int last );
+#endif
+
+
+
+/*
+ * the common attach code, used by all OS versions.
+ */
+void
+common_bktr_attach( bktr_ptr_t bktr, int unit, u_long pci_id, u_int rev )
+{
+ vm_offset_t buf = 0;
+ int need_to_allocate_memory = 1;
+#ifdef BKTR_NEW_MSP34XX_DRIVER
+ int err;
+#endif
+
+/***************************************/
+/* *** OS Specific memory routines *** */
+/***************************************/
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+ /* allocate space for dma program */
+ bktr->dma_prog = get_bktr_mem(bktr, &bktr->dm_prog,
+ DMA_PROG_ALLOC);
+ bktr->odd_dma_prog = get_bktr_mem(bktr, &bktr->dm_oprog,
+ DMA_PROG_ALLOC);
+
+ /* allocate space for the VBI buffer */
+ bktr->vbidata = get_bktr_mem(bktr, &bktr->dm_vbidata,
+ VBI_DATA_SIZE);
+ bktr->vbibuffer = get_bktr_mem(bktr, &bktr->dm_vbibuffer,
+ VBI_BUFFER_SIZE);
+
+ /* allocate space for pixel buffer */
+ if ( BROOKTREE_ALLOC )
+ buf = get_bktr_mem(bktr, &bktr->dm_mem, BROOKTREE_ALLOC);
+ else
+ buf = 0;
+#endif
+
+#if defined(__FreeBSD__) || defined(__bsdi__)
+
+/* If this is a module, check if there is any currently saved contiguous memory */
+#if defined(BKTR_FREEBSD_MODULE)
+ if (bktr_has_stored_addresses(unit) == 1) {
+ /* recover the addresses */
+ bktr->dma_prog = bktr_retrieve_address(unit, BKTR_MEM_DMA_PROG);
+ bktr->odd_dma_prog = bktr_retrieve_address(unit, BKTR_MEM_ODD_DMA_PROG);
+ bktr->vbidata = bktr_retrieve_address(unit, BKTR_MEM_VBIDATA);
+ bktr->vbibuffer = bktr_retrieve_address(unit, BKTR_MEM_VBIBUFFER);
+ buf = bktr_retrieve_address(unit, BKTR_MEM_BUF);
+ need_to_allocate_memory = 0;
+ }
+#endif
+
+ if (need_to_allocate_memory == 1) {
+ /* allocate space for dma program */
+ bktr->dma_prog = get_bktr_mem(unit, DMA_PROG_ALLOC);
+ bktr->odd_dma_prog = get_bktr_mem(unit, DMA_PROG_ALLOC);
+
+ /* allocte space for the VBI buffer */
+ bktr->vbidata = get_bktr_mem(unit, VBI_DATA_SIZE);
+ bktr->vbibuffer = get_bktr_mem(unit, VBI_BUFFER_SIZE);
+
+ /* allocate space for pixel buffer */
+ if ( BROOKTREE_ALLOC )
+ buf = get_bktr_mem(unit, BROOKTREE_ALLOC);
+ else
+ buf = 0;
+ }
+#endif /* FreeBSD or BSDi */
+
+#ifdef USE_VBIMUTEX
+ mtx_init(&bktr->vbimutex, "bktr vbi lock", NULL, MTX_DEF);
+#endif
+
+/* If this is a module, save the current contiguous memory */
+#if defined(BKTR_FREEBSD_MODULE)
+bktr_store_address(unit, BKTR_MEM_DMA_PROG, bktr->dma_prog);
+bktr_store_address(unit, BKTR_MEM_ODD_DMA_PROG, bktr->odd_dma_prog);
+bktr_store_address(unit, BKTR_MEM_VBIDATA, bktr->vbidata);
+bktr_store_address(unit, BKTR_MEM_VBIBUFFER, bktr->vbibuffer);
+bktr_store_address(unit, BKTR_MEM_BUF, buf);
+#endif
+
+
+ if ( bootverbose ) {
+ printf("%s: buffer size %d, addr %p\n",
+ bktr_name(bktr), BROOKTREE_ALLOC,
+ (void *)(uintptr_t)vtophys(buf));
+ }
+
+ if ( buf != 0 ) {
+ bktr->bigbuf = buf;
+ bktr->alloc_pages = BROOKTREE_ALLOC_PAGES;
+ bzero((caddr_t) bktr->bigbuf, BROOKTREE_ALLOC);
+ } else {
+ bktr->alloc_pages = 0;
+ }
+
+
+ bktr->flags = METEOR_INITALIZED | METEOR_AUTOMODE |
+ METEOR_DEV0 | METEOR_RGB16;
+ bktr->dma_prog_loaded = FALSE;
+ bktr->cols = 640;
+ bktr->rows = 480;
+ bktr->frames = 1; /* one frame */
+ bktr->format = METEOR_GEO_RGB16;
+ bktr->pixfmt = oformat_meteor_to_bt( bktr->format );
+ bktr->pixfmt_compat = TRUE;
+
+
+ bktr->vbiinsert = 0;
+ bktr->vbistart = 0;
+ bktr->vbisize = 0;
+ bktr->vbiflags = 0;
+
+
+ /* using the pci device id and revision id */
+ /* and determine the card type */
+ if (PCI_VENDOR(pci_id) == PCI_VENDOR_BROOKTREE)
+ {
+ switch (PCI_PRODUCT(pci_id)) {
+ case PCI_PRODUCT_BROOKTREE_BT848:
+ if (rev == 0x12)
+ bktr->id = BROOKTREE_848A;
+ else
+ bktr->id = BROOKTREE_848;
+ break;
+ case PCI_PRODUCT_BROOKTREE_BT849:
+ bktr->id = BROOKTREE_849A;
+ break;
+ case PCI_PRODUCT_BROOKTREE_BT878:
+ bktr->id = BROOKTREE_878;
+ break;
+ case PCI_PRODUCT_BROOKTREE_BT879:
+ bktr->id = BROOKTREE_879;
+ break;
+ }
+ };
+
+ bktr->clr_on_start = FALSE;
+
+ /* defaults for the tuner section of the card */
+ bktr->tflags = TUNER_INITALIZED;
+ bktr->tuner.frequency = 0;
+ bktr->tuner.channel = 0;
+ bktr->tuner.chnlset = DEFAULT_CHNLSET;
+ bktr->tuner.afc = 0;
+ bktr->tuner.radio_mode = 0;
+ bktr->audio_mux_select = 0;
+ bktr->audio_mute_state = FALSE;
+ bktr->bt848_card = -1;
+ bktr->bt848_tuner = -1;
+ bktr->reverse_mute = -1;
+ bktr->slow_msp_audio = 0;
+ bktr->msp_use_mono_source = 0;
+ bktr->msp_source_selected = -1;
+ bktr->audio_mux_present = 1;
+
+#if defined(__FreeBSD__)
+#ifdef BKTR_NEW_MSP34XX_DRIVER
+ /* get hint on short programming of the msp34xx, so we know */
+ /* if the decision what thread to start should be overwritten */
+ if ( (err = resource_int_value("bktr", unit, "mspsimple",
+ &(bktr->mspsimple)) ) != 0 )
+ bktr->mspsimple = -1; /* fall back to default */
+#endif
+#endif
+
+ probeCard( bktr, TRUE, unit );
+
+ /* Initialise any MSP34xx or TDA98xx audio chips */
+ init_audio_devices( bktr );
+
+#ifdef BKTR_NEW_MSP34XX_DRIVER
+ /* setup the kenrel thread */
+ err = msp_attach( bktr );
+ if ( err != 0 ) /* error doing kernel thread stuff, disable msp3400c */
+ bktr->card.msp3400c = 0;
+#endif
+
+
+}
+
+
+/* Copy the vbi lines from 'vbidata' into the circular buffer, 'vbibuffer'.
+ * The circular buffer holds 'n' fixed size data blocks.
+ * vbisize is the number of bytes in the circular buffer
+ * vbiread is the point we reading data out of the circular buffer
+ * vbiinsert is the point we insert data into the circular buffer
+ */
+static void vbidecode(bktr_ptr_t bktr) {
+ unsigned char *dest;
+ unsigned int *seq_dest;
+
+ /* Check if there is room in the buffer to insert the data. */
+ if (bktr->vbisize + VBI_DATA_SIZE > VBI_BUFFER_SIZE) return;
+
+ /* Copy the VBI data into the next free slot in the buffer. */
+ /* 'dest' is the point in vbibuffer where we want to insert new data */
+ dest = (unsigned char *)bktr->vbibuffer + bktr->vbiinsert;
+ memcpy(dest, (unsigned char*)bktr->vbidata, VBI_DATA_SIZE);
+
+ /* Write the VBI sequence number to the end of the vbi data */
+ /* This is used by the AleVT teletext program */
+ seq_dest = (unsigned int *)((unsigned char *)bktr->vbibuffer
+ + bktr->vbiinsert
+ + (VBI_DATA_SIZE - sizeof(bktr->vbi_sequence_number)));
+ *seq_dest = bktr->vbi_sequence_number;
+
+ /* And increase the VBI sequence number */
+ /* This can wrap around */
+ bktr->vbi_sequence_number++;
+
+
+ /* Increment the vbiinsert pointer */
+ /* This can wrap around */
+ bktr->vbiinsert += VBI_DATA_SIZE;
+ bktr->vbiinsert = (bktr->vbiinsert % VBI_BUFFER_SIZE);
+
+ /* And increase the amount of vbi data in the buffer */
+ bktr->vbisize = bktr->vbisize + VBI_DATA_SIZE;
+
+}
+
+
+/*
+ * the common interrupt handler.
+ * Returns a 0 or 1 depending on whether the interrupt has handled.
+ * In the OS specific section, bktr_intr() is defined which calls this
+ * common interrupt handler.
+ */
+int
+common_bktr_intr( void *arg )
+{
+ bktr_ptr_t bktr;
+ u_long bktr_status;
+ u_char dstatus;
+ u_long field;
+ u_long w_field;
+ u_long req_field;
+
+ bktr = (bktr_ptr_t) arg;
+
+ /*
+ * check to see if any interrupts are unmasked on this device. If
+ * none are, then we likely got here by way of being on a PCI shared
+ * interrupt dispatch list.
+ */
+ if (INL(bktr, BKTR_INT_MASK) == ALL_INTS_DISABLED)
+ return 0; /* bail out now, before we do something we
+ shouldn't */
+
+ if (!(bktr->flags & METEOR_OPEN)) {
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
+ OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
+ /* return; ?? */
+ }
+
+ /* record and clear the INTerrupt status bits */
+ bktr_status = INL(bktr, BKTR_INT_STAT);
+ OUTL(bktr, BKTR_INT_STAT, bktr_status & ~I2C_BITS); /* don't touch i2c */
+
+ /* record and clear the device status register */
+ dstatus = INB(bktr, BKTR_DSTATUS);
+ OUTB(bktr, BKTR_DSTATUS, 0x00);
+
+#if defined( STATUS_SUM )
+ /* add any new device status or INTerrupt status bits */
+ status_sum |= (bktr_status & ~(BT848_INT_RSV0|BT848_INT_RSV1));
+ status_sum |= ((dstatus & (BT848_DSTATUS_COF|BT848_DSTATUS_LOF)) << 6);
+#endif /* STATUS_SUM */
+ /* printf( "%s: STATUS %x %x %x \n", bktr_name(bktr),
+ dstatus, bktr_status, INL(bktr, BKTR_RISC_COUNT) );
+ */
+
+
+ /* if risc was disabled re-start process again */
+ /* if there was one of the following errors re-start again */
+ if ( !(bktr_status & BT848_INT_RISC_EN) ||
+ ((bktr_status &(/* BT848_INT_FBUS | */
+ /* BT848_INT_FTRGT | */
+ /* BT848_INT_FDSR | */
+ BT848_INT_PPERR |
+ BT848_INT_RIPERR | BT848_INT_PABORT |
+ BT848_INT_OCERR | BT848_INT_SCERR) ) != 0)
+ || ((INB(bktr, BKTR_TDEC) == 0) && (bktr_status & TDEC_BITS)) ) {
+
+ u_short tdec_save = INB(bktr, BKTR_TDEC);
+
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
+ OUTB(bktr, BKTR_CAP_CTL, CAPTURE_OFF);
+
+ OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
+
+ /* Reset temporal decimation counter */
+ OUTB(bktr, BKTR_TDEC, 0);
+ OUTB(bktr, BKTR_TDEC, tdec_save);
+
+ /* Reset to no-fields captured state */
+ if (bktr->flags & (METEOR_CONTIN | METEOR_SYNCAP)) {
+ switch(bktr->flags & METEOR_ONLY_FIELDS_MASK) {
+ case METEOR_ONLY_ODD_FIELDS:
+ bktr->flags |= METEOR_WANT_ODD;
+ break;
+ case METEOR_ONLY_EVEN_FIELDS:
+ bktr->flags |= METEOR_WANT_EVEN;
+ break;
+ default:
+ bktr->flags |= METEOR_WANT_MASK;
+ break;
+ }
+ }
+
+ OUTL(bktr, BKTR_RISC_STRT_ADD, vtophys(bktr->dma_prog));
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_ENABLED);
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, bktr->capcontrol);
+
+ OUTL(bktr, BKTR_INT_MASK, BT848_INT_MYSTERYBIT |
+ BT848_INT_RISCI |
+ BT848_INT_VSYNC |
+ BT848_INT_FMTCHG);
+
+ OUTB(bktr, BKTR_CAP_CTL, bktr->bktr_cap_ctl);
+ return 1;
+ }
+
+ /* If this is not a RISC program interrupt, return */
+ if (!(bktr_status & BT848_INT_RISCI))
+ return 0;
+
+/**
+ printf( "%s: intr status %x %x %x\n", bktr_name(bktr),
+ bktr_status, dstatus, INL(bktr, BKTR_RISC_COUNT) );
+ */
+
+
+ /*
+ * Disable future interrupts if a capture mode is not selected.
+ * This can happen when we are in the process of closing or
+ * changing capture modes, otherwise it shouldn't happen.
+ */
+ if (!(bktr->flags & METEOR_CAP_MASK))
+ OUTB(bktr, BKTR_CAP_CTL, CAPTURE_OFF);
+
+
+ /* Determine which field generated this interrupt */
+ field = ( bktr_status & BT848_INT_FIELD ) ? EVEN_F : ODD_F;
+
+
+ /*
+ * Process the VBI data if it is being captured. We do this once
+ * both Odd and Even VBI data is captured. Therefore we do this
+ * in the Even field interrupt handler.
+ */
+ LOCK_VBI(bktr);
+ if ( (bktr->vbiflags & VBI_CAPTURE)
+ &&(bktr->vbiflags & VBI_OPEN)
+ &&(field==EVEN_F)) {
+ /* Put VBI data into circular buffer */
+ vbidecode(bktr);
+
+ /* If someone is blocked on reading from /dev/vbi, wake them */
+ if (bktr->vbi_read_blocked) {
+ bktr->vbi_read_blocked = FALSE;
+ wakeup(VBI_SLEEP);
+ }
+
+ /* If someone has a select() on /dev/vbi, inform them */
+ if (SEL_WAITING(&bktr->vbi_select)) {
+ selwakeuppri(&bktr->vbi_select, VBIPRI);
+ }
+
+
+ }
+ UNLOCK_VBI(bktr);
+
+ /*
+ * Register the completed field
+ * (For dual-field mode, require fields from the same frame)
+ */
+ switch ( bktr->flags & METEOR_WANT_MASK ) {
+ case METEOR_WANT_ODD : w_field = ODD_F ; break;
+ case METEOR_WANT_EVEN : w_field = EVEN_F ; break;
+ default : w_field = (ODD_F|EVEN_F); break;
+ }
+ switch ( bktr->flags & METEOR_ONLY_FIELDS_MASK ) {
+ case METEOR_ONLY_ODD_FIELDS : req_field = ODD_F ; break;
+ case METEOR_ONLY_EVEN_FIELDS : req_field = EVEN_F ; break;
+ default : req_field = (ODD_F|EVEN_F);
+ break;
+ }
+
+ if (( field == EVEN_F ) && ( w_field == EVEN_F ))
+ bktr->flags &= ~METEOR_WANT_EVEN;
+ else if (( field == ODD_F ) && ( req_field == ODD_F ) &&
+ ( w_field == ODD_F ))
+ bktr->flags &= ~METEOR_WANT_ODD;
+ else if (( field == ODD_F ) && ( req_field == (ODD_F|EVEN_F) ) &&
+ ( w_field == (ODD_F|EVEN_F) ))
+ bktr->flags &= ~METEOR_WANT_ODD;
+ else if (( field == ODD_F ) && ( req_field == (ODD_F|EVEN_F) ) &&
+ ( w_field == ODD_F )) {
+ bktr->flags &= ~METEOR_WANT_ODD;
+ bktr->flags |= METEOR_WANT_EVEN;
+ }
+ else {
+ /* We're out of sync. Start over. */
+ if (bktr->flags & (METEOR_CONTIN | METEOR_SYNCAP)) {
+ switch(bktr->flags & METEOR_ONLY_FIELDS_MASK) {
+ case METEOR_ONLY_ODD_FIELDS:
+ bktr->flags |= METEOR_WANT_ODD;
+ break;
+ case METEOR_ONLY_EVEN_FIELDS:
+ bktr->flags |= METEOR_WANT_EVEN;
+ break;
+ default:
+ bktr->flags |= METEOR_WANT_MASK;
+ break;
+ }
+ }
+ return 1;
+ }
+
+ /*
+ * If we have a complete frame.
+ */
+ if (!(bktr->flags & METEOR_WANT_MASK)) {
+ bktr->frames_captured++;
+ /*
+ * post the completion time.
+ */
+ if (bktr->flags & METEOR_WANT_TS) {
+ struct timeval *ts;
+
+ if ((u_int) bktr->alloc_pages * PAGE_SIZE
+ <= (bktr->frame_size + sizeof(struct timeval))) {
+ ts =(struct timeval *)bktr->bigbuf +
+ bktr->frame_size;
+ /* doesn't work in synch mode except
+ * for first frame */
+ /* XXX */
+ microtime(ts);
+ }
+ }
+
+
+ /*
+ * Wake up the user in single capture mode.
+ */
+ if (bktr->flags & METEOR_SINGLE) {
+
+ /* stop dma */
+ OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
+
+ /* disable risc, leave fifo running */
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_ENABLED);
+ wakeup(BKTR_SLEEP);
+ }
+
+ /*
+ * If the user requested to be notified via signal,
+ * let them know the frame is complete.
+ */
+
+ if (bktr->proc != NULL) {
+ PROC_LOCK(bktr->proc);
+ psignal( bktr->proc, bktr->signal);
+ PROC_UNLOCK(bktr->proc);
+ }
+
+ /*
+ * Reset the want flags if in continuous or
+ * synchronous capture mode.
+ */
+/*
+* XXX NOTE (Luigi):
+* currently we only support 3 capture modes: odd only, even only,
+* odd+even interlaced (odd field first). A fourth mode (non interlaced,
+* either even OR odd) could provide 60 (50 for PAL) pictures per
+* second, but it would require this routine to toggle the desired frame
+* each time, and one more different DMA program for the Bt848.
+* As a consequence, this fourth mode is currently unsupported.
+*/
+
+ if (bktr->flags & (METEOR_CONTIN | METEOR_SYNCAP)) {
+ switch(bktr->flags & METEOR_ONLY_FIELDS_MASK) {
+ case METEOR_ONLY_ODD_FIELDS:
+ bktr->flags |= METEOR_WANT_ODD;
+ break;
+ case METEOR_ONLY_EVEN_FIELDS:
+ bktr->flags |= METEOR_WANT_EVEN;
+ break;
+ default:
+ bktr->flags |= METEOR_WANT_MASK;
+ break;
+ }
+ }
+ }
+
+ return 1;
+}
+
+
+
+
+/*
+ *
+ */
+extern int bt848_format; /* used to set the default format, PAL or NTSC */
+int
+video_open( bktr_ptr_t bktr )
+{
+ int frame_rate, video_format=0;
+
+ if (bktr->flags & METEOR_OPEN) /* device is busy */
+ return( EBUSY );
+
+ bktr->flags |= METEOR_OPEN;
+
+#ifdef BT848_DUMP
+ dump_bt848( bt848 );
+#endif
+
+ bktr->clr_on_start = FALSE;
+
+ OUTB(bktr, BKTR_DSTATUS, 0x00); /* clear device status reg. */
+
+ OUTB(bktr, BKTR_ADC, SYNC_LEVEL);
+
+#if BKTR_SYSTEM_DEFAULT == BROOKTREE_PAL
+ video_format = 0;
+#else
+ video_format = 1;
+#endif
+
+ if (bt848_format == 0 )
+ video_format = 0;
+
+ if (bt848_format == 1 )
+ video_format = 1;
+
+ if (video_format == 1 ) {
+ OUTB(bktr, BKTR_IFORM, BT848_IFORM_F_NTSCM);
+ bktr->format_params = BT848_IFORM_F_NTSCM;
+
+ } else {
+ OUTB(bktr, BKTR_IFORM, BT848_IFORM_F_PALBDGHI);
+ bktr->format_params = BT848_IFORM_F_PALBDGHI;
+
+ }
+
+ OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | format_params[bktr->format_params].iform_xtsel);
+
+ /* work around for new Hauppauge 878 cards */
+ if ((bktr->card.card_id == CARD_HAUPPAUGE) &&
+ (bktr->id==BROOKTREE_878 || bktr->id==BROOKTREE_879) )
+ OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX3);
+ else
+ OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX1);
+
+ OUTB(bktr, BKTR_ADELAY, format_params[bktr->format_params].adelay);
+ OUTB(bktr, BKTR_BDELAY, format_params[bktr->format_params].bdelay);
+ frame_rate = format_params[bktr->format_params].frame_rate;
+
+ /* enable PLL mode using 28Mhz crystal for PAL/SECAM users */
+ if (bktr->xtal_pll_mode == BT848_USE_PLL) {
+ OUTB(bktr, BKTR_TGCTRL, 0);
+ OUTB(bktr, BKTR_PLL_F_LO, 0xf9);
+ OUTB(bktr, BKTR_PLL_F_HI, 0xdc);
+ OUTB(bktr, BKTR_PLL_F_XCI, 0x8e);
+ }
+
+ bktr->flags = (bktr->flags & ~METEOR_DEV_MASK) | METEOR_DEV0;
+
+ bktr->max_clip_node = 0;
+
+ OUTB(bktr, BKTR_COLOR_CTL, BT848_COLOR_CTL_GAMMA | BT848_COLOR_CTL_RGB_DED);
+
+ OUTB(bktr, BKTR_E_HSCALE_LO, 170);
+ OUTB(bktr, BKTR_O_HSCALE_LO, 170);
+
+ OUTB(bktr, BKTR_E_DELAY_LO, 0x72);
+ OUTB(bktr, BKTR_O_DELAY_LO, 0x72);
+ OUTB(bktr, BKTR_E_SCLOOP, 0);
+ OUTB(bktr, BKTR_O_SCLOOP, 0);
+
+ OUTB(bktr, BKTR_VBI_PACK_SIZE, 0);
+ OUTB(bktr, BKTR_VBI_PACK_DEL, 0);
+
+ bktr->fifo_errors = 0;
+ bktr->dma_errors = 0;
+ bktr->frames_captured = 0;
+ bktr->even_fields_captured = 0;
+ bktr->odd_fields_captured = 0;
+ bktr->proc = NULL;
+ set_fps(bktr, frame_rate);
+ bktr->video.addr = 0;
+ bktr->video.width = 0;
+ bktr->video.banksize = 0;
+ bktr->video.ramsize = 0;
+ bktr->pixfmt_compat = TRUE;
+ bktr->format = METEOR_GEO_RGB16;
+ bktr->pixfmt = oformat_meteor_to_bt( bktr->format );
+
+ bktr->capture_area_enabled = FALSE;
+
+ OUTL(bktr, BKTR_INT_MASK, BT848_INT_MYSTERYBIT); /* if you take this out triton
+ based motherboards will
+ operate unreliably */
+ return( 0 );
+}
+
+int
+vbi_open( bktr_ptr_t bktr )
+{
+
+ LOCK_VBI(bktr);
+
+ if (bktr->vbiflags & VBI_OPEN) { /* device is busy */
+ UNLOCK_VBI(bktr);
+ return( EBUSY );
+ }
+
+ bktr->vbiflags |= VBI_OPEN;
+
+ /* reset the VBI circular buffer pointers and clear the buffers */
+ bktr->vbiinsert = 0;
+ bktr->vbistart = 0;
+ bktr->vbisize = 0;
+ bktr->vbi_sequence_number = 0;
+ bktr->vbi_read_blocked = FALSE;
+
+ bzero((caddr_t) bktr->vbibuffer, VBI_BUFFER_SIZE);
+ bzero((caddr_t) bktr->vbidata, VBI_DATA_SIZE);
+
+ UNLOCK_VBI(bktr);
+
+ return( 0 );
+}
+
+/*
+ *
+ */
+int
+tuner_open( bktr_ptr_t bktr )
+{
+ if ( !(bktr->tflags & TUNER_INITALIZED) ) /* device not found */
+ return( ENXIO );
+
+ if ( bktr->tflags & TUNER_OPEN ) /* already open */
+ return( 0 );
+
+ bktr->tflags |= TUNER_OPEN;
+ bktr->tuner.frequency = 0;
+ bktr->tuner.channel = 0;
+ bktr->tuner.chnlset = DEFAULT_CHNLSET;
+ bktr->tuner.afc = 0;
+ bktr->tuner.radio_mode = 0;
+
+ /* enable drivers on the GPIO port that control the MUXes */
+ OUTL(bktr, BKTR_GPIO_OUT_EN, INL(bktr, BKTR_GPIO_OUT_EN) | bktr->card.gpio_mux_bits);
+
+ /* unmute the audio stream */
+ set_audio( bktr, AUDIO_UNMUTE );
+
+ /* Initialise any audio chips, eg MSP34xx or TDA98xx */
+ init_audio_devices( bktr );
+
+ return( 0 );
+}
+
+
+
+
+/*
+ *
+ */
+int
+video_close( bktr_ptr_t bktr )
+{
+ bktr->flags &= ~(METEOR_OPEN |
+ METEOR_SINGLE |
+ METEOR_CAP_MASK |
+ METEOR_WANT_MASK);
+
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
+ OUTB(bktr, BKTR_CAP_CTL, CAPTURE_OFF);
+
+ bktr->dma_prog_loaded = FALSE;
+ OUTB(bktr, BKTR_TDEC, 0);
+ OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
+
+/** FIXME: is 0xf magic, wouldn't 0x00 work ??? */
+ OUTL(bktr, BKTR_SRESET, 0xf);
+ OUTL(bktr, BKTR_INT_STAT, ALL_INTS_CLEARED);
+
+ return( 0 );
+}
+
+
+/*
+ * tuner close handle,
+ * place holder for tuner specific operations on a close.
+ */
+int
+tuner_close( bktr_ptr_t bktr )
+{
+ bktr->tflags &= ~TUNER_OPEN;
+
+ /* mute the audio by switching the mux */
+ set_audio( bktr, AUDIO_MUTE );
+
+ /* disable drivers on the GPIO port that control the MUXes */
+ OUTL(bktr, BKTR_GPIO_OUT_EN, INL(bktr, BKTR_GPIO_OUT_EN) & ~bktr->card.gpio_mux_bits);
+
+ return( 0 );
+}
+
+int
+vbi_close( bktr_ptr_t bktr )
+{
+
+ LOCK_VBI(bktr);
+
+ bktr->vbiflags &= ~VBI_OPEN;
+
+ UNLOCK_VBI(bktr);
+
+ return( 0 );
+}
+
+/*
+ *
+ */
+int
+video_read(bktr_ptr_t bktr, int unit, struct cdev *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, start;
+ int status;
+
+ /*
+ * XXX - vbi_read() should be protected against being re-entered
+ * while it is unlocked for the uiomove.
+ */
+ LOCK_VBI(bktr);
+
+ while(bktr->vbisize == 0) {
+ if (ioflag & FNDELAY) {
+ status = EWOULDBLOCK;
+ goto out;
+ }
+
+ bktr->vbi_read_blocked = TRUE;
+#ifdef USE_VBIMUTEX
+ if ((status = msleep(VBI_SLEEP, &bktr->vbimutex, VBIPRI, "vbi",
+ 0))) {
+ goto out;
+ }
+#else
+ if ((status = tsleep(VBI_SLEEP, VBIPRI, "vbi", 0))) {
+ goto out;
+ }
+#endif
+ }
+
+ /* Now we have some data to give to the user */
+
+ /* We cannot read more bytes than there are in
+ * the circular buffer
+ */
+ readsize = (int)uio->uio_iov->iov_len;
+
+ if (readsize > bktr->vbisize) readsize = bktr->vbisize;
+
+ /* Check if we can read this number of bytes without having
+ * to wrap around the circular buffer */
+ if((bktr->vbistart + readsize) >= VBI_BUFFER_SIZE) {
+ /* We need to wrap around */
+
+ readsize2 = VBI_BUFFER_SIZE - bktr->vbistart;
+ start = bktr->vbistart;
+ UNLOCK_VBI(bktr);
+ status = uiomove((caddr_t)bktr->vbibuffer + start, readsize2, uio);
+ if (status == 0)
+ status = uiomove((caddr_t)bktr->vbibuffer, (readsize - readsize2), uio);
+ } else {
+ UNLOCK_VBI(bktr);
+ /* We do not need to wrap around */
+ status = uiomove((caddr_t)bktr->vbibuffer + bktr->vbistart, readsize, uio);
+ }
+
+ LOCK_VBI(bktr);
+
+ /* Update the number of bytes left to read */
+ bktr->vbisize -= readsize;
+
+ /* Update vbistart */
+ bktr->vbistart += readsize;
+ bktr->vbistart = bktr->vbistart % VBI_BUFFER_SIZE; /* wrap around if needed */
+
+out:
+ UNLOCK_VBI(bktr);
+
+ return( status );
+
+}
+
+
+
+/*
+ * video ioctls
+ */
+int
+video_ioctl( bktr_ptr_t bktr, int unit, ioctl_cmd_t cmd, caddr_t arg, struct thread* td )
+{
+ volatile u_char c_temp;
+ unsigned int temp;
+ unsigned int temp_iform;
+ unsigned int error;
+ struct meteor_geomet *geo;
+ struct meteor_counts *counts;
+ struct meteor_video *video;
+ struct bktr_capture_area *cap_area;
+ vm_offset_t buf;
+ int i;
+ int sig;
+ char char_temp;
+
+ switch ( cmd ) {
+
+ case BT848SCLIP: /* set clip region */
+ bktr->max_clip_node = 0;
+ memcpy(&bktr->clip_list, arg, sizeof(bktr->clip_list));
+
+ for (i = 0; i < BT848_MAX_CLIP_NODE; i++) {
+ if (bktr->clip_list[i].y_min == 0 &&
+ bktr->clip_list[i].y_max == 0)
+ break;
+ }
+ bktr->max_clip_node = i;
+
+ /* make sure that the list contains a valid clip secquence */
+ /* the clip rectangles should be sorted by x then by y as the
+ second order sort key */
+
+ /* clip rectangle list is terminated by y_min and y_max set to 0 */
+
+ /* to disable clipping set y_min and y_max to 0 in the first
+ clip rectangle . The first clip rectangle is clip_list[0].
+ */
+
+
+
+ if (bktr->max_clip_node == 0 &&
+ (bktr->clip_list[0].y_min != 0 &&
+ bktr->clip_list[0].y_max != 0)) {
+ return EINVAL;
+ }
+
+ for (i = 0; i < BT848_MAX_CLIP_NODE - 1 ; i++) {
+ if (bktr->clip_list[i].y_min == 0 &&
+ bktr->clip_list[i].y_max == 0) {
+ break;
+ }
+ if ( bktr->clip_list[i+1].y_min != 0 &&
+ bktr->clip_list[i+1].y_max != 0 &&
+ bktr->clip_list[i].x_min > bktr->clip_list[i+1].x_min ) {
+
+ bktr->max_clip_node = 0;
+ return (EINVAL);
+
+ }
+
+ if (bktr->clip_list[i].x_min >= bktr->clip_list[i].x_max ||
+ bktr->clip_list[i].y_min >= bktr->clip_list[i].y_max ||
+ bktr->clip_list[i].x_min < 0 ||
+ bktr->clip_list[i].x_max < 0 ||
+ bktr->clip_list[i].y_min < 0 ||
+ bktr->clip_list[i].y_max < 0 ) {
+ bktr->max_clip_node = 0;
+ return (EINVAL);
+ }
+ }
+
+ bktr->dma_prog_loaded = FALSE;
+
+ break;
+
+ case METEORSTATUS: /* get Bt848 status */
+ c_temp = INB(bktr, BKTR_DSTATUS);
+ temp = 0;
+ if (!(c_temp & 0x40)) temp |= METEOR_STATUS_HCLK;
+ if (!(c_temp & 0x10)) temp |= METEOR_STATUS_FIDT;
+ *(u_short *)arg = temp;
+ break;
+
+ case BT848SFMT: /* set input format */
+ temp = *(unsigned long*)arg & BT848_IFORM_FORMAT;
+ temp_iform = INB(bktr, BKTR_IFORM);
+ temp_iform &= ~BT848_IFORM_FORMAT;
+ temp_iform &= ~BT848_IFORM_XTSEL;
+ OUTB(bktr, BKTR_IFORM, (temp_iform | temp | format_params[temp].iform_xtsel));
+ switch( temp ) {
+ case BT848_IFORM_F_AUTO:
+ bktr->flags = (bktr->flags & ~METEOR_FORM_MASK) |
+ METEOR_AUTOMODE;
+ break;
+
+ case BT848_IFORM_F_NTSCM:
+ case BT848_IFORM_F_NTSCJ:
+ bktr->flags = (bktr->flags & ~METEOR_FORM_MASK) |
+ METEOR_NTSC;
+ OUTB(bktr, BKTR_ADELAY, format_params[temp].adelay);
+ OUTB(bktr, BKTR_BDELAY, format_params[temp].bdelay);
+ bktr->format_params = temp;
+ break;
+
+ case BT848_IFORM_F_PALBDGHI:
+ case BT848_IFORM_F_PALN:
+ case BT848_IFORM_F_SECAM:
+ case BT848_IFORM_F_RSVD:
+ case BT848_IFORM_F_PALM:
+ bktr->flags = (bktr->flags & ~METEOR_FORM_MASK) |
+ METEOR_PAL;
+ OUTB(bktr, BKTR_ADELAY, format_params[temp].adelay);
+ OUTB(bktr, BKTR_BDELAY, format_params[temp].bdelay);
+ bktr->format_params = temp;
+ break;
+
+ }
+ bktr->dma_prog_loaded = FALSE;
+ break;
+
+ case METEORSFMT: /* set input format */
+ temp_iform = INB(bktr, BKTR_IFORM);
+ temp_iform &= ~BT848_IFORM_FORMAT;
+ temp_iform &= ~BT848_IFORM_XTSEL;
+ switch(*(unsigned long *)arg & METEOR_FORM_MASK ) {
+ case 0: /* default */
+ case METEOR_FMT_NTSC:
+ bktr->flags = (bktr->flags & ~METEOR_FORM_MASK) |
+ METEOR_NTSC;
+ OUTB(bktr, BKTR_IFORM, temp_iform | BT848_IFORM_F_NTSCM |
+ format_params[BT848_IFORM_F_NTSCM].iform_xtsel);
+ OUTB(bktr, BKTR_ADELAY, format_params[BT848_IFORM_F_NTSCM].adelay);
+ OUTB(bktr, BKTR_BDELAY, format_params[BT848_IFORM_F_NTSCM].bdelay);
+ bktr->format_params = BT848_IFORM_F_NTSCM;
+ break;
+
+ case METEOR_FMT_PAL:
+ bktr->flags = (bktr->flags & ~METEOR_FORM_MASK) |
+ METEOR_PAL;
+ OUTB(bktr, BKTR_IFORM, temp_iform | BT848_IFORM_F_PALBDGHI |
+ format_params[BT848_IFORM_F_PALBDGHI].iform_xtsel);
+ OUTB(bktr, BKTR_ADELAY, format_params[BT848_IFORM_F_PALBDGHI].adelay);
+ OUTB(bktr, BKTR_BDELAY, format_params[BT848_IFORM_F_PALBDGHI].bdelay);
+ bktr->format_params = BT848_IFORM_F_PALBDGHI;
+ break;
+
+ case METEOR_FMT_AUTOMODE:
+ bktr->flags = (bktr->flags & ~METEOR_FORM_MASK) |
+ METEOR_AUTOMODE;
+ OUTB(bktr, BKTR_IFORM, temp_iform | BT848_IFORM_F_AUTO |
+ format_params[BT848_IFORM_F_AUTO].iform_xtsel);
+ break;
+
+ default:
+ return( EINVAL );
+ }
+ bktr->dma_prog_loaded = FALSE;
+ break;
+
+ case METEORGFMT: /* get input format */
+ *(u_long *)arg = bktr->flags & METEOR_FORM_MASK;
+ break;
+
+
+ case BT848GFMT: /* get input format */
+ *(u_long *)arg = INB(bktr, BKTR_IFORM) & BT848_IFORM_FORMAT;
+ break;
+
+ case METEORSCOUNT: /* (re)set error counts */
+ counts = (struct meteor_counts *) arg;
+ bktr->fifo_errors = counts->fifo_errors;
+ bktr->dma_errors = counts->dma_errors;
+ bktr->frames_captured = counts->frames_captured;
+ bktr->even_fields_captured = counts->even_fields_captured;
+ bktr->odd_fields_captured = counts->odd_fields_captured;
+ break;
+
+ case METEORGCOUNT: /* get error counts */
+ counts = (struct meteor_counts *) arg;
+ counts->fifo_errors = bktr->fifo_errors;
+ counts->dma_errors = bktr->dma_errors;
+ counts->frames_captured = bktr->frames_captured;
+ counts->even_fields_captured = bktr->even_fields_captured;
+ counts->odd_fields_captured = bktr->odd_fields_captured;
+ break;
+
+ case METEORGVIDEO:
+ video = (struct meteor_video *)arg;
+ video->addr = bktr->video.addr;
+ video->width = bktr->video.width;
+ video->banksize = bktr->video.banksize;
+ video->ramsize = bktr->video.ramsize;
+ break;
+
+ case METEORSVIDEO:
+ video = (struct meteor_video *)arg;
+ bktr->video.addr = video->addr;
+ bktr->video.width = video->width;
+ bktr->video.banksize = video->banksize;
+ bktr->video.ramsize = video->ramsize;
+ break;
+
+ case METEORSFPS:
+ set_fps(bktr, *(u_short *)arg);
+ break;
+
+ case METEORGFPS:
+ *(u_short *)arg = bktr->fps;
+ break;
+
+ case METEORSHUE: /* set hue */
+ OUTB(bktr, BKTR_HUE, (*(u_char *) arg) & 0xff);
+ break;
+
+ case METEORGHUE: /* get hue */
+ *(u_char *)arg = INB(bktr, BKTR_HUE);
+ break;
+
+ case METEORSBRIG: /* set brightness */
+ char_temp = ( *(u_char *)arg & 0xff) - 128;
+ OUTB(bktr, BKTR_BRIGHT, char_temp);
+
+ break;
+
+ case METEORGBRIG: /* get brightness */
+ *(u_char *)arg = INB(bktr, BKTR_BRIGHT);
+ break;
+
+ case METEORSCSAT: /* set chroma saturation */
+ temp = (int)*(u_char *)arg;
+
+ OUTB(bktr, BKTR_SAT_U_LO, (temp << 1) & 0xff);
+ OUTB(bktr, BKTR_SAT_V_LO, (temp << 1) & 0xff);
+ OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL)
+ & ~(BT848_E_CONTROL_SAT_U_MSB
+ | BT848_E_CONTROL_SAT_V_MSB));
+ OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL)
+ & ~(BT848_O_CONTROL_SAT_U_MSB |
+ BT848_O_CONTROL_SAT_V_MSB));
+
+ if ( temp & BIT_SEVEN_HIGH ) {
+ OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL)
+ | (BT848_E_CONTROL_SAT_U_MSB
+ | BT848_E_CONTROL_SAT_V_MSB));
+ OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL)
+ | (BT848_O_CONTROL_SAT_U_MSB
+ | BT848_O_CONTROL_SAT_V_MSB));
+ }
+ break;
+
+ case METEORGCSAT: /* get chroma saturation */
+ temp = (INB(bktr, BKTR_SAT_V_LO) >> 1) & 0xff;
+ if ( INB(bktr, BKTR_E_CONTROL) & BT848_E_CONTROL_SAT_V_MSB )
+ temp |= BIT_SEVEN_HIGH;
+ *(u_char *)arg = (u_char)temp;
+ break;
+
+ case METEORSCONT: /* set contrast */
+ temp = (int)*(u_char *)arg & 0xff;
+ temp <<= 1;
+ OUTB(bktr, BKTR_CONTRAST_LO, temp & 0xff);
+ OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) & ~BT848_E_CONTROL_CON_MSB);
+ OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) & ~BT848_O_CONTROL_CON_MSB);
+ OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) |
+ (((temp & 0x100) >> 6 ) & BT848_E_CONTROL_CON_MSB));
+ OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) |
+ (((temp & 0x100) >> 6 ) & BT848_O_CONTROL_CON_MSB));
+ break;
+
+ case METEORGCONT: /* get contrast */
+ temp = (int)INB(bktr, BKTR_CONTRAST_LO) & 0xff;
+ temp |= ((int)INB(bktr, BKTR_O_CONTROL) & 0x04) << 6;
+ *(u_char *)arg = (u_char)((temp >> 1) & 0xff);
+ break;
+
+ case BT848SCBUF: /* set Clear-Buffer-on-start flag */
+ bktr->clr_on_start = (*(int *)arg != 0);
+ break;
+
+ case BT848GCBUF: /* get Clear-Buffer-on-start flag */
+ *(int *)arg = (int) bktr->clr_on_start;
+ break;
+
+ case METEORSSIGNAL:
+ sig = *(int *)arg;
+ /* Historically, applications used METEOR_SIG_MODE_MASK
+ * to reset signal delivery.
+ */
+ if (sig == METEOR_SIG_MODE_MASK)
+ sig = 0;
+ if (sig < 0 || sig > _SIG_MAXSIG)
+ return (EINVAL);
+ bktr->signal = sig;
+ bktr->proc = sig ? td->td_proc : NULL;
+ break;
+
+ case METEORGSIGNAL:
+ *(int *)arg = bktr->signal;
+ break;
+
+ case METEORCAPTUR:
+ temp = bktr->flags;
+ switch (*(int *) arg) {
+ case METEOR_CAP_SINGLE:
+
+ if (bktr->bigbuf==0) /* no frame buffer allocated */
+ return( ENOMEM );
+ /* already capturing */
+ if (temp & METEOR_CAP_MASK)
+ return( EIO );
+
+
+
+ start_capture(bktr, METEOR_SINGLE);
+
+ /* wait for capture to complete */
+ OUTL(bktr, BKTR_INT_STAT, ALL_INTS_CLEARED);
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_ENABLED);
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, bktr->capcontrol);
+
+ OUTL(bktr, BKTR_INT_MASK, BT848_INT_MYSTERYBIT |
+ BT848_INT_RISCI |
+ BT848_INT_VSYNC |
+ BT848_INT_FMTCHG);
+
+ OUTB(bktr, BKTR_CAP_CTL, bktr->bktr_cap_ctl);
+ error = tsleep(BKTR_SLEEP, BKTRPRI, "captur", hz);
+ if (error && (error != ERESTART)) {
+ /* Here if we didn't get complete frame */
+#ifdef DIAGNOSTIC
+ printf( "%s: ioctl: tsleep error %d %x\n",
+ bktr_name(bktr), error,
+ INL(bktr, BKTR_RISC_COUNT));
+#endif
+
+ /* stop dma */
+ OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
+
+ /* disable risc, leave fifo running */
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_ENABLED);
+ }
+
+ bktr->flags &= ~(METEOR_SINGLE|METEOR_WANT_MASK);
+ /* FIXME: should we set bt848->int_stat ??? */
+ break;
+
+ case METEOR_CAP_CONTINOUS:
+ if (bktr->bigbuf==0) /* no frame buffer allocated */
+ return( ENOMEM );
+ /* already capturing */
+ if (temp & METEOR_CAP_MASK)
+ return( EIO );
+
+
+ start_capture(bktr, METEOR_CONTIN);
+
+ /* Clear the interrypt status register */
+ OUTL(bktr, BKTR_INT_STAT, INL(bktr, BKTR_INT_STAT));
+
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_ENABLED);
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, bktr->capcontrol);
+ OUTB(bktr, BKTR_CAP_CTL, bktr->bktr_cap_ctl);
+
+ OUTL(bktr, BKTR_INT_MASK, BT848_INT_MYSTERYBIT |
+ BT848_INT_RISCI |
+ BT848_INT_VSYNC |
+ BT848_INT_FMTCHG);
+#ifdef BT848_DUMP
+ dump_bt848( bt848 );
+#endif
+ break;
+
+ case METEOR_CAP_STOP_CONT:
+ if (bktr->flags & METEOR_CONTIN) {
+ /* turn off capture */
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
+ OUTB(bktr, BKTR_CAP_CTL, CAPTURE_OFF);
+ OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
+ bktr->flags &=
+ ~(METEOR_CONTIN | METEOR_WANT_MASK);
+
+ }
+ }
+ break;
+
+ case METEORSETGEO:
+ /* can't change parameters while capturing */
+ if (bktr->flags & METEOR_CAP_MASK)
+ return( EBUSY );
+
+
+ geo = (struct meteor_geomet *) arg;
+
+ error = 0;
+ /* Either even or odd, if even & odd, then these a zero */
+ if ((geo->oformat & METEOR_GEO_ODD_ONLY) &&
+ (geo->oformat & METEOR_GEO_EVEN_ONLY)) {
+ printf( "%s: ioctl: Geometry odd or even only.\n",
+ bktr_name(bktr));
+ return( EINVAL );
+ }
+
+ /* set/clear even/odd flags */
+ if (geo->oformat & METEOR_GEO_ODD_ONLY)
+ bktr->flags |= METEOR_ONLY_ODD_FIELDS;
+ else
+ bktr->flags &= ~METEOR_ONLY_ODD_FIELDS;
+ if (geo->oformat & METEOR_GEO_EVEN_ONLY)
+ bktr->flags |= METEOR_ONLY_EVEN_FIELDS;
+ else
+ bktr->flags &= ~METEOR_ONLY_EVEN_FIELDS;
+
+ if (geo->columns <= 0) {
+ printf(
+ "%s: ioctl: %d: columns must be greater than zero.\n",
+ bktr_name(bktr), geo->columns);
+ error = EINVAL;
+ }
+ else if ((geo->columns & 0x3fe) != geo->columns) {
+ printf(
+ "%s: ioctl: %d: columns too large or not even.\n",
+ bktr_name(bktr), geo->columns);
+ error = EINVAL;
+ }
+
+ if (geo->rows <= 0) {
+ printf(
+ "%s: ioctl: %d: rows must be greater than zero.\n",
+ bktr_name(bktr), geo->rows);
+ error = EINVAL;
+ }
+ else if (((geo->rows & 0x7fe) != geo->rows) ||
+ ((geo->oformat & METEOR_GEO_FIELD_MASK) &&
+ ((geo->rows & 0x3fe) != geo->rows)) ) {
+ printf(
+ "%s: ioctl: %d: rows too large or not even.\n",
+ bktr_name(bktr), geo->rows);
+ error = EINVAL;
+ }
+
+ if (geo->frames > 32) {
+ printf("%s: ioctl: too many frames.\n",
+ bktr_name(bktr));
+
+ error = EINVAL;
+ }
+
+ if (error)
+ return( error );
+
+ bktr->dma_prog_loaded = FALSE;
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_RISC_DISABLED);
+
+ OUTL(bktr, BKTR_INT_MASK, ALL_INTS_DISABLED);
+
+ if ((temp=(geo->rows * geo->columns * geo->frames * 2))) {
+ if (geo->oformat & METEOR_GEO_RGB24) temp = temp * 2;
+
+ /* meteor_mem structure for SYNC Capture */
+ if (geo->frames > 1) temp += PAGE_SIZE;
+
+ temp = btoc(temp);
+ if ((int) temp > bktr->alloc_pages
+ && bktr->video.addr == 0) {
+
+/*****************************/
+/* *** OS Dependant code *** */
+/*****************************/
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+ bus_dmamap_t dmamap;
+
+ buf = get_bktr_mem(bktr, &dmamap,
+ temp * PAGE_SIZE);
+ if (buf != 0) {
+ free_bktr_mem(bktr, bktr->dm_mem,
+ bktr->bigbuf);
+ bktr->dm_mem = dmamap;
+
+#else
+ buf = get_bktr_mem(unit, temp*PAGE_SIZE);
+ if (buf != 0) {
+ kmem_free(kernel_map, bktr->bigbuf,
+ (bktr->alloc_pages * PAGE_SIZE));
+#endif
+
+ bktr->bigbuf = buf;
+ bktr->alloc_pages = temp;
+ if (bootverbose)
+ printf(
+ "%s: ioctl: Allocating %d bytes\n",
+ bktr_name(bktr), temp*PAGE_SIZE);
+ }
+ else
+ error = ENOMEM;
+ }
+ }
+
+ if (error)
+ return error;
+
+ bktr->rows = geo->rows;
+ bktr->cols = geo->columns;
+ bktr->frames = geo->frames;
+
+ /* Pixel format (if in meteor pixfmt compatibility mode) */
+ if ( bktr->pixfmt_compat ) {
+ bktr->format = METEOR_GEO_YUV_422;
+ switch (geo->oformat & METEOR_GEO_OUTPUT_MASK) {
+ case 0: /* default */
+ case METEOR_GEO_RGB16:
+ bktr->format = METEOR_GEO_RGB16;
+ break;
+ case METEOR_GEO_RGB24:
+ bktr->format = METEOR_GEO_RGB24;
+ break;
+ case METEOR_GEO_YUV_422:
+ bktr->format = METEOR_GEO_YUV_422;
+ if (geo->oformat & METEOR_GEO_YUV_12)
+ bktr->format = METEOR_GEO_YUV_12;
+ break;
+ case METEOR_GEO_YUV_PACKED:
+ bktr->format = METEOR_GEO_YUV_PACKED;
+ break;
+ }
+ bktr->pixfmt = oformat_meteor_to_bt( bktr->format );
+ }
+
+ if (bktr->flags & METEOR_CAP_MASK) {
+
+ if (bktr->flags & (METEOR_CONTIN|METEOR_SYNCAP)) {
+ switch(bktr->flags & METEOR_ONLY_FIELDS_MASK) {
+ case METEOR_ONLY_ODD_FIELDS:
+ bktr->flags |= METEOR_WANT_ODD;
+ break;
+ case METEOR_ONLY_EVEN_FIELDS:
+ bktr->flags |= METEOR_WANT_EVEN;
+ break;
+ default:
+ bktr->flags |= METEOR_WANT_MASK;
+ break;
+ }
+
+ start_capture(bktr, METEOR_CONTIN);
+ OUTL(bktr, BKTR_INT_STAT, INL(bktr, BKTR_INT_STAT));
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, FIFO_ENABLED);
+ OUTW(bktr, BKTR_GPIO_DMA_CTL, bktr->capcontrol);
+ OUTL(bktr, BKTR_INT_MASK, BT848_INT_MYSTERYBIT |
+ BT848_INT_VSYNC |
+ BT848_INT_FMTCHG);
+ }
+ }
+ break;
+ /* end of METEORSETGEO */
+
+ /* FIXME. The Capture Area currently has the following restrictions:
+ GENERAL
+ y_offset may need to be even in interlaced modes
+ RGB24 - Interlaced mode
+ x_size must be greater than or equal to 1.666*METEORSETGEO width (cols)
+ y_size must be greater than or equal to METEORSETGEO height (rows)
+ RGB24 - Even Only (or Odd Only) mode
+ x_size must be greater than or equal to 1.666*METEORSETGEO width (cols)
+ y_size must be greater than or equal to 2*METEORSETGEO height (rows)
+ YUV12 - Interlaced mode
+ x_size must be greater than or equal to METEORSETGEO width (cols)
+ y_size must be greater than or equal to METEORSETGEO height (rows)
+ YUV12 - Even Only (or Odd Only) mode
+ x_size must be greater than or equal to METEORSETGEO width (cols)
+ y_size must be greater than or equal to 2*METEORSETGEO height (rows)
+ */
+
+ case BT848_SCAPAREA: /* set capture area of each video frame */
+ /* can't change parameters while capturing */
+ if (bktr->flags & METEOR_CAP_MASK)
+ return( EBUSY );
+
+ cap_area = (struct bktr_capture_area *) arg;
+ bktr->capture_area_x_offset = cap_area->x_offset;
+ bktr->capture_area_y_offset = cap_area->y_offset;
+ bktr->capture_area_x_size = cap_area->x_size;
+ bktr->capture_area_y_size = cap_area->y_size;
+ bktr->capture_area_enabled = TRUE;
+
+ bktr->dma_prog_loaded = FALSE;
+ break;
+
+ case BT848_GCAPAREA: /* get capture area of each video frame */
+ cap_area = (struct bktr_capture_area *) arg;
+ if (bktr->capture_area_enabled == FALSE) {
+ cap_area->x_offset = 0;
+ cap_area->y_offset = 0;
+ cap_area->x_size = format_params[
+ bktr->format_params].scaled_hactive;
+ cap_area->y_size = format_params[
+ bktr->format_params].vactive;
+ } else {
+ cap_area->x_offset = bktr->capture_area_x_offset;
+ cap_area->y_offset = bktr->capture_area_y_offset;
+ cap_area->x_size = bktr->capture_area_x_size;
+ cap_area->y_size = bktr->capture_area_y_size;
+ }
+ break;
+
+ default:
+ return common_ioctl( bktr, cmd, arg );
+ }
+
+ return( 0 );
+}
+
+/*
+ * tuner ioctls
+ */
+int
+tuner_ioctl( bktr_ptr_t bktr, int unit, ioctl_cmd_t cmd, caddr_t arg, struct thread* td )
+{
+ int tmp_int;
+ unsigned int temp, temp1;
+ int offset;
+ int count;
+ u_char *buf;
+ u_long par;
+ u_char write;
+ int i2c_addr;
+ int i2c_port;
+ u_long data;
+
+ switch ( cmd ) {
+
+ case REMOTE_GETKEY:
+ /* Read the last key pressed by the Remote Control */
+ if (bktr->remote_control == 0) return (EINVAL);
+ remote_read(bktr, (struct bktr_remote *)arg);
+ break;
+
+#if defined( TUNER_AFC )
+ case TVTUNER_SETAFC:
+ bktr->tuner.afc = (*(int *)arg != 0);
+ break;
+
+ case TVTUNER_GETAFC:
+ *(int *)arg = bktr->tuner.afc;
+ /* XXX Perhaps use another bit to indicate AFC success? */
+ break;
+#endif /* TUNER_AFC */
+
+ case TVTUNER_SETCHNL:
+ temp_mute( bktr, TRUE );
+ temp = tv_channel( bktr, (int)*(unsigned long *)arg );
+ if ( temp < 0 ) {
+ temp_mute( bktr, FALSE );
+ return( EINVAL );
+ }
+ *(unsigned long *)arg = temp;
+
+ /* after every channel change, we must restart the MSP34xx */
+ /* audio chip to reselect NICAM STEREO or MONO audio */
+ if ( bktr->card.msp3400c )
+ msp_autodetect( bktr );
+
+ /* after every channel change, we must restart the DPL35xx */
+ if ( bktr->card.dpl3518a )
+ dpl_autodetect( bktr );
+
+ temp_mute( bktr, FALSE );
+ break;
+
+ case TVTUNER_GETCHNL:
+ *(unsigned long *)arg = bktr->tuner.channel;
+ break;
+
+ case TVTUNER_SETTYPE:
+ temp = *(unsigned long *)arg;
+ if ( (temp < CHNLSET_MIN) || (temp > CHNLSET_MAX) )
+ return( EINVAL );
+ bktr->tuner.chnlset = temp;
+ break;
+
+ case TVTUNER_GETTYPE:
+ *(unsigned long *)arg = bktr->tuner.chnlset;
+ break;
+
+ case TVTUNER_GETSTATUS:
+ temp = get_tuner_status( bktr );
+ *(unsigned long *)arg = temp & 0xff;
+ break;
+
+ case TVTUNER_SETFREQ:
+ temp_mute( bktr, TRUE );
+ temp = tv_freq( bktr, (int)*(unsigned long *)arg, TV_FREQUENCY);
+ temp_mute( bktr, FALSE );
+ if ( temp < 0 ) {
+ temp_mute( bktr, FALSE );
+ return( EINVAL );
+ }
+ *(unsigned long *)arg = temp;
+
+ /* after every channel change, we must restart the MSP34xx */
+ /* audio chip to reselect NICAM STEREO or MONO audio */
+ if ( bktr->card.msp3400c )
+ msp_autodetect( bktr );
+
+ /* after every channel change, we must restart the DPL35xx */
+ if ( bktr->card.dpl3518a )
+ dpl_autodetect( bktr );
+
+ temp_mute( bktr, FALSE );
+ break;
+
+ case TVTUNER_GETFREQ:
+ *(unsigned long *)arg = bktr->tuner.frequency;
+ break;
+
+ case TVTUNER_GETCHNLSET:
+ return tuner_getchnlset((struct bktr_chnlset *)arg);
+
+ case BT848_SAUDIO: /* set audio channel */
+ if ( set_audio( bktr, *(int*)arg ) < 0 )
+ return( EIO );
+ break;
+
+ /* hue is a 2's compliment number, -90' to +89.3' in 0.7' steps */
+ case BT848_SHUE: /* set hue */
+ OUTB(bktr, BKTR_HUE, (u_char)(*(int*)arg & 0xff));
+ break;
+
+ case BT848_GHUE: /* get hue */
+ *(int*)arg = (signed char)(INB(bktr, BKTR_HUE) & 0xff);
+ break;
+
+ /* brightness is a 2's compliment #, -50 to +%49.6% in 0.39% steps */
+ case BT848_SBRIG: /* set brightness */
+ OUTB(bktr, BKTR_BRIGHT, (u_char)(*(int *)arg & 0xff));
+ break;
+
+ case BT848_GBRIG: /* get brightness */
+ *(int *)arg = (signed char)(INB(bktr, BKTR_BRIGHT) & 0xff);
+ break;
+
+ /* */
+ case BT848_SCSAT: /* set chroma saturation */
+ tmp_int = *(int*)arg;
+
+ temp = INB(bktr, BKTR_E_CONTROL);
+ temp1 = INB(bktr, BKTR_O_CONTROL);
+ if ( tmp_int & BIT_EIGHT_HIGH ) {
+ temp |= (BT848_E_CONTROL_SAT_U_MSB |
+ BT848_E_CONTROL_SAT_V_MSB);
+ temp1 |= (BT848_O_CONTROL_SAT_U_MSB |
+ BT848_O_CONTROL_SAT_V_MSB);
+ }
+ else {
+ temp &= ~(BT848_E_CONTROL_SAT_U_MSB |
+ BT848_E_CONTROL_SAT_V_MSB);
+ temp1 &= ~(BT848_O_CONTROL_SAT_U_MSB |
+ BT848_O_CONTROL_SAT_V_MSB);
+ }
+
+ OUTB(bktr, BKTR_SAT_U_LO, (u_char)(tmp_int & 0xff));
+ OUTB(bktr, BKTR_SAT_V_LO, (u_char)(tmp_int & 0xff));
+ OUTB(bktr, BKTR_E_CONTROL, temp);
+ OUTB(bktr, BKTR_O_CONTROL, temp1);
+ break;
+
+ case BT848_GCSAT: /* get chroma saturation */
+ tmp_int = (int)(INB(bktr, BKTR_SAT_V_LO) & 0xff);
+ if ( INB(bktr, BKTR_E_CONTROL) & BT848_E_CONTROL_SAT_V_MSB )
+ tmp_int |= BIT_EIGHT_HIGH;
+ *(int*)arg = tmp_int;
+ break;
+
+ /* */
+ case BT848_SVSAT: /* set chroma V saturation */
+ tmp_int = *(int*)arg;
+
+ temp = INB(bktr, BKTR_E_CONTROL);
+ temp1 = INB(bktr, BKTR_O_CONTROL);
+ if ( tmp_int & BIT_EIGHT_HIGH) {
+ temp |= BT848_E_CONTROL_SAT_V_MSB;
+ temp1 |= BT848_O_CONTROL_SAT_V_MSB;
+ }
+ else {
+ temp &= ~BT848_E_CONTROL_SAT_V_MSB;
+ temp1 &= ~BT848_O_CONTROL_SAT_V_MSB;
+ }
+
+ OUTB(bktr, BKTR_SAT_V_LO, (u_char)(tmp_int & 0xff));
+ OUTB(bktr, BKTR_E_CONTROL, temp);
+ OUTB(bktr, BKTR_O_CONTROL, temp1);
+ break;
+
+ case BT848_GVSAT: /* get chroma V saturation */
+ tmp_int = (int)INB(bktr, BKTR_SAT_V_LO) & 0xff;
+ if ( INB(bktr, BKTR_E_CONTROL) & BT848_E_CONTROL_SAT_V_MSB )
+ tmp_int |= BIT_EIGHT_HIGH;
+ *(int*)arg = tmp_int;
+ break;
+
+ /* */
+ case BT848_SUSAT: /* set chroma U saturation */
+ tmp_int = *(int*)arg;
+
+ temp = INB(bktr, BKTR_E_CONTROL);
+ temp1 = INB(bktr, BKTR_O_CONTROL);
+ if ( tmp_int & BIT_EIGHT_HIGH ) {
+ temp |= BT848_E_CONTROL_SAT_U_MSB;
+ temp1 |= BT848_O_CONTROL_SAT_U_MSB;
+ }
+ else {
+ temp &= ~BT848_E_CONTROL_SAT_U_MSB;
+ temp1 &= ~BT848_O_CONTROL_SAT_U_MSB;
+ }
+
+ OUTB(bktr, BKTR_SAT_U_LO, (u_char)(tmp_int & 0xff));
+ OUTB(bktr, BKTR_E_CONTROL, temp);
+ OUTB(bktr, BKTR_O_CONTROL, temp1);
+ break;
+
+ case BT848_GUSAT: /* get chroma U saturation */
+ tmp_int = (int)INB(bktr, BKTR_SAT_U_LO) & 0xff;
+ if ( INB(bktr, BKTR_E_CONTROL) & BT848_E_CONTROL_SAT_U_MSB )
+ tmp_int |= BIT_EIGHT_HIGH;
+ *(int*)arg = tmp_int;
+ break;
+
+/* lr 970528 luma notch etc - 3 high bits of e_control/o_control */
+
+ case BT848_SLNOTCH: /* set luma notch */
+ tmp_int = (*(int *)arg & 0x7) << 5 ;
+ OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) & ~0xe0);
+ OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) & ~0xe0);
+ OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) | tmp_int);
+ OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) | tmp_int);
+ break;
+
+ case BT848_GLNOTCH: /* get luma notch */
+ *(int *)arg = (int) ( (INB(bktr, BKTR_E_CONTROL) & 0xe0) >> 5) ;
+ break;
+
+
+ /* */
+ case BT848_SCONT: /* set contrast */
+ tmp_int = *(int*)arg;
+
+ temp = INB(bktr, BKTR_E_CONTROL);
+ temp1 = INB(bktr, BKTR_O_CONTROL);
+ if ( tmp_int & BIT_EIGHT_HIGH ) {
+ temp |= BT848_E_CONTROL_CON_MSB;
+ temp1 |= BT848_O_CONTROL_CON_MSB;
+ }
+ else {
+ temp &= ~BT848_E_CONTROL_CON_MSB;
+ temp1 &= ~BT848_O_CONTROL_CON_MSB;
+ }
+
+ OUTB(bktr, BKTR_CONTRAST_LO, (u_char)(tmp_int & 0xff));
+ OUTB(bktr, BKTR_E_CONTROL, temp);
+ OUTB(bktr, BKTR_O_CONTROL, temp1);
+ break;
+
+ case BT848_GCONT: /* get contrast */
+ tmp_int = (int)INB(bktr, BKTR_CONTRAST_LO) & 0xff;
+ if ( INB(bktr, BKTR_E_CONTROL) & BT848_E_CONTROL_CON_MSB )
+ tmp_int |= BIT_EIGHT_HIGH;
+ *(int*)arg = tmp_int;
+ break;
+
+ /* FIXME: SCBARS and CCBARS require a valid int * */
+ /* argument to succeed, but its not used; consider */
+ /* using the arg to store the on/off state so */
+ /* there's only one ioctl() needed to turn cbars on/off */
+ case BT848_SCBARS: /* set colorbar output */
+ OUTB(bktr, BKTR_COLOR_CTL, INB(bktr, BKTR_COLOR_CTL) | BT848_COLOR_CTL_COLOR_BARS);
+ break;
+
+ case BT848_CCBARS: /* clear colorbar output */
+ OUTB(bktr, BKTR_COLOR_CTL, INB(bktr, BKTR_COLOR_CTL) & ~(BT848_COLOR_CTL_COLOR_BARS));
+ break;
+
+ case BT848_GAUDIO: /* get audio channel */
+ temp = bktr->audio_mux_select;
+ if ( bktr->audio_mute_state == TRUE )
+ temp |= AUDIO_MUTE;
+ *(int*)arg = temp;
+ break;
+
+ case BT848_SBTSC: /* set audio channel */
+ if ( set_BTSC( bktr, *(int*)arg ) < 0 )
+ return( EIO );
+ break;
+
+ case BT848_WEEPROM: /* write eeprom */
+ offset = (((struct eeProm *)arg)->offset);
+ count = (((struct eeProm *)arg)->count);
+ buf = &(((struct eeProm *)arg)->bytes[ 0 ]);
+ if ( writeEEProm( bktr, offset, count, buf ) < 0 )
+ return( EIO );
+ break;
+
+ case BT848_REEPROM: /* read eeprom */
+ offset = (((struct eeProm *)arg)->offset);
+ count = (((struct eeProm *)arg)->count);
+ buf = &(((struct eeProm *)arg)->bytes[ 0 ]);
+ if ( readEEProm( bktr, offset, count, buf ) < 0 )
+ return( EIO );
+ break;
+
+ case BT848_SIGNATURE:
+ offset = (((struct eeProm *)arg)->offset);
+ count = (((struct eeProm *)arg)->count);
+ buf = &(((struct eeProm *)arg)->bytes[ 0 ]);
+ if ( signCard( bktr, offset, count, buf ) < 0 )
+ return( EIO );
+ break;
+
+ /* Ioctl's for direct gpio access */
+#ifdef BKTR_GPIO_ACCESS
+ case BT848_GPIO_GET_EN:
+ *(int*)arg = INL(bktr, BKTR_GPIO_OUT_EN);
+ break;
+
+ case BT848_GPIO_SET_EN:
+ OUTL(bktr, BKTR_GPIO_OUT_EN, *(int*)arg);
+ break;
+
+ case BT848_GPIO_GET_DATA:
+ *(int*)arg = INL(bktr, BKTR_GPIO_DATA);
+ break;
+
+ case BT848_GPIO_SET_DATA:
+ OUTL(bktr, BKTR_GPIO_DATA, *(int*)arg);
+ break;
+#endif /* BKTR_GPIO_ACCESS */
+
+ /* Ioctl's for running the tuner device in radio mode */
+
+ case RADIO_GETMODE:
+ *(unsigned char *)arg = bktr->tuner.radio_mode;
+ break;
+
+ case RADIO_SETMODE:
+ bktr->tuner.radio_mode = *(unsigned char *)arg;
+ break;
+
+ case RADIO_GETFREQ:
+ *(unsigned long *)arg = bktr->tuner.frequency;
+ break;
+
+ case RADIO_SETFREQ:
+ /* The argument to this ioctl is NOT freq*16. It is
+ ** freq*100.
+ */
+
+ temp=(int)*(unsigned long *)arg;
+
+#ifdef BKTR_RADIO_DEBUG
+ printf("%s: arg=%d temp=%d\n", bktr_name(bktr),
+ (int)*(unsigned long *)arg, temp);
+#endif
+
+#ifndef BKTR_RADIO_NOFREQCHECK
+ /* According to the spec. sheet the band: 87.5MHz-108MHz */
+ /* is supported. */
+ if(temp<8750 || temp>10800) {
+ printf("%s: Radio frequency out of range\n", bktr_name(bktr));
+ return(EINVAL);
+ }
+#endif
+ temp_mute( bktr, TRUE );
+ temp = tv_freq( bktr, temp, FM_RADIO_FREQUENCY );
+ temp_mute( bktr, FALSE );
+#ifdef BKTR_RADIO_DEBUG
+ if(temp)
+ printf("%s: tv_freq returned: %d\n", bktr_name(bktr), temp);
+#endif
+ if ( temp < 0 )
+ return( EINVAL );
+ *(unsigned long *)arg = temp;
+ break;
+
+ /* Luigi's I2CWR ioctl */
+ case BT848_I2CWR:
+ par = *(u_long *)arg;
+ write = (par >> 24) & 0xff ;
+ i2c_addr = (par >> 16) & 0xff ;
+ i2c_port = (par >> 8) & 0xff ;
+ data = (par) & 0xff ;
+
+ if (write) {
+ i2cWrite( bktr, i2c_addr, i2c_port, data);
+ } else {
+ data = i2cRead( bktr, i2c_addr);
+ }
+ *(u_long *)arg = (par & 0xffffff00) | ( data & 0xff );
+ break;
+
+
+#ifdef BT848_MSP_READ
+ /* I2C ioctls to allow userland access to the MSP chip */
+ case BT848_MSP_READ:
+ {
+ struct bktr_msp_control *msp;
+ msp = (struct bktr_msp_control *) arg;
+ msp->data = msp_dpl_read(bktr, bktr->msp_addr,
+ msp->function, msp->address);
+ break;
+ }
+
+ case BT848_MSP_WRITE:
+ {
+ struct bktr_msp_control *msp;
+ msp = (struct bktr_msp_control *) arg;
+ msp_dpl_write(bktr, bktr->msp_addr, msp->function,
+ msp->address, msp->data );
+ break;
+ }
+
+ case BT848_MSP_RESET:
+ msp_dpl_reset(bktr, bktr->msp_addr);
+ break;
+#endif
+
+ default:
+ return common_ioctl( bktr, cmd, arg );
+ }
+
+ return( 0 );
+}
+
+
+/*
+ * common ioctls
+ */
+static int
+common_ioctl( bktr_ptr_t bktr, ioctl_cmd_t cmd, caddr_t arg )
+{
+ int pixfmt;
+ unsigned int temp;
+ struct meteor_pixfmt *pf_pub;
+
+ switch (cmd) {
+
+ case METEORSINPUT: /* set input device */
+ /*Bt848 has 3 MUX Inputs. Bt848A/849A/878/879 has 4 MUX Inputs*/
+ /* On the original bt848 boards, */
+ /* Tuner is MUX0, RCA is MUX1, S-Video is MUX2 */
+ /* On the Hauppauge bt878 boards, */
+ /* Tuner is MUX0, RCA is MUX3 */
+ /* Unfortunatly Meteor driver codes DEV_RCA as DEV_0, so we */
+ /* stick with this system in our Meteor Emulation */
+
+ switch(*(unsigned long *)arg & METEOR_DEV_MASK) {
+
+ /* this is the RCA video input */
+ case 0: /* default */
+ case METEOR_INPUT_DEV0:
+ /* METEOR_INPUT_DEV_RCA: */
+ bktr->flags = (bktr->flags & ~METEOR_DEV_MASK)
+ | METEOR_DEV0;
+ OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM)
+ & ~BT848_IFORM_MUXSEL);
+
+ /* work around for new Hauppauge 878 cards */
+ if ((bktr->card.card_id == CARD_HAUPPAUGE) &&
+ (bktr->id==BROOKTREE_878 ||
+ bktr->id==BROOKTREE_879) )
+ OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX3);
+ else
+ OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX1);
+
+ OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) & ~BT848_E_CONTROL_COMP);
+ OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) & ~BT848_O_CONTROL_COMP);
+ set_audio( bktr, AUDIO_EXTERN );
+ break;
+
+ /* this is the tuner input */
+ case METEOR_INPUT_DEV1:
+ bktr->flags = (bktr->flags & ~METEOR_DEV_MASK)
+ | METEOR_DEV1;
+ OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) & ~BT848_IFORM_MUXSEL);
+ OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX0);
+ OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) & ~BT848_E_CONTROL_COMP);
+ OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) & ~BT848_O_CONTROL_COMP);
+ set_audio( bktr, AUDIO_TUNER );
+ break;
+
+ /* this is the S-VHS input, but with a composite camera */
+ case METEOR_INPUT_DEV2:
+ bktr->flags = (bktr->flags & ~METEOR_DEV_MASK)
+ | METEOR_DEV2;
+ OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) & ~BT848_IFORM_MUXSEL);
+ OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX2);
+ OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) & ~BT848_E_CONTROL_COMP);
+ OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_E_CONTROL) & ~BT848_O_CONTROL_COMP);
+ set_audio( bktr, AUDIO_EXTERN );
+ break;
+
+ /* this is the S-VHS input */
+ case METEOR_INPUT_DEV_SVIDEO:
+ bktr->flags = (bktr->flags & ~METEOR_DEV_MASK)
+ | METEOR_DEV_SVIDEO;
+ OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) & ~BT848_IFORM_MUXSEL);
+ OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX2);
+ OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) | BT848_E_CONTROL_COMP);
+ OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) | BT848_O_CONTROL_COMP);
+ set_audio( bktr, AUDIO_EXTERN );
+ break;
+
+ case METEOR_INPUT_DEV3:
+ if ((bktr->id == BROOKTREE_848A) ||
+ (bktr->id == BROOKTREE_849A) ||
+ (bktr->id == BROOKTREE_878) ||
+ (bktr->id == BROOKTREE_879) ) {
+ bktr->flags = (bktr->flags & ~METEOR_DEV_MASK)
+ | METEOR_DEV3;
+ OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) & ~BT848_IFORM_MUXSEL);
+
+ /* work around for new Hauppauge 878 cards */
+ if ((bktr->card.card_id == CARD_HAUPPAUGE) &&
+ (bktr->id==BROOKTREE_878 ||
+ bktr->id==BROOKTREE_879) )
+ OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX1);
+ else
+ OUTB(bktr, BKTR_IFORM, INB(bktr, BKTR_IFORM) | BT848_IFORM_M_MUX3);
+
+ OUTB(bktr, BKTR_E_CONTROL, INB(bktr, BKTR_E_CONTROL) & ~BT848_E_CONTROL_COMP);
+ OUTB(bktr, BKTR_O_CONTROL, INB(bktr, BKTR_O_CONTROL) & ~BT848_O_CONTROL_COMP);
+ set_audio( bktr, AUDIO_EXTERN );
+
+ break;
+ }
+
+ default:
+ return( EINVAL );
+ }
+ break;
+
+ case METEORGINPUT: /* get input device */
+ *(u_long *)arg = bktr->flags & METEOR_DEV_MASK;
+ break;
+
+ case METEORSACTPIXFMT:
+ if (( *(int *)arg < 0 ) ||
+ ( *(int *)arg >= PIXFMT_TABLE_SIZE ))
+ return( EINVAL );
+
+ bktr->pixfmt = *(int *)arg;
+ OUTB(bktr, BKTR_COLOR_CTL, (INB(bktr, BKTR_COLOR_CTL) & 0xf0)
+ | pixfmt_swap_flags( bktr->pixfmt ));
+ bktr->pixfmt_compat = FALSE;
+ break;
+
+ case METEORGACTPIXFMT:
+ *(int *)arg = bktr->pixfmt;
+ break;
+
+ case METEORGSUPPIXFMT :
+ pf_pub = (struct meteor_pixfmt *)arg;
+ pixfmt = pf_pub->index;
+
+ if (( pixfmt < 0 ) || ( pixfmt >= PIXFMT_TABLE_SIZE ))
+ return( EINVAL );
+
+ memcpy( pf_pub, &pixfmt_table[ pixfmt ].public,
+ sizeof( *pf_pub ) );
+
+ /* Patch in our format index */
+ pf_pub->index = pixfmt;
+ break;
+
+#if defined( STATUS_SUM )
+ case BT848_GSTATUS: /* reap status */
+ {
+ DECLARE_INTR_MASK(s);
+ DISABLE_INTR(s);
+ temp = status_sum;
+ status_sum = 0;
+ ENABLE_INTR(s);
+ *(u_int*)arg = temp;
+ break;
+ }
+#endif /* STATUS_SUM */
+
+ default:
+ return( ENOTTY );
+ }
+
+ return( 0 );
+}
+
+
+
+
+/******************************************************************************
+ * bt848 RISC programming routines:
+ */
+
+
+/*
+ *
+ */
+#ifdef BT848_DEBUG
+static int
+dump_bt848( bktr_ptr_t bktr )
+{
+ int r[60]={
+ 4, 8, 0xc, 0x8c, 0x10, 0x90, 0x14, 0x94,
+ 0x18, 0x98, 0x1c, 0x9c, 0x20, 0xa0, 0x24, 0xa4,
+ 0x28, 0x2c, 0xac, 0x30, 0x34, 0x38, 0x3c, 0x40,
+ 0xc0, 0x48, 0x4c, 0xcc, 0x50, 0xd0, 0xd4, 0x60,
+ 0x64, 0x68, 0x6c, 0xec, 0xd8, 0xdc, 0xe0, 0xe4,
+ 0, 0, 0, 0
+ };
+ int i;
+
+ for (i = 0; i < 40; i+=4) {
+ printf("%s: Reg:value : \t%x:%x \t%x:%x \t %x:%x \t %x:%x\n",
+ bktr_name(bktr),
+ r[i], INL(bktr, r[i]),
+ r[i+1], INL(bktr, r[i+1]),
+ r[i+2], INL(bktr, r[i+2]),
+ r[i+3], INL(bktr, r[i+3]]));
+ }
+
+ printf("%s: INT STAT %x \n", bktr_name(bktr),
+ INL(bktr, BKTR_INT_STAT));
+ printf("%s: Reg INT_MASK %x \n", bktr_name(bktr),
+ INL(bktr, BKTR_INT_MASK));
+ printf("%s: Reg GPIO_DMA_CTL %x \n", bktr_name(bktr),
+ INW(bktr, BKTR_GPIO_DMA_CTL));
+
+ return( 0 );
+}
+
+#endif
+
+/*
+ * build write instruction
+ */
+#define BKTR_FM1 0x6 /* packed data to follow */
+#define BKTR_FM3 0xe /* planar data to follow */
+#define BKTR_VRE 0x4 /* Marks the end of the even field */
+#define BKTR_VRO 0xC /* Marks the end of the odd field */
+#define BKTR_PXV 0x0 /* valid word (never used) */
+#define BKTR_EOL 0x1 /* last dword, 4 bytes */
+#define BKTR_SOL 0x2 /* first dword */
+
+#define OP_WRITE (0x1 << 28)
+#define OP_SKIP (0x2 << 28)
+#define OP_WRITEC (0x5 << 28)
+#define OP_JUMP (0x7 << 28)
+#define OP_SYNC (0x8 << 28)
+#define OP_WRITE123 (0x9 << 28)
+#define OP_WRITES123 (0xb << 28)
+#define OP_SOL (1 << 27) /* first instr for scanline */
+#define OP_EOL (1 << 26)
+
+#define BKTR_RESYNC (1 << 15)
+#define BKTR_GEN_IRQ (1 << 24)
+
+/*
+ * The RISC status bits can be set/cleared in the RISC programs
+ * and tested in the Interrupt Handler
+ */
+#define BKTR_SET_RISC_STATUS_BIT0 (1 << 16)
+#define BKTR_SET_RISC_STATUS_BIT1 (1 << 17)
+#define BKTR_SET_RISC_STATUS_BIT2 (1 << 18)
+#define BKTR_SET_RISC_STATUS_BIT3 (1 << 19)
+
+#define BKTR_CLEAR_RISC_STATUS_BIT0 (1 << 20)
+#define BKTR_CLEAR_RISC_STATUS_BIT1 (1 << 21)
+#define BKTR_CLEAR_RISC_STATUS_BIT2 (1 << 22)
+#define BKTR_CLEAR_RISC_STATUS_BIT3 (1 << 23)
+
+#define BKTR_TEST_RISC_STATUS_BIT0 (1 << 28)
+#define BKTR_TEST_RISC_STATUS_BIT1 (1 << 29)
+#define BKTR_TEST_RISC_STATUS_BIT2 (1 << 30)
+#define BKTR_TEST_RISC_STATUS_BIT3 (1 << 31)
+
+static bool_t notclipped (bktr_reg_t * bktr, int x, int width) {
+ int i;
+ bktr_clip_t * clip_node;
+ bktr->clip_start = -1;
+ bktr->last_y = 0;
+ bktr->y = 0;
+ bktr->y2 = width;
+ bktr->line_length = width;
+ bktr->yclip = -1;
+ bktr->yclip2 = -1;
+ bktr->current_col = 0;
+
+ if (bktr->max_clip_node == 0 ) return TRUE;
+ clip_node = (bktr_clip_t *) &bktr->clip_list[0];
+
+
+ for (i = 0; i < bktr->max_clip_node; i++ ) {
+ clip_node = (bktr_clip_t *) &bktr->clip_list[i];
+ if (x >= clip_node->x_min && x <= clip_node->x_max ) {
+ bktr->clip_start = i;
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static bool_t getline(bktr_reg_t *bktr, int x ) {
+ int i, j;
+ bktr_clip_t * clip_node ;
+
+ if (bktr->line_length == 0 ||
+ bktr->current_col >= bktr->line_length) return FALSE;
+
+ bktr->y = min(bktr->last_y, bktr->line_length);
+ bktr->y2 = bktr->line_length;
+
+ bktr->yclip = bktr->yclip2 = -1;
+ for (i = bktr->clip_start; i < bktr->max_clip_node; i++ ) {
+ clip_node = (bktr_clip_t *) &bktr->clip_list[i];
+ if (x >= clip_node->x_min && x <= clip_node->x_max) {
+ if (bktr->last_y <= clip_node->y_min) {
+ bktr->y = min(bktr->last_y, bktr->line_length);
+ bktr->y2 = min(clip_node->y_min, bktr->line_length);
+ bktr->yclip = min(clip_node->y_min, bktr->line_length);
+ bktr->yclip2 = min(clip_node->y_max, bktr->line_length);
+ bktr->last_y = bktr->yclip2;
+ bktr->clip_start = i;
+
+ for (j = i+1; j < bktr->max_clip_node; j++ ) {
+ clip_node = (bktr_clip_t *) &bktr->clip_list[j];
+ if (x >= clip_node->x_min && x <= clip_node->x_max) {
+ if (bktr->last_y >= clip_node->y_min) {
+ bktr->yclip2 = min(clip_node->y_max, bktr->line_length);
+ bktr->last_y = bktr->yclip2;
+ bktr->clip_start = j;
+ }
+ } else break ;
+ }
+ return TRUE;
+ }
+ }
+ }
+
+ if (bktr->current_col <= bktr->line_length) {
+ bktr->current_col = bktr->line_length;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static bool_t split(bktr_reg_t * bktr, volatile uint32_t **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 uint32_t target_buffer, buffer, target,width;
+ volatile uint32_t pitch;
+ volatile uint32_t *dma_prog; /* DMA prog is an array of
+ 32 bit RISC instructions */
+ volatile uint32_t *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 = (uint32_t *) 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 uint32_t **) &dma_prog,
+ bktr->y2 - bktr->y, OP_WRITE,
+ Bpp, (volatile u_char **)(uintptr_t)&target, cols);
+
+ } else {
+ while(getline(bktr, i)) {
+ if (bktr->y != bktr->y2 ) {
+ split(bktr, (volatile uint32_t **) &dma_prog,
+ bktr->y2 - bktr->y, OP_WRITE,
+ Bpp, (volatile u_char **)(uintptr_t)&target, cols);
+ }
+ if (bktr->yclip != bktr->yclip2 ) {
+ split(bktr,(volatile uint32_t **) &dma_prog,
+ bktr->yclip2 - bktr->yclip,
+ OP_SKIP,
+ Bpp, (volatile u_char **)(uintptr_t)&target, cols);
+ }
+ }
+
+ }
+
+ target_buffer += interlace * pitch;
+
+ }
+
+ } /* end if */
+
+ /* Grab the Even field */
+ /* Look for the VRO, end of Odd field, marker */
+ *dma_prog++ = OP_SYNC | BKTR_GEN_IRQ | BKTR_RESYNC | BKTR_VRO;
+ *dma_prog++ = 0; /* NULL WORD */
+
+ /* store the VBI data */
+ /* look for sync with packed data */
+ *dma_prog++ = OP_SYNC | BKTR_FM1;
+ *dma_prog++ = 0;
+ for(i = 0; i < vbilines; i++) {
+ *dma_prog++ = OP_WRITE | OP_SOL | OP_EOL | vbisamples;
+ *dma_prog++ = (u_long) vtophys((caddr_t)bktr->vbidata +
+ ((i+MAX_VBI_LINES) * VBI_LINE_SIZE));
+ }
+
+ /* store the video image */
+ if (i_flag == 1) /*Even Only*/
+ target_buffer = buffer;
+ if (i_flag == 3) /*interlaced*/
+ target_buffer = buffer+pitch;
+
+
+ if ((i_flag == 1) /*Even Only*/ || (i_flag==3) /*interlaced*/) {
+ /* look for sync with packed data */
+ *dma_prog++ = OP_SYNC | BKTR_FM1;
+ *dma_prog++ = 0; /* NULL WORD */
+ width = cols;
+ for (i = 0; i < (rows/interlace); i++) {
+ target = target_buffer;
+ if ( notclipped(bktr, i, width)) {
+ split(bktr, (volatile uint32_t **) &dma_prog,
+ bktr->y2 - bktr->y, OP_WRITE,
+ Bpp, (volatile u_char **)(uintptr_t)&target, cols);
+ } else {
+ while(getline(bktr, i)) {
+ if (bktr->y != bktr->y2 ) {
+ split(bktr, (volatile uint32_t **) &dma_prog,
+ bktr->y2 - bktr->y, OP_WRITE,
+ Bpp, (volatile u_char **)(uintptr_t)&target,
+ cols);
+ }
+ if (bktr->yclip != bktr->yclip2 ) {
+ split(bktr, (volatile uint32_t **) &dma_prog,
+ bktr->yclip2 - bktr->yclip, OP_SKIP,
+ Bpp, (volatile u_char **)(uintptr_t) &target, cols);
+ }
+
+ }
+
+ }
+
+ target_buffer += interlace * pitch;
+
+ }
+ }
+
+ /* Look for end of 'Even Field' */
+ *dma_prog++ = OP_SYNC | BKTR_GEN_IRQ | BKTR_RESYNC | BKTR_VRE;
+ *dma_prog++ = 0; /* NULL WORD */
+
+ *dma_prog++ = OP_JUMP ;
+ *dma_prog++ = (u_long ) vtophys(loop_point) ;
+ *dma_prog++ = 0; /* NULL WORD */
+
+}
+
+
+
+
+static void
+rgb_prog( bktr_ptr_t bktr, char i_flag, int cols, int rows, int interlace )
+{
+ int i;
+ volatile uint32_t target_buffer, buffer, target,width;
+ volatile uint32_t pitch;
+ volatile uint32_t *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 = (uint32_t *) bktr->dma_prog;
+
+ /* Construct Write */
+
+ if (bktr->video.addr) {
+ target_buffer = (uint32_t) bktr->video.addr;
+ pitch = bktr->video.width;
+ }
+ else {
+ target_buffer = (uint32_t) 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 uint32_t **) &dma_prog,
+ bktr->y2 - bktr->y, OP_WRITE,
+ Bpp, (volatile u_char **)(uintptr_t)&target, cols);
+
+ } else {
+ while(getline(bktr, i)) {
+ if (bktr->y != bktr->y2 ) {
+ split(bktr, (volatile uint32_t **) &dma_prog,
+ bktr->y2 - bktr->y, OP_WRITE,
+ Bpp, (volatile u_char **)(uintptr_t)&target, cols);
+ }
+ if (bktr->yclip != bktr->yclip2 ) {
+ split(bktr,(volatile uint32_t **) &dma_prog,
+ bktr->yclip2 - bktr->yclip,
+ OP_SKIP,
+ Bpp, (volatile u_char **)(uintptr_t)&target, cols);
+ }
+ }
+
+ }
+
+ target_buffer += interlace * pitch;
+
+ }
+
+ switch (i_flag) {
+ case 1:
+ /* sync vre */
+ *dma_prog++ = OP_SYNC | BKTR_GEN_IRQ | BKTR_VRO;
+ *dma_prog++ = 0; /* NULL WORD */
+
+ *dma_prog++ = OP_JUMP;
+ *dma_prog++ = (uint32_t ) 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++ = (uint32_t ) 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 = (uint32_t ) vtophys(bktr->odd_dma_prog);
+ break;
+ }
+
+ if (interlace == 2) {
+
+ target_buffer = buffer + pitch;
+
+ dma_prog = (uint32_t *) 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 uint32_t **) &dma_prog,
+ bktr->y2 - bktr->y, OP_WRITE,
+ Bpp, (volatile u_char **)(uintptr_t)&target, cols);
+ } else {
+ while(getline(bktr, i)) {
+ if (bktr->y != bktr->y2 ) {
+ split(bktr, (volatile uint32_t **) &dma_prog,
+ bktr->y2 - bktr->y, OP_WRITE,
+ Bpp, (volatile u_char **)(uintptr_t)&target,
+ cols);
+ }
+ if (bktr->yclip != bktr->yclip2 ) {
+ split(bktr, (volatile uint32_t **) &dma_prog,
+ bktr->yclip2 - bktr->yclip, OP_SKIP,
+ Bpp, (volatile u_char **)(uintptr_t)&target, cols);
+ }
+
+ }
+
+ }
+
+ target_buffer += interlace * pitch;
+
+ }
+ }
+
+ /* sync vre IRQ bit */
+ *dma_prog++ = OP_SYNC | BKTR_GEN_IRQ | BKTR_RESYNC | BKTR_VRE;
+ *dma_prog++ = 0; /* NULL WORD */
+ *dma_prog++ = OP_JUMP ;
+ *dma_prog++ = (uint32_t ) 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 uint32_t target_buffer, buffer;
+ volatile uint32_t *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 = (uint32_t *) 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 = (uint32_t) bktr->video.addr;
+ else
+ target_buffer = (uint32_t) vtophys(bktr->bigbuf);
+
+ buffer = target_buffer;
+
+ /* contruct sync : for video packet format */
+ /* sync, mode indicator packed data */
+ *dma_prog++ = OP_SYNC | BKTR_RESYNC | BKTR_FM1;
+ *dma_prog++ = 0; /* NULL WORD */
+
+ b = cols;
+
+ for (i = 0; i < (rows/interlace); i++) {
+ *dma_prog++ = inst;
+ *dma_prog++ = target_buffer;
+ *dma_prog++ = inst3;
+ *dma_prog++ = target_buffer + b;
+ target_buffer += interlace*(cols * 2);
+ }
+
+ switch (i_flag) {
+ case 1:
+ /* sync vre */
+ *dma_prog++ = OP_SYNC | BKTR_GEN_IRQ | BKTR_VRE;
+ *dma_prog++ = 0; /* NULL WORD */
+
+ *dma_prog++ = OP_JUMP;
+ *dma_prog++ = (uint32_t) vtophys(bktr->dma_prog);
+ return;
+
+ case 2:
+ /* sync vro */
+ *dma_prog++ = OP_SYNC | BKTR_GEN_IRQ | BKTR_VRO;
+ *dma_prog++ = 0; /* NULL WORD */
+ *dma_prog++ = OP_JUMP;
+ *dma_prog++ = (uint32_t) 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 = (uint32_t) vtophys(bktr->odd_dma_prog);
+ break;
+ }
+
+ if (interlace == 2) {
+
+ target_buffer = (uint32_t) buffer + cols*2;
+
+ dma_prog = (uint32_t *) bktr->odd_dma_prog;
+
+ /* sync vre */
+ *dma_prog++ = OP_SYNC | BKTR_RESYNC | BKTR_FM1;
+ *dma_prog++ = 0; /* NULL WORD */
+
+ for (i = 0; i < (rows/interlace) ; i++) {
+ *dma_prog++ = inst;
+ *dma_prog++ = target_buffer;
+ *dma_prog++ = inst3;
+ *dma_prog++ = target_buffer + b;
+ target_buffer += interlace * ( cols*2);
+ }
+ }
+
+ /* sync vro IRQ bit */
+ *dma_prog++ = OP_SYNC | BKTR_GEN_IRQ | BKTR_RESYNC | BKTR_VRE;
+ *dma_prog++ = 0; /* NULL WORD */
+ *dma_prog++ = OP_JUMP ;
+ *dma_prog++ = (uint32_t) vtophys(bktr->dma_prog);
+
+ *dma_prog++ = OP_JUMP;
+ *dma_prog++ = (uint32_t) 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 uint32_t target_buffer, t1, buffer;
+ volatile uint32_t *dma_prog;
+ struct meteor_pixfmt_internal *pf_int = &pixfmt_table[ bktr->pixfmt ];
+
+ OUTB(bktr, BKTR_COLOR_FMT, pf_int->color_fmt);
+
+ dma_prog = (uint32_t*) 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 = (uint32_t) bktr->video.addr;
+ else
+ target_buffer = (uint32_t) 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++ = (uint32_t) 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++ = (uint32_t) 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 = (uint32_t) vtophys(bktr->odd_dma_prog);
+ break;
+ }
+
+ if (interlace == 2) {
+
+ dma_prog = (uint32_t *) bktr->odd_dma_prog;
+
+ target_buffer = (uint32_t) 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++ = (uint32_t) 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 uint32_t target_buffer, t1, buffer;
+ volatile uint32_t *dma_prog;
+ struct meteor_pixfmt_internal *pf_int = &pixfmt_table[ bktr->pixfmt ];
+
+ OUTB(bktr, BKTR_COLOR_FMT, pf_int->color_fmt);
+
+ dma_prog = (uint32_t *) 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 = (uint32_t) bktr->video.addr;
+ else
+ target_buffer = (uint32_t) 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++ = (uint32_t) 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++ = (uint32_t) 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 = (uint32_t) vtophys(bktr->odd_dma_prog);
+ break;
+ }
+
+ if (interlace == 2) {
+
+ dma_prog = (uint32_t *) bktr->odd_dma_prog;
+
+ target_buffer = (uint32_t) 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++ = (uint32_t) 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.iicbb)
+
+/* 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 */
+