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