Subversion Repositories shark

Compare Revisions

Ignore whitespace Rev 426 → Rev 428

/shark/trunk/drivers/bttv/gpio.c
File deleted
/shark/trunk/drivers/bttv/include/drivers/gpio.h
File deleted
/shark/trunk/drivers/bttv/include/drivers/compbttv.h
File deleted
/shark/trunk/drivers/bttv/include/drivers/videodev.h
File deleted
/shark/trunk/drivers/bttv/include/drivers/bt848.h
204,6 → 204,9
#define BT848_COLOR_FMT_YCrCb411 0x99
#define BT848_COLOR_FMT_RAW 0xee
 
#define BT848_VTOTAL_LO 0xB0
#define BT848_VTOTAL_HI 0xB4
 
#define BT848_COLOR_CTL 0x0D8
#define BT848_COLOR_CTL_EXT_FRMRATE (1<<7)
#define BT848_COLOR_CTL_COLOR_BARS (1<<6)
279,6 → 282,10
#define BT848_GPIO_DMA_CTL_FIFO_ENABLE (1<<0)
 
#define BT848_I2C 0x110
#define BT878_I2C_MODE (1<<7)
#define BT878_I2C_RATE (1<<6)
#define BT878_I2C_NOSTOP (1<<5)
#define BT878_I2C_NOSTART (1<<4)
#define BT848_I2C_DIV (0xf<<4)
#define BT848_I2C_SYNC (1<<3)
#define BT848_I2C_W3B (1<<2)
285,7 → 292,6
#define BT848_I2C_SCL (1<<1)
#define BT848_I2C_SDA (1<<0)
 
 
#define BT848_RISC_STRT_ADD 0x114
#define BT848_GPIO_OUT_EN 0x118
#define BT848_GPIO_REG_INP 0x11C
311,31 → 317,30
 
/* WRITE and SKIP */
/* disable which bytes of each DWORD */
#define BT848_RISC_BYTE0 (1<<12)
#define BT848_RISC_BYTE1 (1<<13)
#define BT848_RISC_BYTE2 (1<<14)
#define BT848_RISC_BYTE3 (1<<15)
#define BT848_RISC_BYTE_ALL (0x0f<<12)
#define BT848_RISC_BYTE0 (1U<<12)
#define BT848_RISC_BYTE1 (1U<<13)
#define BT848_RISC_BYTE2 (1U<<14)
#define BT848_RISC_BYTE3 (1U<<15)
#define BT848_RISC_BYTE_ALL (0x0fU<<12)
#define BT848_RISC_BYTE_NONE 0
/* cause RISCI */
#define BT848_RISC_IRQ (1<<24)
#define BT848_RISC_IRQ (1U<<24)
/* RISC command is last one in this line */
#define BT848_RISC_EOL (1<<26)
#define BT848_RISC_EOL (1U<<26)
/* RISC command is first one in this line */
#define BT848_RISC_SOL (1<<27)
#define BT848_RISC_SOL (1U<<27)
 
#define BT848_RISC_WRITE (0x01<<28)
#define BT848_RISC_SKIP (0x02<<28)
#define BT848_RISC_WRITEC (0x05<<28)
#define BT848_RISC_JUMP (0x07<<28)
#define BT848_RISC_SYNC (0x08<<28)
#define BT848_RISC_WRITE (0x01U<<28)
#define BT848_RISC_SKIP (0x02U<<28)
#define BT848_RISC_WRITEC (0x05U<<28)
#define BT848_RISC_JUMP (0x07U<<28)
#define BT848_RISC_SYNC (0x08U<<28)
 
#define BT848_RISC_WRITE123 (0x09<<28)
#define BT848_RISC_SKIP123 (0x0a<<28)
#define BT848_RISC_WRITE1S23 (0x0b<<28)
#define BT848_RISC_WRITE123 (0x09U<<28)
#define BT848_RISC_SKIP123 (0x0aU<<28)
#define BT848_RISC_WRITE1S23 (0x0bU<<28)
 
 
 
/* Bt848A and higher only !! */
#define BT848_TGLB 0x080
#define BT848_TGCTRL 0x084
347,6 → 352,8
#define BT848_PLL_X (1<<7)
#define BT848_PLL_C (1<<6)
 
#define BT848_DVSIF 0x0FC
 
/* Bt878 register */
 
#define BT878_DEVCTRL 0x40
/shark/trunk/drivers/bttv/include/drivers/tuner.h
62,6 → 62,9
#define TUNER_TEMIC_4012FY5 35 /* 4012 FY5 (3X 0971, 1099)*/
#define TUNER_TEMIC_4136FY5 36 /* 4136 FY5 (3X 7708, 7746)*/
#define TUNER_LG_PAL_NEW_TAPC 37
#define TUNER_PHILIPS_FM1216ME_MK3 38
#define TUNER_LG_NTSC_NEW_TAPC 39
#define TUNER_HITACHI_NTSC 40
 
 
 
80,10 → 83,13
#define SHARP 6
#define Samsung 7
#define Microtune 8
#define HITACHI 9
 
#define TUNER_SET_TYPE _IOW('t',1,int) /* set tuner type */
#define TUNER_SET_TVFREQ _IOW('t',2,int) /* set tv freq */
#define TUNER_SET_RADIOFREQ _IOW('t',3,int) /* set radio freq */
#define TUNER_SET_MODE _IOW('t',4,int) /* set tuner mode */
#if 0 /* obsolete */
# define TUNER_SET_RADIOFREQ _IOW('t',3,int) /* set radio freq */
# define TUNER_SET_MODE _IOW('t',4,int) /* set tuner mode */
#endif
 
#endif
/shark/trunk/drivers/bttv/include/drivers/btcx-risc.h
0,0 → 1,33
 
struct btcx_riscmem {
unsigned int size;
u32 *cpu;
u32 *jmp;
dma_addr_t dma;
};
 
struct btcx_skiplist {
int start;
int end;
};
 
int btcx_riscmem_alloc(struct pci_dev *pci,
struct btcx_riscmem *risc,
unsigned int size);
void btcx_riscmem_free(struct pci_dev *pci,
struct btcx_riscmem *risc);
 
int btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win,
struct v4l2_clip *clips, unsigned int n);
int btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips,
unsigned int n, int mask);
void btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips);
void btcx_calc_skips(int line, int width, unsigned int *maxy,
struct btcx_skiplist *skips, unsigned int *nskips,
const struct v4l2_clip *clips, unsigned int nclips);
 
/*
* Local variables:
* c-basic-offset: 8
* End:
*/
/shark/trunk/drivers/bttv/include/drivers/bttv.h
13,20 → 13,11
#ifndef _BTTV_H_
#define _BTTV_H_
 
#include <sys/types.h>
#include "drivers/compbttv.h"
#include <linux/videodev.h>
 
#include "drivers/videodev.h"
#include "linux/i2c.h"
#include "linux/i2c-algo-bit.h"
/* ---------------------------------------------------------- */
/* exported by bttv-cards.c */
 
#include "drivers/bt848.h"
#include "drivers/audiochip.h"
 
#include "drivers/gpio.h"
 
#define I2C_CLIENTS_MAX 16
 
#define BTTV_UNKNOWN 0x00
#define BTTV_MIRO 0x01
#define BTTV_HAUPPAUGE 0x02
99,22 → 90,39
#define BTTV_SENSORAY311 0x49
#define BTTV_RV605 0x4a
#define BTTV_WINDVR 0x4c
#define BTTV_OSPREY1x0 0x4f
#define BTTV_OSPREY1x0_848 0x50
#define BTTV_OSPREY101_848 0x51
#define BTTV_OSPREY1x1 0x52
#define BTTV_OSPREY1x1_SVID 0x53
#define BTTV_OSPREY2xx 0x54
#define BTTV_OSPREY2x0_SVID 0x55
#define BTTV_OSPREY2x0 0x56
#define BTTV_OSPREY5x0 0x57
#define BTTV_OSPREY2000 0x58
#define BTTV_OSPREY_BEGIN BTTV_OSPREY1x0
#define BTTV_OSPREY_END BTTV_OSPREY2000
#define BTTV_GRANDTEC 0x4d
#define BTTV_KWORLD 0x4e
#define BTTV_HAUPPAUGEPVR 0x50
#define BTTV_GVBCTV5PCI 0x51
#define BTTV_OSPREY1x0 0x52
#define BTTV_OSPREY1x0_848 0x53
#define BTTV_OSPREY101_848 0x54
#define BTTV_OSPREY1x1 0x55
#define BTTV_OSPREY1x1_SVID 0x56
#define BTTV_OSPREY2xx 0x57
#define BTTV_OSPREY2x0_SVID 0x58
#define BTTV_OSPREY2x0 0x59
#define BTTV_OSPREY500 0x5a
#define BTTV_OSPREY540 0x5b
#define BTTV_OSPREY2000 0x5c
#define BTTV_IDS_EAGLE 0x5d
#define BTTV_PINNACLESAT 0x5e
#define BTTV_FORMAC_PROTV 0x5f
#define BTTV_EURESYS_PICOLO 0x61
#define BTTV_PV150 0x62
#define BTTV_AD_TVK503 0x63
#define BTTV_IVC200 0x66
#define BTTV_XGUARD 0x67
#define BTTV_NEBULA_DIGITV 0x68
#define BTTV_PV143 0x69
#define BTTV_IVC100 0x6e
#define BTTV_IVC120 0x6f
 
/* i2c address list */
#define I2C_TSA5522 0xc2
#define I2C_TDA7432 0x8a
#define I2C_BT832_ALT1 0x88
#define I2C_BT832_ALT2 0x8a // alternate setting
#define I2C_TDA8425 0x82
#define I2C_TDA9840 0x84
#define I2C_TDA9850 0xb6 /* also used by 9855,9873 */
124,8 → 132,10
#define I2C_STBEE 0xae
#define I2C_VHX 0xc0
#define I2C_MSP3400 0x80
#define I2C_MSP3400_ALT 0x88
#define I2C_TEA6300 0x80
#define I2C_DPL3518 0x84
#define I2C_TDA9887 0x86
 
/* more card-specific defines */
#define PT2254_L_CHANNEL 0x10
136,193 → 146,20
#define WINVIEW_PT2254_DATA 0x20
#define WINVIEW_PT2254_STROBE 0x80
 
#define dprintk if (bttv_debug) cprintf
/* digital_mode */
#define DIGITAL_MODE_VIDEO 1
#define DIGITAL_MODE_CAMERA 2
 
/* Anybody who uses more than four? */
#define BTTV_MAX 4
extern int bttv_num; /* number of Bt848s in use */
extern struct bttv bttvs[BTTV_MAX];
struct bttv;
 
#ifndef O_NONCAP
#define O_NONCAP O_TRUNC
#endif
 
#ifdef VIDEODAT_HACK
# define VBI_MAXLINES 19
#else
# define VBI_MAXLINES 16
#endif
#define VBIBUF_SIZE (2048*VBI_MAXLINES*2)
#define MAX_GBUFFERS 64
#define RISCMEM_LEN (32744*2)
 
#define BTTV_MAX_FBUF 0x208000
 
struct bttv_window
{
int x, y;
ushort width, height;
ushort bpp, bpl;
ushort swidth, sheight;
unsigned long vidadr;
ushort freq;
int norm;
int interlace;
int color_fmt;
ushort depth;
};
 
struct bttv_pll_info {
unsigned int pll_ifreq; /* PLL input frequency */
unsigned int pll_ofreq; /* PLL output frequency */
unsigned int pll_crystal; /* Crystal used for input */
unsigned int pll_current; /* Currently programmed ofreq */
};
 
struct bttv_gbuf {
int stat;
#define GBUFFER_UNUSED 0
#define GBUFFER_GRABBING 1
#define GBUFFER_DONE 2
#define GBUFFER_ERROR 3
struct timespec tv;
u16 width;
u16 height;
u16 fmt;
u32 *risc;
unsigned long ro;
unsigned long re;
};
 
struct bttv {
struct video_device video_dev;
struct video_device radio_dev;
struct video_device vbi_dev;
struct video_picture picture; /* Current picture params */
struct video_audio audio_dev; /* Current audio params */
 
int user;
int capuser;
 
/* i2c */
struct i2c_adapter i2c_adap;
struct i2c_algo_bit_data i2c_algo;
struct i2c_client i2c_client;
int i2c_state, i2c_rc;
struct i2c_client *i2c_clients[I2C_CLIENTS_MAX];
 
int tuner_type;
int channel;
unsigned int nr;
unsigned short id;
unsigned char revision;
unsigned long bt848_adr; /* bus address of IO mem returned by PCI BIOS */
struct pci_dev *dev;
unsigned char *bt848_mem; /* ptr to mapped IO memory */
struct gpio_adapter gpio_adap;
unsigned long busriscmem;
u32 *riscmem;
unsigned char *vbibuf;
struct bttv_window win;
int fb_color_ctl;
int type; /* card type */
int cardid;
int audio; /* audio mode */
int audio_chip; /* set to one of the chips supported by bttv.c */
int radio;
int has_radio;
 
/* miro/pinnacle + Aimslab VHX
philips matchbox (tea5757 radio tuner) support */
int has_matchbox;
int mbox_we;
int mbox_data;
int mbox_clk;
int mbox_most;
int mbox_mask;
 
u32 *risc_jmp;
u32 *vbi_odd;
u32 *vbi_even;
u32 bus_vbi_even;
u32 bus_vbi_odd;
int vbip;
 
u32 *risc_scr_odd;
u32 *risc_scr_even;
u32 risc_cap_odd;
u32 risc_cap_even;
int scr_on;
int vbi_on;
struct video_clip *cliprecs;
 
struct bttv_gbuf *gbuf;
int gqueue[MAX_GBUFFERS];
int gq_in,gq_out,gq_grab,gq_start;
char *fbuffer;
 
struct bttv_pll_info pll;
unsigned int Fsc;
unsigned int field;
unsigned int last_field; /* number of last grabbed field */
int i2c_command;
int triton1;
 
int errors;
int needs_restart;
 
int shutdown;
};
 
/* insmod options / kernel args */
extern int no_overlay;
extern unsigned int bttv_verbose;
extern unsigned int bttv_debug;
extern unsigned int bttv_gpio;
extern void bttv_gpio_tracking(struct bttv *btv, char *comment);
extern int init_bttv_i2c(struct bttv *btv);
 
#define btwrite(dat,adr) *(unsigned long *) (btv->bt848_mem+(adr)) = (unsigned long)(dat)
#define btread(adr) *(unsigned long *)(btv->bt848_mem+(adr))
 
#define btand(dat,adr) btwrite((dat) & btread(adr), adr)
#define btor(dat,adr) btwrite((dat) | btread(adr), adr)
#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr)
 
#define gpiowrite(dat) gpio_set (&(btv->gpio_adap),dat)
#define gpioread() btread(BT848_GPIO_DATA)
#define gpioand(dat) gpio_and (&(btv->gpio_adap),dat)
#define gpioor(dat) gpio_or (&(btv->gpio_adap),dat)
#define gpioaor(dat,mask) gpio_andor(&(btv->gpio_adap),mask,dat)
 
/* bttv ioctls */
 
#define BTTV_READEE _IOW('v', BASE_VIDIOCPRIVATE+0, char [256])
#define BTTV_WRITEE _IOR('v', BASE_VIDIOCPRIVATE+1, char [256])
#define BTTV_FIELDNR _IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int)
#define BTTV_PLLSET _IOW('v' , BASE_VIDIOCPRIVATE+3, struct bttv_pll_info)
#define BTTV_BURST_ON _IOR('v' , BASE_VIDIOCPRIVATE+4, int)
#define BTTV_BURST_OFF _IOR('v' , BASE_VIDIOCPRIVATE+5, int)
#define BTTV_VERSION _IOR('v' , BASE_VIDIOCPRIVATE+6, int)
#define BTTV_PICNR _IOR('v' , BASE_VIDIOCPRIVATE+7, int)
#define BTTV_VBISIZE _IOR('v' , BASE_VIDIOCPRIVATE+8, int)
 
#define TDA9850 0x01
#define TDA9840 0x02
#define TDA8425 0x03
#define TEA6300 0x04
 
struct tvcard
{
char *name;
int video_inputs;
int audio_inputs;
int tuner;
int svhs;
unsigned int video_inputs;
unsigned int audio_inputs;
unsigned int tuner;
unsigned int svhs;
unsigned int digital_mode; // DIGITAL_MODE_CAMERA or DIGITAL_MODE_VIDEO
u32 gpiomask;
u32 muxsel[16];
u32 audiomux[6]; /* Tuner, Radio, external, internal, mute, stereo */
329,25 → 166,29
u32 gpiomask2; /* GPIO MUX mask */
 
/* i2c audio flags */
int no_msp34xx:1;
int no_tda9875:1;
int no_tda7432:1;
int needs_tvaudio:1;
unsigned int no_msp34xx:1;
unsigned int no_tda9875:1;
unsigned int no_tda7432:1;
unsigned int needs_tvaudio:1;
unsigned int msp34xx_alt:1;
 
/* flag: video pci function is unused */
unsigned int no_video;
 
/* other settings */
int pll;
unsigned int pll;
#define PLL_NONE 0
#define PLL_28 1
#define PLL_35 2
 
int tuner_type;
int has_radio;
unsigned int tuner_type;
unsigned int has_radio;
void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set);
void (*muxsel_hook)(struct bttv *btv, unsigned int input);
};
 
extern struct tvcard bttv_tvcards[];
extern const int bttv_num_tvcards;
extern const unsigned int bttv_num_tvcards;
 
/* identification / initialization of the card */
extern void bttv_idcard(struct bttv *btv);
373,7 → 214,9
for possible values see lines below beginning with #define BTTV_UNKNOWN
returns negative value if error occurred
*/
extern int bttv_get_cardinfo(unsigned int card, int *type, int *cardid);
extern int bttv_get_cardinfo(unsigned int card, int *type,
unsigned int *cardid);
extern struct pci_dev* bttv_get_pcidev(unsigned int card);
 
/* obsolete, use bttv_get_cardinfo instead */
extern int bttv_get_id(unsigned int card);
397,6 → 240,22
extern int bttv_write_gpio(unsigned int card,
unsigned long mask, unsigned long data);
 
/* returns pointer to task queue which can be used as parameter to
interruptible_sleep_on
in interrupt handler if BT848_INT_GPINT bit is set - this queue is activated
(wake_up_interruptible) and following call to the function bttv_read_gpio
should return new value of GPDATA,
returns NULL value if error occurred or queue is not available
WARNING: because there is no buffer for GPIO data, one MUST
process data ASAP
*/
extern wait_queue_head_t* bttv_get_gpio_queue(unsigned int card);
 
/* call i2c clients
*/
extern void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg);
 
 
/* i2c */
extern void bttv_bit_setscl(void *data, int state);
extern void bttv_bit_setsda(void *data, int state);
406,7 → 265,9
unsigned char b2, int both);
extern void bttv_readee(struct bttv *btv, unsigned char *eedata, int addr);
 
struct pci_dev;
extern struct bttv *bttv_find_matching_card( struct pci_dev *dev );
 
#endif /* _BTTV_H_ */
/*
* Local variables:
* c-basic-offset: 8
* End:
*/
/shark/trunk/drivers/bttv/include/drivers/bttvp.h
0,0 → 1,399
/*
bttv - Bt848 frame grabber driver
 
bttv's *private* header file -- nobody other than bttv itself
should ever include this file.
 
(c) 2000-2002 Gerd Knorr <kraxel@bytesex.org>
 
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
 
#ifndef _BTTVP_H_
#define _BTTVP_H_
 
#include <linux/version.h>
#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,12)
 
#include <linux/types.h>
#include <linux/wait.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include <linux/videodev.h>
#include <linux/pci.h>
#include <linux/input.h>
#include <asm/scatterlist.h>
#include <asm/io.h>
 
#include <linux/device.h>
#include <drivers/video-buf.h>
#include <drivers/audiochip.h>
#include <drivers/tuner.h>
 
#include "drivers/bt848.h"
#include "drivers/bttv.h"
#include "drivers/btcx-risc.h"
#ifdef CONFIG_VIDEO_IR
#include "ir-common.h"
#endif
 
#ifdef __KERNEL__
 
#define FORMAT_FLAGS_DITHER 0x01
#define FORMAT_FLAGS_PACKED 0x02
#define FORMAT_FLAGS_PLANAR 0x04
#define FORMAT_FLAGS_RAW 0x08
#define FORMAT_FLAGS_CrCb 0x10
 
#define RISC_SLOT_O_VBI 4
#define RISC_SLOT_O_FIELD 6
#define RISC_SLOT_E_VBI 10
#define RISC_SLOT_E_FIELD 12
#define RISC_SLOT_LOOP 14
 
#define RESOURCE_OVERLAY 1
#define RESOURCE_VIDEO 2
#define RESOURCE_VBI 4
 
#define RAW_LINES 640
#define RAW_BPL 1024
 
#define UNSET (-1U)
 
/* ---------------------------------------------------------- */
 
struct bttv_tvnorm {
int v4l2_id;
char *name;
u32 Fsc;
u16 swidth, sheight; /* scaled standard width, height */
u16 totalwidth;
u8 adelay, bdelay, iform;
u32 scaledtwidth;
u16 hdelayx1, hactivex1;
u16 vdelay;
u8 vbipack;
u16 vtotal;
int sram;
};
extern const struct bttv_tvnorm bttv_tvnorms[];
extern const unsigned int BTTV_TVNORMS;
 
struct bttv_format {
char *name;
int palette; /* video4linux 1 */
int fourcc; /* video4linux 2 */
int btformat; /* BT848_COLOR_FMT_* */
int btswap; /* BT848_COLOR_CTL_* */
int depth; /* bit/pixel */
int flags;
int hshift,vshift; /* for planar modes */
};
extern const struct bttv_format bttv_formats[];
extern const unsigned int BTTV_FORMATS;
 
/* ---------------------------------------------------------- */
 
struct bttv_geometry {
u8 vtc,crop,comb;
u16 width,hscale,hdelay;
u16 sheight,vscale,vdelay,vtotal;
};
 
struct bttv_buffer {
/* common v4l buffer stuff -- must be first */
struct videobuf_buffer vb;
 
/* bttv specific */
const struct bttv_format *fmt;
int tvnorm;
int btformat;
int btswap;
struct bttv_geometry geo;
struct btcx_riscmem top;
struct btcx_riscmem bottom;
};
 
struct bttv_buffer_set {
struct bttv_buffer *top; /* top field buffer */
struct bttv_buffer *bottom; /* bottom field buffer */
struct bttv_buffer *vbi; /* vbi buffer */
unsigned int irqflags;
unsigned int topirq;
};
 
struct bttv_overlay {
int tvnorm;
struct v4l2_rect w;
enum v4l2_field field;
struct v4l2_clip *clips;
int nclips;
int setup_ok;
};
 
struct bttv_fh {
struct bttv *btv;
int resources;
#ifdef VIDIOC_G_PRIORITY
enum v4l2_priority prio;
#endif
enum v4l2_buf_type type;
 
/* video capture */
struct videobuf_queue cap;
const struct bttv_format *fmt;
int width;
int height;
 
/* current settings */
const struct bttv_format *ovfmt;
struct bttv_overlay ov;
 
/* video overlay */
struct videobuf_queue vbi;
int lines;
};
 
/* ---------------------------------------------------------- */
/* bttv-risc.c */
 
/* risc code generators - capture */
int bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
struct scatterlist *sglist,
unsigned int offset, unsigned int bpl,
unsigned int pitch, unsigned int lines);
int bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc,
struct scatterlist *sglist,
unsigned int yoffset, unsigned int ybpl,
unsigned int ypadding, unsigned int ylines,
unsigned int uoffset, unsigned int voffset,
unsigned int hshift, unsigned int vshift,
unsigned int cpadding);
int bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
const struct bttv_format *fmt,
struct bttv_overlay *ov,
int skip_top, int skip_bottom);
 
/* calculate / apply geometry settings */
void bttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo,
int width, int height, int interleaved, int norm);
void bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int top);
 
/* control dma register + risc main loop */
void bttv_set_dma(struct bttv *btv, int override, int irqflags);
int bttv_risc_init_main(struct bttv *btv);
int bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc,
int irqflags);
 
/* capture buffer handling */
int bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf);
int bttv_buffer_set_activate(struct bttv *btv,
struct bttv_buffer_set *set);
void bttv_dma_free(struct bttv *btv, struct bttv_buffer *buf);
 
/* overlay handling */
int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov,
const struct bttv_format *fmt,
struct bttv_buffer *buf);
 
 
/* ---------------------------------------------------------- */
/* bttv-vbi.c */
 
void bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_format *f);
void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f);
void bttv_vbi_setlines(struct bttv_fh *fh, struct bttv *btv, int lines);
 
extern struct videobuf_queue_ops bttv_vbi_qops;
 
/* ---------------------------------------------------------- */
/* bttv-input.c */
 
int bttv_input_init(struct bttv *btv);
void bttv_input_fini(struct bttv *btv);
void bttv_input_irq(struct bttv *btv);
 
/* ---------------------------------------------------------- */
/* bttv-driver.c */
 
/* insmod options */
extern unsigned int bttv_verbose;
extern unsigned int bttv_debug;
extern unsigned int bttv_gpio;
extern void bttv_gpio_tracking(struct bttv *btv, char *comment);
extern int init_bttv_i2c(struct bttv *btv);
extern int fini_bttv_i2c(struct bttv *btv);
extern int pvr_boot(struct bttv *btv);
 
extern int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg);
extern void bttv_reinit_bt848(struct bttv *btv);
extern void bttv_field_count(struct bttv *btv);
 
#define vprintk if (bttv_verbose) printk
#define dprintk if (bttv_debug >= 1) printk
#define d2printk if (bttv_debug >= 2) printk
 
/* our devices */
#define BTTV_MAX 16
extern unsigned int bttv_num;
extern struct bttv bttvs[BTTV_MAX];
 
#define BTTV_MAX_FBUF 0x208000
#define VBIBUF_SIZE (2048*VBI_MAXLINES*2)
#define BTTV_TIMEOUT (HZ/2) /* 0.5 seconds */
#define BTTV_FREE_IDLE (HZ) /* one second */
 
 
struct bttv_pll_info {
unsigned int pll_ifreq; /* PLL input frequency */
unsigned int pll_ofreq; /* PLL output frequency */
unsigned int pll_crystal; /* Crystal used for input */
unsigned int pll_current; /* Currently programmed ofreq */
};
 
#ifdef CONFIG_VIDEO_IR
/* for gpio-connected remote control */
struct bttv_input {
struct input_dev dev;
struct ir_input_state ir;
char name[32];
char phys[32];
u32 mask_keycode;
u32 mask_keydown;
};
#endif
 
struct bttv {
/* pci device config */
struct pci_dev *dev;
unsigned short id;
unsigned char revision;
unsigned char *bt848_mmio; /* pointer to mmio */
 
/* card configuration info */
unsigned int nr; /* dev nr (for printk("bttv%d: ..."); */
char name[8]; /* dev name */
unsigned int cardid; /* pci subsystem id (bt878 based ones) */
unsigned int type; /* card type (pointer into tvcards[]) */
unsigned int tuner_type; /* tuner chip type */
unsigned int pinnacle_id;
unsigned int svhs;
struct bttv_pll_info pll;
int triton1;
 
/* gpio interface */
wait_queue_head_t gpioq;
int shutdown;
void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set);
/* i2c layer */
struct i2c_adapter i2c_adap;
struct i2c_algo_bit_data i2c_algo;
struct i2c_client i2c_client;
int i2c_state, i2c_rc;
 
/* video4linux (1) */
struct video_device *video_dev;
struct video_device *radio_dev;
struct video_device *vbi_dev;
 
/* infrared remote */
int has_remote;
#ifdef CONFIG_VIDEO_IR
struct bttv_input *remote;
#endif
 
/* locking */
spinlock_t s_lock;
struct semaphore lock;
int resources;
struct semaphore reslock;
#ifdef VIDIOC_G_PRIORITY
struct v4l2_prio_state prio;
#endif
/* video state */
unsigned int input;
unsigned int audio;
unsigned long freq;
int tvnorm,hue,contrast,bright,saturation;
struct v4l2_framebuffer fbuf;
unsigned int field_count;
 
/* various options */
int opt_combfilter;
int opt_lumafilter;
int opt_automute;
int opt_chroma_agc;
int opt_adc_crush;
int opt_vcr_hack;
 
/* radio data/state */
int has_radio;
int radio_user;
 
/* miro/pinnacle + Aimslab VHX
philips matchbox (tea5757 radio tuner) support */
int has_matchbox;
int mbox_we;
int mbox_data;
int mbox_clk;
int mbox_most;
int mbox_mask;
 
/* ISA stuff (Terratec Active Radio Upgrade) */
int mbox_ior;
int mbox_iow;
int mbox_csel;
 
/* risc memory management data
- must aquire s_lock before changing these
- only the irq handler is supported to touch top + bottom + vcurr */
struct btcx_riscmem main;
struct bttv_buffer *screen; /* overlay */
struct list_head capture; /* video capture queue */
struct list_head vcapture; /* vbi capture queue */
struct bttv_buffer_set curr; /* active buffers */
int new_input;
 
unsigned long cap_ctl;
unsigned long dma_on;
struct timer_list timeout;
unsigned int errors;
 
unsigned int users;
struct bttv_fh init;
};
 
/* private ioctls */
#define BTTV_VERSION _IOR('v' , BASE_VIDIOCPRIVATE+6, int)
#define BTTV_VBISIZE _IOR('v' , BASE_VIDIOCPRIVATE+8, int)
 
#endif
 
#define btwrite(dat,adr) writel((dat), (char *) (btv->bt848_mmio+(adr)))
#define btread(adr) readl(btv->bt848_mmio+(adr))
 
#define btand(dat,adr) btwrite((dat) & btread(adr), adr)
#define btor(dat,adr) btwrite((dat) | btread(adr), adr)
#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr)
 
#endif /* _BTTVP_H_ */
 
/*
* Local variables:
* c-basic-offset: 8
* End:
*/
/shark/trunk/drivers/bttv/include/drivers/video-buf.h
0,0 → 1,244
/*
* generic helper functions for video4linux capture buffers, to handle
* memory management and PCI DMA. Right now bttv + saa7134 use it.
*
* The functions expect the hardware being able to scatter gatter
* (i.e. the buffers are not linear in physical memory, but fragmented
* into PAGE_SIZE chunks). They also assume the driver does not need
* to touch the video data (thus it is probably not useful for USB as
* data often must be uncompressed by the drivers).
*
* (c) 2001,02 Gerd Knorr <kraxel@bytesex.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
 
#include <linux/videodev.h>
 
/* --------------------------------------------------------------------- */
 
/*
* Return a scatterlist for some page-aligned vmalloc()'ed memory
* block (NULL on errors). Memory for the scatterlist is allocated
* using kmalloc. The caller must free the memory.
*/
struct scatterlist* videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages);
 
/*
* Return a scatterlist for a an array of userpages (NULL on errors).
* Memory for the scatterlist is allocated using kmalloc. The caller
* must free the memory.
*/
struct scatterlist* videobuf_pages_to_sg(struct page **pages, int nr_pages,
int offset);
int videobuf_lock(struct page **pages, int nr_pages);
int videobuf_unlock(struct page **pages, int nr_pages);
 
/* --------------------------------------------------------------------- */
 
/*
* A small set of helper functions to manage buffers (both userland
* and kernel) for DMA.
*
* videobuf_dma_init_*()
* creates a buffer. The userland version takes a userspace
* pointer + length. The kernel version just wants the size and
* does memory allocation too using vmalloc_32().
*
* videobuf_dma_pci_*()
* see Documentation/DMA-mapping.txt, these functions to
* basically the same. The map function does also build a
* scatterlist for the buffer (and unmap frees it ...)
*
* videobuf_dma_free()
* no comment ...
*
*/
 
struct videobuf_dmabuf {
/* for userland buffer */
int offset;
struct page **pages;
 
/* for kernel buffers */
void *vmalloc;
 
/* for overlay buffers (pci-pci dma) */
dma_addr_t bus_addr;
 
/* common */
struct scatterlist *sglist;
int sglen;
int nr_pages;
int direction;
};
 
int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction,
unsigned long data, unsigned long size);
int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction,
int nr_pages);
int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction,
dma_addr_t addr, int nr_pages);
int videobuf_dma_pci_map(struct pci_dev *dev, struct videobuf_dmabuf *dma);
int videobuf_dma_pci_sync(struct pci_dev *dev,
struct videobuf_dmabuf *dma);
int videobuf_dma_pci_unmap(struct pci_dev *dev, struct videobuf_dmabuf *dma);
int videobuf_dma_free(struct videobuf_dmabuf *dma);
 
/* --------------------------------------------------------------------- */
 
/*
* A small set of helper functions to manage video4linux buffers.
*
* struct videobuf_buffer holds the data structures used by the helper
* functions, additionally some commonly used fields for v4l buffers
* (width, height, lists, waitqueue) are in there. That struct should
* be used as first element in the drivers buffer struct.
*
* about the mmap helpers (videobuf_mmap_*):
*
* The mmaper function allows to map any subset of contingous buffers.
* This includes one mmap() call for all buffers (which the original
* video4linux API uses) as well as one mmap() for every single buffer
* (which v4l2 uses).
*
* If there is a valid mapping for a buffer, buffer->baddr/bsize holds
* userspace address + size which can be feeded into the
* videobuf_dma_init_user function listed above.
*
*/
 
struct videobuf_buffer;
struct videobuf_queue;
 
struct videobuf_mapping {
unsigned int count;
int highmem_ok;
unsigned long start;
unsigned long end;
struct videobuf_queue *q;
};
 
enum videobuf_state {
STATE_NEEDS_INIT = 0,
STATE_PREPARED = 1,
STATE_QUEUED = 2,
STATE_ACTIVE = 3,
STATE_DONE = 4,
STATE_ERROR = 5,
STATE_IDLE = 6,
};
 
struct videobuf_buffer {
unsigned int i;
 
/* info about the buffer */
unsigned int width;
unsigned int height;
unsigned int bytesperline; /* use only if != 0 */
unsigned long size;
enum v4l2_field field;
enum videobuf_state state;
struct videobuf_dmabuf dma;
struct list_head stream; /* QBUF/DQBUF list */
 
/* for mmap'ed buffers */
enum v4l2_memory memory;
size_t boff; /* buffer offset (mmap + overlay) */
size_t bsize; /* buffer size */
unsigned long baddr; /* buffer addr (userland ptr!) */
struct videobuf_mapping *map;
 
/* touched by irq handler */
struct list_head queue;
wait_queue_head_t done;
unsigned int field_count;
struct timeval ts;
};
 
struct videobuf_queue_ops {
int (*buf_setup)(struct file *file,
unsigned int *count, unsigned int *size);
int (*buf_prepare)(struct file *file,struct videobuf_buffer *vb,
enum v4l2_field field);
void (*buf_queue)(struct file *file,struct videobuf_buffer *vb);
void (*buf_release)(struct file *file,struct videobuf_buffer *vb);
};
 
struct videobuf_queue {
struct semaphore lock;
spinlock_t *irqlock;
struct pci_dev *pci;
 
enum v4l2_buf_type type;
unsigned int msize;
enum v4l2_field field;
enum v4l2_field last; /* for field=V4L2_FIELD_ALTERNATE */
struct videobuf_buffer *bufs[VIDEO_MAX_FRAME];
struct videobuf_queue_ops *ops;
 
/* capture via mmap() + ioctl(QBUF/DQBUF) */
unsigned int streaming;
struct list_head stream;
 
/* capture via read() */
unsigned int reading;
unsigned int read_off;
struct videobuf_buffer *read_buf;
};
 
void* videobuf_alloc(unsigned int size);
int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr);
int videobuf_iolock(struct pci_dev *pci, struct videobuf_buffer *vb,
struct v4l2_framebuffer *fbuf);
 
void videobuf_queue_init(struct videobuf_queue *q,
struct videobuf_queue_ops *ops,
struct pci_dev *pci, spinlock_t *irqlock,
enum v4l2_buf_type type,
enum v4l2_field field,
unsigned int msize);
int videobuf_queue_is_busy(struct videobuf_queue *q);
void videobuf_queue_cancel(struct file *file, struct videobuf_queue *q);
 
enum v4l2_field videobuf_next_field(struct videobuf_queue *q);
void videobuf_status(struct v4l2_buffer *b, struct videobuf_buffer *vb,
enum v4l2_buf_type type);
int videobuf_reqbufs(struct file *file, struct videobuf_queue *q,
struct v4l2_requestbuffers *req);
int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b);
int videobuf_qbuf(struct file *file, struct videobuf_queue *q,
struct v4l2_buffer *b);
int videobuf_dqbuf(struct file *file, struct videobuf_queue *q,
struct v4l2_buffer *b);
int videobuf_streamon(struct file *file, struct videobuf_queue *q);
int videobuf_streamoff(struct file *file, struct videobuf_queue *q);
 
int videobuf_read_start(struct file *file, struct videobuf_queue *q);
void videobuf_read_stop(struct file *file, struct videobuf_queue *q);
ssize_t videobuf_read_stream(struct file *file, struct videobuf_queue *q,
char *data, size_t count, loff_t *ppos,
int vbihack);
ssize_t videobuf_read_one(struct file *file, struct videobuf_queue *q,
char *data, size_t count, loff_t *ppos);
unsigned int videobuf_poll_stream(struct file *file,
struct videobuf_queue *q,
poll_table *wait);
 
int videobuf_mmap_setup(struct file *file, struct videobuf_queue *q,
unsigned int bcount, unsigned int bsize,
enum v4l2_memory memory);
int videobuf_mmap_free(struct file *file, struct videobuf_queue *q);
int videobuf_mmap_mapper(struct vm_area_struct *vma,
struct videobuf_queue *q);
 
/* --------------------------------------------------------------------- */
 
/*
* Local variables:
* c-basic-offset: 8
* End:
*/
/shark/trunk/drivers/bttv/include/drivers/bt832.h
0,0 → 1,305
/* Bt832 CMOS Camera Video Processor (VP)
 
The Bt832 CMOS Camera Video Processor chip connects a Quartsight CMOS
color digital camera directly to video capture devices via an 8-bit,
4:2:2 YUV or YCrCb video interface.
 
i2c addresses: 0x88 or 0x8a
*/
 
/* The 64 registers: */
 
// Input Processor
#define BT832_OFFSET 0
#define BT832_RCOMP 1
#define BT832_G1COMP 2
#define BT832_G2COMP 3
#define BT832_BCOMP 4
// Exposures:
#define BT832_FINEH 5
#define BT832_FINEL 6
#define BT832_COARSEH 7
#define BT832_COARSEL 8
#define BT832_CAMGAIN 9
// Main Processor:
#define BT832_M00 10
#define BT832_M01 11
#define BT832_M02 12
#define BT832_M10 13
#define BT832_M11 14
#define BT832_M12 15
#define BT832_M20 16
#define BT832_M21 17
#define BT832_M22 18
#define BT832_APCOR 19
#define BT832_GAMCOR 20
// Level Accumulator Inputs
#define BT832_VPCONTROL2 21
#define BT832_ZONECODE0 22
#define BT832_ZONECODE1 23
#define BT832_ZONECODE2 24
#define BT832_ZONECODE3 25
// Level Accumulator Outputs:
#define BT832_RACC 26
#define BT832_GACC 27
#define BT832_BACC 28
#define BT832_BLACKACC 29
#define BT832_EXP_AGC 30
#define BT832_LACC0 31
#define BT832_LACC1 32
#define BT832_LACC2 33
#define BT832_LACC3 34
#define BT832_LACC4 35
#define BT832_LACC5 36
#define BT832_LACC6 37
#define BT832_LACC7 38
// System:
#define BT832_VP_CONTROL0 39
#define BT832_VP_CONTROL1 40
#define BT832_THRESH 41
#define BT832_VP_TESTCONTROL0 42
#define BT832_VP_DMCODE 43
#define BT832_ACB_CONFIG 44
#define BT832_ACB_GNBASE 45
#define BT832_ACB_MU 46
#define BT832_CAM_TEST0 47
#define BT832_AEC_CONFIG 48
#define BT832_AEC_TL 49
#define BT832_AEC_TC 50
#define BT832_AEC_TH 51
// Status:
#define BT832_VP_STATUS 52
#define BT832_VP_LINECOUNT 53
#define BT832_CAM_DEVICEL 54 // e.g. 0x19
#define BT832_CAM_DEVICEH 55 // e.g. 0x40 == 0x194 Mask0, 0x194 = 404 decimal (VVL-404 camera)
#define BT832_CAM_STATUS 56
#define BT832_56_CAMERA_PRESENT 0x20
//Camera Setups:
#define BT832_CAM_SETUP0 57
#define BT832_CAM_SETUP1 58
#define BT832_CAM_SETUP2 59
#define BT832_CAM_SETUP3 60
// System:
#define BT832_DEFCOR 61
#define BT832_VP_TESTCONTROL1 62
#define BT832_DEVICE_ID 63
# define BT832_DEVICE_ID__31 0x31 // Bt832 has ID 0x31
 
/* STMicroelectronivcs VV5404 camera module
i2c: 0x20: sensor address
i2c: 0xa0: eeprom for ccd defect map
*/
#define VV5404_device_h 0x00 // 0x19
#define VV5404_device_l 0x01 // 0x40
#define VV5404_status0 0x02
#define VV5404_linecountc 0x03 // current line counter
#define VV5404_linecountl 0x04
#define VV5404_setup0 0x10
#define VV5404_setup1 0x11
#define VV5404_setup2 0x12
#define VV5404_setup4 0x14
#define VV5404_setup5 0x15
#define VV5404_fine_h 0x20 // fine exposure
#define VV5404_fine_l 0x21
#define VV5404_coarse_h 0x22 //coarse exposure
#define VV5404_coarse_l 0x23
#define VV5404_gain 0x24 // ADC pre-amp gain setting
#define VV5404_clk_div 0x25
#define VV5404_cr 0x76 // control register
#define VV5404_as0 0x77 // ADC setup register
 
 
// IOCTL
#define BT832_HEXDUMP _IOR('b',1,int)
#define BT832_REATTACH _IOR('b',2,int)
 
/* from BT8x8VXD/capdrv/dialogs.cpp */
 
/*
typedef enum { SVI, Logitech, Rockwell } CAMERA;
 
static COMBOBOX_ENTRY gwCameraOptions[] =
{
{ SVI, "Silicon Vision 512N" },
{ Logitech, "Logitech VideoMan 1.3" },
{ Rockwell, "Rockwell QuartzSight PCI 1.0" }
};
 
// SRAM table values
//===========================================================================
typedef enum { TGB_NTSC624, TGB_NTSC780, TGB_NTSC858, TGB_NTSC392 } TimeGenByte;
 
BYTE SRAMTable[][ 60 ] =
{
// TGB_NTSC624
{
0x33, // size of table = 51
0x0E, 0xC0, 0x00, 0x00, 0x90, 0x02, 0x03, 0x10, 0x03, 0x06,
0x10, 0x04, 0x12, 0x12, 0x05, 0x02, 0x13, 0x04, 0x19, 0x00,
0x04, 0x39, 0x00, 0x06, 0x59, 0x08, 0x03, 0x85, 0x08, 0x07,
0x03, 0x50, 0x00, 0x91, 0x40, 0x00, 0x11, 0x01, 0x01, 0x4D,
0x0D, 0x02, 0x03, 0x11, 0x01, 0x05, 0x37, 0x00, 0x37, 0x21, 0x00
},
// TGB_NTSC780
{
0x33, // size of table = 51
0x0e, 0xc0, 0x00, 0x00, 0x90, 0xe2, 0x03, 0x10, 0x03, 0x06,
0x10, 0x34, 0x12, 0x12, 0x65, 0x02, 0x13, 0x24, 0x19, 0x00,
0x24, 0x39, 0x00, 0x96, 0x59, 0x08, 0x93, 0x85, 0x08, 0x97,
0x03, 0x50, 0x50, 0xaf, 0x40, 0x30, 0x5f, 0x01, 0xf1, 0x7f,
0x0d, 0xf2, 0x03, 0x11, 0xf1, 0x05, 0x37, 0x30, 0x85, 0x21, 0x50
},
// TGB_NTSC858
{
0x33, // size of table = 51
0x0c, 0xc0, 0x00, 0x00, 0x90, 0xc2, 0x03, 0x10, 0x03, 0x06,
0x10, 0x34, 0x12, 0x12, 0x65, 0x02, 0x13, 0x24, 0x19, 0x00,
0x24, 0x39, 0x00, 0x96, 0x59, 0x08, 0x93, 0x83, 0x08, 0x97,
0x03, 0x50, 0x30, 0xc0, 0x40, 0x30, 0x86, 0x01, 0x01, 0xa6,
0x0d, 0x62, 0x03, 0x11, 0x61, 0x05, 0x37, 0x30, 0xac, 0x21, 0x50
},
// TGB_NTSC392
// This table has been modified to be used for Fusion Rev D
{
0x2A, // size of table = 42
0x06, 0x08, 0x04, 0x0a, 0xc0, 0x00, 0x18, 0x08, 0x03, 0x24,
0x08, 0x07, 0x02, 0x90, 0x02, 0x08, 0x10, 0x04, 0x0c, 0x10,
0x05, 0x2c, 0x11, 0x04, 0x55, 0x48, 0x00, 0x05, 0x50, 0x00,
0xbf, 0x0c, 0x02, 0x2f, 0x3d, 0x00, 0x2f, 0x3f, 0x00, 0xc3,
0x20, 0x00
}
};
 
//===========================================================================
// This is the structure of the camera specifications
//===========================================================================
typedef struct tag_cameraSpec
{
SignalFormat signal; // which digital signal format the camera has
VideoFormat vidFormat; // video standard
SyncVideoRef syncRef; // which sync video reference is used
State syncOutput; // enable sync output for sync video input?
DecInputClk iClk; // which input clock is used
TimeGenByte tgb; // which timing generator byte does the camera use
int HReset; // select 64, 48, 32, or 16 CLKx1 for HReset
PLLFreq pllFreq; // what synthesized frequency to set PLL to
VSIZEPARMS vSize; // video size the camera produces
int lineCount; // expected total number of half-line per frame - 1
BOOL interlace; // interlace signal?
} CameraSpec;
 
//===========================================================================
// <UPDATE REQUIRED>
// Camera specifications database. Update this table whenever camera spec
// has been changed or added/deleted supported camera models
//===========================================================================
static CameraSpec dbCameraSpec[ N_CAMERAOPTIONS ] =
{ // Silicon Vision 512N
{ Signal_CCIR656, VFormat_NTSC, VRef_alignedCb, Off, DecClk_GPCLK, TGB_NTSC624, 64, KHz19636,
// Clkx1_HACTIVE, Clkx1_HDELAY, VActive, VDelay, linesPerField; lineCount, Interlace
{ 512, 0x64, 480, 0x13, 240 }, 0, TRUE
},
// Logitech VideoMan 1.3
{ Signal_CCIR656, VFormat_NTSC, VRef_alignedCb, Off, DecClk_GPCLK, TGB_NTSC780, 64, KHz24545,
// Clkx1_HACTIVE, Clkx1_HDELAY, VActive, VDelay, linesPerField; lineCount, Interlace
{ 640, 0x80, 480, 0x1A, 240 }, 0, TRUE
},
// Rockwell QuartzSight
// Note: Fusion Rev D (rev ID 0x02) and later supports 16 pixels for HReset which is preferable.
// Use 32 for earlier version of hardware. Clkx1_HDELAY also changed from 0x27 to 0x20.
{ Signal_CCIR656, VFormat_NTSC, VRef_alignedCb, Off, DecClk_GPCLK, TGB_NTSC392, 16, KHz28636,
// Clkx1_HACTIVE, Clkx1_HDELAY, VActive, VDelay, linesPerField; lineCount, Interlace
{ 352, 0x20, 576, 0x08, 288 }, 607, FALSE
}
};
*/
 
/*
The corresponding APIs required to be invoked are:
SetConnector( ConCamera, TRUE/FALSE );
SetSignalFormat( spec.signal );
SetVideoFormat( spec.vidFormat );
SetSyncVideoRef( spec.syncRef );
SetEnableSyncOutput( spec.syncOutput );
SetTimGenByte( SRAMTable[ spec.tgb ], SRAMTableSize[ spec.tgb ] );
SetHReset( spec.HReset );
SetPLL( spec.pllFreq );
SetDecInputClock( spec.iClk );
SetVideoInfo( spec.vSize );
SetTotalLineCount( spec.lineCount );
SetInterlaceMode( spec.interlace );
*/
 
/* from web:
Video Sampling
Digital video is a sampled form of analog video. The most common sampling schemes in use today are:
Pixel Clock Horiz Horiz Vert
Rate Total Active
NTSC square pixel 12.27 MHz 780 640 525
NTSC CCIR-601 13.5 MHz 858 720 525
NTSC 4FSc 14.32 MHz 910 768 525
PAL square pixel 14.75 MHz 944 768 625
PAL CCIR-601 13.5 MHz 864 720 625
PAL 4FSc 17.72 MHz 1135 948 625
 
For the CCIR-601 standards, the sampling is based on a static orthogonal sampling grid. The luminance component (Y) is sampled at 13.5 MHz, while the two color difference signals, Cr and Cb are sampled at half that, or 6.75 MHz. The Cr and Cb samples are colocated with alternate Y samples, and they are taken at the same position on each line, such that one sample is coincident with the 50% point of the falling edge of analog sync. The samples are coded to either 8 or 10 bits per component.
*/
 
/* from DScaler:*/
/*
//===========================================================================
// CCIR656 Digital Input Support: The tables were taken from DScaler proyect
//
// 13 Dec 2000 - Michael Eskin, Conexant Systems - Initial version
//
 
//===========================================================================
// Timing generator SRAM table values for CCIR601 720x480 NTSC
//===========================================================================
// For NTSC CCIR656
BYTE BtCard::SRAMTable_NTSC[] =
{
// SRAM Timing Table for NTSC
0x0c, 0xc0, 0x00,
0x00, 0x90, 0xc2,
0x03, 0x10, 0x03,
0x06, 0x10, 0x34,
0x12, 0x12, 0x65,
0x02, 0x13, 0x24,
0x19, 0x00, 0x24,
0x39, 0x00, 0x96,
0x59, 0x08, 0x93,
0x83, 0x08, 0x97,
0x03, 0x50, 0x30,
0xc0, 0x40, 0x30,
0x86, 0x01, 0x01,
0xa6, 0x0d, 0x62,
0x03, 0x11, 0x61,
0x05, 0x37, 0x30,
0xac, 0x21, 0x50
};
 
//===========================================================================
// Timing generator SRAM table values for CCIR601 720x576 NTSC
//===========================================================================
// For PAL CCIR656
BYTE BtCard::SRAMTable_PAL[] =
{
// SRAM Timing Table for PAL
0x36, 0x11, 0x01,
0x00, 0x90, 0x02,
0x05, 0x10, 0x04,
0x16, 0x14, 0x05,
0x11, 0x00, 0x04,
0x12, 0xc0, 0x00,
0x31, 0x00, 0x06,
0x51, 0x08, 0x03,
0x89, 0x08, 0x07,
0xc0, 0x44, 0x00,
0x81, 0x01, 0x01,
0xa9, 0x0d, 0x02,
0x02, 0x50, 0x03,
0x37, 0x3d, 0x00,
0xaf, 0x21, 0x00,
};
*/
/shark/trunk/drivers/bttv/include/drivers/audiochip.h
3,9 → 3,6
 
/* ---------------------------------------------------------------------- */
 
#define MIN(a,b) (((a)>(b))?(b):(a))
#define MAX(a,b) (((a)>(b))?(a):(b))
 
/* v4l device was opened in Radio mode */
#define AUDC_SET_RADIO _IO('m',2)
/* select from TV,radio,extern,MUTE */
30,41 → 27,7
* make sense in v4l context only. So I think that's acceptable...
*/
 
#if 0
/* misc stuff to pass around config info to i2c chips */
#define AUDC_CONFIG_PINNACLE _IOW('m',32,int)
 
/* TODO (if it is ever [to be] accessible in the V4L[2] spec):
* maybe fade? (back/front)
* notes:
* NEWCHANNEL and SWITCH_MUTE are here because the MSP3400 has a special
* routine to go through when it tunes in to a new channel before turning
* back on the sound.
* Either SET_RADIO, NEWCHANNEL, and SWITCH_MUTE or SET_INPUT need to be
* implemented (MSP3400 uses SET_RADIO to select inputs, and SWITCH_MUTE for
* channel-change mute -- TEA6300 et al use SET_AUDIO to select input [TV,
* radio, external, or MUTE]). If both methods are implemented, you get a
* cookie for doing such a good job! :)
*/
 
#define AUDC_SET_TVNORM _IOW('m',1,int) /* TV mode + PAL/SECAM/NTSC */
#define AUDC_NEWCHANNEL _IO('m',3) /* indicate new chan - off mute */
 
#define AUDC_GET_VOLUME_LEFT _IOR('m',4,__u16)
#define AUDC_GET_VOLUME_RIGHT _IOR('m',5,__u16)
#define AUDC_SET_VOLUME_LEFT _IOW('m',6,__u16)
#define AUDC_SET_VOLUME_RIGHT _IOW('m',7,__u16)
 
#define AUDC_GET_STEREO _IOR('m',8,__u16)
#define AUDC_SET_STEREO _IOW('m',9,__u16)
 
#define AUDC_GET_DC _IOR('m',10,__u16)/* ??? */
 
#define AUDC_GET_BASS _IOR('m',11,__u16)
#define AUDC_SET_BASS _IOW('m',12,__u16)
#define AUDC_GET_TREBLE _IOR('m',13,__u16)
#define AUDC_SET_TREBLE _IOW('m',14,__u16)
 
#define AUDC_GET_UNIT _IOR('m',15,int) /* ??? - unimplemented in MSP3400 */
#define AUDC_SWITCH_MUTE _IO('m',16) /* turn on mute */
#endif
 
#endif /* AUDIOCHIP_H */
/shark/trunk/drivers/bttv/bttv-driver.c
1,170 → 1,662
/*
bttv - Bt848 frame grabber driver
 
Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
& Marcus Metzler (mocm@thp.uni-koeln.de)
(c) 1999,2000 Gerd Knorr <kraxel@goldbach.in-berlin.de>
 
Copyright (C) 1996,97,98 Ralph Metzler <rjkm@thp.uni-koeln.de>
& Marcus Metzler <mocm@thp.uni-koeln.de>
(c) 1999-2002 Gerd Knorr <kraxel@bytesex.org>
some v4l2 code lines are taken from Justin's bttv2 driver which is
(c) 2000 Justin Schoeman <justin@suntiger.ee.up.ac.za>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
 
/* SHARK version by Giacomo Guidi <giacomo@gandalf.sssup.it> */
#include <linuxcomp.h>
 
#include <sys/types.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/kdev_t.h>
 
#include "drivers/compbttv.h"
#include "drivers/bttv.h"
#include "drivers/tuner.h"
#include <asm/io.h>
#include <asm/byteorder.h>
 
#define DEBUG(x) /* Debug driver */
#define MIN(a,b) (((a)>(b))?(b):(a))
#define MAX(a,b) (((a)>(b))?(a):(b))
#include "drivers/bttvp.h"
 
static inline int copy_to_user (void *s, void *d, size_t size)
{
memcpy(s,d,size);
return 0;
unsigned int bttv_num; /* number of Bt848s in use */
struct bttv bttvs[BTTV_MAX];
 
}
unsigned int bttv_debug = 0;
unsigned int bttv_verbose = 1;
unsigned int bttv_gpio = 0;
 
static inline int copy_from_user (void *s, void *d, size_t size)
{
memcpy(s,d,size);
return 0;
 
}
 
static void bt848_set_risc_jmps(struct bttv *btv, int state);
 
int bttv_num; /* number of Bt848s in use */
int in_irq = 0;
DWORD oldpci_command;
struct bttv *btvirq;
struct bttv bttvs[BTTV_MAX];
 
/* configuration variables */
#if defined(__sparc__) || defined(__powerpc__) || defined(__hppa__)
/* config variables */
#ifdef __BIG_ENDIAN
static unsigned int bigendian=1;
#else
static unsigned int bigendian=0;
#endif
static unsigned int radio[BTTV_MAX];
static unsigned int fieldnr = 0;
static unsigned int irq_debug = 0;
static unsigned int gbuffers = 2;
unsigned int gbufsize = BTTV_MAX_FBUF;
static int latency = -1;
static unsigned int gbuffers = 8;
static unsigned int gbufsize = 0x208000;
 
static unsigned int combfilter = 0;
static unsigned int lumafilter = 0;
static unsigned int chroma_agc = 0;
static unsigned int adc_crush = 1;
unsigned int bttv_debug = 0;
unsigned int bttv_verbose = 1;
unsigned int bttv_gpio = 0;
static int video_nr = -1;
static int radio_nr = -1;
static int vbi_nr = -1;
 
//#define I2C_TIMING (0x7<<4)
//#define I2C_DELAY 10
static unsigned int fdsr = 0;
 
#define I2C_TIMING (0x3<<4)
#define I2C_DELAY 40
/* options */
static unsigned int combfilter = 0;
static unsigned int lumafilter = 0;
static unsigned int automute = 1;
static unsigned int chroma_agc = 0;
static unsigned int adc_crush = 1;
static unsigned int vcr_hack = 0;
static unsigned int irq_iswitch = 0;
 
#define I2C_SET(CTRL,DATA) \
{ btwrite((CTRL<<1)|(DATA), BT848_I2C); udelay(I2C_DELAY); }
#define I2C_GET() (btread(BT848_I2C)&1)
/* API features (turn on/off stuff for testing) */
static unsigned int sloppy = 0;
static unsigned int v4l2 = 1;
 
#define BURSTOFFSET 76
#define BTTV_ERRORS 5
 
/* insmod args */
MODULE_PARM(radio,"1-" __stringify(BTTV_MAX) "i");
MODULE_PARM_DESC(radio,"The TV card supports radio, default is 0 (no)");
MODULE_PARM(bigendian,"i");
MODULE_PARM_DESC(bigendian,"byte order of the framebuffer, default is native endian");
MODULE_PARM(bttv_verbose,"i");
MODULE_PARM_DESC(bttv_verbose,"verbose startup messages, default is 1 (yes)");
MODULE_PARM(bttv_gpio,"i");
MODULE_PARM_DESC(bttv_gpio,"log gpio changes, default is 0 (no)");
MODULE_PARM(bttv_debug,"i");
MODULE_PARM_DESC(bttv_debug,"debug messages, default is 0 (no)");
MODULE_PARM(irq_debug,"i");
MODULE_PARM_DESC(irq_debug,"irq handler debug messages, default is 0 (no)");
MODULE_PARM(gbuffers,"i");
MODULE_PARM_DESC(gbuffers,"number of capture buffers. range 2-32, default 8");
MODULE_PARM(gbufsize,"i");
MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000");
 
/*******************************/
/* Memory management functions */
/*******************************/
MODULE_PARM(video_nr,"i");
MODULE_PARM(radio_nr,"i");
MODULE_PARM(vbi_nr,"i");
 
#define MDEBUG(x) do { } while(0) /* Debug memory management */
MODULE_PARM(fdsr,"i");
 
/* [DaveM] I've recoded most of this so that:
* 1) It's easier to tell what is happening
* 2) It's more portable, especially for translating things
* out of vmalloc mapped areas in the kernel.
* 3) Less unnecessary translations happen.
*
* The code used to assume that the kernel vmalloc mappings
* existed in the page tables of every process, this is simply
* not guarenteed. We now use pgd_offset_k which is the
* defined way to get at the kernel page tables.
*/
MODULE_PARM(combfilter,"i");
MODULE_PARM(lumafilter,"i");
MODULE_PARM(automute,"i");
MODULE_PARM_DESC(automute,"mute audio on bad/missing video signal, default is 1 (yes)");
MODULE_PARM(chroma_agc,"i");
MODULE_PARM_DESC(chroma_agc,"enables the AGC of chroma signal, default is 0 (no)");
MODULE_PARM(adc_crush,"i");
MODULE_PARM_DESC(adc_crush,"enables the luminance ADC crush, default is 1 (yes)");
MODULE_PARM(vcr_hack,"i");
MODULE_PARM_DESC(vcr_hack,"enables the VCR hack (improves synch on poor VCR tapes), default is 0 (no)");
MODULE_PARM(irq_iswitch,"i");
MODULE_PARM_DESC(irq_iswitch,"switch inputs in irq handler");
 
MODULE_PARM(sloppy,"i");
MODULE_PARM(v4l2,"i");
 
static inline unsigned long cpu_to_le32(unsigned long adr)
{
return adr;
}
MODULE_DESCRIPTION("bttv - v4l/v4l2 driver module for bt848/878 based cards");
MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr");
MODULE_LICENSE("GPL");
 
static inline unsigned long virt_to_bus(unsigned long adr)
/* kernel args */
#ifndef MODULE
static int __init p_radio(char *str) { return bttv_parse(str,BTTV_MAX,radio); }
__setup("bttv.radio=", p_radio);
#endif
 
/* ----------------------------------------------------------------------- */
/* sysfs */
 
static ssize_t show_card(struct class_device *cd, char *buf)
{
return (unsigned long)(adr);
struct video_device *vfd = to_video_device(cd);
struct bttv *btv = dev_get_drvdata(vfd->dev);
return sprintf(buf, "%d\n", btv ? btv->type : UNSET);
}
static CLASS_DEVICE_ATTR(card, S_IRUGO, show_card, NULL);
 
static void * vmalloc_32(size_t size)
/* ----------------------------------------------------------------------- */
/* static data */
 
/* special timing tables from conexant... */
static u8 SRAM_Table[][60] =
{
void *mem;
unsigned long diff;
/* PAL digital input over GPIO[7:0] */
{
45, // 45 bytes following
0x36,0x11,0x01,0x00,0x90,0x02,0x05,0x10,0x04,0x16,
0x12,0x05,0x11,0x00,0x04,0x12,0xC0,0x00,0x31,0x00,
0x06,0x51,0x08,0x03,0x89,0x08,0x07,0xC0,0x44,0x00,
0x81,0x01,0x01,0xA9,0x0D,0x02,0x02,0x50,0x03,0x37,
0x37,0x00,0xAF,0x21,0x00
},
/* NTSC digital input over GPIO[7:0] */
{
51, // 51 bytes following
0x0C,0xC0,0x00,0x00,0x90,0x02,0x03,0x10,0x03,0x06,
0x10,0x04,0x12,0x12,0x05,0x02,0x13,0x04,0x19,0x00,
0x04,0x39,0x00,0x06,0x59,0x08,0x03,0x83,0x08,0x07,
0x03,0x50,0x00,0xC0,0x40,0x00,0x86,0x01,0x01,0xA6,
0x0D,0x02,0x03,0x11,0x01,0x05,0x37,0x00,0xAC,0x21,
0x00,
},
// TGB_NTSC392 // quartzsight
// This table has been modified to be used for Fusion Rev D
{
0x2A, // size of table = 42
0x06, 0x08, 0x04, 0x0a, 0xc0, 0x00, 0x18, 0x08, 0x03, 0x24,
0x08, 0x07, 0x02, 0x90, 0x02, 0x08, 0x10, 0x04, 0x0c, 0x10,
0x05, 0x2c, 0x11, 0x04, 0x55, 0x48, 0x00, 0x05, 0x50, 0x00,
0xbf, 0x0c, 0x02, 0x2f, 0x3d, 0x00, 0x2f, 0x3f, 0x00, 0xc3,
0x20, 0x00
}
};
 
mem = malloc(size+8);
const struct bttv_tvnorm bttv_tvnorms[] = {
/* PAL-BDGHI */
/* max. active video is actually 922, but 924 is divisible by 4 and 3! */
/* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */
{
.v4l2_id = V4L2_STD_PAL,
.name = "PAL",
.Fsc = 35468950,
.swidth = 924,
.sheight = 576,
.totalwidth = 1135,
.adelay = 0x7f,
.bdelay = 0x72,
.iform = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
.scaledtwidth = 1135,
.hdelayx1 = 186,
.hactivex1 = 924,
.vdelay = 0x20,
.vbipack = 255,
.sram = 0,
},{
.v4l2_id = V4L2_STD_NTSC_M,
.name = "NTSC",
.Fsc = 28636363,
.swidth = 768,
.sheight = 480,
.totalwidth = 910,
.adelay = 0x68,
.bdelay = 0x5d,
.iform = (BT848_IFORM_NTSC|BT848_IFORM_XT0),
.scaledtwidth = 910,
.hdelayx1 = 128,
.hactivex1 = 910,
.vdelay = 0x1a,
.vbipack = 144,
.sram = 1,
},{
.v4l2_id = V4L2_STD_SECAM,
.name = "SECAM",
.Fsc = 35468950,
.swidth = 924,
.sheight = 576,
.totalwidth = 1135,
.adelay = 0x7f,
.bdelay = 0xb0,
.iform = (BT848_IFORM_SECAM|BT848_IFORM_XT1),
.scaledtwidth = 1135,
.hdelayx1 = 186,
.hactivex1 = 922,
.vdelay = 0x20,
.vbipack = 255,
.sram = 0, /* like PAL, correct? */
},{
.v4l2_id = V4L2_STD_PAL_Nc,
.name = "PAL-Nc",
.Fsc = 28636363,
.swidth = 640,
.sheight = 576,
.totalwidth = 910,
.adelay = 0x68,
.bdelay = 0x5d,
.iform = (BT848_IFORM_PAL_NC|BT848_IFORM_XT0),
.scaledtwidth = 780,
.hdelayx1 = 130,
.hactivex1 = 734,
.vdelay = 0x1a,
.vbipack = 144,
.sram = -1,
},{
.v4l2_id = V4L2_STD_PAL_M,
.name = "PAL-M",
.Fsc = 28636363,
.swidth = 640,
.sheight = 480,
.totalwidth = 910,
.adelay = 0x68,
.bdelay = 0x5d,
.iform = (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
.scaledtwidth = 780,
.hdelayx1 = 135,
.hactivex1 = 754,
.vdelay = 0x1a,
.vbipack = 144,
.sram = -1,
},{
.v4l2_id = V4L2_STD_PAL_N,
.name = "PAL-N",
.Fsc = 35468950,
.swidth = 768,
.sheight = 576,
.totalwidth = 1135,
.adelay = 0x7f,
.bdelay = 0x72,
.iform = (BT848_IFORM_PAL_N|BT848_IFORM_XT1),
.scaledtwidth = 944,
.hdelayx1 = 186,
.hactivex1 = 922,
.vdelay = 0x20,
.vbipack = 144,
.sram = -1,
},{
.v4l2_id = V4L2_STD_NTSC_M_JP,
.name = "NTSC-JP",
.Fsc = 28636363,
.swidth = 640,
.sheight = 480,
.totalwidth = 910,
.adelay = 0x68,
.bdelay = 0x5d,
.iform = (BT848_IFORM_NTSC_J|BT848_IFORM_XT0),
.scaledtwidth = 780,
.hdelayx1 = 135,
.hactivex1 = 754,
.vdelay = 0x16,
.vbipack = 144,
.sram = -1,
},{
/* that one hopefully works with the strange timing
* which video recorders produce when playing a NTSC
* tape on a PAL TV ... */
.v4l2_id = V4L2_STD_PAL_60,
.name = "PAL-60",
.Fsc = 35468950,
.swidth = 924,
.sheight = 480,
.totalwidth = 1135,
.adelay = 0x7f,
.bdelay = 0x72,
.iform = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
.scaledtwidth = 1135,
.hdelayx1 = 186,
.hactivex1 = 924,
.vdelay = 0x1a,
.vbipack = 255,
.vtotal = 524,
.sram = -1,
}
};
const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms);
 
diff = (unsigned long)((((unsigned long)mem/4)+1)*4-(unsigned long)mem);
*(unsigned long *)(mem+diff) = (unsigned long)diff;
return (mem+diff+4);
}
/* ----------------------------------------------------------------------- */
/* bttv format list
packed pixel formats must come first */
const struct bttv_format bttv_formats[] = {
{
.name = "8 bpp, gray",
.palette = VIDEO_PALETTE_GREY,
.fourcc = V4L2_PIX_FMT_GREY,
.btformat = BT848_COLOR_FMT_Y8,
.depth = 8,
.flags = FORMAT_FLAGS_PACKED,
},{
.name = "8 bpp, dithered color",
.palette = VIDEO_PALETTE_HI240,
.fourcc = V4L2_PIX_FMT_HI240,
.btformat = BT848_COLOR_FMT_RGB8,
.depth = 8,
.flags = FORMAT_FLAGS_PACKED | FORMAT_FLAGS_DITHER,
},{
.name = "15 bpp RGB, le",
.palette = VIDEO_PALETTE_RGB555,
.fourcc = V4L2_PIX_FMT_RGB555,
.btformat = BT848_COLOR_FMT_RGB15,
.depth = 16,
.flags = FORMAT_FLAGS_PACKED,
},{
.name = "15 bpp RGB, be",
.palette = -1,
.fourcc = V4L2_PIX_FMT_RGB555X,
.btformat = BT848_COLOR_FMT_RGB15,
.btswap = 0x03, /* byteswap */
.depth = 16,
.flags = FORMAT_FLAGS_PACKED,
},{
.name = "16 bpp RGB, le",
.palette = VIDEO_PALETTE_RGB565,
.fourcc = V4L2_PIX_FMT_RGB565,
.btformat = BT848_COLOR_FMT_RGB16,
.depth = 16,
.flags = FORMAT_FLAGS_PACKED,
},{
.name = "16 bpp RGB, be",
.palette = -1,
.fourcc = V4L2_PIX_FMT_RGB565X,
.btformat = BT848_COLOR_FMT_RGB16,
.btswap = 0x03, /* byteswap */
.depth = 16,
.flags = FORMAT_FLAGS_PACKED,
},{
.name = "24 bpp RGB, le",
.palette = VIDEO_PALETTE_RGB24,
.fourcc = V4L2_PIX_FMT_BGR24,
.btformat = BT848_COLOR_FMT_RGB24,
.depth = 24,
.flags = FORMAT_FLAGS_PACKED,
},{
.name = "32 bpp RGB, le",
.palette = VIDEO_PALETTE_RGB32,
.fourcc = V4L2_PIX_FMT_BGR32,
.btformat = BT848_COLOR_FMT_RGB32,
.depth = 32,
.flags = FORMAT_FLAGS_PACKED,
},{
.name = "32 bpp RGB, be",
.palette = -1,
.fourcc = V4L2_PIX_FMT_RGB32,
.btformat = BT848_COLOR_FMT_RGB32,
.btswap = 0x0f, /* byte+word swap */
.depth = 32,
.flags = FORMAT_FLAGS_PACKED,
},{
.name = "4:2:2, packed, YUYV",
.palette = VIDEO_PALETTE_YUV422,
.fourcc = V4L2_PIX_FMT_YUYV,
.btformat = BT848_COLOR_FMT_YUY2,
.depth = 16,
.flags = FORMAT_FLAGS_PACKED,
},{
.name = "4:2:2, packed, YUYV",
.palette = VIDEO_PALETTE_YUYV,
.fourcc = V4L2_PIX_FMT_YUYV,
.btformat = BT848_COLOR_FMT_YUY2,
.depth = 16,
.flags = FORMAT_FLAGS_PACKED,
},{
.name = "4:2:2, packed, UYVY",
.palette = VIDEO_PALETTE_UYVY,
.fourcc = V4L2_PIX_FMT_UYVY,
.btformat = BT848_COLOR_FMT_YUY2,
.btswap = 0x03, /* byteswap */
.depth = 16,
.flags = FORMAT_FLAGS_PACKED,
},{
.name = "4:2:2, planar, Y-Cb-Cr",
.palette = VIDEO_PALETTE_YUV422P,
.fourcc = V4L2_PIX_FMT_YUV422P,
.btformat = BT848_COLOR_FMT_YCrCb422,
.depth = 16,
.flags = FORMAT_FLAGS_PLANAR,
.hshift = 1,
.vshift = 0,
},{
.name = "4:2:0, planar, Y-Cb-Cr",
.palette = VIDEO_PALETTE_YUV420P,
.fourcc = V4L2_PIX_FMT_YUV420,
.btformat = BT848_COLOR_FMT_YCrCb422,
.depth = 12,
.flags = FORMAT_FLAGS_PLANAR,
.hshift = 1,
.vshift = 1,
},{
.name = "4:2:0, planar, Y-Cr-Cb",
.palette = -1,
.fourcc = V4L2_PIX_FMT_YVU420,
.btformat = BT848_COLOR_FMT_YCrCb422,
.depth = 12,
.flags = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb,
.hshift = 1,
.vshift = 1,
},{
.name = "4:1:1, planar, Y-Cb-Cr",
.palette = VIDEO_PALETTE_YUV411P,
.fourcc = V4L2_PIX_FMT_YUV411P,
.btformat = BT848_COLOR_FMT_YCrCb411,
.depth = 12,
.flags = FORMAT_FLAGS_PLANAR,
.hshift = 2,
.vshift = 0,
},{
.name = "4:1:0, planar, Y-Cb-Cr",
.palette = VIDEO_PALETTE_YUV410P,
.fourcc = V4L2_PIX_FMT_YUV410,
.btformat = BT848_COLOR_FMT_YCrCb411,
.depth = 9,
.flags = FORMAT_FLAGS_PLANAR,
.hshift = 2,
.vshift = 2,
},{
.name = "4:1:0, planar, Y-Cr-Cb",
.palette = -1,
.fourcc = V4L2_PIX_FMT_YVU410,
.btformat = BT848_COLOR_FMT_YCrCb411,
.depth = 9,
.flags = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb,
.hshift = 2,
.vshift = 2,
},{
.name = "raw scanlines",
.palette = VIDEO_PALETTE_RAW,
.fourcc = -1,
.btformat = BT848_COLOR_FMT_RAW,
.depth = 8,
.flags = FORMAT_FLAGS_RAW,
}
};
const unsigned int BTTV_FORMATS = ARRAY_SIZE(bttv_formats);
 
static void vfree_32(void *ptr)
/* ----------------------------------------------------------------------- */
 
#define V4L2_CID_PRIVATE_CHROMA_AGC (V4L2_CID_PRIVATE_BASE + 0)
#define V4L2_CID_PRIVATE_COMBFILTER (V4L2_CID_PRIVATE_BASE + 1)
#define V4L2_CID_PRIVATE_AUTOMUTE (V4L2_CID_PRIVATE_BASE + 2)
#define V4L2_CID_PRIVATE_LUMAFILTER (V4L2_CID_PRIVATE_BASE + 3)
#define V4L2_CID_PRIVATE_AGC_CRUSH (V4L2_CID_PRIVATE_BASE + 4)
#define V4L2_CID_PRIVATE_VCR_HACK (V4L2_CID_PRIVATE_BASE + 5)
#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 6)
 
static const struct v4l2_queryctrl no_ctl = {
.name = "42",
.flags = V4L2_CTRL_FLAG_DISABLED,
};
static const struct v4l2_queryctrl bttv_ctls[] = {
/* --- video --- */
{
.id = V4L2_CID_BRIGHTNESS,
.name = "Brightness",
.minimum = 0,
.maximum = 65535,
.step = 256,
.default_value = 32768,
.type = V4L2_CTRL_TYPE_INTEGER,
},{
.id = V4L2_CID_CONTRAST,
.name = "Contrast",
.minimum = 0,
.maximum = 65535,
.step = 128,
.default_value = 32768,
.type = V4L2_CTRL_TYPE_INTEGER,
},{
.id = V4L2_CID_SATURATION,
.name = "Saturation",
.minimum = 0,
.maximum = 65535,
.step = 128,
.default_value = 32768,
.type = V4L2_CTRL_TYPE_INTEGER,
},{
.id = V4L2_CID_HUE,
.name = "Hue",
.minimum = 0,
.maximum = 65535,
.step = 256,
.default_value = 32768,
.type = V4L2_CTRL_TYPE_INTEGER,
},
/* --- audio --- */
{
.id = V4L2_CID_AUDIO_MUTE,
.name = "Mute",
.minimum = 0,
.maximum = 1,
.type = V4L2_CTRL_TYPE_BOOLEAN,
},{
.id = V4L2_CID_AUDIO_VOLUME,
.name = "Volume",
.minimum = 0,
.maximum = 65535,
.step = 65535/100,
.default_value = 65535,
.type = V4L2_CTRL_TYPE_INTEGER,
},{
.id = V4L2_CID_AUDIO_BALANCE,
.name = "Balance",
.minimum = 0,
.maximum = 65535,
.step = 65535/100,
.default_value = 32768,
.type = V4L2_CTRL_TYPE_INTEGER,
},{
.id = V4L2_CID_AUDIO_BASS,
.name = "Bass",
.minimum = 0,
.maximum = 65535,
.step = 65535/100,
.default_value = 32768,
.type = V4L2_CTRL_TYPE_INTEGER,
},{
.id = V4L2_CID_AUDIO_TREBLE,
.name = "Treble",
.minimum = 0,
.maximum = 65535,
.step = 65535/100,
.default_value = 32768,
.type = V4L2_CTRL_TYPE_INTEGER,
},
/* --- private --- */
{
.id = V4L2_CID_PRIVATE_CHROMA_AGC,
.name = "chroma agc",
.minimum = 0,
.maximum = 1,
.type = V4L2_CTRL_TYPE_BOOLEAN,
},{
.id = V4L2_CID_PRIVATE_COMBFILTER,
.name = "combfilter",
.minimum = 0,
.maximum = 1,
.type = V4L2_CTRL_TYPE_BOOLEAN,
},{
.id = V4L2_CID_PRIVATE_AUTOMUTE,
.name = "automute",
.minimum = 0,
.maximum = 1,
.type = V4L2_CTRL_TYPE_BOOLEAN,
},{
.id = V4L2_CID_PRIVATE_LUMAFILTER,
.name = "luma decimation filter",
.minimum = 0,
.maximum = 1,
.type = V4L2_CTRL_TYPE_BOOLEAN,
},{
.id = V4L2_CID_PRIVATE_AGC_CRUSH,
.name = "agc crush",
.minimum = 0,
.maximum = 1,
.type = V4L2_CTRL_TYPE_BOOLEAN,
},{
.id = V4L2_CID_PRIVATE_VCR_HACK,
.name = "vcr hack",
.minimum = 0,
.maximum = 1,
.type = V4L2_CTRL_TYPE_BOOLEAN,
}
};
const int BTTV_CTLS = ARRAY_SIZE(bttv_ctls);
 
/* ----------------------------------------------------------------------- */
/* resource management */
 
static
int check_alloc_btres(struct bttv *btv, struct bttv_fh *fh, int bit)
{
if (fh->resources & bit)
/* have it already allocated */
return 1;
 
free(ptr-4-*(unsigned long *)(ptr-4));
/* is it free? */
down(&btv->reslock);
if (btv->resources & bit) {
/* no, someone else uses it */
up(&btv->reslock);
return 0;
}
/* it's free, grab it */
fh->resources |= bit;
btv->resources |= bit;
up(&btv->reslock);
return 1;
}
 
static
int check_btres(struct bttv_fh *fh, int bit)
{
return (fh->resources & bit);
}
 
void bttv_gpio_tracking(struct bttv *btv, char *comment)
static
int locked_btres(struct bttv *btv, int bit)
{
unsigned int outbits, data;
outbits = btread(BT848_GPIO_OUT_EN);
data = gpioread();
printk(KERN_DEBUG "bttv%d: gpio: en=%08x, out=%08x in=%08x [%s]\n",
btv->nr,outbits,data & outbits, data & ~outbits, comment);
return (btv->resources & bit);
}
 
static inline void bt848_dma(struct bttv *btv, uint state)
static
void free_btres(struct bttv *btv, struct bttv_fh *fh, int bits)
{
if (state)
btor(3, BT848_GPIO_DMA_CTL);
else
btand(~3, BT848_GPIO_DMA_CTL);
#if 1 /* DEBUG */
if ((fh->resources & bits) != bits) {
/* trying to free ressources not allocated by us ... */
printk("bttv: BUG! (btres)\n");
}
#endif
down(&btv->reslock);
fh->resources &= ~bits;
btv->resources &= ~bits;
up(&btv->reslock);
}
 
/* ----------------------------------------------------------------------- */
/* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC */
 
/* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC*/
 
/* Frequency = (F_input / PLL_X) * PLL_I.PLL_F/PLL_C
PLL_X = Reference pre-divider (0=1, 1=2)
PLL_C = Post divider (0=6, 1=4)
192,1704 → 684,2685
fout=(fout%fin)*256;
fl=fout/fin;
 
/*printk("0x%02x 0x%02x 0x%02x\n", fi, fh, fl);*/
btwrite(fl, BT848_PLL_F_LO);
btwrite(fh, BT848_PLL_F_HI);
btwrite(fi|BT848_PLL_X, BT848_PLL_XCI);
}
 
static int set_pll(struct bttv *btv)
static void set_pll(struct bttv *btv)
{
int i;
 
if (!btv->pll.pll_crystal)
return 0;
return;
 
if (btv->pll.pll_ofreq == btv->pll.pll_current) {
dprintk("bttv%d: PLL: no change required\n",btv->nr);
return;
}
 
if (btv->pll.pll_ifreq == btv->pll.pll_ofreq) {
/* no PLL needed */
if (btv->pll.pll_current == 0) {
/* printk ("bttv%d: PLL: is off\n",btv->nr); */
return 0;
}
if (bttv_verbose)
printk(KERN_INFO "bttv%d: PLL: switching off\n",btv->nr);
if (btv->pll.pll_current == 0)
return;
vprintk(KERN_INFO "bttv%d: PLL can sleep, using XTAL (%d).\n",
btv->nr,btv->pll.pll_ifreq);
btwrite(0x00,BT848_TGCTRL);
btwrite(0x00,BT848_PLL_XCI);
btv->pll.pll_current = 0;
return 0;
return;
}
 
if (btv->pll.pll_ofreq == btv->pll.pll_current) {
/* printk("bttv%d: PLL: no change required\n",btv->nr); */
return 1;
}
 
if (bttv_verbose)
cprintf("[info ] bttv%d: PLL: %d => %d ... ",btv->nr,
btv->pll.pll_ifreq, btv->pll.pll_ofreq);
 
vprintk(KERN_INFO "bttv%d: PLL: %d => %d ",btv->nr,
btv->pll.pll_ifreq, btv->pll.pll_ofreq);
set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq);
 
/* Let other people run while the PLL stabilizes */
udelay(100000);
for (i=0; i<100; i++)
{
if ((btread(BT848_DSTATUS)&BT848_DSTATUS_PLOCK))
btwrite(0,BT848_DSTATUS);
else
{
for (i=0; i<10; i++) {
/* Let other people run while the PLL stabilizes */
vprintk(".");
current->state = TASK_INTERRUPTIBLE;
schedule_timeout(HZ/10);
if (btread(BT848_DSTATUS) & BT848_DSTATUS_PLOCK) {
btwrite(0,BT848_DSTATUS);
} else {
btwrite(0x08,BT848_TGCTRL);
btv->pll.pll_current = btv->pll.pll_ofreq;
if (bttv_verbose)
cprintf("ok\n");
return 1;
vprintk(" ok\n");
return;
}
udelay(10000);
}
btv->pll.pll_current = 0;
if (bttv_verbose)
cprintf("oops\n");
return -1;
btv->pll.pll_current = -1;
vprintk("failed\n");
return;
}
 
static void bt848_muxsel(struct bttv *btv, unsigned int input)
/* used to switch between the bt848's analog/digital video capture modes */
void bt848A_set_timing(struct bttv *btv)
{
int i, len;
int table_idx = bttv_tvnorms[btv->tvnorm].sram;
int fsc = bttv_tvnorms[btv->tvnorm].Fsc;
 
if (UNSET == bttv_tvcards[btv->type].muxsel[btv->input]) {
dprintk("bttv%d: load digital timing table (table_idx=%d)\n",
btv->nr,table_idx);
 
/* timing change...reset timing generator address */
btwrite(0x00, BT848_TGCTRL);
btwrite(0x02, BT848_TGCTRL);
btwrite(0x00, BT848_TGCTRL);
 
len=SRAM_Table[table_idx][0];
for(i = 1; i <= len; i++)
btwrite(SRAM_Table[table_idx][i],BT848_TGLB);
btv->pll.pll_ofreq = 27000000;
 
set_pll(btv);
btwrite(0x11, BT848_TGCTRL);
btwrite(0x41, BT848_DVSIF);
} else {
btv->pll.pll_ofreq = fsc;
set_pll(btv);
btwrite(0x0, BT848_DVSIF);
}
}
 
/* ----------------------------------------------------------------------- */
 
static void bt848_bright(struct bttv *btv, int bright)
{
int value;
 
btv->bright = bright;
 
/* We want -128 to 127 we get 0-65535 */
value = (bright >> 8) - 128;
btwrite(value & 0xff, BT848_BRIGHT);
}
 
static void bt848_hue(struct bttv *btv, int hue)
{
int value;
btv->hue = hue;
 
/* -128 to 127 */
value = (hue >> 8) - 128;
btwrite(value & 0xff, BT848_HUE);
}
 
static void bt848_contrast(struct bttv *btv, int cont)
{
int value,hibit;
btv->contrast = cont;
/* 0-511 */
value = (cont >> 7);
hibit = (value >> 6) & 4;
btwrite(value & 0xff, BT848_CONTRAST_LO);
btaor(hibit, ~4, BT848_E_CONTROL);
btaor(hibit, ~4, BT848_O_CONTROL);
}
 
static void bt848_sat(struct bttv *btv, int color)
{
int val_u,val_v,hibits;
btv->saturation = color;
 
/* 0-511 for the color */
val_u = color >> 7;
val_v = ((color>>7)*180L)/254;
hibits = (val_u >> 7) & 2;
hibits |= (val_v >> 8) & 1;
btwrite(val_u & 0xff, BT848_SAT_U_LO);
btwrite(val_v & 0xff, BT848_SAT_V_LO);
btaor(hibits, ~3, BT848_E_CONTROL);
btaor(hibits, ~3, BT848_O_CONTROL);
}
 
/* ----------------------------------------------------------------------- */
 
static int
video_mux(struct bttv *btv, unsigned int input)
{
int mux,mask2;
 
if (input >= bttv_tvcards[btv->type].video_inputs)
return -EINVAL;
 
/* needed by RemoteVideo MX */
btor(bttv_tvcards[btv->type].gpiomask2,BT848_GPIO_OUT_EN);
mask2 = bttv_tvcards[btv->type].gpiomask2;
if (mask2)
btaor(mask2,~mask2,BT848_GPIO_OUT_EN);
 
/* This seems to get rid of some synchronization problems */
btand(~(3<<5), BT848_IFORM);
udelay(10000);
 
input %= bttv_tvcards[btv->type].video_inputs;
if (input==bttv_tvcards[btv->type].svhs)
{
if (input == btv->svhs) {
btor(BT848_CONTROL_COMP, BT848_E_CONTROL);
btor(BT848_CONTROL_COMP, BT848_O_CONTROL);
}
else
{
} else {
btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
}
mux = bttv_tvcards[btv->type].muxsel[input] & 3;
btaor(mux<<5, ~(3<<5), BT848_IFORM);
dprintk(KERN_DEBUG "bttv%d: video mux: input=%d mux=%d\n",
btv->nr,input,mux);
 
btaor((bttv_tvcards[btv->type].muxsel[input]&3)<<5, ~(3<<5), BT848_IFORM);
/* card specific hook */
if(bttv_tvcards[btv->type].muxsel_hook)
bttv_tvcards[btv->type].muxsel_hook (btv, input);
return 0;
}
 
gpioaor(bttv_tvcards[btv->type].muxsel[input]>>4,
~bttv_tvcards[btv->type].gpiomask2);
static char *audio_modes[] = {
"audio: tuner", "audio: radio", "audio: extern",
"audio: intern", "audio: off"
};
 
/* card specific hook */
if( bttv_tvcards[btv->type].muxsel_hook )
bttv_tvcards[btv->type].muxsel_hook ( btv, input );
static int
audio_mux(struct bttv *btv, int mode)
{
int val,mux,i2c_mux,signal;
btaor(bttv_tvcards[btv->type].gpiomask,
~bttv_tvcards[btv->type].gpiomask,BT848_GPIO_OUT_EN);
signal = btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC;
 
switch (mode) {
case AUDIO_MUTE:
btv->audio |= AUDIO_MUTE;
break;
case AUDIO_UNMUTE:
btv->audio &= ~AUDIO_MUTE;
break;
case AUDIO_TUNER:
case AUDIO_RADIO:
case AUDIO_EXTERN:
case AUDIO_INTERN:
btv->audio &= AUDIO_MUTE;
btv->audio |= mode;
}
i2c_mux = mux = (btv->audio & AUDIO_MUTE) ? AUDIO_OFF : btv->audio;
if (btv->opt_automute && !signal && !btv->radio_user)
mux = AUDIO_OFF;
#if 0
printk("bttv%d: amux: mode=%d audio=%d signal=%s mux=%d/%d irq=%s\n",
btv->nr, mode, btv->audio, signal ? "yes" : "no",
mux, i2c_mux, in_interrupt() ? "yes" : "no");
#endif
 
val = bttv_tvcards[btv->type].audiomux[mux];
btaor(val,~bttv_tvcards[btv->type].gpiomask, BT848_GPIO_DATA);
if (bttv_gpio)
bttv_gpio_tracking(btv,"muxsel");
bttv_gpio_tracking(btv,audio_modes[mux]);
if (!in_interrupt())
bttv_call_i2c_clients(btv,AUDC_SET_INPUT,&(i2c_mux));
return 0;
}
 
static void
i2c_vidiocschan(struct bttv *btv)
{
struct video_channel c;
 
memset(&c,0,sizeof(c));
c.norm = btv->tvnorm;
c.channel = btv->input;
bttv_call_i2c_clients(btv,VIDIOCSCHAN,&c);
if (btv->type == BTTV_VOODOOTV_FM)
bttv_tda9880_setnorm(btv,c.norm);
}
 
 
struct tvnorm
static int
set_tvnorm(struct bttv *btv, unsigned int norm)
{
u32 Fsc;
u16 swidth, sheight; /* scaled standard width, height */
u16 totalwidth;
u8 adelay, bdelay, iform;
u32 scaledtwidth;
u16 hdelayx1, hactivex1;
u16 vdelay;
u8 vbipack;
};
const struct bttv_tvnorm *tvnorm;
 
static struct tvnorm tvnorms[] = {
/* PAL-BDGHI */
/* max. active video is actually 922, but 924 is divisible by 4 and 3! */
/* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */
{ 35468950,
924, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
1135, 186, 924,
#ifdef VIDEODAT_HACK
VBI_MAXLINES*2,
#else
0x20,
#endif
255},
if (norm < 0 || norm >= BTTV_TVNORMS)
return -EINVAL;
 
/* NTSC */
{ 28636363,
768, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC|BT848_IFORM_XT0),
910, 128, 910, 0x1a, 144},
btv->tvnorm = norm;
tvnorm = &bttv_tvnorms[norm];
 
btwrite(tvnorm->adelay, BT848_ADELAY);
btwrite(tvnorm->bdelay, BT848_BDELAY);
btaor(tvnorm->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH),
BT848_IFORM);
btwrite(tvnorm->vbipack, BT848_VBI_PACK_SIZE);
btwrite(1, BT848_VBI_PACK_DEL);
bt848A_set_timing(btv);
 
switch (btv->type) {
case BTTV_VOODOOTV_FM:
bttv_tda9880_setnorm(btv,norm);
break;
#if 0
/* SECAM EAST */
{ 35468950,
768, 576, 1135, 0x7f, 0xb0, (BT848_IFORM_SECAM|BT848_IFORM_XT1),
944, 186, 922, 0x20, 255},
#else
/* SECAM L */
{ 35468950,
924, 576, 1135, 0x7f, 0xb0, (BT848_IFORM_SECAM|BT848_IFORM_XT1),
1135, 186, 922, 0x20, 255},
case BTTV_OSPREY540:
osprey_540_set_norm(btv,norm);
break;
#endif
/* PAL-NC */
{ 28636363,
640, 576, 910, 0x68, 0x5d, (BT848_IFORM_PAL_NC|BT848_IFORM_XT0),
780, 130, 734, 0x1a, 144},
/* PAL-M */
{ 28636363,
640, 480, 910, 0x68, 0x5d, (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
780, 135, 754, 0x1a, 144},
/* PAL-N */
{ 35468950,
768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_N|BT848_IFORM_XT1),
944, 186, 922, 0x20, 144},
/* NTSC-Japan */
{ 28636363,
640, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC_J|BT848_IFORM_XT0),
780, 135, 754, 0x16, 144},
};
#define TVNORMS (sizeof(tvnorms)/sizeof(tvnorm))
#define VBI_SPL 2044
}
return 0;
}
 
/* RISC command to write one VBI data line */
#define VBI_RISC BT848_RISC_WRITE|VBI_SPL|BT848_RISC_EOL|BT848_RISC_SOL
 
static void make_vbitab(struct bttv *btv)
static void
set_input(struct bttv *btv, unsigned int input)
{
int i;
unsigned int *po=(unsigned int *) btv->vbi_odd;
unsigned int *pe=(unsigned int *) btv->vbi_even;
if (bttv_debug > 1)
cprintf("bttv%d: vbi1: po=%08lx pe=%08lx\n",
btv->nr,virt_to_bus((unsigned long)po), virt_to_bus((unsigned long)pe));
*(po++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(po++)=0;
for (i=0; i<VBI_MAXLINES; i++)
{
*(po++)=cpu_to_le32(VBI_RISC);
*(po++)=cpu_to_le32(virt_to_bus((unsigned long)btv->vbibuf+i*2048));
unsigned long flags;
btv->input = input;
if (irq_iswitch) {
spin_lock_irqsave(&btv->s_lock,flags);
if (btv->curr.irqflags) {
/* active capture -> delayed input switch */
btv->new_input = input;
} else {
video_mux(btv,input);
}
spin_unlock_irqrestore(&btv->s_lock,flags);
} else {
video_mux(btv,input);
}
*(po++)=cpu_to_le32(BT848_RISC_JUMP);
*(po++)=cpu_to_le32(virt_to_bus((unsigned long)btv->risc_jmp+16));
audio_mux(btv,(input == bttv_tvcards[btv->type].tuner ?
AUDIO_TUNER : AUDIO_EXTERN));
set_tvnorm(btv,btv->tvnorm);
}
 
*(pe++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(pe++)=0;
for (i=VBI_MAXLINES; i<VBI_MAXLINES*2; i++)
{
*(pe++)=cpu_to_le32(VBI_RISC);
*(pe++)=cpu_to_le32(virt_to_bus((unsigned long)btv->vbibuf+i*2048));
static void init_bt848(struct bttv *btv)
{
int val;
btwrite(0, BT848_SRESET);
btwrite(0x00, BT848_CAP_CTL);
btwrite(BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL);
btwrite(BT848_IFORM_XTAUTO | BT848_IFORM_AUTO, BT848_IFORM);
 
/* set planar and packed mode trigger points and */
/* set rising edge of inverted GPINTR pin as irq trigger */
btwrite(BT848_GPIO_DMA_CTL_PKTP_32|
BT848_GPIO_DMA_CTL_PLTP1_16|
BT848_GPIO_DMA_CTL_PLTP23_16|
BT848_GPIO_DMA_CTL_GPINTC|
BT848_GPIO_DMA_CTL_GPINTI,
BT848_GPIO_DMA_CTL);
 
val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
btwrite(val, BT848_E_SCLOOP);
btwrite(val, BT848_O_SCLOOP);
 
btwrite(0x20, BT848_E_VSCALE_HI);
btwrite(0x20, BT848_O_VSCALE_HI);
btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
BT848_ADC);
 
if (btv->opt_lumafilter) {
btwrite(0, BT848_E_CONTROL);
btwrite(0, BT848_O_CONTROL);
} else {
btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL);
btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL);
}
*(pe++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(0x01<<16));
*(pe++)=cpu_to_le32(virt_to_bus((unsigned long)btv->risc_jmp+40));
 
if (bttv_debug > 1)
cprintf("bttv%d: vbi2: po=%08lx pe=%08lx\n",
btv->nr,virt_to_bus((unsigned long)po), virt_to_bus((unsigned long)pe));
/* interrupt */
btwrite(0xfffffUL, BT848_INT_STAT);
btwrite((btv->triton1) |
BT848_INT_GPINT |
BT848_INT_SCERR |
(fdsr ? BT848_INT_FDSR : 0) |
BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES|
BT848_INT_FMTCHG|BT848_INT_HLOCK,
BT848_INT_MASK);
}
 
static int fmtbppx2[16] = {
8, 6, 4, 4, 4, 3, 2, 2, 4, 3, 0, 0, 0, 0, 2, 0
};
extern void bttv_reinit_bt848(struct bttv *btv)
{
unsigned long flags;
 
static int palette2fmt[] = {
0,
BT848_COLOR_FMT_Y8,
BT848_COLOR_FMT_RGB8,
BT848_COLOR_FMT_RGB16,
BT848_COLOR_FMT_RGB24,
BT848_COLOR_FMT_RGB32,
BT848_COLOR_FMT_RGB15,
BT848_COLOR_FMT_YUY2,
BT848_COLOR_FMT_YUY2,
-1,
-1,
-1,
BT848_COLOR_FMT_RAW,
BT848_COLOR_FMT_YCrCb422,
BT848_COLOR_FMT_YCrCb411,
BT848_COLOR_FMT_YCrCb422,
BT848_COLOR_FMT_YCrCb411,
};
#define PALETTEFMT_MAX (sizeof(palette2fmt)/sizeof(int))
if (bttv_verbose)
printk(KERN_INFO "bttv%d: reset, reinitialize\n",btv->nr);
spin_lock_irqsave(&btv->s_lock,flags);
btv->errors=0;
bttv_set_dma(btv,0,0);
spin_unlock_irqrestore(&btv->s_lock,flags);
 
static int make_rawrisctab(struct bttv *btv, unsigned int *ro,
unsigned int *re, unsigned int *vbuf)
init_bt848(btv);
btv->pll.pll_current = -1;
set_input(btv,btv->input);
}
 
static int get_control(struct bttv *btv, struct v4l2_control *c)
{
unsigned long line;
unsigned long bpl=1024; /* bytes per line */
unsigned long vadr = (unsigned long)vbuf;
struct video_audio va;
int i;
for (i = 0; i < BTTV_CTLS; i++)
if (bttv_ctls[i].id == c->id)
break;
if (i == BTTV_CTLS)
return -EINVAL;
if (i >= 4 && i <= 8) {
memset(&va,0,sizeof(va));
bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
if (btv->audio_hook)
btv->audio_hook(btv,&va,0);
}
switch (c->id) {
case V4L2_CID_BRIGHTNESS:
c->value = btv->bright;
break;
case V4L2_CID_HUE:
c->value = btv->hue;
break;
case V4L2_CID_CONTRAST:
c->value = btv->contrast;
break;
case V4L2_CID_SATURATION:
c->value = btv->saturation;
break;
 
*(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
*(ro++)=cpu_to_le32(0);
*(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
*(re++)=cpu_to_le32(0);
/* In PAL 650 blocks of 256 DWORDs are sampled, but only if VDELAY
is 2 and without separate VBI grabbing.
We'll have to handle this inside the IRQ handler ... */
case V4L2_CID_AUDIO_MUTE:
c->value = (VIDEO_AUDIO_MUTE & va.flags) ? 1 : 0;
break;
case V4L2_CID_AUDIO_VOLUME:
c->value = va.volume;
break;
case V4L2_CID_AUDIO_BALANCE:
c->value = va.balance;
break;
case V4L2_CID_AUDIO_BASS:
c->value = va.bass;
break;
case V4L2_CID_AUDIO_TREBLE:
c->value = va.treble;
break;
 
for (line=0; line < 640; line++)
{
*(ro++)=cpu_to_le32(BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL);
*(ro++)=cpu_to_le32(virt_to_bus(vadr));
*(re++)=cpu_to_le32(BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL);
*(re++)=cpu_to_le32(virt_to_bus(vadr+gbufsize/2));
vadr+=bpl;
case V4L2_CID_PRIVATE_CHROMA_AGC:
c->value = btv->opt_chroma_agc;
break;
case V4L2_CID_PRIVATE_COMBFILTER:
c->value = btv->opt_combfilter;
break;
case V4L2_CID_PRIVATE_LUMAFILTER:
c->value = btv->opt_lumafilter;
break;
case V4L2_CID_PRIVATE_AUTOMUTE:
c->value = btv->opt_automute;
break;
case V4L2_CID_PRIVATE_AGC_CRUSH:
c->value = btv->opt_adc_crush;
break;
case V4L2_CID_PRIVATE_VCR_HACK:
c->value = btv->opt_vcr_hack;
break;
default:
return -EINVAL;
}
*(ro++)=cpu_to_le32(BT848_RISC_JUMP);
*(ro++)=cpu_to_le32(btv->bus_vbi_even);
*(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16));
*(re++)=cpu_to_le32(btv->bus_vbi_odd);
return 0;
}
 
static int make_prisctab(struct bttv *btv, unsigned int *ro,
unsigned int *re,
unsigned int *vbuf, unsigned short width,
unsigned short height, unsigned short fmt)
static int set_control(struct bttv *btv, struct v4l2_control *c)
{
unsigned long line, lmask;
unsigned long bl, blcr, blcb, rcmd;
unsigned long todo;
unsigned int **rp;
int inter;
unsigned long cbadr, cradr;
unsigned long vadr=(unsigned long) vbuf;
int shift, csize;
struct video_audio va;
int i,val;
 
if (bttv_debug > 1)
cprintf("bttv%d: prisc1: ro=%08lx re=%08lx\n",
btv->nr,virt_to_bus((unsigned long)ro), virt_to_bus((unsigned long)re));
 
switch(fmt)
{
case VIDEO_PALETTE_YUV422P:
csize=(width*height)>>1;
shift=1;
lmask=0;
break;
case VIDEO_PALETTE_YUV411P:
csize=(width*height)>>2;
shift=2;
lmask=0;
break;
case VIDEO_PALETTE_YUV420P:
csize=(width*height)>>2;
shift=1;
lmask=1;
break;
case VIDEO_PALETTE_YUV410P:
csize=(width*height)>>4;
shift=2;
lmask=3;
break;
default:
return -1;
for (i = 0; i < BTTV_CTLS; i++)
if (bttv_ctls[i].id == c->id)
break;
if (i == BTTV_CTLS)
return -EINVAL;
if (i >= 4 && i <= 8) {
memset(&va,0,sizeof(va));
bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
if (btv->audio_hook)
btv->audio_hook(btv,&va,0);
}
cbadr=vadr+(width*height);
cradr=cbadr+csize;
inter = (height>tvnorms[btv->win.norm].sheight/2) ? 1 : 0;
*(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3);
*(ro++)=0;
*(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3);
*(re++)=0;
for (line=0; line < (height<<(1^inter)); line++)
{
if(line==height)
{
vadr+=csize<<1;
cbadr=vadr+(width*height);
cradr=cbadr+csize;
switch (c->id) {
case V4L2_CID_BRIGHTNESS:
bt848_bright(btv,c->value);
break;
case V4L2_CID_HUE:
bt848_hue(btv,c->value);
break;
case V4L2_CID_CONTRAST:
bt848_contrast(btv,c->value);
break;
case V4L2_CID_SATURATION:
bt848_sat(btv,c->value);
break;
case V4L2_CID_AUDIO_MUTE:
if (c->value) {
va.flags |= VIDEO_AUDIO_MUTE;
audio_mux(btv, AUDIO_MUTE);
} else {
va.flags &= ~VIDEO_AUDIO_MUTE;
audio_mux(btv, AUDIO_UNMUTE);
}
if (inter)
rp= (line&1) ? &re : &ro;
else
rp= (line>=height) ? &ro : &re;
break;
 
if(line&lmask)
rcmd=BT848_RISC_WRITE1S23|BT848_RISC_SOL;
else
rcmd=BT848_RISC_WRITE123|BT848_RISC_SOL;
case V4L2_CID_AUDIO_VOLUME:
va.volume = c->value;
break;
case V4L2_CID_AUDIO_BALANCE:
va.balance = c->value;
break;
case V4L2_CID_AUDIO_BASS:
va.bass = c->value;
break;
case V4L2_CID_AUDIO_TREBLE:
va.treble = c->value;
break;
 
todo=width;
while(todo)
{
bl=PAGE_SIZE-((PAGE_SIZE-1)&vadr);
blcr=(PAGE_SIZE-((PAGE_SIZE-1)&cradr))<<shift;
blcb=(PAGE_SIZE-((PAGE_SIZE-1)&cbadr))<<shift;
bl=(blcr<bl) ? blcr : bl;
bl=(blcb<bl) ? blcb : bl;
bl=(bl>todo) ? todo : bl;
blcr=bl>>shift;
blcb=blcr;
/* bl now containts the longest row that can be written */
todo-=bl;
if(!todo) rcmd|=BT848_RISC_EOL; /* if this is the last EOL */
*((*rp)++)=cpu_to_le32(rcmd|bl);
*((*rp)++)=cpu_to_le32(blcb|(blcr<<16));
*((*rp)++)=cpu_to_le32(virt_to_bus(vadr));
vadr+=bl;
if((rcmd&(15<<28))==BT848_RISC_WRITE123)
{
*((*rp)++)=cpu_to_le32(virt_to_bus(cbadr));
cbadr+=blcb;
*((*rp)++)=cpu_to_le32(virt_to_bus(cradr));
cradr+=blcr;
}
rcmd&=~BT848_RISC_SOL; /* only the first has SOL */
case V4L2_CID_PRIVATE_CHROMA_AGC:
btv->opt_chroma_agc = c->value;
val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
btwrite(val, BT848_E_SCLOOP);
btwrite(val, BT848_O_SCLOOP);
break;
case V4L2_CID_PRIVATE_COMBFILTER:
btv->opt_combfilter = c->value;
break;
case V4L2_CID_PRIVATE_LUMAFILTER:
btv->opt_lumafilter = c->value;
if (btv->opt_lumafilter) {
btand(~BT848_CONTROL_LDEC, BT848_E_CONTROL);
btand(~BT848_CONTROL_LDEC, BT848_O_CONTROL);
} else {
btor(BT848_CONTROL_LDEC, BT848_E_CONTROL);
btor(BT848_CONTROL_LDEC, BT848_O_CONTROL);
}
break;
case V4L2_CID_PRIVATE_AUTOMUTE:
btv->opt_automute = c->value;
break;
case V4L2_CID_PRIVATE_AGC_CRUSH:
btv->opt_adc_crush = c->value;
btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
BT848_ADC);
break;
case V4L2_CID_PRIVATE_VCR_HACK:
btv->opt_vcr_hack = c->value;
break;
default:
return -EINVAL;
}
*(ro++)=cpu_to_le32(BT848_RISC_JUMP);
*(ro++)=cpu_to_le32(btv->bus_vbi_even);
*(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16));
*(re++)=cpu_to_le32(btv->bus_vbi_odd);
if (bttv_debug > 1)
cprintf("bttv%d: prisc2: ro=%08lx re=%08lx\n",
btv->nr,virt_to_bus((unsigned long)ro), virt_to_bus((unsigned long)re));
 
if (i >= 4 && i <= 8) {
bttv_call_i2c_clients(btv, VIDIOCSAUDIO, &va);
if (btv->audio_hook)
btv->audio_hook(btv,&va,1);
}
return 0;
}
static int make_vrisctab(struct bttv *btv, unsigned int *ro,
unsigned int *re,
unsigned int *vbuf, unsigned short width,
unsigned short height, unsigned short palette)
 
/* ----------------------------------------------------------------------- */
 
void bttv_gpio_tracking(struct bttv *btv, char *comment)
{
unsigned long line;
unsigned long bpl; /* bytes per line */
unsigned int **rp;
int inter;
unsigned long vadr=(unsigned long) vbuf;
unsigned int outbits, data;
outbits = btread(BT848_GPIO_OUT_EN);
data = btread(BT848_GPIO_DATA);
printk(KERN_DEBUG "bttv%d: gpio: en=%08x, out=%08x in=%08x [%s]\n",
btv->nr,outbits,data & outbits, data & ~outbits, comment);
}
 
if (palette==VIDEO_PALETTE_RAW)
return make_rawrisctab(btv, ro, re, vbuf);
if (palette>=VIDEO_PALETTE_PLANAR)
return make_prisctab(btv, ro, re, vbuf, width, height, palette);
void bttv_field_count(struct bttv *btv)
{
int need_count = 0;
 
if (bttv_debug > 1)
cprintf("bttv%d: vrisc1: ro=%08lx re=%08lx\n",
btv->nr,virt_to_bus((unsigned long)ro), virt_to_bus((unsigned long)re));
inter = (height>tvnorms[btv->win.norm].sheight/2) ? 1 : 0;
bpl=width*fmtbppx2[palette2fmt[palette]&0xf]/2;
*(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
*(ro++)=cpu_to_le32(0);
*(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
*(re++)=cpu_to_le32(0);
for (line=0; line < (height<<(1^inter)); line++)
{
if (inter)
rp= (line&1) ? &re : &ro;
else
rp= (line>=height) ? &ro : &re;
if (btv->users)
need_count++;
 
*((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
BT848_RISC_EOL|bpl);
*((*rp)++)=cpu_to_le32(virt_to_bus(vadr));
vadr+=bpl;
if (need_count) {
/* start field counter */
btor(BT848_INT_VSYNC,BT848_INT_MASK);
} else {
/* stop field counter */
btand(~BT848_INT_VSYNC,BT848_INT_MASK);
btv->field_count = 0;
}
*(ro++)=cpu_to_le32(BT848_RISC_JUMP);
*(ro++)=cpu_to_le32(btv->bus_vbi_even);
*(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16));
*(re++)=cpu_to_le32(btv->bus_vbi_odd);
 
if (bttv_debug > 1)
cprintf("bttv%d: vrisc2: ro=%08lx re=%08lx\n",
btv->nr,virt_to_bus((unsigned long)ro), virt_to_bus((unsigned long)re));
return 0;
}
 
static unsigned char lmaskt[8] =
{ 0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80};
static unsigned char rmaskt[8] =
{ 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
 
static void clip_draw_rectangle(unsigned char *clipmap, int x, int y, int w, int h)
static const struct bttv_format*
format_by_palette(int palette)
{
unsigned char lmask, rmask, *p;
int W, l, r;
int i;
unsigned int i;
 
if (bttv_debug > 1)
cprintf("bttv clip: %dx%d+%d+%d\n",w,h,x,y);
for (i = 0; i < BTTV_FORMATS; i++) {
if (-1 == bttv_formats[i].palette)
continue;
if (bttv_formats[i].palette == palette)
return bttv_formats+i;
}
return NULL;
}
 
/* bitmap is fixed width, 128 bytes (1024 pixels represented) */
if (x<0)
{
w+=x;
x=0;
}
if (y<0)
{
h+=y;
y=0;
}
if (w < 0 || h < 0) /* catch bad clips */
return;
/* out of range data should just fall through */
if (y+h>=625)
h=625-y;
if (x+w>=1024)
w=1024-x;
static const struct bttv_format*
format_by_fourcc(int fourcc)
{
unsigned int i;
 
l=x>>3;
r=(x+w-1)>>3;
W=r-l-1;
lmask=lmaskt[x&7];
rmask=rmaskt[(x+w-1)&7];
p=clipmap+128*y+l;
if (W>0)
{
for (i=0; i<h; i++, p+=128)
{
*p|=lmask;
memset(p+1, 0xff, W);
p[W+1]|=rmask;
}
} else if (!W) {
for (i=0; i<h; i++, p+=128)
{
p[0]|=lmask;
p[1]|=rmask;
}
} else {
for (i=0; i<h; i++, p+=128)
p[0]|=lmask&rmask;
}
 
for (i = 0; i < BTTV_FORMATS; i++) {
if (-1 == bttv_formats[i].fourcc)
continue;
if (bttv_formats[i].fourcc == fourcc)
return bttv_formats+i;
}
return NULL;
}
 
static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr)
/* ----------------------------------------------------------------------- */
/* misc helpers */
 
static int
bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
struct bttv_buffer *new)
{
int i, line, x, y, bpl, width, height, inter, maxw;
unsigned int bpp, dx, sx, **rp, *ro, *re, flags, len;
unsigned long adr;
unsigned char *clipmap, *clipline, cbit, lastbit, outofmem;
struct bttv_buffer *old;
unsigned long flags;
int retval = 0;
 
/* take care: bpp != btv->win.bpp is allowed here */
bpp = fmtbppx2[btv->win.color_fmt&0xf]/2;
bpl=btv->win.bpl;
adr=btv->win.vidadr + btv->win.x * btv->win.bpp + btv->win.y * bpl;
inter=(btv->win.interlace&1)^1;
width=btv->win.width;
height=btv->win.height;
if (bttv_debug > 1)
cprintf("bttv%d: clip1: pal=%d size=%dx%d, bpl=%d bpp=%d\n",
btv->nr,btv->picture.palette,width,height,bpl,bpp);
if(width > 1023)
width = 1023; /* sanity check */
if(height > 625)
height = 625; /* sanity check */
ro=(unsigned int *)btv->risc_scr_odd;
re=(unsigned int *)btv->risc_scr_even;
dprintk("switch_overlay: enter [new=%p]\n",new);
if (new)
new->vb.state = STATE_DONE;
spin_lock_irqsave(&btv->s_lock,flags);
old = btv->screen;
btv->screen = new;
bttv_set_dma(btv, 0x03, 1);
spin_unlock_irqrestore(&btv->s_lock,flags);
if (NULL == new)
free_btres(btv,fh,RESOURCE_OVERLAY);
if (NULL != old) {
dprintk("switch_overlay: old=%p state is %d\n",old,old->vb.state);
bttv_dma_free(btv, old);
kfree(old);
}
dprintk("switch_overlay: done\n");
return retval;
}
 
if (bttv_debug)
cprintf("bttv%d: clip: ro=%08lx re=%08lx\n",
btv->nr,virt_to_bus((unsigned long)ro), virt_to_bus((unsigned long)re));
/* ----------------------------------------------------------------------- */
/* video4linux (1) interface */
 
if ((clipmap=vmalloc_32(VIDEO_CLIPMAP_SIZE))==NULL) {
/* can't clip, don't generate any risc code */
*(ro++)=cpu_to_le32(BT848_RISC_JUMP);
*(ro++)=cpu_to_le32(btv->bus_vbi_even);
*(re++)=cpu_to_le32(BT848_RISC_JUMP);
*(re++)=cpu_to_le32(btv->bus_vbi_odd);
static int bttv_prepare_buffer(struct bttv *btv, struct bttv_buffer *buf,
const struct bttv_format *fmt,
unsigned int width, unsigned int height,
enum v4l2_field field)
{
int redo_dma_risc = 0;
int rc;
/* check settings */
if (NULL == fmt)
return -EINVAL;
if (fmt->btformat == BT848_COLOR_FMT_RAW) {
width = RAW_BPL;
height = RAW_LINES*2;
if (width*height > buf->vb.bsize)
return -EINVAL;
buf->vb.size = buf->vb.bsize;
} else {
if (width < 48 ||
height < 32 ||
width > bttv_tvnorms[btv->tvnorm].swidth ||
height > bttv_tvnorms[btv->tvnorm].sheight)
return -EINVAL;
buf->vb.size = (width * height * fmt->depth) >> 3;
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
return -EINVAL;
}
if (ncr < 0) { /* bitmap was pased */
memcpy(clipmap, (unsigned char *)cr, VIDEO_CLIPMAP_SIZE);
} else { /* convert rectangular clips to a bitmap */
memset(clipmap, 0, VIDEO_CLIPMAP_SIZE); /* clear map */
for (i=0; i<ncr; i++)
clip_draw_rectangle(clipmap, cr[i].x, cr[i].y,
cr[i].width, cr[i].height);
}
/* clip against viewing window AND screen
so we do not have to rely on the user program
*/
maxw = (bpl - btv->win.x * btv->win.bpp) / bpp;
clip_draw_rectangle(clipmap, (width > maxw) ? maxw : width,
0, 1024, 768);
clip_draw_rectangle(clipmap,0,(btv->win.y+height>btv->win.sheight) ?
(btv->win.sheight-btv->win.y) : height,1024,768);
if (btv->win.x<0)
clip_draw_rectangle(clipmap, 0, 0, -(btv->win.x), 768);
if (btv->win.y<0)
clip_draw_rectangle(clipmap, 0, 0, 1024, -(btv->win.y));
*(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
*(ro++)=cpu_to_le32(0);
*(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
*(re++)=cpu_to_le32(0);
/* translate bitmap to risc code */
for (line=outofmem=0; line < (height<<inter) && !outofmem; line++)
{
y = line>>inter;
rp= (line&1) ? &re : &ro;
clipline = clipmap + (y<<7); /* running pointers ... */
lastbit = *clipline & 1;
for(x=dx=0,sx=0; x<=width && !outofmem;) {
if (0 == (x&7)) {
/* check bytes not bits if we can ... */
if (lastbit) {
while (0xff==*clipline && x<width-8) {
x += 8;
dx += 8;
clipline++;
}
} else {
while (0x00==*clipline && x<width-8) {
x += 8;
dx += 8;
clipline++;
}
}
}
cbit = *clipline & (1<<(x&7));
if (x < width && !lastbit == !cbit) {
dx++;
} else {
/* generate the dma controller code */
len = dx * bpp;
flags = ((bpp==4) ? BT848_RISC_BYTE3 : 0);
flags |= ((!sx) ? BT848_RISC_SOL : 0);
flags |= ((sx + dx == width) ? BT848_RISC_EOL : 0);
if (!lastbit) {
*((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|flags|len);
*((*rp)++)=cpu_to_le32(adr + bpp * sx);
} else {
*((*rp)++)=cpu_to_le32(BT848_RISC_SKIP|flags|len);
}
lastbit=cbit;
sx += dx;
dx = 1;
if (ro - (unsigned int *)btv->risc_scr_odd>(RISCMEM_LEN>>3) - 16)
outofmem++;
if (re - (unsigned int *)btv->risc_scr_even>(RISCMEM_LEN>>3) - 16)
outofmem++;
}
x++;
if (0 == (x&7))
clipline++;
}
if ((!inter)||(line&1))
adr+=bpl;
/* alloc + fill struct bttv_buffer (if changed) */
if (buf->vb.width != width || buf->vb.height != height ||
buf->vb.field != field ||
buf->tvnorm != btv->tvnorm || buf->fmt != fmt) {
buf->vb.width = width;
buf->vb.height = height;
buf->vb.field = field;
buf->tvnorm = btv->tvnorm;
buf->fmt = fmt;
redo_dma_risc = 1;
}
 
vfree_32(clipmap);
/* outofmem flag relies on the following code to discard extra data */
*(ro++)=cpu_to_le32(BT848_RISC_JUMP);
*(ro++)=cpu_to_le32(btv->bus_vbi_even);
*(re++)=cpu_to_le32(BT848_RISC_JUMP);
*(re++)=cpu_to_le32(btv->bus_vbi_odd);
/* alloc risc memory */
if (STATE_NEEDS_INIT == buf->vb.state) {
redo_dma_risc = 1;
if (0 != (rc = videobuf_iolock(btv->dev,&buf->vb,&btv->fbuf)))
goto fail;
}
 
if (bttv_debug > 1)
cprintf("bttv%d: clip2: pal=%d size=%dx%d, bpl=%d bpp=%d\n",
btv->nr,btv->picture.palette,width,height,bpl,bpp);
if (redo_dma_risc)
if (0 != (rc = bttv_buffer_risc(btv,buf)))
goto fail;
 
buf->vb.state = STATE_PREPARED;
return 0;
 
fail:
bttv_dma_free(btv,buf);
return rc;
}
 
/*
* Set the registers for the size we have specified. Don't bother
* trying to understand this without the BT848 manual in front of
* you [AC].
*
* PS: The manual is free for download in .pdf format from
* www.brooktree.com - nicely done those folks.
*/
static inline void bt848_set_eogeo(struct bttv *btv, struct tvnorm *tvn,
int odd, int width, int height)
static int
buffer_setup(struct file *file, unsigned int *count, unsigned int *size)
{
u16 vscale, hscale;
u32 xsf, sr;
u16 hdelay;
u8 crop, vtc;
int inter = (height>tvn->sheight/2) ? 0 : 1;
int off = odd ? 0x80 : 0x00;
struct bttv_fh *fh = file->private_data;
*size = fh->fmt->depth*fh->width*fh->height >> 3;
if (0 == *count)
*count = gbuffers;
while (*size * *count > gbuffers * gbufsize)
(*count)--;
return 0;
}
 
xsf = (width*tvn->scaledtwidth)/tvn->swidth;
hscale = ((tvn->totalwidth*4096UL)/xsf-4096);
hdelay = tvn->hdelayx1;
hdelay = (hdelay*width)/tvn->swidth;
hdelay &= 0x3fe;
sr=((tvn->sheight>>inter)*512)/height-512;
vscale=(0x10000UL-sr)&0x1fff;
crop=((width>>8)&0x03)|((hdelay>>6)&0x0c)|
((tvn->sheight>>4)&0x30)|((tvn->vdelay>>2)&0xc0);
vscale |= inter ? (BT848_VSCALE_INT<<8) : 0;
static int
buffer_prepare(struct file *file, struct videobuf_buffer *vb,
enum v4l2_field field)
{
struct bttv_buffer *buf = (struct bttv_buffer*)vb;
struct bttv_fh *fh = file->private_data;
 
if (combfilter) {
/* Some people say interpolation looks bad ... */
vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
if (width < 769)
btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
else
btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
} else {
vtc = 0;
btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
}
 
btwrite(vtc, BT848_E_VTC+off);
btwrite(hscale>>8, BT848_E_HSCALE_HI+off);
btwrite(hscale&0xff, BT848_E_HSCALE_LO+off);
btaor((vscale>>8), 0xe0, BT848_E_VSCALE_HI+off);
btwrite(vscale&0xff, BT848_E_VSCALE_LO+off);
btwrite(width&0xff, BT848_E_HACTIVE_LO+off);
btwrite(hdelay&0xff, BT848_E_HDELAY_LO+off);
btwrite(tvn->sheight&0xff, BT848_E_VACTIVE_LO+off);
btwrite(tvn->vdelay&0xff, BT848_E_VDELAY_LO+off);
btwrite(crop, BT848_E_CROP+off);
return bttv_prepare_buffer(fh->btv, buf, fh->fmt,
fh->width, fh->height, field);
}
 
 
static void bt848_set_geo(struct bttv *btv)
static void
buffer_queue(struct file *file, struct videobuf_buffer *vb)
{
u16 ewidth, eheight, owidth, oheight;
u16 format, bswap;
struct tvnorm *tvn;
struct bttv_buffer *buf = (struct bttv_buffer*)vb;
struct bttv_fh *fh = file->private_data;
 
tvn=&tvnorms[btv->win.norm];
btwrite(tvn->adelay, BT848_ADELAY);
btwrite(tvn->bdelay, BT848_BDELAY);
btaor(tvn->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH), BT848_IFORM);
btwrite(tvn->vbipack, BT848_VBI_PACK_SIZE);
btwrite(1, BT848_VBI_PACK_DEL);
buf->vb.state = STATE_QUEUED;
list_add_tail(&buf->vb.queue,&fh->btv->capture);
bttv_set_dma(fh->btv, 0x03, 1);
}
 
btv->pll.pll_ofreq = tvn->Fsc;
if (!in_irq) set_pll(btv);
static void buffer_release(struct file *file, struct videobuf_buffer *vb)
{
struct bttv_buffer *buf = (struct bttv_buffer*)vb;
struct bttv_fh *fh = file->private_data;
 
btv->win.interlace = (btv->win.height>tvn->sheight/2) ? 1 : 0;
 
if (0 == btv->risc_cap_odd &&
0 == btv->risc_cap_even) {
/* overlay only */
owidth = btv->win.width;
oheight = btv->win.height;
ewidth = btv->win.width;
eheight = btv->win.height;
format = btv->win.color_fmt;
bswap = btv->fb_color_ctl;
} else if (-1 != btv->gq_grab &&
0 == btv->risc_cap_odd &&
!btv->win.interlace &&
btv->scr_on) {
/* odd field -> overlay, even field -> capture */
owidth = btv->win.width;
oheight = btv->win.height;
ewidth = btv->gbuf[btv->gq_grab].width;
eheight = btv->gbuf[btv->gq_grab].height;
format = (btv->win.color_fmt & 0xf0) |
(btv->gbuf[btv->gq_grab].fmt & 0x0f);
bswap = btv->fb_color_ctl & 0x0a;
} else {
/* capture only */
owidth = btv->gbuf[btv->gq_grab].width;
oheight = btv->gbuf[btv->gq_grab].height;
ewidth = btv->gbuf[btv->gq_grab].width;
eheight = btv->gbuf[btv->gq_grab].height;
format = btv->gbuf[btv->gq_grab].fmt;
bswap = 0;
}
 
/* program odd + even fields */
bt848_set_eogeo(btv, tvn, 1, owidth, oheight);
bt848_set_eogeo(btv, tvn, 0, ewidth, eheight);
 
btwrite(format, BT848_COLOR_FMT);
btwrite(bswap | BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL);
bttv_dma_free(fh->btv,buf);
}
 
 
static int bpp2fmt[4] = {
BT848_COLOR_FMT_RGB8, BT848_COLOR_FMT_RGB16,
BT848_COLOR_FMT_RGB24, BT848_COLOR_FMT_RGB32
static struct videobuf_queue_ops bttv_video_qops = {
.buf_setup = buffer_setup,
.buf_prepare = buffer_prepare,
.buf_queue = buffer_queue,
.buf_release = buffer_release,
};
 
static void bt848_set_winsize(struct bttv *btv)
static const char *v4l1_ioctls[] = {
"?", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT",
"CCAPTURE", "GWIN", "SWIN", "GFBUF", "SFBUF", "KEY", "GFREQ",
"SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT",
"GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO",
"SMICROCODE", "GVBIFMT", "SVBIFMT" };
#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls)
 
int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
{
unsigned short format;
switch (cmd) {
case BTTV_VERSION:
return BTTV_VERSION_CODE;
 
if (btv->picture.palette > 0 && btv->picture.palette <= VIDEO_PALETTE_YUV422) {
/* format set by VIDIOCSPICT */
format = palette2fmt[btv->picture.palette];
} else {
/* use default for the given color depth */
format = (btv->win.depth==15) ? BT848_COLOR_FMT_RGB15 :
bpp2fmt[(btv->win.bpp-1)&3];
/* *** v4l1 *** ************************************************ */
case VIDIOCGFREQ:
{
unsigned long *freq = arg;
*freq = btv->freq;
return 0;
}
btv->win.color_fmt = format;
if (bigendian &&
format == BT848_COLOR_FMT_RGB32) {
btv->fb_color_ctl =
BT848_COLOR_CTL_WSWAP_ODD |
BT848_COLOR_CTL_WSWAP_EVEN |
BT848_COLOR_CTL_BSWAP_ODD |
BT848_COLOR_CTL_BSWAP_EVEN;
} else if (bigendian &&
(format == BT848_COLOR_FMT_RGB16 ||
format == BT848_COLOR_FMT_RGB15)) {
btv->fb_color_ctl =
BT848_COLOR_CTL_BSWAP_ODD |
BT848_COLOR_CTL_BSWAP_EVEN;
} else {
btv->fb_color_ctl = 0;
case VIDIOCSFREQ:
{
unsigned long *freq = arg;
down(&btv->lock);
btv->freq=*freq;
bttv_call_i2c_clients(btv,VIDIOCSFREQ,freq);
if (btv->has_matchbox && btv->radio_user)
tea5757_set_freq(btv,*freq);
up(&btv->lock);
return 0;
}
 
/* RGB8 seems to be a 9x5x5 GRB color cube starting at
* color 16. Why the h... can't they even mention this in the
* data sheet? [AC - because it's a standard format so I guess
* it never occurred to them]
* Enable dithering in this mode.
*/
case VIDIOCGTUNER:
{
struct video_tuner *v = arg;
if (UNSET == bttv_tvcards[btv->type].tuner)
return -EINVAL;
if (v->tuner) /* Only tuner 0 */
return -EINVAL;
strcpy(v->name, "Television");
v->rangelow = 0;
v->rangehigh = 0x7FFFFFFF;
v->flags = VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM;
v->mode = btv->tvnorm;
v->signal = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0;
bttv_call_i2c_clients(btv,cmd,v);
return 0;
}
case VIDIOCSTUNER:
{
struct video_tuner *v = arg;
 
if (format==BT848_COLOR_FMT_RGB8)
btand(~BT848_CAP_CTL_DITH_FRAME, BT848_CAP_CTL);
else
btor(BT848_CAP_CTL_DITH_FRAME, BT848_CAP_CTL);
if (v->tuner) /* Only tuner 0 */
return -EINVAL;
if (v->mode >= BTTV_TVNORMS)
return -EINVAL;
 
bt848_set_geo(btv);
}
down(&btv->lock);
set_tvnorm(btv,v->mode);
bttv_call_i2c_clients(btv,cmd,v);
up(&btv->lock);
return 0;
}
case VIDIOCGCHAN:
{
struct video_channel *v = arg;
unsigned int channel = v->channel;
 
/*
* Grab into virtual memory.
*/
static int vgrab(struct bttv *btv, struct video_mmap *mp)
{
unsigned int *ro, *re;
unsigned int *vbuf;
if (channel >= bttv_tvcards[btv->type].video_inputs)
return -EINVAL;
v->tuners=0;
v->flags = VIDEO_VC_AUDIO;
v->type = VIDEO_TYPE_CAMERA;
v->norm = btv->tvnorm;
if (channel == bttv_tvcards[btv->type].tuner) {
strcpy(v->name,"Television");
v->flags|=VIDEO_VC_TUNER;
v->type=VIDEO_TYPE_TV;
v->tuners=1;
} else if (channel == btv->svhs) {
strcpy(v->name,"S-Video");
} else {
sprintf(v->name,"Composite%d",channel);
}
return 0;
}
case VIDIOCSCHAN:
{
struct video_channel *v = arg;
unsigned int channel = v->channel;
 
if(btv->fbuffer==NULL)
return -ENOBUFS;
if (channel >= bttv_tvcards[btv->type].video_inputs)
return -EINVAL;
if (v->norm >= BTTV_TVNORMS)
return -EINVAL;
 
if(mp->frame >= gbuffers || mp->frame < 0)
return -EINVAL;
if(mp->height < 32 || mp->width < 48)
return -EINVAL;
if (mp->format >= PALETTEFMT_MAX)
return -EINVAL;
down(&btv->lock);
if (channel == btv->input &&
v->norm == btv->tvnorm) {
/* nothing to do */
up(&btv->lock);
return 0;
}
 
if (mp->height*mp->width*fmtbppx2[palette2fmt[mp->format]&0x0f]/2
> gbufsize)
return -EINVAL;
if (-1 == palette2fmt[mp->format])
return -EINVAL;
btv->tvnorm = v->norm;
set_input(btv,v->channel);
up(&btv->lock);
return 0;
}
 
/*
* Ok load up the BT848
*/
vbuf=(unsigned int *)(btv->fbuffer+gbufsize*mp->frame);
ro=(unsigned int *)btv->gbuf[mp->frame].risc;
re=ro+2048;
make_vrisctab(btv, ro, re, vbuf, mp->width, mp->height, mp->format);
case VIDIOCGAUDIO:
{
struct video_audio *v = arg;
 
if (bttv_debug)
printk("bttv%d: cap vgrab: queue %d (%d:%dx%d)\n",
btv->nr,mp->frame,mp->format,mp->width,mp->height);
btv->gbuf[mp->frame].stat = GBUFFER_GRABBING;
btv->gbuf[mp->frame].fmt = palette2fmt[mp->format];
btv->gbuf[mp->frame].width = mp->width;
btv->gbuf[mp->frame].height = mp->height;
btv->gbuf[mp->frame].ro = virt_to_bus((unsigned long)ro);
btv->gbuf[mp->frame].re = virt_to_bus((unsigned long)re);
memset(v,0,sizeof(*v));
strcpy(v->name,"Television");
v->flags |= VIDEO_AUDIO_MUTABLE;
v->mode = VIDEO_SOUND_MONO;
 
#if 1
if (mp->height <= tvnorms[btv->win.norm].sheight/2 &&
mp->format != VIDEO_PALETTE_RAW)
btv->gbuf[mp->frame].ro = 0;
#endif
down(&btv->lock);
bttv_call_i2c_clients(btv,cmd,v);
 
if (-1 == btv->gq_grab && btv->gq_in == btv->gq_out) {
btv->gq_start = 1;
btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ);
}
btv->gqueue[btv->gq_in++] = mp->frame;
btv->gq_in = btv->gq_in % MAX_GBUFFERS;
/* card specific hooks */
if (btv->audio_hook)
btv->audio_hook(btv,v,0);
 
btor(3, BT848_CAP_CTL);
btor(3, BT848_GPIO_DMA_CTL);
return 0;
}
up(&btv->lock);
return 0;
}
case VIDIOCSAUDIO:
{
struct video_audio *v = arg;
unsigned int audio = v->audio;
 
static inline void burst(int on)
{
tvnorms[0].scaledtwidth = 1135 - (on?BURSTOFFSET-2:0);
tvnorms[0].hdelayx1 = 186 - (on?BURSTOFFSET :0);
tvnorms[2].scaledtwidth = 1135 - (on?BURSTOFFSET-2:0);
tvnorms[2].hdelayx1 = 186 - (on?BURSTOFFSET :0);
}
if (audio >= bttv_tvcards[btv->type].audio_inputs)
return -EINVAL;
 
/*
* called from irq handler on fatal errors. Takes the grabber chip
* offline, flag it needs a reinitialization (which can't be done
* from irq context) and wake up all sleeping proccesses. They would
* block forever else. We also need someone who actually does the
* reinitialization from process context...
*/
static void bt848_offline(struct bttv *btv)
{
int i;
down(&btv->lock);
audio_mux(btv, (v->flags&VIDEO_AUDIO_MUTE) ? AUDIO_MUTE : AUDIO_UNMUTE);
bttv_call_i2c_clients(btv,cmd,v);
 
/* cancel all outstanding grab requests */
btv->gq_in = 0;
btv->gq_out = 0;
btv->gq_grab = -1;
for (i = 0; i < gbuffers; i++)
if (btv->gbuf[i].stat == GBUFFER_GRABBING)
btv->gbuf[i].stat = GBUFFER_ERROR;
/* card specific hooks */
if (btv->audio_hook)
btv->audio_hook(btv,v,1);
up(&btv->lock);
return 0;
}
 
/* disable screen overlay and DMA */
btv->risc_cap_odd = 0;
btv->risc_cap_even = 0;
bt848_set_risc_jmps(btv,0);
/* *** v4l2 *** ************************************************ */
case VIDIOC_ENUMSTD:
{
struct v4l2_standard *e = arg;
unsigned int index = e->index;
if (index >= BTTV_TVNORMS)
return -EINVAL;
v4l2_video_std_construct(e, bttv_tvnorms[e->index].v4l2_id,
bttv_tvnorms[e->index].name);
e->index = index;
return 0;
}
case VIDIOC_G_STD:
{
v4l2_std_id *id = arg;
*id = bttv_tvnorms[btv->tvnorm].v4l2_id;
return 0;
}
case VIDIOC_S_STD:
{
v4l2_std_id *id = arg;
unsigned int i;
 
/* flag the chip needs a restart */
btv->needs_restart = 1;
for (i = 0; i < BTTV_TVNORMS; i++)
if (*id & bttv_tvnorms[i].v4l2_id)
break;
if (i == BTTV_TVNORMS)
return -EINVAL;
 
}
down(&btv->lock);
set_tvnorm(btv,i);
i2c_vidiocschan(btv);
up(&btv->lock);
return 0;
}
case VIDIOC_QUERYSTD:
{
v4l2_std_id *id = arg;
if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML)
*id = V4L2_STD_625_50;
else
*id = V4L2_STD_525_60;
return 0;
}
 
static void bt848_restart(struct bttv *btv)
{
if (bttv_verbose)
printk(KERN_INFO "bttv%d: resetting chip\n",btv->nr);
btwrite(0xfffffUL, BT848_INT_STAT);
btand(~15, BT848_GPIO_DMA_CTL);
btwrite(0, BT848_SRESET);
btwrite(virt_to_bus((unsigned long)btv->risc_jmp+8),
BT848_RISC_STRT_ADD);
case VIDIOC_ENUMINPUT:
{
struct v4l2_input *i = arg;
unsigned int n;
n = i->index;
if (n >= bttv_tvcards[btv->type].video_inputs)
return -EINVAL;
memset(i,0,sizeof(*i));
i->index = n;
i->type = V4L2_INPUT_TYPE_CAMERA;
i->audioset = 1;
if (i->index == bttv_tvcards[btv->type].tuner) {
sprintf(i->name, "Television");
i->type = V4L2_INPUT_TYPE_TUNER;
i->tuner = 0;
} else if (i->index == btv->svhs) {
sprintf(i->name, "S-Video");
} else {
sprintf(i->name,"Composite%d",i->index);
}
if (i->index == btv->input) {
__u32 dstatus = btread(BT848_DSTATUS);
if (0 == (dstatus & BT848_DSTATUS_PRES))
i->status |= V4L2_IN_ST_NO_SIGNAL;
if (0 == (dstatus & BT848_DSTATUS_HLOC))
i->status |= V4L2_IN_ST_NO_H_LOCK;
}
for (n = 0; n < BTTV_TVNORMS; n++)
i->std |= bttv_tvnorms[n].v4l2_id;
return 0;
}
case VIDIOC_G_INPUT:
{
int *i = arg;
*i = btv->input;
return 0;
}
case VIDIOC_S_INPUT:
{
unsigned int *i = arg;
if (*i > bttv_tvcards[btv->type].video_inputs)
return -EINVAL;
down(&btv->lock);
set_input(btv,*i);
i2c_vidiocschan(btv);
up(&btv->lock);
return 0;
}
case VIDIOC_G_TUNER:
{
struct v4l2_tuner *t = arg;
 
/* enforce pll reprogramming */
btv->pll.pll_current = 0;
set_pll(btv);
if (UNSET == bttv_tvcards[btv->type].tuner)
return -EINVAL;
if (0 != t->index)
return -EINVAL;
down(&btv->lock);
memset(t,0,sizeof(*t));
strcpy(t->name, "Television");
t->type = V4L2_TUNER_ANALOG_TV;
t->rangehigh = 0xffffffffUL;
t->capability = V4L2_TUNER_CAP_NORM;
t->rxsubchans = V4L2_TUNER_SUB_MONO;
if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)
t->signal = 0xffff;
{
/* Hmmm ... */
struct video_audio va;
memset(&va, 0, sizeof(struct video_audio));
bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
if (btv->audio_hook)
btv->audio_hook(btv,&va,0);
if(va.mode & VIDEO_SOUND_STEREO) {
t->audmode = V4L2_TUNER_MODE_STEREO;
t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
}
if(va.mode & VIDEO_SOUND_LANG1) {
t->audmode = V4L2_TUNER_MODE_LANG1;
t->rxsubchans = V4L2_TUNER_SUB_LANG1
| V4L2_TUNER_SUB_LANG2;
}
}
/* FIXME: fill capability+audmode */
up(&btv->lock);
return 0;
}
case VIDIOC_S_TUNER:
{
struct v4l2_tuner *t = arg;
 
btv->errors = 0;
btv->needs_restart = 0;
bt848_set_geo(btv);
bt848_set_risc_jmps(btv,-1);
if (UNSET == bttv_tvcards[btv->type].tuner)
return -EINVAL;
if (0 != t->index)
return -EINVAL;
down(&btv->lock);
{
struct video_audio va;
memset(&va, 0, sizeof(struct video_audio));
bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
if (t->audmode == V4L2_TUNER_MODE_MONO)
va.mode = VIDEO_SOUND_MONO;
else if (t->audmode == V4L2_TUNER_MODE_STEREO)
va.mode = VIDEO_SOUND_STEREO;
else if (t->audmode == V4L2_TUNER_MODE_LANG1)
va.mode = VIDEO_SOUND_LANG1;
else if (t->audmode == V4L2_TUNER_MODE_LANG2)
va.mode = VIDEO_SOUND_LANG2;
bttv_call_i2c_clients(btv, VIDIOCSAUDIO, &va);
if (btv->audio_hook)
btv->audio_hook(btv,&va,1);
}
up(&btv->lock);
return 0;
}
 
case VIDIOC_G_FREQUENCY:
{
struct v4l2_frequency *f = arg;
 
memset(f,0,sizeof(*f));
f->type = V4L2_TUNER_ANALOG_TV;
f->frequency = btv->freq;
return 0;
}
case VIDIOC_S_FREQUENCY:
{
struct v4l2_frequency *f = arg;
 
if (unlikely(f->tuner != 0))
return -EINVAL;
if (unlikely(f->type != V4L2_TUNER_ANALOG_TV))
return -EINVAL;
down(&btv->lock);
btv->freq = f->frequency;
bttv_call_i2c_clients(btv,VIDIOCSFREQ,&btv->freq);
if (btv->has_matchbox && btv->radio_user)
tea5757_set_freq(btv,btv->freq);
up(&btv->lock);
return 0;
}
 
default:
return -ENOIOCTLCMD;
}
return 0;
}
 
/*
* Open a bttv card. Right now the flags stuff is just playing
*/
 
int bttv_open(struct bttv *btv)
static int verify_window(const struct bttv_tvnorm *tvn,
struct v4l2_window *win, int fixup)
{
int i,ret;
enum v4l2_field field;
int maxw, maxh;
 
ret = -EBUSY;
if (bttv_debug)
cprintf("bttv%d: open called\n",btv->nr);
if (win->w.width < 48 || win->w.height < 32)
return -EINVAL;
if (win->clipcount > 2048)
return -EINVAL;
 
btv->fbuffer=(unsigned char *) vmalloc_32(gbuffers*gbufsize);
ret = -ENOMEM;
field = win->field;
maxw = tvn->swidth;
maxh = tvn->sheight;
 
btv->gq_in = 0;
btv->gq_out = 0;
btv->gq_grab = -1;
for (i = 0; i < gbuffers; i++)
btv->gbuf[i].stat = GBUFFER_UNUSED;
if (V4L2_FIELD_ANY == field) {
field = (win->w.height > maxh/2)
? V4L2_FIELD_INTERLACED
: V4L2_FIELD_TOP;
}
switch (field) {
case V4L2_FIELD_TOP:
case V4L2_FIELD_BOTTOM:
maxh = maxh / 2;
break;
case V4L2_FIELD_INTERLACED:
break;
default:
return -EINVAL;
}
 
burst(0);
set_pll(btv);
btv->user++;
return 0;
if (!fixup && (win->w.width > maxw || win->w.height > maxh))
return -EINVAL;
 
if (win->w.width > maxw)
win->w.width = maxw;
if (win->w.height > maxh)
win->w.height = maxh;
win->field = field;
return 0;
}
 
void bttv_close(struct bttv *btv)
static int setup_window(struct bttv_fh *fh, struct bttv *btv,
struct v4l2_window *win, int fixup)
{
int need_wait;
struct v4l2_clip *clips = NULL;
int n,size,retval = 0;
 
handler_remove(btv->dev->irq);
if (NULL == fh->ovfmt)
return -EINVAL;
retval = verify_window(&bttv_tvnorms[btv->tvnorm],win,fixup);
if (0 != retval)
return retval;
 
vfree_32(btv->fbuffer);
btv->fbuffer = NULL;
/* copy clips -- luckily v4l1 + v4l2 are binary
compatible here ...*/
n = win->clipcount;
size = sizeof(*clips)*(n+4);
clips = kmalloc(size,GFP_KERNEL);
if (NULL == clips)
return -ENOMEM;
if (n > 0) {
if (copy_from_user(clips,win->clips,sizeof(struct v4l2_clip)*n)) {
kfree(clips);
return -EFAULT;
}
}
/* clip against screen */
if (NULL != btv->fbuf.base)
n = btcx_screen_clips(btv->fbuf.fmt.width, btv->fbuf.fmt.height,
&win->w, clips, n);
btcx_sort_clips(clips,n);
 
/* 4-byte alignments */
switch (fh->ovfmt->depth) {
case 8:
case 24:
btcx_align(&win->w, clips, n, 3);
break;
case 16:
btcx_align(&win->w, clips, n, 1);
break;
case 32:
/* no alignment fixups needed */
break;
default:
BUG();
}
btv->user--;
need_wait = (-1 != btv->gq_grab);
btv->gq_start = 0;
btv->gq_in = 0;
btv->gq_out = 0;
btv->gq_grab = -1;
btv->scr_on = 0;
btv->risc_cap_odd = 0;
btv->risc_cap_even = 0;
 
pci_write_config_dword(btv->dev,PCI_COMMAND,oldpci_command);
 
down(&fh->cap.lock);
if (fh->ov.clips)
kfree(fh->ov.clips);
fh->ov.clips = clips;
fh->ov.nclips = n;
fh->ov.w = win->w;
fh->ov.field = win->field;
fh->ov.setup_ok = 1;
btv->init.ov.w.width = win->w.width;
btv->init.ov.w.height = win->w.height;
btv->init.ov.field = win->field;
/* update overlay if needed */
retval = 0;
if (check_btres(fh, RESOURCE_OVERLAY)) {
struct bttv_buffer *new;
new = videobuf_alloc(sizeof(*new));
bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
retval = bttv_switch_overlay(btv,fh,new);
}
up(&fh->cap.lock);
return retval;
}
 
/***********************************/
/* ioctls and supporting functions */
/***********************************/
/* ----------------------------------------------------------------------- */
 
static inline void bt848_bright(struct bttv *btv, uint bright)
static struct videobuf_queue* bttv_queue(struct bttv_fh *fh)
{
btwrite(bright&0xff, BT848_BRIGHT);
struct videobuf_queue* q = NULL;
switch (fh->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
q = &fh->cap;
break;
case V4L2_BUF_TYPE_VBI_CAPTURE:
q = &fh->vbi;
break;
default:
BUG();
}
return q;
}
 
static inline void bt848_hue(struct bttv *btv, uint hue)
static int bttv_resource(struct bttv_fh *fh)
{
btwrite(hue&0xff, BT848_HUE);
int res = 0;
switch (fh->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
res = RESOURCE_VIDEO;
break;
case V4L2_BUF_TYPE_VBI_CAPTURE:
res = RESOURCE_VBI;
break;
default:
BUG();
}
return res;
}
 
static inline void bt848_contrast(struct bttv *btv, uint cont)
static int bttv_switch_type(struct bttv_fh *fh, enum v4l2_buf_type type)
{
unsigned int conthi;
struct videobuf_queue *q = bttv_queue(fh);
int res = bttv_resource(fh);
 
conthi=(cont>>6)&4;
btwrite(cont&0xff, BT848_CONTRAST_LO);
btaor(conthi, ~4, BT848_E_CONTROL);
btaor(conthi, ~4, BT848_O_CONTROL);
if (check_btres(fh,res))
return -EBUSY;
if (videobuf_queue_is_busy(q))
return -EBUSY;
fh->type = type;
return 0;
}
 
static inline void bt848_sat_u(struct bttv *btv, unsigned long data)
static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f)
{
u32 datahi;
switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
memset(&f->fmt.pix,0,sizeof(struct v4l2_pix_format));
f->fmt.pix.width = fh->width;
f->fmt.pix.height = fh->height;
f->fmt.pix.field = fh->cap.field;
f->fmt.pix.pixelformat = fh->fmt->fourcc;
f->fmt.pix.bytesperline =
(f->fmt.pix.width * fh->fmt->depth) >> 3;
f->fmt.pix.sizeimage =
f->fmt.pix.height * f->fmt.pix.bytesperline;
return 0;
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
memset(&f->fmt.win,0,sizeof(struct v4l2_window));
f->fmt.win.w = fh->ov.w;
f->fmt.win.field = fh->ov.field;
return 0;
case V4L2_BUF_TYPE_VBI_CAPTURE:
bttv_vbi_get_fmt(fh,f);
return 0;
default:
return -EINVAL;
}
}
 
datahi=(data>>7)&2;
btwrite(data&0xff, BT848_SAT_U_LO);
btaor(datahi, ~2, BT848_E_CONTROL);
btaor(datahi, ~2, BT848_O_CONTROL);
static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv,
struct v4l2_format *f)
{
switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
{
const struct bttv_format *fmt;
enum v4l2_field field;
unsigned int maxw,maxh;
 
fmt = format_by_fourcc(f->fmt.pix.pixelformat);
if (NULL == fmt)
return -EINVAL;
 
/* fixup format */
maxw = bttv_tvnorms[btv->tvnorm].swidth;
maxh = bttv_tvnorms[btv->tvnorm].sheight;
field = f->fmt.pix.field;
if (V4L2_FIELD_ANY == field)
field = (f->fmt.pix.height > maxh/2)
? V4L2_FIELD_INTERLACED
: V4L2_FIELD_BOTTOM;
if (V4L2_FIELD_SEQ_BT == field)
field = V4L2_FIELD_SEQ_TB;
switch (field) {
case V4L2_FIELD_TOP:
case V4L2_FIELD_BOTTOM:
case V4L2_FIELD_ALTERNATE:
maxh = maxh/2;
break;
case V4L2_FIELD_INTERLACED:
break;
case V4L2_FIELD_SEQ_TB:
if (fmt->flags & FORMAT_FLAGS_PLANAR)
return -EINVAL;
break;
default:
return -EINVAL;
}
 
/* update data for the application */
f->fmt.pix.field = field;
if (f->fmt.pix.width < 48)
f->fmt.pix.width = 48;
if (f->fmt.pix.height < 32)
f->fmt.pix.height = 32;
if (f->fmt.pix.width > maxw)
f->fmt.pix.width = maxw;
if (f->fmt.pix.height > maxh)
f->fmt.pix.height = maxh;
f->fmt.pix.bytesperline =
(f->fmt.pix.width * fmt->depth) >> 3;
f->fmt.pix.sizeimage =
f->fmt.pix.height * f->fmt.pix.bytesperline;
return 0;
}
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
return verify_window(&bttv_tvnorms[btv->tvnorm],
&f->fmt.win, 1);
case V4L2_BUF_TYPE_VBI_CAPTURE:
bttv_vbi_try_fmt(fh,f);
return 0;
default:
return -EINVAL;
}
}
 
static inline void bt848_sat_v(struct bttv *btv, unsigned long data)
static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
struct v4l2_format *f)
{
u32 datahi;
int retval;
switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
{
const struct bttv_format *fmt;
 
datahi=(data>>8)&1;
btwrite(data&0xff, BT848_SAT_V_LO);
btaor(datahi, ~1, BT848_E_CONTROL);
btaor(datahi, ~1, BT848_O_CONTROL);
retval = bttv_switch_type(fh,f->type);
if (0 != retval)
return retval;
retval = bttv_try_fmt(fh,btv,f);
if (0 != retval)
return retval;
fmt = format_by_fourcc(f->fmt.pix.pixelformat);
/* update our state informations */
down(&fh->cap.lock);
fh->fmt = fmt;
fh->cap.field = f->fmt.pix.field;
fh->cap.last = V4L2_FIELD_NONE;
fh->width = f->fmt.pix.width;
fh->height = f->fmt.pix.height;
btv->init.fmt = fmt;
btv->init.width = f->fmt.pix.width;
btv->init.height = f->fmt.pix.height;
up(&fh->cap.lock);
return 0;
}
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
return setup_window(fh, btv, &f->fmt.win, 1);
case V4L2_BUF_TYPE_VBI_CAPTURE:
retval = bttv_switch_type(fh,f->type);
if (0 != retval)
return retval;
if (locked_btres(fh->btv, RESOURCE_VBI))
return -EBUSY;
bttv_vbi_try_fmt(fh,f);
bttv_vbi_setlines(fh,btv,f->fmt.vbi.count[0]);
bttv_vbi_get_fmt(fh,f);
return 0;
default:
return -EINVAL;
}
}
 
/*
* ioctl routine
*/
 
int bttv_ioctl(struct bttv *btv, unsigned int cmd, void *arg)
static int bttv_do_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *arg)
{
int i;
struct bttv_fh *fh = file->private_data;
struct bttv *btv = fh->btv;
unsigned long flags;
int retval = 0;
 
if (bttv_debug > 1)
cprintf("bttv%d: ioctl 0x%x\n",btv->nr,cmd);
if (bttv_debug > 1) {
switch (_IOC_TYPE(cmd)) {
case 'v':
printk("bttv%d: ioctl 0x%x (v4l1, VIDIOC%s)\n",
btv->nr, cmd, (_IOC_NR(cmd) < V4L1_IOCTLS) ?
v4l1_ioctls[_IOC_NR(cmd)] : "???");
break;
case 'V':
printk("bttv%d: ioctl 0x%x (v4l2, %s)\n",
btv->nr, cmd, v4l2_ioctl_names[_IOC_NR(cmd)]);
break;
default:
printk("bttv%d: ioctl 0x%x ()\n",
btv->nr, cmd);
}
}
if (btv->errors)
bttv_reinit_bt848(btv);
 
#ifdef VIDIOC_G_PRIORITY
switch (cmd) {
case VIDIOCSFREQ:
case VIDIOCSTUNER:
case VIDIOCSCHAN:
case VIDIOC_S_CTRL:
case VIDIOC_S_STD:
case VIDIOC_S_INPUT:
case VIDIOC_S_TUNER:
case VIDIOC_S_FREQUENCY:
retval = v4l2_prio_check(&btv->prio,&fh->prio);
if (0 != retval)
return retval;
};
#endif
switch (cmd) {
 
/* *** v4l1 *** ************************************************ */
case VIDIOCGCAP:
{
struct video_capability b;
strcpy(b.name,btv->video_dev.name);
b.type = VID_TYPE_CAPTURE|
((bttv_tvcards[btv->type].tuner != -1) ? VID_TYPE_TUNER : 0) |
VID_TYPE_OVERLAY|
VID_TYPE_CLIPPING|
VID_TYPE_FRAMERAM|
VID_TYPE_SCALES;
b.channels = bttv_tvcards[btv->type].video_inputs;
b.audios = bttv_tvcards[btv->type].audio_inputs;
b.maxwidth = tvnorms[btv->win.norm].swidth;
b.maxheight = tvnorms[btv->win.norm].sheight;
b.minwidth = 48;
b.minheight = 32;
if(copy_to_user(arg,&b,sizeof(b)))
return -EFAULT;
return 0;
struct video_capability *cap = arg;
 
memset(cap,0,sizeof(*cap));
strcpy(cap->name,btv->video_dev->name);
if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
/* vbi */
cap->type = VID_TYPE_TUNER|VID_TYPE_TELETEXT;
} else {
/* others */
cap->type = VID_TYPE_CAPTURE|
VID_TYPE_TUNER|
VID_TYPE_OVERLAY|
VID_TYPE_CLIPPING|
VID_TYPE_SCALES;
cap->channels = bttv_tvcards[btv->type].video_inputs;
cap->audios = bttv_tvcards[btv->type].audio_inputs;
cap->maxwidth = bttv_tvnorms[btv->tvnorm].swidth;
cap->maxheight = bttv_tvnorms[btv->tvnorm].sheight;
cap->minwidth = 48;
cap->minheight = 32;
}
return 0;
}
case VIDIOCGCHAN:
 
case VIDIOCGPICT:
{
struct video_channel v;
if(copy_from_user(&v, arg,sizeof(v)))
return -EFAULT;
v.flags=VIDEO_VC_AUDIO;
v.tuners=0;
v.type=VIDEO_TYPE_CAMERA;
v.norm = btv->win.norm;
if (v.channel>=bttv_tvcards[btv->type].video_inputs)
return -EINVAL;
if(v.channel==bttv_tvcards[btv->type].tuner)
{
strcpy(v.name,"Television");
v.flags|=VIDEO_VC_TUNER;
v.type=VIDEO_TYPE_TV;
v.tuners=1;
}
else if(v.channel==bttv_tvcards[btv->type].svhs)
strcpy(v.name,"S-Video");
else
sprintf(v.name,"Composite%d",v.channel);
if(copy_to_user(arg,&v,sizeof(v)))
return -EFAULT;
struct video_picture *pic = arg;
 
memset(pic,0,sizeof(*pic));
pic->brightness = btv->bright;
pic->contrast = btv->contrast;
pic->hue = btv->hue;
pic->colour = btv->saturation;
if (fh->fmt) {
pic->depth = fh->fmt->depth;
pic->palette = fh->fmt->palette;
}
return 0;
}
/*
* Each channel has 1 tuner
*/
case VIDIOCSCHAN:
case VIDIOCSPICT:
{
struct video_channel v;
if(copy_from_user(&v, arg,sizeof(v)))
return -EFAULT;
struct video_picture *pic = arg;
const struct bttv_format *fmt;
if (v.channel>bttv_tvcards[btv->type].video_inputs)
fmt = format_by_palette(pic->palette);
if (NULL == fmt)
return -EINVAL;
if (v.norm > (sizeof(tvnorms)/sizeof(*tvnorms)))
return -EOPNOTSUPP;
down(&fh->cap.lock);
if (fmt->depth != pic->depth && !sloppy) {
retval = -EINVAL;
goto fh_unlock_and_return;
}
fh->ovfmt = fmt;
fh->fmt = fmt;
btv->init.ovfmt = fmt;
btv->init.fmt = fmt;
if (bigendian) {
/* dirty hack time: swap bytes for overlay if the
display adaptor is big endian (insmod option) */
if (fmt->palette == VIDEO_PALETTE_RGB555 ||
fmt->palette == VIDEO_PALETTE_RGB565 ||
fmt->palette == VIDEO_PALETTE_RGB32) {
fh->ovfmt = fmt+1;
}
}
bt848_bright(btv,pic->brightness);
bt848_contrast(btv,pic->contrast);
bt848_hue(btv,pic->hue);
bt848_sat(btv,pic->colour);
up(&fh->cap.lock);
return 0;
}
 
bttv_call_i2c_clients(btv,cmd,&v);
bt848_muxsel(btv, v.channel);
btv->channel=v.channel;
if (btv->win.norm != v.norm) {
if(btv->type== BTTV_VOODOOTV_FM)
bttv_tda9880_setnorm(btv,v.norm);
btv->win.norm = v.norm;
make_vbitab(btv);
bt848_set_winsize(btv);
}
case VIDIOCGWIN:
{
struct video_window *win = arg;
 
memset(win,0,sizeof(*win));
win->x = fh->ov.w.left;
win->y = fh->ov.w.top;
win->width = fh->ov.w.width;
win->height = fh->ov.w.height;
return 0;
}
case VIDIOCGTUNER:
case VIDIOCSWIN:
{
struct video_tuner v;
if(copy_from_user(&v,arg,sizeof(v))!=0)
return -EFAULT;
#if 0 /* tuner.signal might be of intrest for non-tuner sources too ... */
if(v.tuner||btv->channel) /* Only tuner 0 */
return -EINVAL;
#endif
strcpy(v.name, "Television");
v.rangelow=0;
v.rangehigh=0xFFFFFFFF;
v.flags=VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM;
v.mode = btv->win.norm;
v.signal = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0;
bttv_call_i2c_clients(btv,cmd,&v);
if(copy_to_user(arg,&v,sizeof(v)))
return -EFAULT;
struct video_window *win = arg;
struct v4l2_window w2;
 
w2.field = V4L2_FIELD_ANY;
w2.w.left = win->x;
w2.w.top = win->y;
w2.w.width = win->width;
w2.w.height = win->height;
w2.clipcount = win->clipcount;
w2.clips = (struct v4l2_clip*)win->clips;
retval = setup_window(fh, btv, &w2, 0);
if (0 == retval) {
/* on v4l1 this ioctl affects the read() size too */
fh->width = fh->ov.w.width;
fh->height = fh->ov.w.height;
btv->init.width = fh->ov.w.width;
btv->init.height = fh->ov.w.height;
}
return retval;
}
 
case VIDIOCGFBUF:
{
struct video_buffer *fbuf = arg;
 
fbuf->base = btv->fbuf.base;
fbuf->width = btv->fbuf.fmt.width;
fbuf->height = btv->fbuf.fmt.height;
fbuf->bytesperline = btv->fbuf.fmt.bytesperline;
if (fh->ovfmt)
fbuf->depth = fh->ovfmt->depth;
return 0;
}
/* We have but one tuner */
case VIDIOCSTUNER:
case VIDIOCSFBUF:
{
struct video_tuner v;
if(copy_from_user(&v, arg, sizeof(v)))
return -EFAULT;
/* Only one channel has a tuner */
if(v.tuner!=bttv_tvcards[btv->type].tuner)
return -EINVAL;
if(v.mode!=VIDEO_MODE_PAL&&v.mode!=VIDEO_MODE_NTSC
&&v.mode!=VIDEO_MODE_SECAM)
return -EOPNOTSUPP;
bttv_call_i2c_clients(btv,cmd,&v);
if (btv->win.norm != v.mode) {
btv->win.norm = v.mode;
set_pll(btv);
make_vbitab(btv);
bt848_set_winsize(btv);
struct video_buffer *fbuf = arg;
const struct bttv_format *fmt;
unsigned long end;
 
if(!capable(CAP_SYS_ADMIN) &&
!capable(CAP_SYS_RAWIO))
return -EPERM;
end = (unsigned long)fbuf->base +
fbuf->height * fbuf->bytesperline;
down(&fh->cap.lock);
retval = -EINVAL;
if (sloppy) {
/* also set the default palette -- for backward
compatibility with older versions */
switch (fbuf->depth) {
case 8:
fmt = format_by_palette(VIDEO_PALETTE_HI240);
break;
case 16:
fmt = format_by_palette(VIDEO_PALETTE_RGB565);
break;
case 24:
fmt = format_by_palette(VIDEO_PALETTE_RGB24);
break;
case 32:
fmt = format_by_palette(VIDEO_PALETTE_RGB32);
break;
case 15:
fbuf->depth = 16;
fmt = format_by_palette(VIDEO_PALETTE_RGB555);
break;
default:
fmt = NULL;
break;
}
if (NULL == fmt)
goto fh_unlock_and_return;
fh->ovfmt = fmt;
fh->fmt = fmt;
btv->init.ovfmt = fmt;
btv->init.fmt = fmt;
} else {
if (15 == fbuf->depth)
fbuf->depth = 16;
if (fbuf->depth != 8 && fbuf->depth != 16 &&
fbuf->depth != 24 && fbuf->depth != 32)
goto fh_unlock_and_return;
}
btv->fbuf.base = fbuf->base;
btv->fbuf.fmt.width = fbuf->width;
btv->fbuf.fmt.height = fbuf->height;
if (fbuf->bytesperline)
btv->fbuf.fmt.bytesperline = fbuf->bytesperline;
else
btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fbuf->depth/8;
up(&fh->cap.lock);
return 0;
}
case VIDIOCGPICT:
 
case VIDIOCCAPTURE:
case VIDIOC_OVERLAY:
{
struct video_picture p=btv->picture;
if(copy_to_user(arg, &p, sizeof(p)))
return -EFAULT;
struct bttv_buffer *new;
int *on = arg;
 
if (*on) {
/* verify args */
if (NULL == btv->fbuf.base)
return -EINVAL;
if (!fh->ov.setup_ok) {
dprintk("bttv%d: overlay: !setup_ok\n",btv->nr);
return -EINVAL;
}
}
 
if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY))
return -EBUSY;
down(&fh->cap.lock);
if (*on) {
fh->ov.tvnorm = btv->tvnorm;
new = videobuf_alloc(sizeof(*new));
bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
} else {
new = NULL;
}
 
/* switch over */
retval = bttv_switch_overlay(btv,fh,new);
up(&fh->cap.lock);
return retval;
}
 
case VIDIOCGMBUF:
{
struct video_mbuf *mbuf = arg;
unsigned int i;
 
down(&fh->cap.lock);
retval = videobuf_mmap_setup(file,&fh->cap,gbuffers,gbufsize,
V4L2_MEMORY_MMAP);
if (retval < 0)
goto fh_unlock_and_return;
memset(mbuf,0,sizeof(*mbuf));
mbuf->frames = gbuffers;
mbuf->size = gbuffers * gbufsize;
for (i = 0; i < gbuffers; i++)
mbuf->offsets[i] = i * gbufsize;
up(&fh->cap.lock);
return 0;
}
case VIDIOCSPICT:
case VIDIOCMCAPTURE:
{
struct video_picture p;
if (copy_from_user(&p, arg,sizeof(p)))
return -EFAULT;
if (p.palette > PALETTEFMT_MAX)
struct video_mmap *vm = arg;
struct bttv_buffer *buf;
enum v4l2_field field;
 
if (vm->frame >= VIDEO_MAX_FRAME)
return -EINVAL;
if (-1 == palette2fmt[p.palette])
return -EINVAL;
/* We want -128 to 127 we get 0-65535 */
bt848_bright(btv, (p.brightness>>8)-128);
/* 0-511 for the colour */
bt848_sat_u(btv, p.colour>>7);
bt848_sat_v(btv, ((p.colour>>7)*201L)/237);
/* -128 to 127 */
bt848_hue(btv, (p.hue>>8)-128);
/* 0-511 */
bt848_contrast(btv, p.contrast>>7);
btv->picture = p;
 
down(&fh->cap.lock);
retval = -EINVAL;
buf = (struct bttv_buffer *)fh->cap.bufs[vm->frame];
if (NULL == buf)
goto fh_unlock_and_return;
if (0 == buf->vb.baddr)
goto fh_unlock_and_return;
if (buf->vb.state == STATE_QUEUED ||
buf->vb.state == STATE_ACTIVE)
goto fh_unlock_and_return;
field = (vm->height > bttv_tvnorms[btv->tvnorm].sheight/2)
? V4L2_FIELD_INTERLACED
: V4L2_FIELD_BOTTOM;
retval = bttv_prepare_buffer(btv,buf,
format_by_palette(vm->format),
vm->width,vm->height,field);
if (0 != retval)
goto fh_unlock_and_return;
spin_lock_irqsave(&btv->s_lock,flags);
buffer_queue(file,&buf->vb);
spin_unlock_irqrestore(&btv->s_lock,flags);
up(&fh->cap.lock);
return 0;
}
case VIDIOCSWIN:
case VIDIOCSYNC:
{
struct video_window vw;
struct video_clip *vcp = NULL;
if(copy_from_user(&vw,arg,sizeof(vw)))
return -EFAULT;
int *frame = arg;
struct bttv_buffer *buf;
 
if(vw.flags || vw.width < 16 || vw.height < 16)
{
btv->scr_on = 0;
bt848_set_risc_jmps(btv,-1);
if (*frame >= VIDEO_MAX_FRAME)
return -EINVAL;
}
if (btv->win.bpp < 4)
{ /* adjust and align writes */
vw.x = (vw.x + 3) & ~3;
vw.width &= ~3;
}
if (btv->needs_restart)
bt848_restart(btv);
btv->win.x=vw.x;
btv->win.y=vw.y;
btv->win.width=vw.width;
btv->win.height=vw.height;
bt848_set_risc_jmps(btv,0);
bt848_set_winsize(btv);
 
/*
* Do any clips.
*/
if(vw.clipcount<0) {
if((vcp=vmalloc_32(VIDEO_CLIPMAP_SIZE))==NULL) {
return -ENOMEM;
}
if(copy_from_user(vcp, vw.clips,
VIDEO_CLIPMAP_SIZE)) {
vfree_32(vcp);
return -EFAULT;
}
} else if (vw.clipcount > 2048) {
return -EINVAL;
} else if (vw.clipcount) {
if((vcp=vmalloc_32(sizeof(struct video_clip)*
(vw.clipcount))) == NULL) {
return -ENOMEM;
}
if(copy_from_user(vcp,vw.clips,
sizeof(struct video_clip)*
vw.clipcount)) {
vfree_32(vcp);
return -EFAULT;
}
down(&fh->cap.lock);
retval = -EINVAL;
buf = (struct bttv_buffer *)fh->cap.bufs[*frame];
if (NULL == buf)
goto fh_unlock_and_return;
retval = videobuf_waiton(&buf->vb,0,1);
if (0 != retval)
goto fh_unlock_and_return;
switch (buf->vb.state) {
case STATE_ERROR:
retval = -EIO;
/* fall through */
case STATE_DONE:
videobuf_dma_pci_sync(btv->dev,&buf->vb.dma);
bttv_dma_free(btv,buf);
break;
default:
retval = -EINVAL;
break;
}
make_clip_tab(btv, vcp, vw.clipcount);
if (vw.clipcount != 0)
vfree_32(vcp);
bt848_set_risc_jmps(btv,-1);
return 0;
up(&fh->cap.lock);
return retval;
}
case VIDIOCGWIN:
 
case VIDIOCGVBIFMT:
{
struct video_window vw;
memset(&vw,0,sizeof(vw));
vw.x=btv->win.x;
vw.y=btv->win.y;
vw.width=btv->win.width;
vw.height=btv->win.height;
if(btv->win.interlace)
vw.flags|=VIDEO_WINDOW_INTERLACE;
if(copy_to_user(arg,&vw,sizeof(vw)))
return -EFAULT;
struct vbi_format *fmt = (void *) arg;
struct v4l2_format fmt2;
 
if (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE) {
retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
if (0 != retval)
return retval;
}
bttv_vbi_get_fmt(fh, &fmt2);
 
memset(fmt,0,sizeof(*fmt));
fmt->sampling_rate = fmt2.fmt.vbi.sampling_rate;
fmt->samples_per_line = fmt2.fmt.vbi.samples_per_line;
fmt->sample_format = VIDEO_PALETTE_RAW;
fmt->start[0] = fmt2.fmt.vbi.start[0];
fmt->count[0] = fmt2.fmt.vbi.count[0];
fmt->start[1] = fmt2.fmt.vbi.start[1];
fmt->count[1] = fmt2.fmt.vbi.count[1];
if (fmt2.fmt.vbi.flags & VBI_UNSYNC)
fmt->flags |= V4L2_VBI_UNSYNC;
if (fmt2.fmt.vbi.flags & VBI_INTERLACED)
fmt->flags |= V4L2_VBI_INTERLACED;
return 0;
}
case VIDIOCCAPTURE:
case VIDIOCSVBIFMT:
{
int v;
if(copy_from_user(&v, arg,sizeof(v)))
return -EFAULT;
if(btv->win.vidadr == 0)
struct vbi_format *fmt = (void *) arg;
struct v4l2_format fmt2;
 
retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
if (0 != retval)
return retval;
bttv_vbi_get_fmt(fh, &fmt2);
 
if (fmt->sampling_rate != fmt2.fmt.vbi.sampling_rate ||
fmt->samples_per_line != fmt2.fmt.vbi.samples_per_line ||
fmt->sample_format != VIDEO_PALETTE_RAW ||
fmt->start[0] != fmt2.fmt.vbi.start[0] ||
fmt->start[1] != fmt2.fmt.vbi.start[1] ||
fmt->count[0] != fmt->count[1] ||
fmt->count[0] < 1 ||
fmt->count[0] > 32 /* VBI_MAXLINES */)
return -EINVAL;
if (btv->win.width==0 || btv->win.height==0)
return -EINVAL;
if (1 == no_overlay)
return -EIO;
if (v == 1 && btv->win.vidadr != 0)
btv->scr_on = 1;
if (v == 0)
btv->scr_on = 0;
bt848_set_risc_jmps(btv,-1);
 
bttv_vbi_setlines(fh,btv,fmt->count[0]);
return 0;
}
case VIDIOCGFBUF:
 
case BTTV_VERSION:
case VIDIOCGFREQ:
case VIDIOCSFREQ:
case VIDIOCGTUNER:
case VIDIOCSTUNER:
case VIDIOCGCHAN:
case VIDIOCSCHAN:
case VIDIOCGAUDIO:
case VIDIOCSAUDIO:
return bttv_common_ioctls(btv,cmd,arg);
 
/* *** v4l2 *** ************************************************ */
case VIDIOC_QUERYCAP:
{
struct video_buffer v;
v.base=(void *)btv->win.vidadr;
v.height=btv->win.sheight;
v.width=btv->win.swidth;
v.depth=btv->win.depth;
v.bytesperline=btv->win.bpl;
if(copy_to_user(arg, &v,sizeof(v)))
return -EFAULT;
struct v4l2_capability *cap = arg;
 
if (0 == v4l2)
return -EINVAL;
strcpy(cap->driver,"bttv");
strlcpy(cap->card,btv->video_dev->name,sizeof(cap->card));
sprintf(cap->bus_info,"PCI:%s",pci_name(btv->dev));
cap->version = BTTV_VERSION_CODE;
cap->capabilities =
V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_VIDEO_OVERLAY |
V4L2_CAP_VBI_CAPTURE |
V4L2_CAP_TUNER |
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING;
return 0;
}
case VIDIOCSFBUF:
 
case VIDIOC_ENUM_FMT:
{
struct video_buffer v;
if(copy_from_user(&v, arg,sizeof(v)))
return -EFAULT;
if(v.depth!=8 && v.depth!=15 && v.depth!=16 &&
v.depth!=24 && v.depth!=32 && v.width > 16 &&
v.height > 16 && v.bytesperline > 16)
struct v4l2_fmtdesc *f = arg;
enum v4l2_buf_type type;
unsigned int i;
int index;
 
type = f->type;
if (V4L2_BUF_TYPE_VBI_CAPTURE == type) {
/* vbi */
index = f->index;
if (0 != index)
return -EINVAL;
memset(f,0,sizeof(*f));
f->index = index;
f->type = type;
f->pixelformat = V4L2_PIX_FMT_GREY;
strcpy(f->description,"vbi data");
return 0;
}
 
/* video capture + overlay */
index = -1;
for (i = 0; i < BTTV_FORMATS; i++) {
if (bttv_formats[i].fourcc != -1)
index++;
if ((unsigned int)index == f->index)
break;
}
if (BTTV_FORMATS == i)
return -EINVAL;
if (v.base)
btv->win.vidadr=(unsigned long)v.base;
btv->win.sheight=v.height;
btv->win.swidth=v.width;
btv->win.bpp=((v.depth+7)&0x38)/8;
btv->win.depth=v.depth;
btv->win.bpl=v.bytesperline;
 
#if 0 /* was broken for ages and nobody noticed. Looks like we don't need
it any more as everybody explicitly sets the palette using VIDIOCSPICT
these days */
/* set sefault color format */
switch (v.depth) {
case 8: btv->picture.palette = VIDEO_PALETTE_HI240; break;
case 15: btv->picture.palette = VIDEO_PALETTE_RGB555; break;
case 16: btv->picture.palette = VIDEO_PALETTE_RGB565; break;
case 24: btv->picture.palette = VIDEO_PALETTE_RGB24; break;
case 32: btv->picture.palette = VIDEO_PALETTE_RGB32; break;
switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
break;
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
if (!(bttv_formats[i].flags & FORMAT_FLAGS_PACKED))
return -EINVAL;
break;
default:
return -EINVAL;
}
#endif
if (bttv_debug)
cprintf("Display at %p is %d by %d, bytedepth %d, bpl %d\n",
v.base, v.width,v.height, btv->win.bpp, btv->win.bpl);
bt848_set_winsize(btv);
return 0;
memset(f,0,sizeof(*f));
f->index = index;
f->type = type;
f->pixelformat = bttv_formats[i].fourcc;
strlcpy(f->description,bttv_formats[i].name,sizeof(f->description));
return 0;
}
case VIDIOCKEY:
 
case VIDIOC_TRY_FMT:
{
/* Will be handled higher up .. */
return 0;
struct v4l2_format *f = arg;
return bttv_try_fmt(fh,btv,f);
}
case VIDIOCGFREQ:
case VIDIOC_G_FMT:
{
unsigned long v=btv->win.freq;
if(copy_to_user(arg,&v,sizeof(v)))
return -EFAULT;
return 0;
struct v4l2_format *f = arg;
return bttv_g_fmt(fh,f);
}
case VIDIOCSFREQ:
case VIDIOC_S_FMT:
{
unsigned long v;
if(copy_from_user(&v, arg, sizeof(v)))
return -EFAULT;
btv->win.freq=v;
bttv_call_i2c_clients(btv,cmd,&v);
struct v4l2_format *f = arg;
return bttv_s_fmt(fh,btv,f);
}
 
case VIDIOC_G_FBUF:
{
struct v4l2_framebuffer *fb = arg;
 
*fb = btv->fbuf;
fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
if (fh->ovfmt)
fb->fmt.pixelformat = fh->ovfmt->fourcc;
return 0;
}
case VIDIOCSYNC:
case VIDIOC_S_FBUF:
{
return (btv->gbuf[0].stat == GBUFFER_DONE);
struct v4l2_framebuffer *fb = arg;
const struct bttv_format *fmt;
}
if(!capable(CAP_SYS_ADMIN) &&
!capable(CAP_SYS_RAWIO))
return -EPERM;
 
case BTTV_FIELDNR:
if(copy_to_user((void *) arg, (void *) &btv->last_field,
sizeof(btv->last_field)))
return -EFAULT;
break;
case BTTV_PLLSET: {
struct bttv_pll_info p;
if(!capable(CAP_SYS_ADMIN))
return -EPERM;
if(copy_from_user(&p , (void *) arg, sizeof(btv->pll)))
return -EFAULT;
btv->pll.pll_ifreq = p.pll_ifreq;
btv->pll.pll_ofreq = p.pll_ofreq;
btv->pll.pll_crystal = p.pll_crystal;
break;
/* check args */
fmt = format_by_fourcc(fb->fmt.pixelformat);
if (NULL == fmt)
return -EINVAL;
if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))
return -EINVAL;
 
down(&fh->cap.lock);
retval = -EINVAL;
if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
if (fb->fmt.width > bttv_tvnorms[btv->tvnorm].swidth)
goto fh_unlock_and_return;
if (fb->fmt.height > bttv_tvnorms[btv->tvnorm].sheight)
goto fh_unlock_and_return;
}
 
/* ok, accept it */
btv->fbuf.base = fb->base;
btv->fbuf.fmt.width = fb->fmt.width;
btv->fbuf.fmt.height = fb->fmt.height;
if (0 != fb->fmt.bytesperline)
btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline;
else
btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8;
retval = 0;
fh->ovfmt = fmt;
btv->init.ovfmt = fmt;
if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
fh->ov.w.left = 0;
fh->ov.w.top = 0;
fh->ov.w.width = fb->fmt.width;
fh->ov.w.height = fb->fmt.height;
btv->init.ov.w.width = fb->fmt.width;
btv->init.ov.w.height = fb->fmt.height;
if (fh->ov.clips)
kfree(fh->ov.clips);
fh->ov.clips = NULL;
fh->ov.nclips = 0;
 
if (check_btres(fh, RESOURCE_OVERLAY)) {
struct bttv_buffer *new;
new = videobuf_alloc(sizeof(*new));
bttv_overlay_risc(btv,&fh->ov,fh->ovfmt,new);
retval = bttv_switch_overlay(btv,fh,new);
}
}
up(&fh->cap.lock);
return retval;
}
 
case VIDIOCMCAPTURE:
case VIDIOC_REQBUFS:
return videobuf_reqbufs(file,bttv_queue(fh),arg);
 
case VIDIOC_QUERYBUF:
return videobuf_querybuf(bttv_queue(fh),arg);
 
case VIDIOC_QBUF:
return videobuf_qbuf(file,bttv_queue(fh),arg);
 
case VIDIOC_DQBUF:
return videobuf_dqbuf(file,bttv_queue(fh),arg);
 
case VIDIOC_STREAMON:
{
struct video_mmap vm;
int ret;
if(copy_from_user((void *) &vm, (void *) arg, sizeof(vm)))
return -EFAULT;
ret = vgrab(btv, &vm);
return ret;
int res = bttv_resource(fh);
 
if (!check_alloc_btres(btv,fh,res))
return -EBUSY;
return videobuf_streamon(file,bttv_queue(fh));
}
case VIDIOCGMBUF:
case VIDIOC_STREAMOFF:
{
struct video_mbuf vm;
memset(&vm, 0 , sizeof(vm));
vm.size=gbufsize*gbuffers;
vm.frames=gbuffers;
for (i = 0; i < gbuffers; i++)
vm.offsets[i]=i*gbufsize;
if(copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
return -EFAULT;
int res = bttv_resource(fh);
 
retval = videobuf_streamoff(file,bttv_queue(fh));
if (retval < 0)
return retval;
free_btres(btv,fh,res);
return 0;
}
case VIDIOCGUNIT:
 
case VIDIOC_QUERYCTRL:
{
struct video_unit vu;
vu.video=btv->video_dev.minor;
vu.vbi=btv->vbi_dev.minor;
if(btv->radio_dev.minor!=-1)
vu.radio=btv->radio_dev.minor;
else
vu.radio=VIDEO_NO_UNIT;
vu.audio=VIDEO_NO_UNIT;
vu.teletext=VIDEO_NO_UNIT;
if(copy_to_user((void *)arg, (void *)&vu, sizeof(vu)))
return -EFAULT;
struct v4l2_queryctrl *c = arg;
int i;
 
if ((c->id < V4L2_CID_BASE ||
c->id >= V4L2_CID_LASTP1) &&
(c->id < V4L2_CID_PRIVATE_BASE ||
c->id >= V4L2_CID_PRIVATE_LASTP1))
return -EINVAL;
for (i = 0; i < BTTV_CTLS; i++)
if (bttv_ctls[i].id == c->id)
break;
if (i == BTTV_CTLS) {
*c = no_ctl;
return 0;
}
*c = bttv_ctls[i];
if (i >= 4 && i <= 8) {
struct video_audio va;
memset(&va,0,sizeof(va));
bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
if (btv->audio_hook)
btv->audio_hook(btv,&va,0);
switch (bttv_ctls[i].id) {
case V4L2_CID_AUDIO_VOLUME:
if (!(va.flags & VIDEO_AUDIO_VOLUME))
*c = no_ctl;
break;
case V4L2_CID_AUDIO_BALANCE:
if (!(va.flags & VIDEO_AUDIO_BALANCE))
*c = no_ctl;
break;
case V4L2_CID_AUDIO_BASS:
if (!(va.flags & VIDEO_AUDIO_BASS))
*c = no_ctl;
break;
case V4L2_CID_AUDIO_TREBLE:
if (!(va.flags & VIDEO_AUDIO_TREBLE))
*c = no_ctl;
break;
}
}
return 0;
}
case BTTV_BURST_ON:
case VIDIOC_G_CTRL:
return get_control(btv,arg);
case VIDIOC_S_CTRL:
return set_control(btv,arg);
case VIDIOC_G_PARM:
{
burst(1);
struct v4l2_streamparm *parm = arg;
struct v4l2_standard s;
if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
memset(parm,0,sizeof(*parm));
v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id,
bttv_tvnorms[btv->tvnorm].name);
parm->parm.capture.timeperframe = s.frameperiod;
return 0;
}
 
case BTTV_BURST_OFF:
#ifdef VIDIOC_G_PRIORITY
case VIDIOC_G_PRIORITY:
{
burst(0);
return 0;
}
enum v4l2_priority *p = arg;
 
case BTTV_VERSION:
{
*p = v4l2_prio_max(&btv->prio);
return 0;
}
case BTTV_PICNR:
case VIDIOC_S_PRIORITY:
{
/* return picture;*/
return 0;
enum v4l2_priority *prio = arg;
 
return v4l2_prio_change(&btv->prio, &fh->prio, *prio);
}
#endif
 
case VIDIOC_ENUMSTD:
case VIDIOC_G_STD:
case VIDIOC_S_STD:
case VIDIOC_ENUMINPUT:
case VIDIOC_G_INPUT:
case VIDIOC_S_INPUT:
case VIDIOC_G_TUNER:
case VIDIOC_S_TUNER:
case VIDIOC_G_FREQUENCY:
case VIDIOC_S_FREQUENCY:
return bttv_common_ioctls(btv,cmd,arg);
 
default:
return 0;
return -ENOIOCTLCMD;
}
return 0;
 
fh_unlock_and_return:
up(&fh->cap.lock);
return retval;
}
 
static void bt848_set_risc_jmps(struct bttv *btv, int flags)
static int bttv_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
if (-1 == flags) {
/* defaults */
flags = 0;
if (btv->scr_on)
flags |= 0x03;
if (btv->vbi_on)
flags |= 0x0c;
#if 0
/* Hmm ... */
if ((0 != btv->risc_cap_even) ||
(0 != btv->risc_cap_odd))
flags |= 0x0c;
#endif
struct bttv_fh *fh = file->private_data;
 
switch (cmd) {
case BTTV_VBISIZE:
bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
return fh->lines * 2 * 2048;
default:
return video_usercopy(inode, file, cmd, arg, bttv_do_ioctl);
}
}
 
if (bttv_debug > 1)
cprintf("bttv%d: set_risc_jmp %08lx:",
btv->nr,virt_to_bus((unsigned long)btv->risc_jmp));
static ssize_t bttv_read(struct file *file, char *data,
size_t count, loff_t *ppos)
{
struct bttv_fh *fh = file->private_data;
int retval = 0;
 
/* Sync to start of odd field */
btv->risc_jmp[0]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC
|BT848_FIFO_STATUS_VRE);
btv->risc_jmp[1]=cpu_to_le32(0);
if (fh->btv->errors)
bttv_reinit_bt848(fh->btv);
dprintk("bttv%d: read count=%d type=%s\n",
fh->btv->nr,(int)count,v4l2_type_names[fh->type]);
 
/* Jump to odd vbi sub */
btv->risc_jmp[2]=cpu_to_le32(BT848_RISC_JUMP|(0xd<<20));
if (flags&8) {
if (bttv_debug > 1)
cprintf(" ev=%08lx",virt_to_bus((unsigned long)btv->vbi_odd));
btv->risc_jmp[3]=cpu_to_le32(virt_to_bus((unsigned long)btv->vbi_odd));
} else {
if (bttv_debug > 1)
cprintf(" -----------");
btv->risc_jmp[3]=cpu_to_le32(virt_to_bus((unsigned long)btv->risc_jmp+16));
switch (fh->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
if (locked_btres(fh->btv,RESOURCE_VIDEO))
return -EBUSY;
retval = videobuf_read_one(file, &fh->cap, data, count, ppos);
break;
case V4L2_BUF_TYPE_VBI_CAPTURE:
if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
return -EBUSY;
retval = videobuf_read_stream(file, &fh->vbi, data, count, ppos, 1);
break;
default:
BUG();
}
return retval;
}
 
/* Jump to odd sub */
btv->risc_jmp[4]=cpu_to_le32(BT848_RISC_JUMP|(0xe<<20));
if (0 != btv->risc_cap_odd) {
if (bttv_debug > 1)
cprintf(" e%d=%08lx",btv->gq_grab,btv->risc_cap_odd);
flags |= 3;
btv->risc_jmp[5]=cpu_to_le32(btv->risc_cap_odd);
} else if ((flags&2) &&
(!btv->win.interlace || 0 == btv->risc_cap_even)) {
if (bttv_debug > 1)
cprintf(" eo=%08lx",virt_to_bus((unsigned long)btv->risc_scr_odd));
btv->risc_jmp[5]=cpu_to_le32(virt_to_bus((unsigned long)btv->risc_scr_odd));
static unsigned int bttv_poll(struct file *file, poll_table *wait)
{
struct bttv_fh *fh = file->private_data;
struct bttv_buffer *buf;
enum v4l2_field field;
 
if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
return -EBUSY;
return videobuf_poll_stream(file, &fh->vbi, wait);
}
 
if (check_btres(fh,RESOURCE_VIDEO)) {
/* streaming capture */
if (list_empty(&fh->cap.stream))
return POLLERR;
buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream);
} else {
if (bttv_debug > 1)
cprintf(" -----------");
btv->risc_jmp[5]=cpu_to_le32(virt_to_bus((unsigned long)btv->risc_jmp+24));
/* read() capture */
down(&fh->cap.lock);
if (NULL == fh->cap.read_buf) {
/* need to capture a new frame */
if (locked_btres(fh->btv,RESOURCE_VIDEO)) {
up(&fh->cap.lock);
return POLLERR;
}
fh->cap.read_buf = videobuf_alloc(fh->cap.msize);
if (NULL == fh->cap.read_buf) {
up(&fh->cap.lock);
return POLLERR;
}
fh->cap.read_buf->memory = V4L2_MEMORY_USERPTR;
field = videobuf_next_field(&fh->cap);
if (0 != fh->cap.ops->buf_prepare(file,fh->cap.read_buf,field)) {
up(&fh->cap.lock);
return POLLERR;
}
fh->cap.ops->buf_queue(file,fh->cap.read_buf);
fh->cap.read_off = 0;
}
up(&fh->cap.lock);
buf = (struct bttv_buffer*)fh->cap.read_buf;
}
poll_wait(file, &buf->vb.done, wait);
if (buf->vb.state == STATE_DONE ||
buf->vb.state == STATE_ERROR)
return POLLIN|POLLRDNORM;
return 0;
}
 
static int bttv_open(struct inode *inode, struct file *file)
{
int minor = iminor(inode);
struct bttv *btv = NULL;
struct bttv_fh *fh;
enum v4l2_buf_type type = 0;
unsigned int i;
 
/* Sync to start of even field */
btv->risc_jmp[6]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC
|BT848_FIFO_STATUS_VRO);
btv->risc_jmp[7]=cpu_to_le32(0);
dprintk(KERN_DEBUG "bttv: open minor=%d\n",minor);
 
/* Jump to even vbi sub */
btv->risc_jmp[8]=cpu_to_le32(BT848_RISC_JUMP);
if (flags&4) {
if (bttv_debug > 1)
cprintf(" ov=%08lx",virt_to_bus((unsigned long)btv->vbi_even));
btv->risc_jmp[9]=cpu_to_le32(virt_to_bus((unsigned long)btv->vbi_even));
} else {
if (bttv_debug > 1)
cprintf(" -----------");
btv->risc_jmp[9]=cpu_to_le32(virt_to_bus((unsigned long)btv->risc_jmp+40));
for (i = 0; i < bttv_num; i++) {
if (bttvs[i].video_dev->minor == minor) {
btv = &bttvs[i];
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
break;
}
if (bttvs[i].vbi_dev->minor == minor) {
btv = &bttvs[i];
type = V4L2_BUF_TYPE_VBI_CAPTURE;
break;
}
}
if (NULL == btv)
return -ENODEV;
 
/* Jump to even sub */
btv->risc_jmp[10]=cpu_to_le32(BT848_RISC_JUMP|(8<<20));
if (0 != btv->risc_cap_even) {
if (bttv_debug > 1)
cprintf(" o%d=%08lx",btv->gq_grab,btv->risc_cap_even);
flags |= 3;
btv->risc_jmp[11]=cpu_to_le32(btv->risc_cap_even);
} else if ((flags&1) &&
btv->win.interlace) {
if (bttv_debug > 1)
cprintf(" oo=%08lx",virt_to_bus((unsigned long)btv->risc_scr_even));
btv->risc_jmp[11]=cpu_to_le32(virt_to_bus((unsigned long)btv->risc_scr_even));
} else {
if (bttv_debug > 1)
cprintf(" -----------");
btv->risc_jmp[11]=cpu_to_le32(virt_to_bus((unsigned long)btv->risc_jmp+48));
dprintk(KERN_DEBUG "bttv%d: open called (type=%s)\n",
btv->nr,v4l2_type_names[type]);
 
/* allocate per filehandle data */
fh = kmalloc(sizeof(*fh),GFP_KERNEL);
if (NULL == fh)
return -ENOMEM;
file->private_data = fh;
*fh = btv->init;
fh->type = type;
fh->ov.setup_ok = 0;
#ifdef VIDIOC_G_PRIORITY
v4l2_prio_open(&btv->prio,&fh->prio);
#endif
 
videobuf_queue_init(&fh->cap, &bttv_video_qops,
btv->dev, &btv->s_lock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
sizeof(struct bttv_buffer));
videobuf_queue_init(&fh->vbi, &bttv_vbi_qops,
btv->dev, &btv->s_lock,
V4L2_BUF_TYPE_VBI_CAPTURE,
V4L2_FIELD_SEQ_TB,
sizeof(struct bttv_buffer));
i2c_vidiocschan(btv);
 
btv->users++;
if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type)
bttv_vbi_setlines(fh,btv,16);
bttv_field_count(btv);
return 0;
}
 
static int bttv_release(struct inode *inode, struct file *file)
{
struct bttv_fh *fh = file->private_data;
struct bttv *btv = fh->btv;
 
/* turn off overlay */
if (check_btres(fh, RESOURCE_OVERLAY))
bttv_switch_overlay(btv,fh,NULL);
/* stop video capture */
if (check_btres(fh, RESOURCE_VIDEO)) {
videobuf_streamoff(file,&fh->cap);
free_btres(btv,fh,RESOURCE_VIDEO);
}
if (fh->cap.read_buf) {
buffer_release(file,fh->cap.read_buf);
kfree(fh->cap.read_buf);
}
 
if (btv->gq_start) {
btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ);
} else {
btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP);
/* stop vbi capture */
if (check_btres(fh, RESOURCE_VBI)) {
if (fh->vbi.streaming)
videobuf_streamoff(file,&fh->vbi);
if (fh->vbi.reading)
videobuf_read_stop(file,&fh->vbi);
free_btres(btv,fh,RESOURCE_VBI);
}
btv->risc_jmp[13]=cpu_to_le32(virt_to_bus((unsigned long)btv->risc_jmp));
 
/* enable cpaturing and DMA */
if (bttv_debug > 1)
cprintf(" flags=0x%x dma=%s\n",
flags,(flags&0x0f) ? "on" : "off");
btaor(flags, ~0x0f, BT848_CAP_CTL);
if (flags&0x0f)
bt848_dma(btv, 3);
else
bt848_dma(btv, 0);
#ifdef VIDIOC_G_PRIORITY
v4l2_prio_close(&btv->prio,&fh->prio);
#endif
file->private_data = NULL;
kfree(fh);
 
btv->users--;
bttv_field_count(btv);
return 0;
}
 
static int init_bt848(struct bttv *btv)
static int
bttv_mmap(struct file *file, struct vm_area_struct *vma)
{
int j,val;
struct bttv_fh *fh = file->private_data;
 
btv->user=0;
dprintk("bttv%d: mmap type=%s 0x%lx+%ld\n",
fh->btv->nr, v4l2_type_names[fh->type],
vma->vm_start, vma->vm_end - vma->vm_start);
return videobuf_mmap_mapper(vma,bttv_queue(fh));
}
 
/* bringup the gpio internals (quick! before anyone uses it) */
init_gpio_adapter(&(btv->gpio_adap));
/* dump current state of the gpio registers before changing them,
* might help to make a new card work */
if (bttv_gpio)
bttv_gpio_tracking(btv,"init #1");
static struct file_operations bttv_fops =
{
.owner = THIS_MODULE,
.open = bttv_open,
.release = bttv_release,
.ioctl = bttv_ioctl,
.llseek = no_llseek,
.read = bttv_read,
.mmap = bttv_mmap,
.poll = bttv_poll,
};
 
static struct video_device bttv_video_template =
{
.name = "UNSET",
.type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_OVERLAY|
VID_TYPE_CLIPPING|VID_TYPE_SCALES,
.hardware = VID_HARDWARE_BT848,
.fops = &bttv_fops,
.minor = -1,
};
 
/* reset the bt848 */
btwrite(0, BT848_SRESET);
DEBUG(printk(KERN_DEBUG "bttv%d: bt848_mem: 0x%lx\n", btv->nr, (unsigned long) btv->bt848_mem));
struct video_device bttv_vbi_template =
{
.name = "bt848/878 vbi",
.type = VID_TYPE_TUNER|VID_TYPE_TELETEXT,
.hardware = VID_HARDWARE_BT848,
.fops = &bttv_fops,
.minor = -1,
};
 
/* not registered yet */
btv->video_dev.minor = -1;
btv->radio_dev.minor = -1;
btv->vbi_dev.minor = -1;
/* ----------------------------------------------------------------------- */
/* radio interface */
 
/* default setup for max. PAL size in a 1024xXXX hicolor framebuffer */
btv->win.norm=0; /* change this to 1 for NTSC, 2 for SECAM */
btv->win.interlace=1;
btv->win.x=0;
btv->win.y=0;
btv->win.width=320;
btv->win.height=240;
btv->win.bpp=2;
btv->win.depth=16;
btv->win.color_fmt=BT848_COLOR_FMT_RGB16;
btv->win.bpl=1024*btv->win.bpp;
btv->win.swidth=1024;
btv->win.sheight=768;
btv->win.vidadr=0;
btv->vbi_on=0;
btv->scr_on=0;
static int radio_open(struct inode *inode, struct file *file)
{
int minor = iminor(inode);
struct bttv *btv = NULL;
unsigned int i;
 
btv->risc_scr_odd=0;
btv->risc_scr_even=0;
btv->risc_cap_odd=0;
btv->risc_cap_even=0;
btv->risc_jmp=0;
btv->vbibuf=0;
btv->field=btv->last_field=0;
dprintk("bttv: open minor=%d\n",minor);
 
btv->errors=0;
btv->needs_restart=0;
btv->has_radio=radio[btv->nr];
for (i = 0; i < bttv_num; i++) {
if (bttvs[i].radio_dev->minor == minor) {
btv = &bttvs[i];
break;
}
}
if (NULL == btv)
return -ENODEV;
 
if (!(btv->risc_scr_odd= (unsigned long *) vmalloc_32(RISCMEM_LEN/2)))
return -1;
if (!(btv->risc_scr_even=(unsigned long *) vmalloc_32(RISCMEM_LEN/2)))
return -1;
if (!(btv->risc_jmp =(unsigned long *) vmalloc_32(2048)))
return -1;
btv->vbi_odd=btv->risc_jmp+64;
btv->vbi_even=btv->vbi_odd+1024;
btv->bus_vbi_odd=virt_to_bus((unsigned long)btv->risc_jmp+48);
btv->bus_vbi_even=virt_to_bus((unsigned long)btv->risc_jmp+24);
dprintk("bttv%d: open called (radio)\n",btv->nr);
down(&btv->lock);
if (btv->radio_user) {
up(&btv->lock);
return -EBUSY;
}
btv->radio_user++;
file->private_data = btv;
 
btwrite(virt_to_bus((unsigned long)btv->risc_jmp+8), BT848_RISC_STRT_ADD);
btv->vbibuf=(unsigned char *) vmalloc_32(VBIBUF_SIZE);
if (!btv->vbibuf)
return -1;
if (!(btv->gbuf = vmalloc_32(sizeof(struct bttv_gbuf)*gbuffers)))
return -1;
for (j = 0; j < gbuffers; j++) {
if (!(btv->gbuf[j].risc = vmalloc_32(16384)))
return -1;
i2c_vidiocschan(btv);
bttv_call_i2c_clients(btv,AUDC_SET_RADIO,&btv->tuner_type);
audio_mux(btv,AUDIO_RADIO);
 
up(&btv->lock);
return 0;
}
 
static int radio_release(struct inode *inode, struct file *file)
{
struct bttv *btv = file->private_data;
 
btv->radio_user--;
return 0;
}
 
static int radio_do_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *arg)
{
struct bttv *btv = file->private_data;
 
switch (cmd) {
case VIDIOCGCAP:
{
struct video_capability *cap = arg;
 
memset(cap,0,sizeof(*cap));
strcpy(cap->name,btv->radio_dev->name);
cap->type = VID_TYPE_TUNER;
cap->channels = 1;
cap->audios = 1;
return 0;
}
 
case VIDIOCGTUNER:
{
struct video_tuner *v = arg;
 
if(v->tuner)
return -EINVAL;
memset(v,0,sizeof(*v));
strcpy(v->name, "Radio");
/* japan: 76.0 MHz - 89.9 MHz
western europe: 87.5 MHz - 108.0 MHz
russia: 65.0 MHz - 108.0 MHz */
v->rangelow=(int)(65*16);
v->rangehigh=(int)(108*16);
bttv_call_i2c_clients(btv,cmd,v);
return 0;
}
case VIDIOCSTUNER:
/* nothing to do */
return 0;
memset(btv->vbibuf, 0, VBIBUF_SIZE); /* We don't want to return random
memory to the user */
case BTTV_VERSION:
case VIDIOCGFREQ:
case VIDIOCSFREQ:
case VIDIOCGAUDIO:
case VIDIOCSAUDIO:
return bttv_common_ioctls(btv,cmd,arg);
 
btv->fbuffer=NULL;
default:
return -ENOIOCTLCMD;
}
return 0;
}
 
/* btwrite(0, BT848_TDEC); */
btwrite(0x10, BT848_COLOR_CTL);
btwrite(0x00, BT848_CAP_CTL);
/* set planar and packed mode trigger points and */
/* set rising edge of inverted GPINTR pin as irq trigger */
btwrite(BT848_GPIO_DMA_CTL_PKTP_32|
BT848_GPIO_DMA_CTL_PLTP1_16|
BT848_GPIO_DMA_CTL_PLTP23_16|
BT848_GPIO_DMA_CTL_GPINTC|
BT848_GPIO_DMA_CTL_GPINTI,
BT848_GPIO_DMA_CTL);
static int radio_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
return video_usercopy(inode, file, cmd, arg, radio_do_ioctl);
}
 
/* select direct input */
btwrite(0x00, BT848_GPIO_REG_INP);
btwrite(0x00, BT848_GPIO_OUT_EN);
if (bttv_gpio)
bttv_gpio_tracking(btv,"init #2");
static struct file_operations radio_fops =
{
.owner = THIS_MODULE,
.open = radio_open,
.release = radio_release,
.ioctl = radio_ioctl,
.llseek = no_llseek,
};
 
btwrite(BT848_IFORM_MUX1 | BT848_IFORM_XTAUTO | BT848_IFORM_AUTO,
BT848_IFORM);
static struct video_device radio_template =
{
.name = "bt848/878 radio",
.type = VID_TYPE_TUNER,
.hardware = VID_HARDWARE_BT848,
.fops = &radio_fops,
.minor = -1,
};
 
btwrite(0xd8, BT848_CONTRAST_LO);
bt848_bright(btv, 0x10);
/* ----------------------------------------------------------------------- */
/* irq handler */
 
btwrite(0x20, BT848_E_VSCALE_HI);
btwrite(0x20, BT848_O_VSCALE_HI);
btwrite(BT848_ADC_RESERVED | (adc_crush ? BT848_ADC_CRUSH : 0),
BT848_ADC);
static char *irq_name[] = { "FMTCHG", "VSYNC", "HSYNC", "OFLOW", "HLOCK",
"VPRES", "6", "7", "I2CDONE", "GPINT", "10",
"RISCI", "FBUS", "FTRGT", "FDSR", "PPERR",
"RIPERR", "PABORT", "OCERR", "SCERR" };
 
if (lumafilter) {
btwrite(0, BT848_E_CONTROL);
btwrite(0, BT848_O_CONTROL);
} else {
btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL);
btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL);
static void bttv_print_irqbits(u32 print, u32 mark)
{
unsigned int i;
printk("bits:");
for (i = 0; i < ARRAY_SIZE(irq_name); i++) {
if (print & (1 << i))
printk(" %s",irq_name[i]);
if (mark & (1 << i))
printk("*");
}
}
 
btv->picture.colour=254<<7;
btv->picture.brightness=128<<8;
btv->picture.hue=128<<8;
btv->picture.contrast=0xd8<<7;
static void bttv_print_riscaddr(struct bttv *btv)
{
printk(" main: %08Lx\n",
(unsigned long long)btv->main.dma);
printk(" vbi : o=%08Lx e=%08Lx\n",
btv->curr.vbi ? (unsigned long long)btv->curr.vbi->top.dma : 0,
btv->curr.vbi ? (unsigned long long)btv->curr.vbi->bottom.dma : 0);
printk(" cap : o=%08Lx e=%08Lx\n",
btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0,
btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0);
printk(" scr : o=%08Lx e=%08Lx\n",
btv->screen ? (unsigned long long)btv->screen->top.dma : 0,
btv->screen ? (unsigned long long)btv->screen->bottom.dma : 0);
}
 
val = chroma_agc ? BT848_SCLOOP_CAGC : 0;
btwrite(val, BT848_E_SCLOOP);
btwrite(val, BT848_O_SCLOOP);
static int
bttv_irq_next_set(struct bttv *btv, struct bttv_buffer_set *set)
{
struct bttv_buffer *item;
 
/* clear interrupt status */
btwrite(0xfffffUL, BT848_INT_STAT);
/* set interrupt mask */
btwrite(btv->triton1|
/*BT848_INT_PABORT|BT848_INT_RIPERR|BT848_INT_PPERR|
BT848_INT_FDSR|BT848_INT_FTRGT|BT848_INT_FBUS|*/
(fieldnr ? BT848_INT_VSYNC : 0)|
BT848_INT_GPINT|
BT848_INT_SCERR|
BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES|
BT848_INT_FMTCHG|BT848_INT_HLOCK,
BT848_INT_MASK);
memset(set,0,sizeof(*set));
 
bt848_muxsel(btv, 1);
bt848_set_winsize(btv);
make_vbitab(btv);
bt848_set_risc_jmps(btv,-1);
/* vbi request ? */
if (!list_empty(&btv->vcapture)) {
set->irqflags = 1;
set->vbi = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
}
 
/* needs to be done before i2c is registered */
bttv_init_card1(btv);
/* capture request ? */
if (!list_empty(&btv->capture)) {
set->irqflags = 1;
item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
if (V4L2_FIELD_HAS_TOP(item->vb.field))
set->top = item;
if (V4L2_FIELD_HAS_BOTTOM(item->vb.field))
set->bottom = item;
 
/* register i2c */
btv->tuner_type=-1;
init_bttv_i2c(btv);
/* capture request for other field ? */
if (!V4L2_FIELD_HAS_BOTH(item->vb.field) &&
(item->vb.queue.next != &btv->capture)) {
item = list_entry(item->vb.queue.next, struct bttv_buffer, vb.queue);
if (!V4L2_FIELD_HAS_BOTH(item->vb.field)) {
if (NULL == set->top &&
V4L2_FIELD_TOP == item->vb.field) {
set->top = item;
}
if (NULL == set->bottom &&
V4L2_FIELD_BOTTOM == item->vb.field) {
set->bottom = item;
}
if (NULL != set->top && NULL != set->bottom)
set->topirq = 2;
}
}
}
 
/* some card-specific stuff (needs working i2c) */
bttv_init_card2(btv);
/* screen overlay ? */
if (NULL != btv->screen) {
if (V4L2_FIELD_HAS_BOTH(btv->screen->vb.field)) {
if (NULL == set->top && NULL == set->bottom) {
set->top = btv->screen;
set->bottom = btv->screen;
}
} else {
if (V4L2_FIELD_TOP == btv->screen->vb.field &&
NULL == set->top) {
set->top = btv->screen;
}
if (V4L2_FIELD_BOTTOM == btv->screen->vb.field &&
NULL == set->bottom) {
set->bottom = btv->screen;
}
}
}
 
dprintk("bttv%d: next set: top=%p bottom=%p vbi=%p "
"[screen=%p,irq=%d,%d]\n",
btv->nr,set->top, set->bottom, set->vbi,
btv->screen,set->irqflags,set->topirq);
return 0;
}
 
/* ----------------------------------------------------------------------- */
static void
bttv_irq_wakeup_set(struct bttv *btv, struct bttv_buffer_set *wakeup,
struct bttv_buffer_set *curr, unsigned int state)
{
struct timeval ts;
 
static char *irq_name[] = { "FMTCHG", "VSYNC", "HSYNC", "OFLOW", "HLOCK",
"VPRES", "6", "7", "I2CDONE", "GPINT", "10",
"RISCI", "FBUS", "FTRGT", "FDSR", "PPERR",
"RIPERR", "PABORT", "OCERR", "SCERR" };
do_gettimeofday(&ts);
 
static void bttv_irq(void *arg)
if (NULL != wakeup->vbi) {
wakeup->vbi->vb.ts = ts;
wakeup->vbi->vb.field_count = btv->field_count;
wakeup->vbi->vb.state = state;
wake_up(&wakeup->vbi->vb.done);
}
if (wakeup->top == wakeup->bottom) {
if (NULL != wakeup->top && curr->top != wakeup->top) {
if (irq_debug > 1)
printk("bttv%d: wakeup: both=%p\n",btv->nr,wakeup->top);
wakeup->top->vb.ts = ts;
wakeup->top->vb.field_count = btv->field_count;
wakeup->top->vb.state = state;
wake_up(&wakeup->top->vb.done);
}
} else {
if (NULL != wakeup->top && curr->top != wakeup->top) {
if (irq_debug > 1)
printk("bttv%d: wakeup: top=%p\n",btv->nr,wakeup->top);
wakeup->top->vb.ts = ts;
wakeup->top->vb.field_count = btv->field_count;
wakeup->top->vb.state = state;
wake_up(&wakeup->top->vb.done);
}
if (NULL != wakeup->bottom && curr->bottom != wakeup->bottom) {
if (irq_debug > 1)
printk("bttv%d: wakeup: bottom=%p\n",btv->nr,wakeup->bottom);
wakeup->bottom->vb.ts = ts;
wakeup->bottom->vb.field_count = btv->field_count;
wakeup->bottom->vb.state = state;
wake_up(&wakeup->bottom->vb.done);
}
}
}
 
static void bttv_irq_timeout(unsigned long data)
{
struct bttv *btv = (struct bttv *)data;
struct bttv_buffer_set old,new;
struct bttv_buffer *item;
if (bttv_verbose) {
printk(KERN_INFO "bttv%d: timeout: risc=%08x, ",
btv->nr,btread(BT848_RISC_COUNT));
bttv_print_irqbits(btread(BT848_INT_STAT),0);
printk("\n");
}
 
spin_lock(&btv->s_lock);
/* deactivate stuff */
memset(&new,0,sizeof(new));
old = btv->curr;
btv->curr = new;
bttv_buffer_set_activate(btv, &new);
bttv_set_dma(btv, 0, 0);
 
/* wake up */
bttv_irq_wakeup_set(btv, &old, &new, STATE_ERROR);
 
/* cancel all outstanding capture / vbi requests */
while (!list_empty(&btv->capture)) {
item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
list_del(&item->vb.queue);
item->vb.state = STATE_ERROR;
wake_up(&item->vb.done);
}
while (!list_empty(&btv->vcapture)) {
item = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
list_del(&item->vb.queue);
item->vb.state = STATE_ERROR;
wake_up(&item->vb.done);
}
btv->errors++;
spin_unlock(&btv->s_lock);
}
 
static void
bttv_irq_wakeup_top(struct bttv *btv)
{
struct bttv_buffer *wakeup = btv->curr.top;
 
if (NULL == wakeup)
return;
 
spin_lock(&btv->s_lock);
btv->curr.topirq = 0;
btv->curr.top = NULL;
bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
 
do_gettimeofday(&wakeup->vb.ts);
wakeup->vb.field_count = btv->field_count;
wakeup->vb.state = STATE_DONE;
wake_up(&wakeup->vb.done);
spin_unlock(&btv->s_lock);
}
 
static void
bttv_irq_switch_fields(struct bttv *btv)
{
struct bttv_buffer_set new;
struct bttv_buffer_set old;
dma_addr_t rc;
 
spin_lock(&btv->s_lock);
 
/* new buffer set */
bttv_irq_next_set(btv, &new);
rc = btread(BT848_RISC_COUNT);
if (rc < btv->main.dma || rc > btv->main.dma + 0x100) {
if (1 /* irq_debug */)
printk("bttv%d: skipped frame. no signal? high irq latency?\n",
btv->nr);
spin_unlock(&btv->s_lock);
return;
}
/* switch over */
old = btv->curr;
btv->curr = new;
bttv_buffer_set_activate(btv, &new);
bttv_set_dma(btv, 0, new.irqflags);
 
/* switch input */
if (UNSET != btv->new_input) {
video_mux(btv,btv->new_input);
btv->new_input = UNSET;
}
 
/* wake up finished buffers */
bttv_irq_wakeup_set(btv, &old, &new, STATE_DONE);
spin_unlock(&btv->s_lock);
}
 
static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
{
u32 stat,astat;
u32 dstat;
int count;
struct bttv *btv = btvirq;
struct bttv *btv;
int handled = 0;
 
cli();
 
in_irq = 1;
btv=(struct bttv *)dev_id;
count=0;
while (1)
{
while (1) {
/* get/clear interrupt status bits */
stat=btread(BT848_INT_STAT);
astat=stat&btread(BT848_INT_MASK);
if (!astat) {
in_irq = 0;
sti();
return;
}
if (!astat)
break;
handled = 1;
btwrite(stat,BT848_INT_STAT);
 
/* get device status bits */
1896,236 → 3369,447
dstat=btread(BT848_DSTATUS);
 
if (irq_debug) {
int i;
cprintf("bttv%d: irq loop=%d risc=%lx, bits:",
btv->nr, count, stat>>28);
for (i = 0; i < (sizeof(irq_name)/sizeof(char*)); i++) {
if (stat & (1 << i))
cprintf(" %s",irq_name[i]);
if (astat & (1 << i))
cprintf(" *");
}
printk(KERN_DEBUG "bttv%d: irq loop=%d fc=%d "
"riscs=%x, riscc=%08x, ",
btv->nr, count, btv->field_count,
stat>>28, btread(BT848_RISC_COUNT));
bttv_print_irqbits(stat,astat);
if (stat & BT848_INT_HLOCK)
cprintf(" HLOC => %s", (dstat & BT848_DSTATUS_HLOC)
printk(" HLOC => %s", (dstat & BT848_DSTATUS_HLOC)
? "yes" : "no");
if (stat & BT848_INT_VPRES)
cprintf(" PRES => %s", (dstat & BT848_DSTATUS_PRES)
printk(" PRES => %s", (dstat & BT848_DSTATUS_PRES)
? "yes" : "no");
if (stat & BT848_INT_FMTCHG)
cprintf(" NUML => %s", (dstat & BT848_DSTATUS_PRES)
printk(" NUML => %s", (dstat & BT848_DSTATUS_NUML)
? "625" : "525");
cprintf("\n");
printk("\n");
}
 
if (astat&BT848_INT_VSYNC)
btv->field++;
btv->field_count++;
 
if (astat&(BT848_INT_SCERR|BT848_INT_OCERR)) {
if (bttv_verbose)
cprintf("bttv%d: irq:%s%s risc_count=%08lx\n",
btv->nr,
(astat&BT848_INT_SCERR) ? " SCERR" : "",
(astat&BT848_INT_OCERR) ? " OCERR" : "",
btread(BT848_RISC_COUNT));
btv->errors++;
if (btv->errors < BTTV_ERRORS) {
btand(~15, BT848_GPIO_DMA_CTL);
btwrite(virt_to_bus((unsigned long)(btv->risc_jmp+8)),
BT848_RISC_STRT_ADD);
bt848_set_geo(btv);
bt848_set_risc_jmps(btv,-1);
} else {
if (bttv_verbose)
cprintf("bttv%d: aiee: error loops\n",btv->nr);
bt848_offline(btv);
}
if (astat & BT848_INT_GPINT) {
#ifdef CONFIG_VIDEO_IR
if (btv->remote)
bttv_input_irq(btv);
#endif
wake_up(&btv->gpioq);
}
if (astat&BT848_INT_RISCI)
{
if (bttv_debug > 1)
cprintf("bttv%d: IRQ_RISCI\n",btv->nr);
 
/* captured VBI frame */
if (stat&(1<<28))
{
btv->vbip=0;
/* inc vbi frame count for detecting drops */
(*(u32 *)&(btv->vbibuf[VBIBUF_SIZE - 4]))++;
}
if ((astat & BT848_INT_RISCI) && (stat & (2<<28)))
bttv_irq_wakeup_top(btv);
 
/* captured full frame */
if (stat&(2<<28) && btv->gq_grab != -1)
{
btv->last_field=btv->field;
if (bttv_debug)
cprintf("bttv%d: cap irq: done %d\n",btv->nr,btv->gq_grab);
btv->gbuf[btv->gq_grab].stat = GBUFFER_DONE;
btv->gq_grab = -1;
if (btv->gq_in != btv->gq_out)
{
btv->gq_grab = btv->gqueue[btv->gq_out++];
btv->gq_out = btv->gq_out % MAX_GBUFFERS;
if (bttv_debug)
cprintf("bttv%d: cap irq: capture %d\n",btv->nr,btv->gq_grab);
btv->risc_cap_odd = btv->gbuf[btv->gq_grab].ro;
btv->risc_cap_even = btv->gbuf[btv->gq_grab].re;
bt848_set_risc_jmps(btv,-1);
bt848_set_geo(btv);
btwrite(BT848_COLOR_CTL_GAMMA,
BT848_COLOR_CTL);
} else {
btv->risc_cap_odd = 0;
btv->risc_cap_even = 0;
bt848_set_risc_jmps(btv,-1);
bt848_set_geo(btv);
btwrite(btv->fb_color_ctl | BT848_COLOR_CTL_GAMMA,
BT848_COLOR_CTL);
}
break;
}
if (stat&(8<<28) && btv->gq_start)
{
btv->gq_start = 0;
btv->gq_grab = btv->gqueue[btv->gq_out++];
btv->gq_out = btv->gq_out % MAX_GBUFFERS;
if (bttv_debug)
cprintf("bttv%d: cap irq: capture %d [start]\n",btv->nr,btv->gq_grab);
btv->risc_cap_odd = btv->gbuf[btv->gq_grab].ro;
btv->risc_cap_even = btv->gbuf[btv->gq_grab].re;
bt848_set_risc_jmps(btv,-1);
bt848_set_geo(btv);
btwrite(BT848_COLOR_CTL_GAMMA,
BT848_COLOR_CTL);
}
if ((astat & BT848_INT_RISCI) && (stat & (1<<28)))
bttv_irq_switch_fields(btv);
 
if ((astat & BT848_INT_HLOCK) && btv->opt_automute)
audio_mux(btv, -1);
 
if (astat & (BT848_INT_SCERR|BT848_INT_OCERR)) {
printk(KERN_INFO "bttv%d: %s%s @ %08x,",btv->nr,
(astat & BT848_INT_SCERR) ? "SCERR" : "",
(astat & BT848_INT_OCERR) ? "OCERR" : "",
btread(BT848_RISC_COUNT));
bttv_print_irqbits(stat,astat);
printk("\n");
if (bttv_debug)
bttv_print_riscaddr(btv);
}
if (fdsr && astat & BT848_INT_FDSR) {
printk(KERN_INFO "bttv%d: FDSR @ %08x\n",
btv->nr,btread(BT848_RISC_COUNT));
if (bttv_debug)
bttv_print_riscaddr(btv);
}
 
count++;
if (count > 20) {
if (count > 4) {
btwrite(0, BT848_INT_MASK);
cprintf("bttv%d: IRQ lockup, cleared int mask\n", btv->nr);
bt848_offline(btv);
printk(KERN_ERR
"bttv%d: IRQ lockup, cleared int mask [", btv->nr);
bttv_print_irqbits(stat,astat);
printk("]\n");
}
}
return IRQ_RETVAL(handled);
}
 
in_irq = 0;
 
sti();
/* ----------------------------------------------------------------------- */
/* initialitation */
 
static struct video_device *vdev_init(struct bttv *btv,
struct video_device *template,
char *type)
{
struct video_device *vfd;
 
vfd = video_device_alloc();
if (NULL == vfd)
return NULL;
*vfd = *template;
vfd->minor = -1;
vfd->dev = &btv->dev->dev;
vfd->release = video_device_release;
snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)",
btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "",
type, bttv_tvcards[btv->type].name);
return vfd;
}
 
static void bttv_unregister_video(struct bttv *btv)
{
if (btv->video_dev) {
if (-1 != btv->video_dev->minor)
video_unregister_device(btv->video_dev);
else
video_device_release(btv->video_dev);
btv->video_dev = NULL;
}
if (btv->vbi_dev) {
if (-1 != btv->vbi_dev->minor)
video_unregister_device(btv->vbi_dev);
else
video_device_release(btv->vbi_dev);
btv->vbi_dev = NULL;
}
if (btv->radio_dev) {
if (-1 != btv->radio_dev->minor)
video_unregister_device(btv->radio_dev);
else
video_device_release(btv->radio_dev);
btv->radio_dev = NULL;
}
}
 
/* register video4linux devices */
static int __devinit bttv_register_video(struct bttv *btv)
{
/* video */
btv->video_dev = vdev_init(btv, &bttv_video_template, "video");
if (NULL == btv->video_dev)
goto err;
if (video_register_device(btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
goto err;
printk(KERN_INFO "bttv%d: registered device video%d\n",
btv->nr,btv->video_dev->minor & 0x1f);
video_device_create_file(btv->video_dev, &class_device_attr_card);
 
/* vbi */
btv->vbi_dev = vdev_init(btv, &bttv_vbi_template, "vbi");
if (NULL == btv->vbi_dev)
goto err;
if (video_register_device(btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0)
goto err;
printk(KERN_INFO "bttv%d: registered device vbi%d\n",
btv->nr,btv->vbi_dev->minor & 0x1f);
 
if (!btv->has_radio)
return 0;
/* radio */
btv->radio_dev = vdev_init(btv, &radio_template, "radio");
if (NULL == btv->radio_dev)
goto err;
if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,radio_nr)<0)
goto err;
printk(KERN_INFO "bttv%d: registered device radio%d\n",
btv->nr,btv->radio_dev->minor & 0x1f);
 
/* all done */
return 0;
 
err:
bttv_unregister_video(btv);
return -1;
}
 
 
/* on OpenFirmware machines (PowerMac at least), PCI memory cycle */
/* response on cards with no firmware is not enabled by OF */
static void pci_set_command(struct pci_dev *dev)
{
#if defined(__powerpc__)
unsigned int cmd;
pci_read_config_dword(dev, PCI_COMMAND, &cmd);
cmd = (cmd | PCI_COMMAND_MEMORY );
pci_write_config_dword(dev, PCI_COMMAND, cmd);
#endif
}
 
int bttv_probe(struct bttv *btv)
static int __devinit bttv_probe(struct pci_dev *dev,
const struct pci_device_id *pci_id)
{
int result;
unsigned char lat;
struct bttv *btv;
 
if (bttv_num == BTTV_MAX)
return -ENOMEM;
printk(KERN_INFO "bttv: Bt8xx card found (%d).\n", bttv_num);
btv=&bttvs[bttv_num];
memset(btv,0,sizeof(*btv));
btv->nr = bttv_num;
sprintf(btv->name,"bttv%d",btv->nr);
 
btvirq = btv;
btv->nr = bttv_num;
//because not all compilers allow anonymous unions duplication is needed
btv->gpio_adap.bt848_mem = btv->bt848_mem = NULL;
btv->vbibuf=NULL;
btv->risc_jmp=NULL;
btv->vbi_odd=NULL;
btv->vbi_even=NULL;
btv->vbip=VBIBUF_SIZE;
btv->shutdown=0;
/* initialize structs / fill in defaults */
init_MUTEX(&btv->lock);
init_MUTEX(&btv->reslock);
btv->s_lock = SPIN_LOCK_UNLOCKED;
init_waitqueue_head(&btv->gpioq);
INIT_LIST_HEAD(&btv->capture);
INIT_LIST_HEAD(&btv->vcapture);
#ifdef VIDIOC_G_PRIORITY
v4l2_prio_init(&btv->prio);
#endif
 
btv->id = 848;
btv->bt848_adr=pci_resource_start(btv->dev,0);
if (btv->id >= 878)
btv->i2c_command = 0x83;
else
btv->i2c_command=(I2C_TIMING | BT848_I2C_SCL | BT848_I2C_SDA);
init_timer(&btv->timeout);
btv->timeout.function = bttv_irq_timeout;
btv->timeout.data = (unsigned long)btv;
btv->i2c_rc = -1;
btv->tuner_type = UNSET;
btv->pinnacle_id = UNSET;
btv->new_input = UNSET;
btv->has_radio=radio[btv->nr];
/* pci stuff (init, get irq/mmio, ... */
btv->dev = dev;
btv->id = dev->device;
if (pci_enable_device(dev)) {
printk(KERN_WARNING "bttv%d: Can't enable device.\n",
btv->nr);
return -EIO;
}
if (pci_set_dma_mask(dev, 0xffffffff)) {
printk(KERN_WARNING "bttv%d: No suitable DMA available.\n",
btv->nr);
return -EIO;
}
if (!request_mem_region(pci_resource_start(dev,0),
pci_resource_len(dev,0),
btv->name)) {
printk(KERN_WARNING "bttv%d: can't request iomem (0x%lx).\n",
btv->nr, pci_resource_start(dev,0));
return -EBUSY;
}
pci_set_master(dev);
pci_set_command(dev);
pci_set_drvdata(dev,btv);
if (!pci_dma_supported(dev,0xffffffff)) {
printk("bttv%d: Oops: no 32bit PCI DMA ???\n", btv->nr);
result = -EIO;
goto fail1;
}
 
if (-1 != latency) {
printk(KERN_INFO "bttv%d: setting pci latency timer to %d\n",
bttv_num,latency);
pci_write_config_byte(btv->dev, PCI_LATENCY_TIMER, latency);
pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ",
bttv_num,btv->id, btv->revision, pci_name(dev));
printk("irq: %d, latency: %d, mmio: 0x%lx\n",
btv->dev->irq, lat, pci_resource_start(dev,0));
schedule();
btv->bt848_mmio=ioremap(pci_resource_start(dev,0), 0x1000);
if (NULL == ioremap(pci_resource_start(dev,0), 0x1000)) {
printk("bttv%d: ioremap() failed\n", btv->nr);
result = -EIO;
goto fail1;
}
pci_read_config_byte(btv->dev, PCI_CLASS_REVISION, &btv->revision);
pci_read_config_byte(btv->dev, PCI_LATENCY_TIMER, &lat);
printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %2x:%2x\n", bttv_num,btv->id, btv->revision, btv->dev->bus->number, btv->dev->devfn);
printk(KERN_INFO "irq: %d, latency: %d, mmio: 0x%lx\n",
btv->dev->irq, lat, btv->bt848_adr);
btv->bt848_mem = (void *)btv->bt848_adr;
btv->gpio_adap.bt848_mem = btv->bt848_mem;
 
btv->pll.pll_crystal = 0;
/* identify card */
bttv_idcard(btv);
 
/* clear interrupt mask */
/* disable irqs, register irq handler */
btwrite(0, BT848_INT_MASK);
result = request_irq(btv->dev->irq, bttv_irq,
SA_SHIRQ | SA_INTERRUPT,btv->name,(void *)btv);
if (result < 0) {
printk(KERN_ERR "bttv%d: can't get IRQ %d\n",
bttv_num,btv->dev->irq);
goto fail1;
}
 
handler_set(btv->dev->irq, (void (*)(int)) bttv_irq, NIL);
if (0 != bttv_handle_chipset(btv)) {
result = -EIO;
goto fail2;
}
 
/* init options from insmod args */
btv->opt_combfilter = combfilter;
btv->opt_lumafilter = lumafilter;
btv->opt_automute = automute;
btv->opt_chroma_agc = chroma_agc;
btv->opt_adc_crush = adc_crush;
btv->opt_vcr_hack = vcr_hack;
bttv_handle_chipset(btv);
init_bt848(btv);
/* fill struct bttv with some useful defaults */
btv->init.btv = btv;
btv->init.ov.w.width = 320;
btv->init.ov.w.height = 240;
btv->init.fmt = format_by_palette(VIDEO_PALETTE_RGB24);
btv->init.width = 320;
btv->init.height = 240;
btv->init.lines = 16;
btv->input = 0;
 
/* initialize hardware */
if (bttv_gpio)
bttv_gpio_tracking(btv,"pre-init");
 
bttv_risc_init_main(btv);
if (!bttv_tvcards[btv->type].no_video)
init_bt848(btv);
 
/* gpio */
btwrite(0x00, BT848_GPIO_REG_INP);
btwrite(0x00, BT848_GPIO_OUT_EN);
if (bttv_gpio)
bttv_gpio_tracking(btv,"init");
 
/* needs to be done before i2c is registered */
bttv_init_card1(btv);
 
/* register i2c */
init_bttv_i2c(btv);
 
/* some card-specific stuff (needs working i2c) */
bttv_init_card2(btv);
 
/* register video4linux + input */
if (!bttv_tvcards[btv->type].no_video) {
bttv_register_video(btv);
#ifdef CONFIG_VIDEO_IR
bttv_input_init(btv);
#endif
 
bt848_bright(btv,32768);
bt848_contrast(btv,32768);
bt848_hue(btv,32768);
bt848_sat(btv,32768);
audio_mux(btv,AUDIO_MUTE);
set_input(btv,0);
}
 
/* everything is fine */
bttv_num++;
 
return 0;
 
fail2:
free_irq(btv->dev->irq,btv);
fail1:
if (btv->bt848_mmio)
iounmap(btv->bt848_mmio);
release_mem_region(pci_resource_start(btv->dev,0),
pci_resource_len(btv->dev,0));
pci_set_drvdata(dev,NULL);
return result;
}
 
extern void i2c_init_all(void);
 
int bttv_start(struct bttv *btv)
static void __devexit bttv_remove(struct pci_dev *pci_dev)
{
struct pci_regs *reg;
BYTE dv, bus;
DWORD dw;
struct bttv *btv = pci_get_drvdata(pci_dev);
 
printk(KERN_INFO "Initializing PCI BUS...\n");
btv->dev = vmalloc_32(sizeof(struct pci_dev));
if (bttv_verbose)
printk("bttv%d: unloading\n",btv->nr);
 
/* Scan the devices connected to the PCI bus */
if (pci_init() != 1) return -1;
/* shutdown everything (DMA+IRQs) */
btand(~15, BT848_GPIO_DMA_CTL);
btwrite(0, BT848_INT_MASK);
btwrite(~0x0, BT848_INT_STAT);
btwrite(0x0, BT848_GPIO_OUT_EN);
if (bttv_gpio)
bttv_gpio_tracking(btv,"cleanup");
 
/* tell gpio modules we are leaving ... */
btv->shutdown=1;
wake_up(&btv->gpioq);
 
/* unregister i2c_bus + input */
fini_bttv_i2c(btv);
#ifdef CONFIG_VIDEO_IR
bttv_input_fini(btv);
#endif
 
/* unregister video4linux */
bttv_unregister_video(btv);
 
/* free allocated memory */
btcx_riscmem_free(btv->dev,&btv->main);
 
/* free ressources */
free_irq(btv->dev->irq,btv);
iounmap(btv->bt848_mmio);
release_mem_region(pci_resource_start(btv->dev,0),
pci_resource_len(btv->dev,0));
 
pci_set_drvdata(pci_dev, NULL);
return;
}
 
static struct pci_device_id bttv_pci_tbl[] = {
{PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0,}
};
 
MODULE_DEVICE_TABLE(pci, bttv_pci_tbl);
 
static struct pci_driver bttv_pci_driver = {
.name = "bttv",
.id_table = bttv_pci_tbl,
.probe = bttv_probe,
.remove = __devexit_p(bttv_remove),
};
 
static int bttv_init_module(void)
{
int rc;
bttv_num = 0;
 
if (gbuffers < 2 || gbuffers > MAX_GBUFFERS)
printk(KERN_INFO "bttv: driver version %d.%d.%d loaded\n",
(BTTV_VERSION_CODE >> 16) & 0xff,
(BTTV_VERSION_CODE >> 8) & 0xff,
BTTV_VERSION_CODE & 0xff);
if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME)
gbuffers = 2;
if (gbufsize < 0 || gbufsize > BTTV_MAX_FBUF)
gbufsize = BTTV_MAX_FBUF;
gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK;
if (bttv_verbose)
printk(KERN_INFO "bttv: using %d buffers with %dk (%dk total) for capture\n",
gbuffers,gbufsize/1024,gbuffers*gbufsize/1024);
printk(KERN_INFO "bttv: using %d buffers with %dk (%d pages) each for capture\n",
gbuffers, gbufsize >> 10, gbufsize >> PAGE_SHIFT);
 
if (pci_present()) {
reg = (struct pci_regs *) pci_class((0x0400) << 8,0,&bus,&dv) ;
if (reg != NULL) {
btv->dev->bus->number = bus;
btv->dev->devfn = dv;
btv->dev->base_address[0] = (reg->IoBaseAddress-0x08);
btv->dev->irq = reg->InterruptLine;
} else {
return -1;
}
bttv_check_chipset();
 
printk(KERN_INFO "PCI INFO bus=%d devfn=%d irq=%d base=%08lx\n",bus,dv,btv->dev->irq,btv->dev->base_address[0]);
rc = pci_module_init(&bttv_pci_driver);
if (-ENODEV == rc) {
/* plenty of people trying to use bttv for the cx2388x ... */
if (NULL != pci_find_device(0x14f1, 0x8800, NULL))
printk("bttv doesn't support your Conexant 2388x card.\n");
}
return rc;
}
 
pcibios_read_config_dword(bus,dv,PCI_COMMAND,&dw);
oldpci_command = dw;
dw |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
pcibios_write_config_dword(bus,dv,PCI_COMMAND,dw);
static void bttv_cleanup_module(void)
{
pci_unregister_driver(&bttv_pci_driver);
return;
}
 
}
module_init(bttv_init_module);
module_exit(bttv_cleanup_module);
 
i2c_init_all();
 
bttv_check_chipset();
 
bttv_probe(btv);
bttv_open(btv);
 
return 0;
 
}
/*
* Local variables:
* c-basic-offset: 8
* End:
*/
/shark/trunk/drivers/bttv/bttv-cards.c
21,28 → 21,35
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
*/
 
/* SHARK version by Giacomo Guidi <giacomo@gandalf.sssup.it> */
#include <linuxcomp.h>
 
#define __NO_VERSION__ 1
 
#include <unistd.h>
#include <linux/config.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/kmod.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/vmalloc.h>
#ifdef CONFIG_FW_LOADER
# include <linux/firmware.h>
#endif
 
#include "drivers/bttv.h"
#include "drivers/tuner.h"
#include <asm/io.h>
 
#include "drivers/bttvp.h"
#include "drivers/bt832.h"
 
/* fwd decl */
static void boot_msp34xx(struct bttv *btv, int pin);
static void boot_bt832(struct bttv *btv);
static void hauppauge_eeprom(struct bttv *btv);
static void avermedia_eeprom(struct bttv *btv);
static void osprey_eeprom(struct bttv *btv);
static void avermedia_eeprom(struct bttv *btv);
static void modtec_eeprom(struct bttv *btv);
static void init_PXC200(struct bttv *btv);
#if 0
static void init_tea5757(struct bttv *btv);
#endif
 
static void winview_audio(struct bttv *btv, struct video_audio *v, int set);
static void lt9415_audio(struct bttv *btv, struct video_audio *v, int set);
54,19 → 61,81
static void pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set);
static void fv2000s_audio(struct bttv *btv, struct video_audio *v, int set);
static void windvr_audio(struct bttv *btv, struct video_audio *v, int set);
static void adtvk503_audio(struct bttv *btv, struct video_audio *v, int set);
static void rv605_muxsel(struct bttv *btv, unsigned int input);
static void eagle_muxsel(struct bttv *btv, unsigned int input);
static void xguard_muxsel(struct bttv *btv, unsigned int input);
static void ivc120_muxsel(struct bttv *btv, unsigned int input);
 
static int terratec_active_radio_upgrade(struct bttv *btv);
static int tea5757_read(struct bttv *btv);
static int tea5757_write(struct bttv *btv, int value);
static void identify_by_eeprom(struct bttv *btv,
unsigned char eeprom_data[256]);
 
/* config variables */
static int triton1=0;
static int vsfx=0;
int no_overlay=-1;
static unsigned int card[4] = { -1, -1, -1, -1 };
static unsigned int pll[4] = { -1, -1, -1, -1 };
static unsigned int tuner[4] = { -1, -1, -1, -1 };
static unsigned int gpiomask = -1;
static unsigned int audioall = -1;
static unsigned int audiomux[5] = { -1, -1, -1, -1, -1 };
static unsigned int triton1=0;
static unsigned int vsfx=0;
static unsigned int latency = UNSET;
unsigned int no_overlay=-1;
 
static unsigned int card[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET};
static unsigned int pll[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET};
static unsigned int tuner[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET};
static unsigned int svhs[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET};
#ifdef MODULE
static unsigned int autoload = 1;
#else
static unsigned int autoload = 0;
#endif
static unsigned int gpiomask = UNSET;
static unsigned int audioall = UNSET;
static unsigned int audiomux[5] = { [ 0 ... 4 ] = UNSET };
 
/* insmod options */
MODULE_PARM(triton1,"i");
MODULE_PARM_DESC(triton1,"set ETBF pci config bit "
"[enable bug compatibility for triton1 + others]");
MODULE_PARM(vsfx,"i");
MODULE_PARM_DESC(vsfx,"set VSFX pci config bit "
"[yet another chipset flaw workaround]");
MODULE_PARM(no_overlay,"i");
MODULE_PARM(latency,"i");
MODULE_PARM_DESC(latency,"pci latency timer");
MODULE_PARM(card,"1-" __stringify(BTTV_MAX) "i");
MODULE_PARM_DESC(card,"specify TV/grabber card model, see CARDLIST file for a list");
MODULE_PARM(pll,"1-" __stringify(BTTV_MAX) "i");
MODULE_PARM_DESC(pll,"specify installed crystal (0=none, 28=28 MHz, 35=35 MHz)");
MODULE_PARM(tuner,"1-" __stringify(BTTV_MAX) "i");
MODULE_PARM_DESC(tuner,"specify installed tuner type");
MODULE_PARM(autoload,"i");
MODULE_PARM_DESC(autoload,"automatically load i2c modules like tuner.o, default is 1 (yes)");
MODULE_PARM(gpiomask,"i");
MODULE_PARM(audioall,"i");
MODULE_PARM(audiomux,"1-5i");
 
/* kernel args */
#ifndef MODULE
static int __init p_card(char *str) { return bttv_parse(str,BTTV_MAX,card); }
static int __init p_pll(char *str) { return bttv_parse(str,BTTV_MAX,pll); }
static int __init p_tuner(char *str) { return bttv_parse(str,BTTV_MAX,tuner); }
__setup("bttv.card=", p_card);
__setup("bttv.pll=", p_pll);
__setup("bttv.tuner=", p_tuner);
 
int __init bttv_parse(char *str, int max, int *vals)
{
int i,number,res = 2;
for (i = 0; res == 2 && i < max; i++) {
res = get_option(&str,&number);
if (res)
vals[i] = number;
}
return 1;
}
#endif
 
/* ----------------------------------------------------------------------- */
/* list of card IDs for bt878+ cards */
 
74,71 → 143,128
unsigned id;
int cardnr;
char *name;
} cards[] = {
} cards[] __devinitdata = {
{ 0x13eb0070, BTTV_HAUPPAUGE878, "Hauppauge WinTV" },
{ 0x39000070, BTTV_HAUPPAUGE878, "Hauppauge WinTV-D" },
{ 0x45000070, BTTV_HAUPPAUGE878, "Hauppauge WinTV/PVR" },
{ 0x45000070, BTTV_HAUPPAUGEPVR, "Hauppauge WinTV/PVR" },
{ 0xff000070, BTTV_OSPREY1x0, "Osprey-100" },
{ 0xff010070, BTTV_OSPREY2x0_SVID,"Osprey-200" },
{ 0x036e109e, BTTV_OSPREY2x0_SVID,"Osprey-210" },
{ 0xff020070, BTTV_OSPREY5x0, "Osprey-500" },
{ 0xff020070, BTTV_OSPREY500, "Osprey-500" },
{ 0xff030070, BTTV_OSPREY2000, "Osprey-2000" },
{ 0xff040070, BTTV_OSPREY540, "Osprey-540" },
 
{ 0x00011002, BTTV_ATI_TVWONDER, "ATI TV Wonder" },
{ 0x00031002, BTTV_ATI_TVWONDERVE,"ATI TV Wonder/VE" },
 
{ 0x6606107d, BTTV_WINFAST2000, "Leadtek WinFast TV 2000" },
{ 0x263610b4, BTTV_STB2, "STB TV PCI FM, P/N 6000704" },
{ 0x6607107d, BTTV_WINFAST2000, "Leadtek WinFast VC 100" },
{ 0x263610b4, BTTV_STB2, "STB TV PCI FM, Gateway P/N 6000704" },
{ 0x264510b4, BTTV_STB2, "STB TV PCI FM, Gateway P/N 6000704" },
{ 0x402010fc, BTTV_GVBCTV3PCI, "I-O Data Co. GV-BCTV3/PCI" },
{ 0x405010fc, BTTV_GVBCTV4PCI, "I-O Data Co. GV-BCTV4/PCI" },
{ 0x407010fc, BTTV_GVBCTV5PCI, "I-O Data Co. GV-BCTV5/PCI" },
 
{ 0x1200bd11, BTTV_PINNACLE, "Pinnacle PCTV" },
{ 0x001211bd, BTTV_PINNACLE, "Pinnacle PCTV" },
{ 0x001c11bd, BTTV_PINNACLE, "Pinnacle PCTV Sat" },
{ 0x001c11bd, BTTV_PINNACLESAT, "Pinnacle PCTV Sat" },
// some cards ship with byteswapped IDs ...
{ 0x1200bd11, BTTV_PINNACLE, "Pinnacle PCTV [bswap]" },
{ 0xff00bd11, BTTV_PINNACLE, "Pinnacle PCTV [bswap]" },
 
{ 0x3000121a, BTTV_VOODOOTV_FM, "3Dfx VoodooTV FM/ VoodooTV 200" },
{ 0x3060121a, BTTV_STB2, "3Dfx VoodooTV 100/ STB OEM" },
{ 0x3000144f, BTTV_MAGICTVIEW063, "(Askey Magic/others) TView99 CPH06x" },
{ 0x3002144f, BTTV_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH05x" },
{ 0x3005144f, BTTV_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH061/06L (T1/LC)" },
{ 0x5000144f, BTTV_MAGICTVIEW061, "Askey CPH050" },
{ 0x00011461, BTTV_AVPHONE98, "AVerMedia TVPhone98" },
{ 0x00021461, BTTV_AVERMEDIA98, "AVermedia TVCapture 98" },
{ 0x00031461, BTTV_AVPHONE98, "AVerMedia TVPhone98" },
{ 0x00041461, BTTV_AVERMEDIA98, "AVerMedia TVCapture 98" },
{ 0x03001461, BTTV_AVERMEDIA98, "VDOMATE TV TUNER CARD" },
 
{ 0x300014ff, BTTV_MAGICTVIEW061, "TView 99 (CPH061)" },
{ 0x300214ff, BTTV_PHOEBE_TVMAS, "Phoebe TV Master (CPH060)" },
 
{ 0x1117153b, BTTV_TERRATVALUE, "Terratec TValue" },
{ 0x1118153b, BTTV_TERRATVALUE, "Terratec TValue" },
{ 0x1119153b, BTTV_TERRATVALUE, "Terratec TValue" },
{ 0x111a153b, BTTV_TERRATVALUE, "Terratec TValue" },
{ 0x1117153b, BTTV_TERRATVALUE, "Terratec TValue (Philips PAL B/G)" },
{ 0x1118153b, BTTV_TERRATVALUE, "Terratec TValue (Temic PAL B/G)" },
{ 0x1119153b, BTTV_TERRATVALUE, "Terratec TValue (Philips PAL I)" },
{ 0x111a153b, BTTV_TERRATVALUE, "Terratec TValue (Temic PAL I)" },
{ 0x1123153b, BTTV_TERRATVRADIO, "Terratec TV Radio+" },
{ 0x1127153b, BTTV_TERRATV, "Terratec TV+" },
// clashes with flyvideo
//{ 0x18521852, BTTV_TERRATV, "Terratec TV+" },
{ 0x1134153b, BTTV_TERRATVALUE, "Terratec TValue" },
{ 0x1135153b, BTTV_TERRATVALUER, "Terratec TValue Radio" },
{ 0x5018153b, BTTV_TERRATVALUE, "Terratec TValue" },
{ 0x1127153b, BTTV_TERRATV, "Terratec TV+ (V1.05)" },
// clashes with FlyVideo
//{ 0x18521852, BTTV_TERRATV, "Terratec TV+ (V1.10)" },
{ 0x1134153b, BTTV_TERRATVALUE, "Terratec TValue (LR102)" },
{ 0x1135153b, BTTV_TERRATVALUER, "Terratec TValue Radio" }, // LR102
{ 0x5018153b, BTTV_TERRATVALUE, "Terratec TValue" }, // ??
 
{ 0x400015b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
{ 0x400a15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
{ 0x400d15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
{ 0x401015b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
{ 0x401615b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
 
{ 0x1430aa00, BTTV_PV143, "Provideo PV143A" },
{ 0x1431aa00, BTTV_PV143, "Provideo PV143B" },
{ 0x1432aa00, BTTV_PV143, "Provideo PV143C" },
{ 0x1433aa00, BTTV_PV143, "Provideo PV143D" },
 
{ 0x1460aa00, BTTV_PV150, "Provideo PV150A-1" },
{ 0x1461aa01, BTTV_PV150, "Provideo PV150A-2" },
{ 0x1462aa02, BTTV_PV150, "Provideo PV150A-3" },
{ 0x1463aa03, BTTV_PV150, "Provideo PV150A-4" },
 
{ 0x1464aa04, BTTV_PV150, "Provideo PV150B-1" },
{ 0x1465aa05, BTTV_PV150, "Provideo PV150B-2" },
{ 0x1466aa06, BTTV_PV150, "Provideo PV150B-3" },
{ 0x1467aa07, BTTV_PV150, "Provideo PV150B-4" },
 
{ 0xa132ff00, BTTV_IVC100, "IVC-100" },
{ 0xa1550000, BTTV_IVC200, "IVC-200" },
{ 0xa1550001, BTTV_IVC200, "IVC-200" },
{ 0xa1550002, BTTV_IVC200, "IVC-200" },
{ 0xa1550003, BTTV_IVC200, "IVC-200" },
{ 0xa1550100, BTTV_IVC200, "IVC-200G" },
{ 0xa1550101, BTTV_IVC200, "IVC-200G" },
{ 0xa1550102, BTTV_IVC200, "IVC-200G" },
{ 0xa1550103, BTTV_IVC200, "IVC-200G" },
{ 0xa182ff00, BTTV_IVC120, "IVC-120G" },
{ 0xa182ff01, BTTV_IVC120, "IVC-120G" },
{ 0xa182ff02, BTTV_IVC120, "IVC-120G" },
{ 0xa182ff03, BTTV_IVC120, "IVC-120G" },
{ 0xa182ff04, BTTV_IVC120, "IVC-120G" },
{ 0xa182ff05, BTTV_IVC120, "IVC-120G" },
{ 0xa182ff06, BTTV_IVC120, "IVC-120G" },
{ 0xa182ff07, BTTV_IVC120, "IVC-120G" },
{ 0xa182ff08, BTTV_IVC120, "IVC-120G" },
{ 0xa182ff09, BTTV_IVC120, "IVC-120G" },
{ 0xa182ff0a, BTTV_IVC120, "IVC-120G" },
{ 0xa182ff0b, BTTV_IVC120, "IVC-120G" },
{ 0xa182ff0c, BTTV_IVC120, "IVC-120G" },
{ 0xa182ff0d, BTTV_IVC120, "IVC-120G" },
{ 0xa182ff0e, BTTV_IVC120, "IVC-120G" },
{ 0xa182ff0f, BTTV_IVC120, "IVC-120G" },
{ 0x41424344, BTTV_GRANDTEC, "GrandTec Multi Capture" },
{ 0x01020304, BTTV_XGUARD, "Grandtec Grand X-Guard" },
{ 0x010115cb, BTTV_GMV1, "AG GMV1" },
{ 0x010114c7, BTTV_MODTEC_205, "Modular Technology MM205 PCTV" },
{ 0x18501851, BTTV_CHRONOS_VS2, "Flyvideo 98 (LR50)/ Chronos Video Shuttle II" },
{ 0x18511851, BTTV_FLYVIDEO98EZ, "Flyvideo 98EZ (LR51)/ CyberMail AV" },
{ 0x18521852, BTTV_TYPHOON_TVIEW, "Flyvideo 98FM (LR50)/ Typhoon TView TV/FM Tuner" },
{ 0x010114c7, BTTV_MODTEC_205, "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV" },
{ 0x18501851, BTTV_CHRONOS_VS2, "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" },
{ 0x18511851, BTTV_FLYVIDEO98EZ, "FlyVideo 98EZ (LR51)/ CyberMail AV" },
{ 0x18521852, BTTV_TYPHOON_TVIEW, "FlyVideo 98FM (LR50)/ Typhoon TView TV/FM Tuner" },
{ 0x10b42636, BTTV_HAUPPAUGE878, "STB ???" },
{ 0x217d6606, BTTV_WINFAST2000, "Leadtek WinFast TV 2000" },
{ 0x03116000, BTTV_SENSORAY311, "Sensoray 311" },
{ 0x00790e11, BTTV_WINDVR, "Canopus WinDVR PCI" },
{ 0xa0fca1a0, BTTV_ZOLTRIX, "Face to Face Tvmax" },
{ 0x0350109e, BTTV_PXC200, "Imagenation PXC200" },
{ 0x01010071, BTTV_NEBULA_DIGITV, "Nebula Electronics DigiTV" },
 
// likely broken, vendor id doesn't match the other magic views ...
//{ 0xa0fca04f, BTTV_MAGICTVIEW063, "Guillemot Maxi TV Video 3" },
{ 0, -1, NULL }
};
 
148,1144 → 274,1587
struct tvcard bttv_tvcards[] = {
{
/* ---- card 0x00 ---------------------------------- */
name: " *** UNKNOWN/GENERIC *** ",
video_inputs: 4,
audio_inputs: 1,
tuner: 0,
svhs: 2,
muxsel: { 2, 3, 1, 0},
tuner_type: -1,
.name = " *** UNKNOWN/GENERIC *** ",
.video_inputs = 4,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.muxsel = { 2, 3, 1, 0},
.tuner_type = -1,
},{
name: "MIRO PCTV",
video_inputs: 4,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 15,
muxsel: { 2, 3, 1, 1},
audiomux: { 2, 0, 0, 0, 10},
needs_tvaudio: 1,
tuner_type: -1,
.name = "MIRO PCTV",
.video_inputs = 4,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 15,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 2, 0, 0, 0, 10},
.needs_tvaudio = 1,
.tuner_type = -1,
},{
name: "Hauppauge (bt848)",
video_inputs: 4,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 7,
muxsel: { 2, 3, 1, 1},
audiomux: { 0, 1, 2, 3, 4},
needs_tvaudio: 1,
tuner_type: -1,
.name = "Hauppauge (bt848)",
.video_inputs = 4,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 7,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 0, 1, 2, 3, 4},
.needs_tvaudio = 1,
.tuner_type = -1,
},{
name: "STB",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 7,
muxsel: { 2, 3, 1, 1},
audiomux: { 4, 0, 2, 3, 1},
no_msp34xx: 1,
needs_tvaudio: 1,
tuner_type: -1,
.name = "STB, Gateway P/N 6000699 (bt848)",
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 7,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 4, 0, 2, 3, 1},
.no_msp34xx = 1,
.needs_tvaudio = 1,
.tuner_type = TUNER_PHILIPS_NTSC,
.pll = PLL_28,
.has_radio = 1,
},{
 
/* ---- card 0x04 ---------------------------------- */
name: "Intel",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: -1,
gpiomask: 7,
muxsel: { 2, 3, 1, 1},
audiomux: { 0, 1, 2, 3, 4},
needs_tvaudio: 1,
tuner_type: -1,
.name = "Intel Create and Share PCI/ Smart Video Recorder III",
.video_inputs = 4,
.audio_inputs = 0,
.tuner = -1,
.svhs = 2,
.gpiomask = 0,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 0 },
.needs_tvaudio = 0,
.tuner_type = 4,
},{
name: "Diamond DTV2000",
video_inputs: 4,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 3,
muxsel: { 2, 3, 1, 0},
audiomux: { 0, 1, 0, 1, 3},
needs_tvaudio: 1,
tuner_type: -1,
.name = "Diamond DTV2000",
.video_inputs = 4,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 3,
.muxsel = { 2, 3, 1, 0},
.audiomux = { 0, 1, 0, 1, 3},
.needs_tvaudio = 1,
.tuner_type = -1,
},{
name: "AVerMedia TVPhone",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 3,
muxsel: { 2, 3, 1, 1},
gpiomask: 0x0f,
audiomux: { 0x0c, 0x04, 0x08, 0x04, 0},
.name = "AVerMedia TVPhone",
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
.svhs = 3,
.muxsel = { 2, 3, 1, 1},
.gpiomask = 0x0f,
.audiomux = { 0x0c, 0x04, 0x08, 0x04, 0},
/* 0x04 for some cards ?? */
needs_tvaudio: 1,
tuner_type: -1,
audio_hook: avermedia_tvphone_audio,
.needs_tvaudio = 1,
.tuner_type = -1,
.audio_hook = avermedia_tvphone_audio,
},{
name: "MATRIX-Vision MV-Delta",
video_inputs: 5,
audio_inputs: 1,
tuner: -1,
svhs: 3,
gpiomask: 0,
muxsel: { 2, 3, 1, 0, 0},
audiomux: {0 },
needs_tvaudio: 1,
tuner_type: -1,
.name = "MATRIX-Vision MV-Delta",
.video_inputs = 5,
.audio_inputs = 1,
.tuner = -1,
.svhs = 3,
.gpiomask = 0,
.muxsel = { 2, 3, 1, 0, 0},
.audiomux = {0 },
.needs_tvaudio = 1,
.tuner_type = -1,
},{
 
/* ---- card 0x08 ---------------------------------- */
name: "FlyVideo II (Bt848) LR26",
video_inputs: 4,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 0xc00,
muxsel: { 2, 3, 1, 1},
audiomux: { 0, 0xc00, 0x800, 0x400, 0xc00, 0},
needs_tvaudio: 1,
pll: PLL_28,
tuner_type: -1,
.name = "Lifeview FlyVideo II (Bt848) LR26 / MAXI TV Video PCI2 LR26",
.video_inputs = 4,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 0xc00,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 0, 0xc00, 0x800, 0x400, 0xc00, 0},
.needs_tvaudio = 1,
.pll = PLL_28,
.tuner_type = -1,
},{
name: "IXMicro TurboTV",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 3,
muxsel: { 2, 3, 1, 1},
audiomux: { 1, 1, 2, 3, 0},
needs_tvaudio: 1,
tuner_type: -1,
.name = "IMS/IXmicro TurboTV",
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 3,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 1, 1, 2, 3, 0},
.needs_tvaudio = 0,
.pll = PLL_28,
.tuner_type = TUNER_TEMIC_PAL,
},{
name: "Hauppauge (bt878)",
video_inputs: 4,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 0x0f, /* old: 7 */
muxsel: { 2, 0, 1, 1},
audiomux: { 0, 1, 2, 3, 4},
needs_tvaudio: 1,
pll: PLL_28,
tuner_type: -1,
.name = "Hauppauge (bt878)",
.video_inputs = 4,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 0x0f, /* old: 7 */
.muxsel = { 2, 0, 1, 1},
.audiomux = { 0, 1, 2, 3, 4},
.needs_tvaudio = 1,
.pll = PLL_28,
.tuner_type = -1,
},{
name: "MIRO PCTV pro",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 0x3014f,
muxsel: { 2, 3, 1, 1},
audiomux: { 0x20001,0x10001, 0, 0,10},
needs_tvaudio: 1,
tuner_type: -1,
.name = "MIRO PCTV pro",
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 0x3014f,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 0x20001,0x10001, 0, 0,10},
.needs_tvaudio = 1,
.tuner_type = -1,
},{
 
/* ---- card 0x0c ---------------------------------- */
name: "ADS Technologies Channel Surfer TV",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 15,
muxsel: { 2, 3, 1, 1},
audiomux: { 13, 14, 11, 7, 0, 0},
needs_tvaudio: 1,
tuner_type: -1,
.name = "ADS Technologies Channel Surfer TV (bt848)",
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 15,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 13, 14, 11, 7, 0, 0},
.needs_tvaudio = 1,
.tuner_type = -1,
},{
name: "AVerMedia TVCapture 98",
video_inputs: 3,
audio_inputs: 4,
tuner: 0,
svhs: 2,
gpiomask: 15,
muxsel: { 2, 3, 1, 1},
audiomux: { 13, 14, 11, 7, 0, 0},
needs_tvaudio: 1,
pll: PLL_28,
tuner_type: -1,
.name = "AVerMedia TVCapture 98",
.video_inputs = 3,
.audio_inputs = 4,
.tuner = 0,
.svhs = 2,
.gpiomask = 15,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 13, 14, 11, 7, 0, 0},
.needs_tvaudio = 1,
.msp34xx_alt = 1,
.pll = PLL_28,
.tuner_type = TUNER_PHILIPS_PAL,
},{
name: "Aimslab Video Highway Xtreme (VHX)",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 7,
muxsel: { 2, 3, 1, 1},
audiomux: { 0, 2, 1, 3, 4}, /* old: { 0, 1, 2, 3, 4} */
needs_tvaudio: 1,
tuner_type: -1,
.name = "Aimslab Video Highway Xtreme (VHX)",
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 7,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 0, 2, 1, 3, 4}, /* old: { 0, 1, 2, 3, 4} */
.needs_tvaudio = 1,
.pll = PLL_28,
.tuner_type = -1,
},{
name: "Zoltrix TV-Max",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 15,
muxsel: { 2, 3, 1, 1},
audiomux: {0 , 0, 1 , 0, 10},
needs_tvaudio: 1,
tuner_type: -1,
.name = "Zoltrix TV-Max",
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 15,
.muxsel = { 2, 3, 1, 1},
.audiomux = {0 , 0, 1 , 0, 10},
.needs_tvaudio = 1,
.tuner_type = -1,
},{
 
/* ---- card 0x10 ---------------------------------- */
name: "Pixelview PlayTV (bt878)",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 0x01fe00,
muxsel: { 2, 3, 1, 1},
audiomux: { 0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 },
needs_tvaudio: 1,
pll: PLL_28,
tuner_type: -1,
.name = "Prolink Pixelview PlayTV (bt878)",
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 0x01fe00,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 },
.needs_tvaudio = 1,
.pll = PLL_28,
.tuner_type = -1,
},{
name: "Leadtek WinView 601",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 0x8300f8,
muxsel: { 2, 3, 1, 1,0},
audiomux: { 0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007},
needs_tvaudio: 1,
tuner_type: -1,
audio_hook: winview_audio,
has_radio: 1,
.name = "Leadtek WinView 601",
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 0x8300f8,
.muxsel = { 2, 3, 1, 1,0},
.audiomux = { 0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007},
.needs_tvaudio = 1,
.tuner_type = -1,
.audio_hook = winview_audio,
.has_radio = 1,
},{
name: "AVEC Intercapture",
video_inputs: 3,
audio_inputs: 2,
tuner: 0,
svhs: 2,
gpiomask: 0,
muxsel: {2, 3, 1, 1},
audiomux: {1, 0, 0, 0, 0},
needs_tvaudio: 1,
tuner_type: -1,
.name = "AVEC Intercapture",
.video_inputs = 3,
.audio_inputs = 2,
.tuner = 0,
.svhs = 2,
.gpiomask = 0,
.muxsel = {2, 3, 1, 1},
.audiomux = {1, 0, 0, 0, 0},
.needs_tvaudio = 1,
.tuner_type = -1,
},{
name: "LifeView FlyKit w/o Tuner",
video_inputs: 3,
audio_inputs: 1,
tuner: -1,
svhs: -1,
gpiomask: 0x8dff00,
muxsel: { 2, 3, 1, 1},
audiomux: { 0 },
no_msp34xx: 1,
tuner_type: -1,
.name = "Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)",
.video_inputs = 4,
.audio_inputs = 1,
.tuner = -1,
.svhs = -1,
.gpiomask = 0x8dff00,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 0 },
.no_msp34xx = 1,
.tuner_type = -1,
},{
 
/* ---- card 0x14 ---------------------------------- */
name: "CEI Raffles Card",
video_inputs: 3,
audio_inputs: 3,
tuner: 0,
svhs: 2,
muxsel: {2, 3, 1, 1},
tuner_type: -1,
.name = "CEI Raffles Card",
.video_inputs = 3,
.audio_inputs = 3,
.tuner = 0,
.svhs = 2,
.muxsel = {2, 3, 1, 1},
.tuner_type = -1,
},{
name: "Lucky Star Image World ConferenceTV",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 0x00fffe07,
muxsel: { 2, 3, 1, 1},
audiomux: { 131072, 1, 1638400, 3, 4},
needs_tvaudio: 1,
pll: PLL_28,
tuner_type: TUNER_PHILIPS_PAL_I,
.name = "Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50",
.video_inputs = 4,
.audio_inputs = 2, // tuner, line in
.tuner = 0,
.svhs = 2,
.gpiomask = 0x1800,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 0, 0x800, 0x1000, 0x1000, 0x1800},
.pll = PLL_28,
.tuner_type = TUNER_PHILIPS_PAL_I,
},{
name: "Phoebe Tv Master + FM (CPH050)",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 0xc00,
muxsel: { 2, 3, 1, 1},
audiomux: {0, 1, 0x800, 0x400, 0xc00, 0},
needs_tvaudio: 1,
tuner_type: -1,
.name = "Askey CPH050/ Phoebe Tv Master + FM",
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 0xc00,
.muxsel = { 2, 3, 1, 1},
.audiomux = {0, 1, 0x800, 0x400, 0xc00, 0},
.needs_tvaudio = 1,
.pll = PLL_28,
.tuner_type = -1,
},{
name: "Modular Technology MM205 PCTV, bt878",
video_inputs: 2,
audio_inputs: 1,
tuner: 0,
svhs: -1,
gpiomask: 7,
muxsel: { 2, 3 },
audiomux: { 0, 0, 0, 0, 0 },
no_msp34xx: 1,
pll: PLL_28,
tuner_type: TUNER_ALPS_TSBB5_PAL_I,
.name = "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV, bt878",
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
.svhs = -1,
.gpiomask = 7,
.muxsel = { 2, 3, -1 },
.digital_mode = DIGITAL_MODE_CAMERA,
.audiomux = { 0, 0, 0, 0, 0 },
.no_msp34xx = 1,
.pll = PLL_28,
.tuner_type = TUNER_ALPS_TSBB5_PAL_I,
},{
 
/* ---- card 0x18 ---------------------------------- */
name: "[many vendors] CPH05X/06X (bt878)",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 0xe00,
muxsel: { 2, 3, 1, 1},
audiomux: {0x400, 0x400, 0x400, 0x400, 0xc00},
needs_tvaudio: 1,
pll: PLL_28,
tuner_type: -1,
.name = "Askey CPH05X/06X (bt878) [many vendors]",
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 0xe00,
.muxsel = { 2, 3, 1, 1},
.audiomux = {0x400, 0x400, 0x400, 0x400, 0xc00},
.needs_tvaudio = 1,
.pll = PLL_28,
.tuner_type = -1,
},{
name: "Terratec/Vobis TV-Boostar",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 16777215,
muxsel: { 2, 3, 1, 1},
audiomux: { 131072, 1, 1638400, 3,4},
needs_tvaudio: 1,
tuner_type: -1,
.name = "Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar",
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 0x1f0fff,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 0x20000, 0x30000, 0x10000, 0, 0x40000},
.needs_tvaudio = 0,
.tuner_type = TUNER_PHILIPS_PAL,
.audio_hook = terratv_audio,
},{
name: "Newer Hauppauge WinCam (bt878)",
video_inputs: 4,
audio_inputs: 1,
tuner: 0,
svhs: 3,
gpiomask: 7,
muxsel: { 2, 0, 1, 1},
audiomux: { 0, 1, 2, 3, 4},
needs_tvaudio: 1,
tuner_type: -1,
.name = "Hauppauge WinCam newer (bt878)",
.video_inputs = 4,
.audio_inputs = 1,
.tuner = 0,
.svhs = 3,
.gpiomask = 7,
.muxsel = { 2, 0, 1, 1},
.audiomux = { 0, 1, 2, 3, 4},
.needs_tvaudio = 1,
.tuner_type = -1,
},{
name: "MAXI TV Video PCI2",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 0xffff,
muxsel: { 2, 3, 1, 1},
audiomux: { 0, 1, 2, 3, 0xc00},
needs_tvaudio: 1,
tuner_type: TUNER_PHILIPS_SECAM,
.name = "Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50",
.video_inputs = 4,
.audio_inputs = 2,
.tuner = 0,
.svhs = 2,
.gpiomask = 0x1800,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 0, 0x800, 0x1000, 0x1000, 0x1800},
.pll = PLL_28,
.tuner_type = TUNER_PHILIPS_SECAM,
},{
 
/* ---- card 0x1c ---------------------------------- */
name: "Terratec TerraTV+",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 0x70000,
muxsel: { 2, 3, 1, 1},
audiomux: { 0x20000, 0x30000, 0x10000, 0x00000, 0x40000},
needs_tvaudio: 1,
tuner_type: TUNER_PHILIPS_PAL,
audio_hook: terratv_audio,
.name = "Terratec TerraTV+ Version 1.1 (bt878)",
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 0x1f0fff,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 0x20000, 0x30000, 0x10000, 0x00000, 0x40000},
.needs_tvaudio = 0,
.tuner_type = TUNER_PHILIPS_PAL,
.audio_hook = terratv_audio,
/* GPIO wiring:
External 20 pin connector (for Active Radio Upgrade board)
gpio00: i2c-sda
gpio01: i2c-scl
gpio02: om5610-data
gpio03: om5610-clk
gpio04: om5610-wre
gpio05: om5610-stereo
gpio06: rds6588-davn
gpio07: Pin 7 n.c.
gpio08: nIOW
gpio09+10: nIOR, nSEL ?? (bt878)
gpio09: nIOR (bt848)
gpio10: nSEL (bt848)
Sound Routing:
gpio16: u2-A0 (1st 4052bt)
gpio17: u2-A1
gpio18: u2-nEN
gpio19: u4-A0 (2nd 4052)
gpio20: u4-A1
u4-nEN - GND
Btspy:
00000 : Cdrom (internal audio input)
10000 : ext. Video audio input
20000 : TV Mono
a0000 : TV Mono/2
1a0000 : TV Stereo
30000 : Radio
40000 : Mute
*/
 
},{
/* Jannik Fritsch <jannik@techfak.uni-bielefeld.de> */
name: "Imagenation PXC200",
video_inputs: 5,
audio_inputs: 1,
tuner: -1,
svhs: 1, /* was: 4 */
gpiomask: 0,
muxsel: { 2, 3, 1, 0, 0},
audiomux: { 0 },
needs_tvaudio: 1,
tuner_type: -1,
.name = "Imagenation PXC200",
.video_inputs = 5,
.audio_inputs = 1,
.tuner = -1,
.svhs = 1, /* was: 4 */
.gpiomask = 0,
.muxsel = { 2, 3, 1, 0, 0},
.audiomux = { 0 },
.needs_tvaudio = 1,
.tuner_type = -1,
},{
name: "FlyVideo 98",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 0x1800, //0x8dfe00
muxsel: {2, 3, 1, 1},
audiomux: { 0, 0x0800, 0x1000, 0x1000, 0x1800, 0 },
needs_tvaudio: 1,
tuner_type: -1,
.name = "Lifeview FlyVideo 98 LR50",
.video_inputs = 4,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 0x1800, //0x8dfe00
.muxsel = { 2, 3, 1, 1},
.audiomux = { 0, 0x0800, 0x1000, 0x1000, 0x1800, 0 },
.pll = PLL_28,
.tuner_type = -1,
},{
name: "iProTV",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 1,
muxsel: { 2, 3, 1, 1},
audiomux: { 1, 0, 0, 0, 0 },
tuner_type: -1,
.name = "Formac iProTV, Formac ProTV I (bt848)",
.video_inputs = 4,
.audio_inputs = 1,
.tuner = 0,
.svhs = 3,
.gpiomask = 1,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 1, 0, 0, 0, 0 },
.pll = PLL_28,
.tuner_type = TUNER_PHILIPS_PAL,
},{
 
/* ---- card 0x20 ---------------------------------- */
name: "Intel Create and Share PCI",
video_inputs: 4,
audio_inputs: 1,
tuner: -1,
svhs: 2,
gpiomask: 7,
muxsel: { 2, 3, 1, 1},
audiomux: { 4, 4, 4, 4, 4},
needs_tvaudio: 1,
tuner_type: -1,
.name = "Intel Create and Share PCI/ Smart Video Recorder III",
.video_inputs = 4,
.audio_inputs = 0,
.tuner = -1,
.svhs = 2,
.gpiomask = 0,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 0 },
.needs_tvaudio = 0,
.tuner_type = 4,
},{
name: "Terratec TerraTValue",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 0xffff00,
muxsel: { 2, 3, 1, 1},
audiomux: { 0x500, 0, 0x300, 0x900, 0x900},
needs_tvaudio: 1,
pll: PLL_28,
tuner_type: TUNER_PHILIPS_PAL,
.name = "Terratec TerraTValue Version Bt878",
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 0xffff00,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 0x500, 0, 0x300, 0x900, 0x900},
.needs_tvaudio = 1,
.pll = PLL_28,
.tuner_type = TUNER_PHILIPS_PAL,
},{
name: "Leadtek WinFast 2000",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 0xc33000,
muxsel: { 2, 3, 1, 1,0},
audiomux: { 0x422000,0x001000,0x621100,0x620000,0x800000,0x620000},
needs_tvaudio: 0,
pll: PLL_28,
tuner_type: -1,
audio_hook: winfast2000_audio,
.name = "Leadtek WinFast 2000/ WinFast 2000 XP",
.video_inputs = 4,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 0xc33000,
.muxsel = { 2, 3, 1, 1, 0}, // TV, CVid, SVid, CVid over SVid connector
.audiomux = { 0x422000,0x1000,0x0000,0x620000,0x800000},
/* Audio Routing for "WinFast 2000 XP" (no tv stereo !)
gpio23 -- hef4052:nEnable (0x800000)
gpio12 -- hef4052:A1
gpio13 -- hef4052:A0
0x0000: external audio
0x1000: FM
0x2000: TV
0x3000: n.c.
Note: There exists another variant "Winfast 2000" with tv stereo !?
Note: eeprom only contains FF and pci subsystem id 107d:6606
*/
.needs_tvaudio = 0,
.pll = PLL_28,
.has_radio = 1,
.tuner_type = 5, // default for now, gpio reads BFFF06 for Pal bg+dk
.audio_hook = winfast2000_audio,
},{
name: "Flyvideo 98 (LR50Q) / Chronos Video Shuttle II",
video_inputs: 3,
audio_inputs: 3,
tuner: 0,
svhs: 2,
gpiomask: 0x1800,
muxsel: { 2, 3, 1, 1},
audiomux: { 0, 0x800, 0x1000, 0x1000, 0x1800},
needs_tvaudio: 1,
pll: PLL_28,
tuner_type: -1,
.name = "Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II",
.video_inputs = 4,
.audio_inputs = 3,
.tuner = 0,
.svhs = 2,
.gpiomask = 0x1800,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 0, 0x800, 0x1000, 0x1000, 0x1800},
.pll = PLL_28,
.tuner_type = -1,
},{
 
/* ---- card 0x24 ---------------------------------- */
name: "Flyvideo 98FM (LR50Q) / Typhoon TView TV/FM Tuner",
video_inputs: 3,
audio_inputs: 3,
tuner: 0,
svhs: 2,
gpiomask: 0x1800,
muxsel: { 2, 3, 1, 1},
audiomux: { 0, 0x800, 0x1000, 0x1000, 0x1800, 0 },
needs_tvaudio: 1,
pll: PLL_28,
tuner_type: -1,
has_radio: 1,
.name = "Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner",
.video_inputs = 4,
.audio_inputs = 3,
.tuner = 0,
.svhs = 2,
.gpiomask = 0x1800,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 0, 0x800, 0x1000, 0x1000, 0x1800, 0 },
.pll = PLL_28,
.tuner_type = -1,
.has_radio = 1,
},{
name: "PixelView PlayTV pro",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 0xff,
muxsel: { 2, 3, 1, 1 },
audiomux: { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 },
no_msp34xx: 1,
pll: PLL_28,
tuner_type: -1,
.name = "Prolink PixelView PlayTV pro",
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 0xff,
.muxsel = { 2, 3, 1, 1 },
.audiomux = { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 },
.no_msp34xx = 1,
.pll = PLL_28,
.tuner_type = -1,
},{
name: "TView99 CPH06X",
video_inputs: 4,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 0x551e00,
muxsel: { 2, 3, 1, 0},
audiomux: { 0x551400, 0x551200, 0, 0, 0x551c00, 0x551200 },
needs_tvaudio: 1,
pll: PLL_28,
tuner_type: -1,
.name = "Askey CPH06X TView99",
.video_inputs = 4,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 0x551e00,
.muxsel = { 2, 3, 1, 0},
.audiomux = { 0x551400, 0x551200, 0, 0, 0x551c00, 0x551200 },
.needs_tvaudio = 1,
.pll = PLL_28,
.tuner_type = 1,
},{
name: "Pinnacle PCTV Studio/Rave",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 0x03000F,
muxsel: { 2, 3, 1, 1},
audiomux: { 2, 0, 0, 0, 1},
needs_tvaudio: 1,
pll: PLL_28,
tuner_type: -1,
.name = "Pinnacle PCTV Studio/Rave",
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 0x03000F,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 2, 0, 0, 0, 1},
.needs_tvaudio = 1,
.pll = PLL_28,
.tuner_type = -1,
},{
 
/* ---- card 0x28 ---------------------------------- */
name: "STB2",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 7,
muxsel: { 2, 3, 1, 1},
audiomux: { 4, 0, 2, 3, 1},
no_msp34xx: 1,
needs_tvaudio: 1,
tuner_type: -1,
.name = "STB TV PCI FM, Gateway P/N 6000704 (bt878), 3Dfx VoodooTV 100",
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 7,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 4, 0, 2, 3, 1},
.no_msp34xx = 1,
.needs_tvaudio = 1,
.tuner_type = TUNER_PHILIPS_NTSC,
.pll = PLL_28,
.has_radio = 1,
},{
name: "AVerMedia TVPhone 98",
video_inputs: 3,
audio_inputs: 4,
tuner: 0,
svhs: 2,
gpiomask: 12,
muxsel: { 2, 3, 1, 1},
audiomux: { 13, 4, 11, 7, 0, 0},
needs_tvaudio: 1,
pll: PLL_28,
tuner_type: -1,
has_radio: 1,
.name = "AVerMedia TVPhone 98",
.video_inputs = 3,
.audio_inputs = 4,
.tuner = 0,
.svhs = 2,
.gpiomask = 15,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 13, 4, 11, 7, 0, 0},
.needs_tvaudio = 1,
.pll = PLL_28,
.tuner_type = -1,
.has_radio = 1,
.audio_hook = avermedia_tvphone_audio,
},{
name: "ProVideo PV951", /* pic16c54 */
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 0,
muxsel: { 2, 3, 1, 1},
audiomux: { 0, 0, 0, 0, 0},
no_msp34xx: 1,
pll: PLL_28,
tuner_type: 1,
.name = "ProVideo PV951", /* pic16c54 */
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 0,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 0, 0, 0, 0, 0},
.needs_tvaudio = 1,
.no_msp34xx = 1,
.pll = PLL_28,
.tuner_type = 1,
},{
name: "Little OnAir TV",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 0xe00b,
muxsel: {2, 3, 1, 1},
audiomux: {0xff9ff6, 0xff9ff6, 0xff1ff7, 0, 0xff3ffc},
no_msp34xx: 1,
tuner_type: -1,
.name = "Little OnAir TV",
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 0xe00b,
.muxsel = {2, 3, 1, 1},
.audiomux = {0xff9ff6, 0xff9ff6, 0xff1ff7, 0, 0xff3ffc},
.no_msp34xx = 1,
.tuner_type = -1,
},{
 
/* ---- card 0x2c ---------------------------------- */
name: "Sigma TVII-FM",
video_inputs: 2,
audio_inputs: 1,
tuner: 0,
svhs: -1,
gpiomask: 3,
muxsel: {2, 3, 1, 1},
audiomux: {1, 1, 0, 2, 3},
no_msp34xx: 1,
pll: PLL_NONE,
tuner_type: -1,
.name = "Sigma TVII-FM",
.video_inputs = 2,
.audio_inputs = 1,
.tuner = 0,
.svhs = -1,
.gpiomask = 3,
.muxsel = {2, 3, 1, 1},
.audiomux = {1, 1, 0, 2, 3},
.no_msp34xx = 1,
.pll = PLL_NONE,
.tuner_type = -1,
},{
name: "MATRIX-Vision MV-Delta 2",
video_inputs: 5,
audio_inputs: 1,
tuner: -1,
svhs: 3,
gpiomask: 0,
muxsel: { 2, 3, 1, 0, 0},
audiomux: {0 },
no_msp34xx: 1,
pll: PLL_28,
tuner_type: -1,
.name = "MATRIX-Vision MV-Delta 2",
.video_inputs = 5,
.audio_inputs = 1,
.tuner = -1,
.svhs = 3,
.gpiomask = 0,
.muxsel = { 2, 3, 1, 0, 0},
.audiomux = {0 },
.no_msp34xx = 1,
.pll = PLL_28,
.tuner_type = -1,
},{
name: "Zoltrix Genie TV/FM",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 0xbcf03f,
muxsel: { 2, 3, 1, 1},
audiomux: { 0xbc803f, 0xbc903f, 0xbcb03f, 0, 0xbcb03f},
no_msp34xx: 1,
pll: PLL_28,
tuner_type: 21,
.name = "Zoltrix Genie TV/FM",
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 0xbcf03f,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 0xbc803f, 0xbc903f, 0xbcb03f, 0, 0xbcb03f},
.no_msp34xx = 1,
.pll = PLL_28,
.tuner_type = 21,
},{
name: "Terratec TV/Radio+",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 0x1f0000,
muxsel: { 2, 3, 1, 1},
audiomux: { 0xe2ffff, 0xebffff, 0, 0, 0xe0ffff, 0xe2ffff },
needs_tvaudio: 1,
no_msp34xx: 1,
pll: PLL_35,
tuner_type: 1,
has_radio: 1,
.name = "Terratec TV/Radio+",
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 0x70000,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 0x20000, 0x30000, 0x10000, 0, 0x40000, 0x20000 },
.needs_tvaudio = 1,
.no_msp34xx = 1,
.pll = PLL_35,
.tuner_type = 1,
.has_radio = 1,
},{
 
/* ---- card 0x30 ---------------------------------- */
name: "Dynalink Magic TView ",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 15,
muxsel: { 2, 3, 1, 1},
audiomux: {2,0,0,0,1},
needs_tvaudio: 1,
pll: PLL_28,
tuner_type: -1,
.name = "Askey CPH03x/ Dynalink Magic TView",
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 15,
.muxsel = { 2, 3, 1, 1},
.audiomux = {2,0,0,0,1},
.needs_tvaudio = 1,
.pll = PLL_28,
.tuner_type = -1,
},{
name: "IODATA GV-BCTV3/PCI",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 0x010f00,
muxsel: {2, 3, 0, 0},
audiomux: {0x10000, 0, 0x10000, 0, 0, 0},
no_msp34xx: 1,
pll: PLL_28,
tuner_type: TUNER_ALPS_TSHC6_NTSC,
audio_hook: gvbctv3pci_audio,
.name = "IODATA GV-BCTV3/PCI",
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 0x010f00,
.muxsel = {2, 3, 0, 0},
.audiomux = {0x10000, 0, 0x10000, 0, 0, 0},
.no_msp34xx = 1,
.pll = PLL_28,
.tuner_type = TUNER_ALPS_TSHC6_NTSC,
.audio_hook = gvbctv3pci_audio,
},{
name: "Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP",
video_inputs: 4,
audio_inputs: 1,
tuner: 0,
svhs: 3,
gpiomask: 0xAA0000,
muxsel: { 2,3,1,1 },
audiomux: { 0x20000, 0, 0x80000, 0x80000, 0xa8000, 0x46000 },
no_msp34xx: 1,
pll: PLL_28,
tuner_type: TUNER_PHILIPS_PAL_I,
.name = "Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP",
.video_inputs = 5,
.audio_inputs = 1,
.tuner = 0,
.svhs = 3,
.gpiomask = 0xAA0000,
.muxsel = { 2,3,1,1,-1 },
.digital_mode = DIGITAL_MODE_CAMERA,
.audiomux = { 0x20000, 0, 0x80000, 0x80000, 0xa8000, 0x46000 },
.no_msp34xx = 1,
.pll = PLL_28,
.tuner_type = TUNER_PHILIPS_PAL_I,
/* GPIO wiring: (different from Rev.4C !)
GPIO17: U4.A0 (first hef4052bt)
GPIO19: U4.A1
GPIO20: U5.A1 (second hef4052bt)
GPIO21: U4.nEN
GPIO22: BT832 Reset Line
GPIO23: A5,A0, U5,nEN
Note: At i2c=0x8a is a Bt832 chip, which changes to 0x88 after being reset via GPIO22
*/
},{
name: "Eagle Wireless Capricorn2 (bt878A)",
video_inputs: 4,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 7,
muxsel: { 2, 0, 1, 1},
audiomux: { 0, 1, 2, 3, 4},
pll: PLL_28,
tuner_type: -1 /* TUNER_ALPS_TMDH2_NTSC */,
.name = "Eagle Wireless Capricorn2 (bt878A)",
.video_inputs = 4,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 7,
.muxsel = { 2, 0, 1, 1},
.audiomux = { 0, 1, 2, 3, 4},
.pll = PLL_28,
.tuner_type = -1 /* TUNER_ALPS_TMDH2_NTSC */,
},{
 
/* ---- card 0x34 ---------------------------------- */
/* David H€rdeman <david@2gen.com> */
name: "Pinnacle PCTV Studio Pro",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 0x03000F,
muxsel: { 2, 3, 1, 1},
audiomux: { 1, 0x10001, 0, 0, 10},
needs_tvaudio: 1,
pll: PLL_28,
tuner_type: -1,
/* David Härdeman <david@2gen.com> */
.name = "Pinnacle PCTV Studio Pro",
.video_inputs = 4,
.audio_inputs = 1,
.tuner = 0,
.svhs = 3,
.gpiomask = 0x03000F,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 1, 0xd0001, 0, 0, 10},
/* sound path (5 sources):
MUX1 (mask 0x03), Enable Pin 0x08 (0=enable, 1=disable)
0= ext. Audio IN
1= from MUX2
2= Mono TV sound from Tuner
3= not connected
MUX2 (mask 0x30000):
0,2,3= from MSP34xx
1= FM stereo Radio from Tuner */
.needs_tvaudio = 1,
.pll = PLL_28,
.tuner_type = -1,
},{
/* Claas Langbehn <claas@bigfoot.com>,
Sven Grothklags <sven@upb.de> */
name: "Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS",
video_inputs: 3,
audio_inputs: 3,
tuner: 0,
svhs: 2,
gpiomask: 0x1c,
muxsel: { 2, 3, 1, 1},
audiomux: { 0, 0, 0x10, 8, 4 },
needs_tvaudio: 1,
pll: PLL_28,
tuner_type: TUNER_PHILIPS_PAL_I,
has_radio: 1,
.name = "Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS",
.video_inputs = 3,
.audio_inputs = 3,
.tuner = 0,
.svhs = 2,
.gpiomask = 0x1c,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 0, 0, 0x10, 8, 4 },
.needs_tvaudio = 1,
.pll = PLL_28,
.tuner_type = TUNER_PHILIPS_PAL_I,
.has_radio = 1,
},{
/* Tim R€stermundt <rosterm@uni-muenster.de>
/* Tim Röstermundt <rosterm@uni-muenster.de>
in de.comp.os.unix.linux.hardware:
options bttv card=0 pll=1 radio=1 gpiomask=0x18e0
audiomux=0x44c71f,0x44d71f,0,0x44d71f,0x44dfff
options tuner type=5 */
name: "Lifetec LT 9415 TV (LR90 Rev.F)",
video_inputs: 4,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 0x18e0,
muxsel: { 2, 3, 1, 1},
audiomux: { 0x0000,0x0800,0x1000,0x1000,0x18e0 },
/* 0x0000: Tuner normal stereo
.name = "Lifeview FlyVideo 2000 /FlyVideo A2/ Lifetec LT 9415 TV [LR90]",
.video_inputs = 4,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 0x18e0,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 0x0000,0x0800,0x1000,0x1000,0x18e0 },
/* For cards with tda9820/tda9821:
0x0000: Tuner normal stereo
0x0080: Tuner A2 SAP (second audio program = Zweikanalton)
0x0880: Tuner A2 stereo */
pll: PLL_28,
tuner_type: TUNER_PHILIPS_PAL,
audio_hook: lt9415_audio,
has_radio: 1,
.pll = PLL_28,
.tuner_type = -1,
},{
/* Miguel Angel Alvarez <maacruz@navegalia.com>
old Easy TV BT848 version (model CPH031) */
name: "BESTBUY Easy TV (CPH031)",
video_inputs: 4,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 0xF,
muxsel: { 2, 3, 1, 0},
audiomux: { 2, 0, 0, 0, 10},
needs_tvaudio: 0,
pll: PLL_28,
tuner_type: TUNER_TEMIC_PAL,
.name = "Askey CPH031/ BESTBUY Easy TV",
.video_inputs = 4,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 0xF,
.muxsel = { 2, 3, 1, 0},
.audiomux = { 2, 0, 0, 0, 10},
.needs_tvaudio = 0,
.pll = PLL_28,
.tuner_type = TUNER_TEMIC_PAL,
},{
 
/* ---- card 0x38 ---------------------------------- */
/* Gordon Heydon <gjheydon@bigfoot.com ('98) */
name: "FlyVideo '98/FM",
video_inputs: 3,
audio_inputs: 3,
tuner: 0,
svhs: 2,
gpiomask: 0x1800,
muxsel: { 2, 3, 0, 1},
audiomux: { 0, 0x800, 0x1000, 0x1000, 0x1800, 0 },
needs_tvaudio: 1,
pll: PLL_28,
tuner_type: 5,
.name = "Lifeview FlyVideo 98FM LR50",
.video_inputs = 4,
.audio_inputs = 3,
.tuner = 0,
.svhs = 2,
.gpiomask = 0x1800,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 0, 0x800, 0x1000, 0x1000, 0x1800, 0 },
.pll = PLL_28,
.tuner_type = 5,
},{
/* This is the ultimate cheapo capture card
* just a BT848A on a small PCB!
* Steve Hosgood <steve@equiinet.com> */
name: "GrandTec 'Grand Video Capture' (Bt848)",
video_inputs: 2,
audio_inputs: 0,
tuner: -1,
svhs: 1,
gpiomask: 0,
muxsel: { 3, 1 },
audiomux: { 0 },
needs_tvaudio: 0,
no_msp34xx: 1,
pll: PLL_35,
tuner_type: -1,
.name = "GrandTec 'Grand Video Capture' (Bt848)",
.video_inputs = 2,
.audio_inputs = 0,
.tuner = -1,
.svhs = 1,
.gpiomask = 0,
.muxsel = { 3, 1 },
.audiomux = { 0 },
.needs_tvaudio = 0,
.no_msp34xx = 1,
.pll = PLL_35,
.tuner_type = -1,
},{
/* Daniel Herrington <daniel.herrington@home.com> */
name: "Phoebe TV Master Only (No FM) CPH060",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 0xe00,
muxsel: { 2, 3, 1, 1},
audiomux: { 0x400, 0x400, 0x400, 0x400, 0x800, 0x400 },
needs_tvaudio: 1,
pll: PLL_NONE,
tuner_type: TUNER_TEMIC_4036FY5_NTSC,
.name = "Askey CPH060/ Phoebe TV Master Only (No FM)",
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 0xe00,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 0x400, 0x400, 0x400, 0x400, 0x800, 0x400 },
.needs_tvaudio = 1,
.pll = PLL_28,
.tuner_type = TUNER_TEMIC_4036FY5_NTSC,
},{
/* Matti Mottus <mottus@physic.ut.ee> */
name: "TV Capturer (CPH03X)",
video_inputs: 4,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 0x03000F,
muxsel: { 2, 3, 1, 0},
audiomux: { 2,0,0,0,1 },
pll: PLL_28,
tuner_type: 0,
.name = "Askey CPH03x TV Capturer",
.video_inputs = 4,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 0x03000F,
.muxsel = { 2, 3, 1, 0},
.audiomux = { 2,0,0,0,1 },
.pll = PLL_28,
.tuner_type = 0,
},{
 
/* ---- card 0x3c ---------------------------------- */
/* Philip Blundell <philb@gnu.org> */
name: "Modular Technology MM100PCTV",
video_inputs: 2,
audio_inputs: 2,
tuner: 0,
svhs: -1,
gpiomask: 11,
muxsel: { 2, 3, 1, 1},
audiomux: { 2, 0, 0, 1, 8},
pll: PLL_35,
tuner_type: TUNER_TEMIC_PAL,
.name = "Modular Technology MM100PCTV",
.video_inputs = 2,
.audio_inputs = 2,
.tuner = 0,
.svhs = -1,
.gpiomask = 11,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 2, 0, 0, 1, 8},
.pll = PLL_35,
.tuner_type = TUNER_TEMIC_PAL,
 
},{
/* Adrian Cox <adrian@humboldt.co.uk */
name: "AG Electronics GMV1",
video_inputs: 2,
audio_inputs: 0,
tuner: -1,
svhs: 1,
gpiomask: 0xF,
muxsel: { 2, 2},
audiomux: { },
no_msp34xx: 1,
needs_tvaudio: 0,
pll: PLL_28,
tuner_type: -1,
.name = "AG Electronics GMV1",
.video_inputs = 2,
.audio_inputs = 0,
.tuner = -1,
.svhs = 1,
.gpiomask = 0xF,
.muxsel = { 2, 2},
.audiomux = { },
.no_msp34xx = 1,
.needs_tvaudio = 0,
.pll = PLL_28,
.tuner_type = -1,
},{
/* Miguel Angel Alvarez <maacruz@navegalia.com>
new Easy TV BT878 version (model CPH061)
special thanks to Informatica Mieres for providing the card */
name: "BESTBUY Easy TV (bt878)",
video_inputs: 3,
audio_inputs: 2,
tuner: 0,
svhs: 2,
gpiomask: 0xFF,
muxsel: { 2, 3, 1, 0},
audiomux: { 1, 0, 4, 4, 9},
needs_tvaudio: 0,
pll: PLL_28,
tuner_type: TUNER_PHILIPS_PAL,
.name = "Askey CPH061/ BESTBUY Easy TV (bt878)",
.video_inputs = 3,
.audio_inputs = 2,
.tuner = 0,
.svhs = 2,
.gpiomask = 0xFF,
.muxsel = { 2, 3, 1, 0},
.audiomux = { 1, 0, 4, 4, 9},
.needs_tvaudio = 0,
.pll = PLL_28,
.tuner_type = TUNER_PHILIPS_PAL,
},{
/* Lukas Gebauer <geby@volny.cz> */
name: "ATI TV-Wonder",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 0xf03f,
muxsel: { 2, 3, 1, 0 },
audiomux: { 0xbffe, 0, 0xbfff, 0, 0xbffe},
pll: PLL_28,
tuner_type: TUNER_TEMIC_4006FN5_MULTI_PAL,
.name = "ATI TV-Wonder",
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 0xf03f,
.muxsel = { 2, 3, 1, 0 },
.audiomux = { 0xbffe, 0, 0xbfff, 0, 0xbffe},
.pll = PLL_28,
.tuner_type = TUNER_TEMIC_4006FN5_MULTI_PAL,
},{
 
/* ---- card 0x40 ---------------------------------- */
/* Lukas Gebauer <geby@volny.cz> */
name: "ATI TV-Wonder VE",
video_inputs: 2,
audio_inputs: 1,
tuner: 0,
svhs: -1,
gpiomask: 1,
muxsel: { 2, 3, 0, 1},
audiomux: { 0, 0, 1, 0, 0},
no_msp34xx: 1,
pll: PLL_28,
tuner_type: TUNER_TEMIC_4006FN5_MULTI_PAL,
.name = "ATI TV-Wonder VE",
.video_inputs = 2,
.audio_inputs = 1,
.tuner = 0,
.svhs = -1,
.gpiomask = 1,
.muxsel = { 2, 3, 0, 1},
.audiomux = { 0, 0, 1, 0, 0},
.no_msp34xx = 1,
.pll = PLL_28,
.tuner_type = TUNER_TEMIC_4006FN5_MULTI_PAL,
},{
/* DeeJay <deejay@westel900.net (2000S) */
name: "FlyVideo 2000S",
video_inputs: 3,
audio_inputs: 3,
tuner: 0,
svhs: 2,
gpiomask: 0x18e0,
muxsel: { 2, 3, 0, 1},
.name = "Lifeview FlyVideo 2000S LR90",
.video_inputs = 3,
.audio_inputs = 3,
.tuner = 0,
.svhs = 2,
.gpiomask = 0x18e0,
.muxsel = { 2, 3, 0, 1},
/* Radio changed from 1e80 to 0x800 to make
Flyvideo2000S in .hu happy (gm)*/
FlyVideo2000S in .hu happy (gm)*/
/* -dk-???: set mute=0x1800 for tda9874h daughterboard */
audiomux: { 0x0000,0x0800,0x1000,0x1000,0x1800, 0x1080 },
audio_hook: fv2000s_audio,
no_msp34xx: 1,
no_tda9875: 1,
needs_tvaudio: 1,
pll: PLL_28,
tuner_type: 5,
.audiomux = { 0x0000,0x0800,0x1000,0x1000,0x1800, 0x1080 },
.audio_hook = fv2000s_audio,
.no_msp34xx = 1,
.no_tda9875 = 1,
.needs_tvaudio = 1,
.pll = PLL_28,
.tuner_type = 5,
},{
name: "Terratec TValueRadio",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 0xffff00,
muxsel: { 2, 3, 1, 1},
audiomux: { 0x500, 0x500, 0x300, 0x900, 0x900},
needs_tvaudio: 1,
pll: PLL_28,
tuner_type: TUNER_PHILIPS_PAL,
has_radio: 1,
.name = "Terratec TValueRadio",
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 0xffff00,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 0x500, 0x500, 0x300, 0x900, 0x900},
.needs_tvaudio = 1,
.pll = PLL_28,
.tuner_type = TUNER_PHILIPS_PAL,
.has_radio = 1,
},{
/* TANAKA Kei <peg00625@nifty.com> */
name: "IODATA GV-BCTV4/PCI",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 0x010f00,
muxsel: {2, 3, 0, 0},
audiomux: {0x10000, 0, 0x10000, 0, 0, 0},
no_msp34xx: 1,
pll: PLL_28,
tuner_type: TUNER_SHARP_2U5JF5540_NTSC,
audio_hook: gvbctv3pci_audio,
.name = "IODATA GV-BCTV4/PCI",
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 0x010f00,
.muxsel = {2, 3, 0, 0},
.audiomux = {0x10000, 0, 0x10000, 0, 0, 0},
.no_msp34xx = 1,
.pll = PLL_28,
.tuner_type = TUNER_SHARP_2U5JF5540_NTSC,
.audio_hook = gvbctv3pci_audio,
},{
 
/* ---- card 0x44 ---------------------------------- */
name: "3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)",
.name = "3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)",
// try "insmod msp3400 simple=0" if you have
// sound problems with this card.
video_inputs: 4,
audio_inputs: 1,
tuner: 0,
svhs: -1,
gpiomask: 0x4f8a00,
.video_inputs = 4,
.audio_inputs = 1,
.tuner = 0,
.svhs = -1,
.gpiomask = 0x4f8a00,
// 0x100000: 1=MSP enabled (0=disable again)
// 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC)
audiomux: {0x947fff, 0x987fff,0x947fff,0x947fff, 0x947fff},
.audiomux = {0x947fff, 0x987fff,0x947fff,0x947fff, 0x947fff},
// tvtuner, radio, external,internal, mute, stereo
/* tuner, Composit, SVid, Composit-on-Svid-adapter*/
muxsel: { 2, 3 ,0 ,1},
tuner_type: TUNER_MT2032,
pll: PLL_28,
has_radio: 1,
.muxsel = { 2, 3 ,0 ,1},
.tuner_type = TUNER_MT2032,
.pll = PLL_28,
.has_radio = 1,
},{
/* Philip Blundell <pb@nexus.co.uk> */
name: "Active Imaging AIMMS",
video_inputs: 1,
audio_inputs: 0,
tuner: -1,
tuner_type: -1,
pll: PLL_28,
muxsel: { 2 },
gpiomask: 0
.name = "Active Imaging AIMMS",
.video_inputs = 1,
.audio_inputs = 0,
.tuner = -1,
.tuner_type = -1,
.pll = PLL_28,
.muxsel = { 2 },
.gpiomask = 0
},{
/* Tomasz Pyra <hellfire@sedez.iq.pl> */
name: "Pixelview PV-BT878P+ (Rev.4C)",
video_inputs: 3,
audio_inputs: 4,
tuner: 0,
svhs: 2,
gpiomask: 15,
muxsel: { 2, 3, 1, 1},
audiomux: { 0, 0, 11, 7, 13, 0},
needs_tvaudio: 1,
pll: PLL_28,
tuner_type: 25,
.name = "Prolink Pixelview PV-BT878P+ (Rev.4C,8E)",
.video_inputs = 3,
.audio_inputs = 4,
.tuner = 0,
.svhs = 2,
.gpiomask = 15,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 0, 0, 11, 7, 13, 0}, // TV and Radio with same GPIO !
.needs_tvaudio = 1,
.pll = PLL_28,
.tuner_type = 25,
/* GPIO wiring:
GPIO0: U4.A0 (hef4052bt)
GPIO1: U4.A1
GPIO2: U4.A1 (second hef4052bt)
GPIO3: U4.nEN, U5.A0, A5.nEN
GPIO8-15: vrd866b ?
*/
},{
name: "Flyvideo 98EZ (capture only)",
video_inputs: 4,
audio_inputs: 0,
tuner: -1,
svhs: 2,
muxsel: { 2, 3, 1, 1}, // AV1, AV2, SVHS, CVid adapter on SVHS
pll: PLL_28,
no_msp34xx: 1,
.name = "Lifeview FlyVideo 98EZ (capture only) LR51",
.video_inputs = 4,
.audio_inputs = 0,
.tuner = -1,
.svhs = 2,
.muxsel = { 2, 3, 1, 1}, // AV1, AV2, SVHS, CVid adapter on SVHS
.pll = PLL_28,
.no_msp34xx = 1,
},{
 
/* ---- card 0x48 ---------------------------------- */
/* Dariusz Kowalewski <darekk@automex.pl> */
name: "Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 0x3f,
muxsel: { 2, 3, 0, 1 },
audiomux: { 0x01, 0x00, 0x03, 0x03, 0x09, 0x02 },
needs_tvaudio: 1,
no_msp34xx: 1,
no_tda9875: 1,
pll: PLL_28,
tuner_type: -1,
audio_hook: pvbt878p9b_audio,
has_radio: 1,
.name = "Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)",
.video_inputs = 4,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 0x3f,
.muxsel = { 2, 3, 1, 1 },
.audiomux = { 0x01, 0x00, 0x03, 0x03, 0x09, 0x02 },
.needs_tvaudio = 1,
.no_msp34xx = 1,
.no_tda9875 = 1,
.pll = PLL_28,
.tuner_type = 5,
.audio_hook = pvbt878p9b_audio, // Note: not all cards have stereo
.has_radio = 1, // Note: not all cards have radio
/* GPIO wiring:
GPIO0: A0 hef4052
GPIO1: A1 hef4052
GPIO3: nEN hef4052
GPIO8-15: vrd866b
GPIO20,22,23: R30,R29,R28
*/
},{
/* Clay Kunz <ckunz@mail.arc.nasa.gov> */
/* you must jumper JP5 for the card to work */
name: "Sensoray 311",
video_inputs: 5,
audio_inputs: 0,
tuner: -1,
svhs: 4,
gpiomask: 0,
muxsel: { 2, 3, 1, 0, 0},
audiomux: { 0 },
needs_tvaudio: 0,
tuner_type: -1,
.name = "Sensoray 311",
.video_inputs = 5,
.audio_inputs = 0,
.tuner = -1,
.svhs = 4,
.gpiomask = 0,
.muxsel = { 2, 3, 1, 0, 0},
.audiomux = { 0 },
.needs_tvaudio = 0,
.tuner_type = -1,
},{
/* Miguel Freitas <miguel@cetuc.puc-rio.br> */
name: "RemoteVision MX (RV605)",
video_inputs: 16,
audio_inputs: 0,
tuner: -1,
svhs: -1,
gpiomask: 0x00,
gpiomask2: 0x07ff,
muxsel: { 0x33, 0x13, 0x23, 0x43, 0xf3, 0x73, 0xe3, 0x03,
.name = "RemoteVision MX (RV605)",
.video_inputs = 16,
.audio_inputs = 0,
.tuner = -1,
.svhs = -1,
.gpiomask = 0x00,
.gpiomask2 = 0x07ff,
.muxsel = { 0x33, 0x13, 0x23, 0x43, 0xf3, 0x73, 0xe3, 0x03,
0xd3, 0xb3, 0xc3, 0x63, 0x93, 0x53, 0x83, 0xa3 },
no_msp34xx: 1,
no_tda9875: 1,
tuner_type: -1,
muxsel_hook: rv605_muxsel,
.no_msp34xx = 1,
.no_tda9875 = 1,
.tuner_type = -1,
.muxsel_hook = rv605_muxsel,
},{
name: "Powercolor MTV878/ MTV878R/ MTV878F",
video_inputs: 3,
audio_inputs: 2,
tuner: 0,
svhs: 2,
gpiomask: 0x1C800F, // Bit0-2: Audio select, 8-12:remote control 14:remote valid 15:remote reset
muxsel: { 2, 1, 1, },
audiomux: { 0, 1, 2, 2, 4 },
needs_tvaudio: 0,
tuner_type: TUNER_PHILIPS_PAL,
pll: PLL_28,
has_radio: 1,
.name = "Powercolor MTV878/ MTV878R/ MTV878F",
.video_inputs = 3,
.audio_inputs = 2,
.tuner = 0,
.svhs = 2,
.gpiomask = 0x1C800F, // Bit0-2: Audio select, 8-12:remote control 14:remote valid 15:remote reset
.muxsel = { 2, 1, 1, },
.audiomux = { 0, 1, 2, 2, 4 },
.needs_tvaudio = 0,
.tuner_type = TUNER_PHILIPS_PAL,
.pll = PLL_28,
.has_radio = 1,
},{
 
/* ---- card 0x4c ---------------------------------- */
/* Masaki Suzuki <masaki@btree.org> */
name: "Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP)",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 0x140007,
muxsel: { 2, 3, 1, 1 },
audiomux: { 0, 1, 2, 3, 4, 0 },
tuner_type: TUNER_PHILIPS_NTSC,
audio_hook: windvr_audio,
.name = "Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP)",
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 0x140007,
.muxsel = { 2, 3, 1, 1 },
.audiomux = { 0, 1, 2, 3, 4, 0 },
.tuner_type = TUNER_PHILIPS_NTSC,
.audio_hook = windvr_audio,
},{
name: "GrandTec Multi Capture Card (Bt878)",
video_inputs: 4,
audio_inputs: 0,
tuner: -1,
svhs: -1,
gpiomask: 0,
muxsel: { 2, 3, 1, 0 },
audiomux: { 0 },
needs_tvaudio: 0,
no_msp34xx: 1,
pll: PLL_28,
tuner_type: -1,
.name = "GrandTec Multi Capture Card (Bt878)",
.video_inputs = 4,
.audio_inputs = 0,
.tuner = -1,
.svhs = -1,
.gpiomask = 0,
.muxsel = { 2, 3, 1, 0 },
.audiomux = { 0 },
.needs_tvaudio = 0,
.no_msp34xx = 1,
.pll = PLL_28,
.tuner_type = -1,
},{
/* http://www.aopen.com/products/video/va1000.htm */
name: "AOPEN VA1000",
video_inputs: 3, /* coax, AV, s-vid */
audio_inputs: 1,
tuner: 0,
tuner_type: TUNER_LG_PAL, /* actually TP18PSB12P (PAL B/G) */
audiomux: { 2, 0, 0, 0 },
muxsel: { 2, 3, 1, 0 },
pll: PLL_28,
.name = "Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF",
.video_inputs = 4,
.audio_inputs = 3,
.tuner = 0,
.svhs = 2,
.gpiomask = 7,
.muxsel = { 2, 3, 1, 1 }, // Tuner, SVid, SVHS, SVid to SVHS connector
.audiomux = { 0 ,0 ,4, 4,4,4},// Yes, this tuner uses the same audio output for TV and FM radio!
// This card lacks external Audio In, so we mute it on Ext. & Int.
// The PCB can take a sbx1637/sbx1673, wiring unknown.
// This card lacks PCI subsystem ID, sigh.
// audiomux=1: lower volume, 2+3: mute
// btwincap uses 0x80000/0x80003
.needs_tvaudio = 0,
.no_msp34xx = 1,
.pll = PLL_28,
.tuner_type = 5, // Samsung TCPA9095PC27A (BG+DK), philips compatible, w/FM, stereo and
// radio signal strength indicators work fine.
.has_radio = 1,
/* GPIO Info:
GPIO0,1: HEF4052 A0,A1
GPIO2: HEF4052 nENABLE
GPIO3-7: n.c.
GPIO8-13: IRDC357 data0-5 (data6 n.c. ?) [chip not present on my card]
GPIO14,15: ??
GPIO16-21: n.c.
GPIO22,23: ??
?? : mtu8b56ep microcontroller for IR (GPIO wiring unknown)*/
},{
name: "Osprey 100/150 (878)", /* 0x1(2|3)-45C6-C1 */
video_inputs: 4, /* id-inputs-clock */
audio_inputs: 0,
tuner: -1,
svhs: 3,
muxsel: { 3, 2, 0, 1 },
pll: PLL_28,
tuner_type: -1,
no_msp34xx: 1,
no_tda9875: 1,
no_tda7432: 1,
/* Arthur Tetzlaff-Deas, DSP Design Ltd <software@dspdesign.com> */
.name = "DSP Design TCVIDEO",
.video_inputs = 4,
.svhs = -1,
.muxsel = { 2, 3, 1, 0},
.pll = PLL_28,
.tuner_type = -1,
},{
/* ---- card 0x50 ---------------------------------- */
name: "Osprey 100/150 (848)", /* 0x04-54C0-C1 & older boards */
video_inputs: 3,
audio_inputs: 0,
tuner: -1,
svhs: 2,
muxsel: { 2, 3, 1 },
pll: PLL_28,
tuner_type: -1,
no_msp34xx: 1,
no_tda9875: 1,
no_tda7432: 1,
 
/* ---- card 0x50 ---------------------------------- */
.name = "Hauppauge WinTV PVR",
.video_inputs = 4,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.muxsel = { 2, 0, 1, 1},
.needs_tvaudio = 1,
.pll = PLL_28,
.tuner_type = -1,
 
.gpiomask = 7,
.audiomux = {7},
},{
name: "Osprey 101 (848)", /* 0x05-40C0-C1 */
video_inputs: 2,
audio_inputs: 0,
tuner: -1,
svhs: 1,
muxsel: { 3, 1 },
pll: PLL_28,
tuner_type: -1,
no_msp34xx: 1,
no_tda9875: 1,
no_tda7432: 1,
.name = "IODATA GV-BCTV5/PCI",
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 0x0f0f80,
.muxsel = {2, 3, 1, 0},
.audiomux = {0x030000, 0x010000, 0x030000, 0, 0x020000, 0},
.no_msp34xx = 1,
.pll = PLL_28,
.tuner_type = TUNER_PHILIPS_NTSC_M,
.audio_hook = gvbctv3pci_audio,
.has_radio = 1,
},{
name: "Osprey 101/151", /* 0x1(4|5)-0004-C4 */
video_inputs: 1,
audio_inputs: 0,
tuner: -1,
svhs: -1,
muxsel: { 0 },
pll: PLL_28,
tuner_type: -1,
no_msp34xx: 1,
no_tda9875: 1,
no_tda7432: 1,
.name = "Osprey 100/150 (878)", /* 0x1(2|3)-45C6-C1 */
.video_inputs = 4, /* id-inputs-clock */
.audio_inputs = 0,
.tuner = -1,
.svhs = 3,
.muxsel = { 3, 2, 0, 1 },
.pll = PLL_28,
.tuner_type = -1,
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
},{
name: "Osprey 101/151 w/ svid", /* 0x(16|17|20)-00C4-C1 */
video_inputs: 2,
audio_inputs: 0,
tuner: -1,
svhs: 1,
muxsel: { 0, 1 },
pll: PLL_28,
tuner_type: -1,
no_msp34xx: 1,
no_tda9875: 1,
no_tda7432: 1,
.name = "Osprey 100/150 (848)", /* 0x04-54C0-C1 & older boards */
.video_inputs = 3,
.audio_inputs = 0,
.tuner = -1,
.svhs = 2,
.muxsel = { 2, 3, 1 },
.pll = PLL_28,
.tuner_type = -1,
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
},{
/* ---- card 0x54 ---------------------------------- */
name: "Osprey 200/201/250/251", /* 0x1(8|9|E|F)-0004-C4 */
video_inputs: 1,
audio_inputs: 1,
tuner: -1,
svhs: -1,
muxsel: { 0 },
pll: PLL_28,
tuner_type: -1,
no_msp34xx: 1,
no_tda9875: 1,
no_tda7432: 1,
 
/* ---- card 0x54 ---------------------------------- */
.name = "Osprey 101 (848)", /* 0x05-40C0-C1 */
.video_inputs = 2,
.audio_inputs = 0,
.tuner = -1,
.svhs = 1,
.muxsel = { 3, 1 },
.pll = PLL_28,
.tuner_type = -1,
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
},{
name: "Osprey 200/250", /* 0x1(A|B)-00C4-C1 */
video_inputs: 2,
audio_inputs: 1,
tuner: -1,
svhs: 1,
muxsel: { 0, 1 },
pll: PLL_28,
tuner_type: -1,
no_msp34xx: 1,
no_tda9875: 1,
no_tda7432: 1,
.name = "Osprey 101/151", /* 0x1(4|5)-0004-C4 */
.video_inputs = 1,
.audio_inputs = 0,
.tuner = -1,
.svhs = -1,
.muxsel = { 0 },
.pll = PLL_28,
.tuner_type = -1,
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
},{
name: "Osprey 210/220", /* 0x1(A|B)-04C0-C1 */
video_inputs: 2,
audio_inputs: 1,
tuner: -1,
svhs: 1,
muxsel: { 2, 3 },
pll: PLL_28,
tuner_type: -1,
no_msp34xx: 1,
no_tda9875: 1,
no_tda7432: 1,
.name = "Osprey 101/151 w/ svid", /* 0x(16|17|20)-00C4-C1 */
.video_inputs = 2,
.audio_inputs = 0,
.tuner = -1,
.svhs = 1,
.muxsel = { 0, 1 },
.pll = PLL_28,
.tuner_type = -1,
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
},{
name: "Osprey 5x0", /* 500 and 540 */
video_inputs: 2,
audio_inputs: 1,
tuner: -1,
svhs: 1,
muxsel: { 0, 1 },
pll: PLL_28,
tuner_type: -1,
no_msp34xx: 1,
no_tda9875: 1,
no_tda7432: 1,
.name = "Osprey 200/201/250/251", /* 0x1(8|9|E|F)-0004-C4 */
.video_inputs = 1,
.audio_inputs = 1,
.tuner = -1,
.svhs = -1,
.muxsel = { 0 },
.pll = PLL_28,
.tuner_type = -1,
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
},{
/* ---- card 0x58 ---------------------------------- */
name: "Osprey 2000", /* 2000 */
video_inputs: 2,
audio_inputs: 1,
tuner: -1,
svhs: 1,
muxsel: { 2, 3 },
pll: PLL_28,
tuner_type: -1,
no_msp34xx: 1,
no_tda9875: 1,
no_tda7432: 1, /* must avoid, conflicts with the bt860 */
/* ---- card 0x58 ---------------------------------- */
.name = "Osprey 200/250", /* 0x1(A|B)-00C4-C1 */
.video_inputs = 2,
.audio_inputs = 1,
.tuner = -1,
.svhs = 1,
.muxsel = { 0, 1 },
.pll = PLL_28,
.tuner_type = -1,
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
},{
.name = "Osprey 210/220", /* 0x1(A|B)-04C0-C1 */
.video_inputs = 2,
.audio_inputs = 1,
.tuner = -1,
.svhs = 1,
.muxsel = { 2, 3 },
.pll = PLL_28,
.tuner_type = -1,
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
},{
.name = "Osprey 500", /* 500 */
.video_inputs = 2,
.audio_inputs = 1,
.tuner = -1,
.svhs = 1,
.muxsel = { 2, 3 },
.pll = PLL_28,
.tuner_type = -1,
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
},{
.name = "Osprey 540", /* 540 */
.video_inputs = 4,
.audio_inputs = 1,
.tuner = -1,
#if 0 /* TODO ... */
.svhs = OSPREY540_SVID_ANALOG,
.muxsel = { [OSPREY540_COMP_ANALOG] = 2,
[OSPREY540_SVID_ANALOG] = 3, },
#endif
.pll = PLL_28,
.tuner_type = -1,
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
#if 0 /* TODO ... */
.muxsel_hook = osprey_540_muxsel,
.picture_hook = osprey_540_set_picture,
#endif
},{
 
/* ---- card 0x5C ---------------------------------- */
.name = "Osprey 2000", /* 2000 */
.video_inputs = 2,
.audio_inputs = 1,
.tuner = -1,
.svhs = 1,
.muxsel = { 2, 3 },
.pll = PLL_28,
.tuner_type = -1,
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1, /* must avoid, conflicts with the bt860 */
},{
/* M G Berberich <berberic@forwiss.uni-passau.de> */
.name = "IDS Eagle",
.video_inputs = 4,
.audio_inputs = 0,
.tuner = -1,
.tuner_type = -1,
.svhs = -1,
.gpiomask = 0,
.muxsel = { 0, 1, 2, 3 },
.muxsel_hook = eagle_muxsel,
.no_msp34xx = 1,
.no_tda9875 = 1,
.pll = PLL_28,
},{
.name = "Pinnacle PCTV Sat",
.video_inputs = 2,
.audio_inputs = 0,
.svhs = 1,
.tuner = -1,
.tuner_type = -1,
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
.gpiomask = 0x01,
.audiomux = { 0, 0, 0, 0, 1 },
.muxsel = { 3, 0, 1, 2},
.needs_tvaudio = 0,
.pll = PLL_28,
},{
.name = "Formac ProTV II (bt878)",
.video_inputs = 4,
.audio_inputs = 1,
.tuner = 0,
.svhs = 3,
.gpiomask = 2,
// TV, Comp1, Composite over SVID con, SVID
.muxsel = { 2, 3, 1, 1},
.audiomux = { 2, 2, 0, 0, 0 },
.pll = PLL_28,
.has_radio = 1,
.tuner_type = TUNER_PHILIPS_PAL,
/* sound routing:
GPIO=0x00,0x01,0x03: mute (?)
0x02: both TV and radio (tuner: FM1216/I)
The card has onboard audio connectors labeled "cdrom" and "board",
not soldered here, though unknown wiring.
Card lacks: external audio in, pci subsystem id.
*/
},{
 
/* ---- card 0x60 ---------------------------------- */
.name = "MachTV",
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
.svhs = -1,
.gpiomask = 7,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 0, 1, 2, 3, 4},
.needs_tvaudio = 1,
.tuner_type = 5,
.pll = 1,
},{
.name = "Euresys Picolo",
.video_inputs = 3,
.audio_inputs = 0,
.tuner = -1,
.svhs = 2,
.gpiomask = 0,
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
.muxsel = { 2, 0, 1},
.pll = PLL_28,
},{
/* Luc Van Hoeylandt <luc@e-magic.be> */
.name = "ProVideo PV150", /* 0x4f */
.video_inputs = 2,
.audio_inputs = 0,
.tuner = -1,
.svhs = -1,
.gpiomask = 0,
.muxsel = { 2, 3 },
.audiomux = { 0 },
.needs_tvaudio = 0,
.no_msp34xx = 1,
.pll = PLL_28,
.tuner_type = -1,
},{
/* Hiroshi Takekawa <sian@big.or.jp> */
/* This card lacks subsystem ID */
.name = "AD-TVK503", /* 0x63 */
.video_inputs = 4,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 0x001e8007,
.muxsel = { 2, 3, 1, 0 },
/* Tuner, Radio, external, internal, off, on */
.audiomux = { 0x08, 0x0f, 0x0a, 0x08, 0x0f, 0x08 },
.needs_tvaudio = 0,
.no_msp34xx = 1,
.pll = PLL_28,
.tuner_type = 2,
.audio_hook = adtvk503_audio,
},{
 
/* ---- card 0x64 ---------------------------------- */
.name = "Hercules Smart TV Stereo",
.video_inputs = 4,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 0x00,
.muxsel = { 2, 3, 1, 1 },
.needs_tvaudio = 1,
.no_msp34xx = 1,
.pll = PLL_28,
.tuner_type = 5,
/* Notes:
- card lacks subsystem ID
- stereo variant w/ daughter board with tda9874a @0xb0
- Audio Routing:
always from tda9874 independent of GPIO (?)
external line in: unknown
- Other chips: em78p156elp @ 0x96 (probably IR remote control)
hef4053 (instead 4052) for unknown function
*/
},{
.name = "Pace TV & Radio Card",
.video_inputs = 4,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.muxsel = { 2, 3, 1, 1}, // Tuner, CVid, SVid, CVid over SVid connector
.gpiomask = 0,
.no_tda9875 = 1,
.no_tda7432 = 1,
.tuner_type = 1,
.has_radio = 1,
.pll = PLL_28,
/* Bt878, Bt832, FI1246 tuner; no pci subsystem id
only internal line out: (4pin header) RGGL
Radio must be decoded by msp3410d (not routed through)*/
// .digital_mode = DIGITAL_MODE_CAMERA, // todo!
},{
/* Chris Willing <chris@vislab.usyd.edu.au> */
.name = "IVC-200",
.video_inputs = 1,
.audio_inputs = 0,
.tuner = -1,
.tuner_type = -1,
.svhs = -1,
.gpiomask = 0xdf,
.muxsel = { 2 },
.pll = PLL_28,
},{
.name = "Grand X-Guard / Trust 814PCI",
.video_inputs = 16,
.audio_inputs = 0,
.tuner = -1,
.svhs = -1,
.tuner_type = 4,
.gpiomask2 = 0xff,
.muxsel = { 2,2,2,2, 3,3,3,3, 1,1,1,1, 0,0,0,0 },
.muxsel_hook = xguard_muxsel,
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
.pll = PLL_28,
},{
 
/* ---- card 0x68 ---------------------------------- */
.name = "Nebula Electronics DigiTV",
.svhs = -1,
.muxsel = { 2, 3, 1, 0},
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
.pll = PLL_28,
.tuner_type = -1,
.no_video = 1,
},{
/* Jorge Boncompte - DTI2 <jorge@dti2.net> */
.name = "ProVideo PV143",
.video_inputs = 4,
.audio_inputs = 0,
.tuner = -1,
.svhs = -1,
.gpiomask = 0,
.muxsel = { 2, 3, 1, 0 },
.audiomux = { 0 },
.needs_tvaudio = 0,
.no_msp34xx = 1,
.pll = PLL_28,
.tuner_type = -1,
},{
/* M.Klahr@phytec.de */
.name = "PHYTEC VD-009-X1 MiniDIN (bt878)",
.video_inputs = 4,
.audio_inputs = 0,
.tuner = -1, /* card has no tuner */
.svhs = 3,
.gpiomask = 0x00,
.muxsel = { 2, 3, 1, 0},
.audiomux = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
.needs_tvaudio = 1,
.pll = PLL_28,
.tuner_type = -1,
},{
.name = "PHYTEC VD-009-X1 Combi (bt878)",
.video_inputs = 4,
.audio_inputs = 0,
.tuner = -1, /* card has no tuner */
.svhs = 3,
.gpiomask = 0x00,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
.needs_tvaudio = 1,
.pll = PLL_28,
.tuner_type = -1,
},{
 
/* ---- card 0x6c ---------------------------------- */
.name = "PHYTEC VD-009 MiniDIN (bt878)",
.video_inputs = 10,
.audio_inputs = 0,
.tuner = -1, /* card has no tuner */
.svhs = 9,
.gpiomask = 0x00,
.gpiomask2 = 0x03, /* gpiomask2 defines the bits used to switch audio
via the upper nibble of muxsel. here: used for
xternal video-mux */
.muxsel = { 0x02, 0x12, 0x22, 0x32, 0x03, 0x13, 0x23, 0x33, 0x01, 0x00 },
.audiomux = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
.needs_tvaudio = 1,
.pll = PLL_28,
.tuner_type = -1,
},{
.name = "PHYTEC VD-009 Combi (bt878)",
.video_inputs = 10,
.audio_inputs = 0,
.tuner = -1, /* card has no tuner */
.svhs = 9,
.gpiomask = 0x00,
.gpiomask2 = 0x03, /* gpiomask2 defines the bits used to switch audio
via the upper nibble of muxsel. here: used for
xternal video-mux */
.muxsel = { 0x02, 0x12, 0x22, 0x32, 0x03, 0x13, 0x23, 0x33, 0x01, 0x01 },
.audiomux = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
.needs_tvaudio = 1,
.pll = PLL_28,
.tuner_type = -1,
},{
.name = "IVC-100",
.video_inputs = 4,
.audio_inputs = 0,
.tuner = -1,
.tuner_type = -1,
.svhs = -1,
.gpiomask = 0xdf,
.muxsel = { 2, 3, 1, 0 },
.pll = PLL_28,
},{
/* IVC-120G - Alan Garfield <alan@fromorbit.com> */
.name = "IVC-120G",
.video_inputs = 16,
.audio_inputs = 0, /* card has no audio */
.tuner = -1, /* card has no tuner */
.tuner_type = -1,
.svhs = -1, /* card has no svhs */
.needs_tvaudio = 0,
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
.gpiomask = 0x00,
.muxsel = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 },
.muxsel_hook = ivc120_muxsel,
.pll = PLL_28,
}};
 
const int bttv_num_tvcards = (sizeof(bttv_tvcards)/sizeof(struct tvcard));
const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
 
/* ----------------------------------------------------------------------- */
 
1294,7 → 1863,7
/*
* identify card
*/
void bttv_idcard(struct bttv *btv)
void __devinit bttv_idcard(struct bttv *btv)
{
unsigned int gpiobits;
int i,type;
1301,12 → 1870,11
unsigned short tmp;
 
/* read PCI subsystem ID */
pci_read_config_word(btv->dev, 2, &tmp);
pci_read_config_word(btv->dev, PCI_SUBSYSTEM_ID, &tmp);
btv->cardid = tmp << 16;
pci_read_config_word(btv->dev, 0, &tmp);
pci_read_config_word(btv->dev, PCI_SUBSYSTEM_VENDOR_ID, &tmp);
btv->cardid |= tmp;
 
printk(KERN_INFO "cardid=%08x",btv->cardid);
if (0 != btv->cardid && 0xffffffff != btv->cardid) {
/* look for the card */
for (type = -1, i = 0; cards[i].id != 0; i++)
1315,37 → 1883,37
if (type != -1) {
/* found it */
printk(KERN_INFO "bttv%d: %s [card=%d], "
"PCI ID is %04x:%04x\n",
printk(KERN_INFO "bttv%d: detected: %s [card=%d], "
"PCI subsystem ID is %04x:%04x\n",
btv->nr,cards[type].name,cards[type].cardnr,
btv->cardid & 0xffff, btv->cardid >> 16);
btv->cardid & 0xffff,
(btv->cardid >> 16) & 0xffff);
btv->type = cards[type].cardnr;
} else {
/* 404 */
printk(KERN_INFO "bttv%d: subsystem: %04x:%04x (UNKNOWN)\n",
btv->nr, btv->cardid&0xffff, btv->cardid>>16);
btv->nr, btv->cardid & 0xffff,
(btv->cardid >> 16) & 0xffff);
printk(KERN_DEBUG "please mail id, board name and "
"the correct card= insmod option to kraxel@bytesex.org\n");
}
}
}
 
/* let the user override the autodetected type */
if (card[btv->nr] >= 0 && card[btv->nr] < bttv_num_tvcards)
if (card[btv->nr] < bttv_num_tvcards)
btv->type=card[btv->nr];
/* print which card config we are using */
sprintf(btv->video_dev.name,"BT%d%s(%.23s)",
btv->id,
(btv->id==848 && btv->revision==0x12) ? "A" : "",
bttv_tvcards[btv->type].name);
printk(KERN_INFO "bttv%d: using: %s [card=%d,%s]\n",btv->nr,
btv->video_dev.name,btv->type,
(card[btv->nr] >= 0 && card[btv->nr] < bttv_num_tvcards) ?
"insmod option" : "autodetected");
bttv_tvcards[btv->type].name, btv->type,
card[btv->nr] < bttv_num_tvcards
? "insmod option" : "autodetected");
 
/* overwrite gpio stuff ?? */
if (-1 == audioall && -1 == audiomux[0])
if (UNSET == audioall && UNSET == audiomux[0])
return;
 
if (-1 != audiomux[0]) {
if (UNSET != audiomux[0]) {
gpiobits = 0;
for (i = 0; i < 5; i++) {
bttv_tvcards[btv->type].audiomux[i] = audiomux[i];
1357,13 → 1925,13
bttv_tvcards[btv->type].audiomux[i] = audioall;
}
}
bttv_tvcards[btv->type].gpiomask = (-1 != gpiomask) ? gpiomask : gpiobits;
cprintf("[info ] bttv%d: gpio config override: mask=0x%lx, mux=",
bttv_tvcards[btv->type].gpiomask = (UNSET != gpiomask) ? gpiomask : gpiobits;
printk(KERN_INFO "bttv%d: gpio config override: mask=0x%x, mux=",
btv->nr,bttv_tvcards[btv->type].gpiomask);
for (i = 0; i < 5; i++) {
cprintf("%s0x%lx", i ? "," : "", bttv_tvcards[btv->type].audiomux[i]);
printk("%s0x%x", i ? "," : "", bttv_tvcards[btv->type].audiomux[i]);
}
cprintf("\n");
printk("\n");
}
 
/*
1370,71 → 1938,108
* (most) board specific initialisations goes here
*/
 
/* Some Modular Technology cards have an eeprom, but no subsystem ID */
void identify_by_eeprom(struct bttv *btv, unsigned char eeprom_data[256])
{
int type = -1;
if (0 == strncmp(eeprom_data,"GET.MM20xPCTV",13))
type = BTTV_MODTEC_205;
else if (0 == strncmp(eeprom_data+20,"Picolo",7))
type = BTTV_EURESYS_PICOLO;
else if (eeprom_data[0] == 0x84 && eeprom_data[2]== 0)
type = BTTV_HAUPPAUGE; /* old bt848 */
 
if (-1 != type) {
btv->type = type;
printk("bttv%d: detected by eeprom: %s [card=%d]\n",
btv->nr, bttv_tvcards[btv->type].name, btv->type);
}
}
 
static void flyvideo_gpio(struct bttv *btv)
{
int gpio,outbits;
{
int gpio,outbits,has_remote,has_radio,is_capture_only,is_lr90,has_tda9820_tda9821;
int tuner=-1,ttype;
outbits = btread(BT848_GPIO_OUT_EN);
btwrite(0x00, BT848_GPIO_OUT_EN);
udelay(8); // without this we would see the 0x1800 mask
gpio=gpioread();
gpio=btread(BT848_GPIO_DATA);
btwrite(outbits, BT848_GPIO_OUT_EN);
// all cards provide GPIO info, some have an additional eeprom
// LR50: GPIO coding can be found lower right CP1 .. CP9
// CP9=GPIO23 .. CP1=GPIO15; when OPEN, the corresponding GPIO reads 1.
// GPIO14-12: n.c.
// LR90: GP9=GPIO23 .. GP1=GPIO15 (right above the bt878)
// lowest 3 bytes are remote control codes (no handshake needed)
// xxxFFF: No remote control chip soldered
// xxxF00(LR26/LR50), xxxFE0(LR90): Remote control chip (LVA001 or CF45) soldered
// Note: Some bits are Audio_Mask !
 
ttype=(gpio&0x0f0000)>>16;
switch(ttype) {
case 0: tuner=4; // None
case 0x0: tuner=2; // NTSC, e.g. TPI8NSR11P
break;
case 4: tuner=5; // Philips PAL
case 0x2: tuner=39;// LG NTSC (newer TAPC series) TAPC-H701P
break;
case 6: tuner=37; // LG PAL (newer TAPC series)
case 0x4: tuner=5; // Philips PAL TPI8PSB02P, TPI8PSB12P, TPI8PSB12D or FI1216, FM1216
break;
case 0xC: tuner=3; // Philips SECAM(+PAL)
case 0x6: tuner=37; // LG PAL (newer TAPC series) TAPC-G702P
break;
case 0xC: tuner=3; // Philips SECAM(+PAL) FQ1216ME or FI1216MF
break;
default:
printk(KERN_INFO "bttv%d: flyvideo_gpio: unknown tuner type.\n", btv->nr);
printk(KERN_INFO "bttv%d: FlyVideo_gpio: unknown tuner type.\n", btv->nr);
}
printk(KERN_INFO "bttv%d: Flyvideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n",
btv->nr,
gpio&0x400000? "yes":"no",
gpio&0x800000? "yes":"no", tuner, gpio);
btv->tuner_type = tuner;
btv->has_radio = gpio&0x400000? 1:0;
 
has_remote = gpio & 0x800000;
has_radio = gpio & 0x400000;
// unknown 0x200000;
// unknown2 0x100000;
is_capture_only = !(gpio & 0x008000); //GPIO15
has_tda9820_tda9821 = !(gpio & 0x004000);
is_lr90 = !(gpio & 0x002000); // else LR26/LR50 (LR38/LR51 f. capture only)
// gpio & 0x001000 // output bit for audio routing
 
if(is_capture_only)
tuner=4; // No tuner present
 
printk(KERN_INFO "bttv%d: FlyVideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n",
btv->nr, has_radio? "yes":"no ", has_remote? "yes":"no ", tuner, gpio);
printk(KERN_INFO "bttv%d: FlyVideo LR90=%s tda9821/tda9820=%s capture_only=%s\n",
btv->nr, is_lr90?"yes":"no ", has_tda9820_tda9821?"yes":"no ",
is_capture_only?"yes":"no ");
 
if(tuner!= -1) // only set if known tuner autodetected, else let insmod option through
btv->tuner_type = tuner;
btv->has_radio = has_radio;
 
// LR90 Audio Routing is done by 2 hef4052, so Audio_Mask has 4 bits: 0x001c80
// LR26/LR50 only has 1 hef4052, Audio_Mask 0x000c00
// Audio options: from tuner, from tda9821/tda9821(mono,stereo,sap), from tda9874, ext., mute
if(has_tda9820_tda9821) btv->audio_hook = lt9415_audio;
//todo: if(has_tda9874) btv->audio_hook = fv2000s_audio;
}
 
int miro_tunermap[] = { 0,6,2,3, 4,5,6,0, 3,0,4,5, 5,2,16,1,
14,2,17,1, 4,1,4,3, 1,2,16,1, 4,4,4,4 };
int miro_fmtuner[] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1,
1,1,1,1, 1,1,1,0, 0,0,0,0, 0,0,0,0 };
1,1,1,1, 1,1,1,0, 0,0,0,0, 0,1,0,0 };
 
/* initialization part one -- before registering i2c bus */
void bttv_init_card1(struct bttv *btv)
static void miro_pinnacle_gpio(struct bttv *btv)
{
if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878)
boot_msp34xx(btv,5);
if (btv->type == BTTV_VOODOOTV_FM)
boot_msp34xx(btv,20);
/*printk("bttv: end of init -- pre i2c\n");*/
}
int id,msp,gpio;
char *info;
 
/* initialization part one -- after registering i2c bus */
void bttv_init_card2(struct bttv *btv)
{
/* miro/pinnacle */
if (btv->type == BTTV_MIRO ||
btv->type == BTTV_MIROPRO ||
btv->type == BTTV_PINNACLE ||
btv->type == BTTV_PINNACLEPRO) {
int id,msp;
id = ((gpioread()>>10) & 31) -1;
msp = bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx");
btwrite(0,BT848_GPIO_OUT_EN);
gpio = btread(BT848_GPIO_DATA);
id = ((gpio>>10) & 63) -1;
msp = bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx");
if (id < 32) {
btv->tuner_type = miro_tunermap[id];
if (0 == (gpioread() & 0x20)) {
if (0 == (gpio & 0x20)) {
btv->has_radio = 1;
if (!miro_fmtuner[id]) {
btv->has_matchbox = 1;
1453,52 → 2058,190
if (btv->type == BTTV_PINNACLE)
btv->type = BTTV_PINNACLEPRO;
}
if (bttv_verbose)
printk(KERN_INFO "bttv%d: miro: id=%d tuner=%d "
"radio=%s stereo=%s\n",
btv->nr, id+1, btv->tuner_type,
!btv->has_radio ? "no" :
(btv->has_matchbox ? "matchbox" : "fmtuner"),
(-1 == msp) ? "no" : "yes");
printk(KERN_INFO
"bttv%d: miro: id=%d tuner=%d radio=%s stereo=%s\n",
btv->nr, id+1, btv->tuner_type,
!btv->has_radio ? "no" :
(btv->has_matchbox ? "matchbox" : "fmtuner"),
(-1 == msp) ? "no" : "yes");
} else {
/* new cards with microtune tuner */
id = 63 - id;
btv->has_radio = 0;
switch (id) {
case 1:
info = "PAL / mono";
break;
case 2:
info = "PAL+SECAM / stereo";
btv->has_radio = 1;
break;
case 3:
info = "NTSC / stereo";
btv->has_radio = 1;
break;
case 4:
info = "PAL+SECAM / mono";
break;
case 5:
info = "NTSC / mono";
break;
case 6:
info = "NTSC / stereo";
break;
default:
info = "oops: unknown card";
break;
}
if (-1 != msp)
btv->type = BTTV_PINNACLEPRO;
printk(KERN_INFO
"bttv%d: pinnacle/mt: id=%d info=\"%s\" radio=%s\n",
btv->nr, id, info, btv->has_radio ? "yes" : "no");
btv->tuner_type = 33;
btv->pinnacle_id = id;
}
}
 
/* GPIO21 L: Buffer aktiv, H: Buffer inaktiv */
#define LM1882_SYNC_DRIVE 0x200000L
 
static void init_ids_eagle(struct bttv *btv)
{
btwrite(0xFFFF37, BT848_GPIO_OUT_EN);
btwrite(0x000000, BT848_GPIO_REG_INP);
btwrite(0x200020, BT848_GPIO_DATA);
/* flash strobe inverter ?! */
btwrite(0x200024, BT848_GPIO_DATA);
/* switch sync drive off */
btor(LM1882_SYNC_DRIVE, BT848_GPIO_DATA);
/* set BT848 muxel to 2 */
btaor((2)<<5, ~(2<<5), BT848_IFORM);
}
 
/* Muxsel helper for the IDS Eagle.
* the eagles does not use the standard muxsel-bits but
* has its own multiplexer */
static void eagle_muxsel(struct bttv *btv, unsigned int input)
{
btaor((2)<<5, ~(3<<5), BT848_IFORM);
btaor((bttv_tvcards[btv->type].muxsel[input&7]&3),
~3, BT848_GPIO_DATA);
 
#if 0
if (btv->has_matchbox) {
if (bttv_verbose)
printk(KERN_INFO "Initializing TEA5757...\n");
init_tea5757(btv);
}
/* svhs */
/* wake chroma ADC */
btand(~BT848_ADC_C_SLEEP, BT848_ADC);
/* set to YC video */
btor(BT848_CONTROL_COMP, BT848_E_CONTROL);
btor(BT848_CONTROL_COMP, BT848_O_CONTROL);
#else
/* composite */
/* set chroma ADC to sleep */
btor(BT848_ADC_C_SLEEP, BT848_ADC);
/* set to composite video */
btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
#endif
 
/* switch sync drive off */
btor(LM1882_SYNC_DRIVE, BT848_GPIO_DATA);
}
 
/* ----------------------------------------------------------------------- */
 
void bttv_reset_audio(struct bttv *btv)
{
/*
* BT878A has a audio-reset register.
* 1. This register is an audio reset function but it is in
* function-0 (video capture) address space.
* 2. It is enough to do this once per power-up of the card.
* 3. There is a typo in the Conexant doc -- it is not at
* 0x5B, but at 0x058. (B is an odd-number, obviously a typo!).
* --//Shrikumar 030609
*/
if (btv->id != 878)
return;
if (bttv_debug)
printk("bttv%d: BT878A ARESET\n",btv->nr);
btwrite((1<<7), 0x058);
udelay(10);
btwrite( 0, 0x058);
}
 
/* initialization part one -- before registering i2c bus */
void __devinit bttv_init_card1(struct bttv *btv)
{
switch (btv->type) {
case BTTV_HAUPPAUGE:
case BTTV_HAUPPAUGE878:
boot_msp34xx(btv,5);
break;
case BTTV_VOODOOTV_FM:
boot_msp34xx(btv,20);
break;
case BTTV_AVERMEDIA98:
boot_msp34xx(btv,11);
break;
case BTTV_HAUPPAUGEPVR:
pvr_boot(btv);
break;
}
}
 
if (btv->type == BTTV_FLYVIDEO_98 ||
btv->type == BTTV_FLYVIDEO ||
btv->type == BTTV_TYPHOON_TVIEW ||
btv->type == BTTV_CHRONOS_VS2 ||
btv->type == BTTV_FLYVIDEO_98FM ||
btv->type == BTTV_FLYVIDEO2000 ||
btv->type == BTTV_FLYVIDEO98EZ)
/* initialization part two -- after registering i2c bus */
void __devinit bttv_init_card2(struct bttv *btv)
{
btv->tuner_type = -1;
 
if (BTTV_UNKNOWN == btv->type) {
bttv_readee(btv,eeprom_data,0xa0);
identify_by_eeprom(btv,eeprom_data);
}
 
switch (btv->type) {
case BTTV_MIRO:
case BTTV_MIROPRO:
case BTTV_PINNACLE:
case BTTV_PINNACLEPRO:
/* miro/pinnacle */
miro_pinnacle_gpio(btv);
break;
case BTTV_FLYVIDEO_98:
case BTTV_MAXI:
case BTTV_LIFE_FLYKIT:
case BTTV_FLYVIDEO:
case BTTV_TYPHOON_TVIEW:
case BTTV_CHRONOS_VS2:
case BTTV_FLYVIDEO_98FM:
case BTTV_FLYVIDEO2000:
case BTTV_FLYVIDEO98EZ:
case BTTV_CONFERENCETV:
case BTTV_LIFETEC_9415:
flyvideo_gpio(btv);
 
if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878) {
break;
case BTTV_HAUPPAUGE:
case BTTV_HAUPPAUGE878:
case BTTV_HAUPPAUGEPVR:
/* pick up some config infos from the eeprom */
bttv_readee(btv,eeprom_data,0xa0);
hauppauge_eeprom(btv);
}
 
if ((btv->type >= BTTV_OSPREY_BEGIN) && (btv->type <= BTTV_OSPREY_END)) {
/* check for config info in the eeprom */
break;
case BTTV_AVERMEDIA98:
case BTTV_AVPHONE98:
bttv_readee(btv,eeprom_data,0xa0);
osprey_eeprom(btv);
}
 
if (btv->type == BTTV_AVERMEDIA98 || btv->type == BTTV_AVPHONE98) {
bttv_readee(btv,eeprom_data,0xa0);
avermedia_eeprom(btv);
}
 
if (btv->type == BTTV_PXC200)
break;
case BTTV_PXC200:
init_PXC200(btv);
 
if (btv->type == BTTV_VHX) {
break;
case BTTV_VHX:
btv->has_radio = 1;
btv->has_matchbox = 1;
btv->mbox_we = 0x20;
1506,20 → 2249,46
btv->mbox_clk = 0x08;
btv->mbox_data = 0x10;
btv->mbox_mask = 0x38;
}
 
if (btv->type == BTTV_LIFETEC_9415) {
if (gpioread() & 0x4000)
cprintf("bttv%d: lifetec: tv mono/fm stereo card\n", btv->nr);
else
cprintf("bttv%d: lifetec: stereo(TDA9821) card\n",btv->nr);
}
 
if (btv->type == BTTV_MAGICTVIEW061) {
if(btv->cardid == 0x4002144f) {
break;
case BTTV_VOBIS_BOOSTAR:
case BTTV_TERRATV:
terratec_active_radio_upgrade(btv);
break;
case BTTV_MAGICTVIEW061:
if (btv->cardid == 0x3002144f) {
btv->has_radio=1;
cprintf("bttv%d: radio detected by subsystem id (CPH05x)\n",btv->nr);
printk("bttv%d: radio detected by subsystem id (CPH05x)\n",btv->nr);
}
break;
case BTTV_STB2:
if (btv->cardid == 0x3060121a) {
/* Fix up entry for 3DFX VoodooTV 100,
which is an OEM STB card variant. */
btv->has_radio=0;
btv->tuner_type=TUNER_TEMIC_NTSC;
}
break;
case BTTV_OSPREY1x0:
case BTTV_OSPREY1x0_848:
case BTTV_OSPREY101_848:
case BTTV_OSPREY1x1:
case BTTV_OSPREY1x1_SVID:
case BTTV_OSPREY2xx:
case BTTV_OSPREY2x0_SVID:
case BTTV_OSPREY2x0:
case BTTV_OSPREY500:
case BTTV_OSPREY540:
case BTTV_OSPREY2000:
bttv_readee(btv,eeprom_data,0xa0);
osprey_eeprom(btv);
break;
case BTTV_IDS_EAGLE:
init_ids_eagle(btv);
break;
case BTTV_MODTEC_205:
bttv_readee(btv,eeprom_data,0xa0);
modtec_eeprom(btv);
break;
}
 
/* pll configuration */
1554,34 → 2323,75
break;
}
}
btv->pll.pll_current = -1;
 
/* tuner configuration (from card list / insmod option) */
if (-1 != bttv_tvcards[btv->type].tuner_type)
btv->tuner_type = bttv_tvcards[btv->type].tuner_type;
if (-1 != tuner[btv->nr])
/* tuner configuration (from card list / autodetect / insmod option) */
if (UNSET != bttv_tvcards[btv->type].tuner_type)
if(UNSET == btv->tuner_type)
btv->tuner_type = bttv_tvcards[btv->type].tuner_type;
if (UNSET != tuner[btv->nr])
btv->tuner_type = tuner[btv->nr];
printk("bttv%d: using tuner=%d\n",btv->nr,btv->tuner_type);
if (btv->pinnacle_id != UNSET)
bttv_call_i2c_clients(btv,AUDC_CONFIG_PINNACLE,
&btv->pinnacle_id);
if (btv->tuner_type != UNSET)
bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type);
btv->svhs = bttv_tvcards[btv->type].svhs;
if (svhs[btv->nr] != UNSET)
btv->svhs = svhs[btv->nr];
 
if (bttv_tvcards[btv->type].has_radio)
btv->has_radio=1;
if (bttv_tvcards[btv->type].audio_hook)
btv->audio_hook=bttv_tvcards[btv->type].audio_hook;
 
if (bttv_tvcards[btv->type].digital_mode == DIGITAL_MODE_CAMERA) {
/* detect Bt832 chip for quartzsight digital camera */
if ((bttv_I2CRead(btv, I2C_BT832_ALT1, "Bt832") >=0) ||
(bttv_I2CRead(btv, I2C_BT832_ALT2, "Bt832") >=0))
boot_bt832(btv);
}
 
/* try to detect audio/fader chips */
if (!bttv_tvcards[btv->type].no_msp34xx &&
bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx") >=0) {
if (autoload)
request_module("msp3400");
}
 
if (bttv_tvcards[btv->type].msp34xx_alt &&
bttv_I2CRead(btv, I2C_MSP3400_ALT, "MSP34xx (alternate address)") >=0) {
if (autoload)
request_module("msp3400");
}
 
if (!bttv_tvcards[btv->type].no_tda9875 &&
bttv_I2CRead(btv, I2C_TDA9875, "TDA9875") >=0) {
if (autoload)
request_module("tda9875");
}
 
if (!bttv_tvcards[btv->type].no_tda7432 &&
bttv_I2CRead(btv, I2C_TDA7432, "TDA7432") >=0) {
bttv_I2CRead(btv, I2C_TDA7432, "TDA7432") >=0) {
if (autoload)
request_module("tda7432");
}
 
if (bttv_tvcards[btv->type].needs_tvaudio) {
if (autoload)
request_module("tvaudio");
}
 
if (bttv_tvcards[btv->type].tuner != -1) {
/* tuner modules */
if (btv->pinnacle_id != UNSET) {
if (autoload)
request_module("tda9887");
}
if (btv->tuner_type != UNSET) {
if (autoload)
request_module("tuner");
}
}
 
 
1593,7 → 2403,7
int id;
char *name;
}
hauppauge_tuner[] =
hauppauge_tuner[] __devinitdata =
{
{ TUNER_ABSENT, "" },
{ TUNER_ABSENT, "External" },
1631,8 → 2441,8
{ TUNER_TEMIC_4039FR5_NTSC, "Temic 4039FR5" },
{ TUNER_PHILIPS_FQ1216ME, "Philips FQ1216 ME" },
{ TUNER_TEMIC_4066FY5_PAL_I, "Temic 4066FY5" },
{ TUNER_ABSENT, "Philips TD1536" },
{ TUNER_ABSENT, "Philips TD1536D" },
{ TUNER_PHILIPS_NTSC, "Philips TD1536" },
{ TUNER_PHILIPS_NTSC, "Philips TD1536D" },
{ TUNER_PHILIPS_NTSC, "Philips FMR1236" }, /* mono radio */
{ TUNER_ABSENT, "Philips FI1256MP" },
{ TUNER_ABSENT, "Samsung TCPQ9091P" },
1641,17 → 2451,29
{ TUNER_TEMIC_4046FM5, "Temic 4046FM5" },
{ TUNER_TEMIC_4009FN5_MULTI_PAL_FM, "Temic 4009FN5" },
{ TUNER_ABSENT, "Philips TD1536D_FH_44"},
{ TUNER_LG_NTSC_FM, "LG TP18NSR01F"},
{ TUNER_LG_PAL_FM, "LG TP18PSB01D"},
{ TUNER_LG_PAL, "LG TP18PSB11D"},
{ TUNER_LG_NTSC_FM, "LG TPI8NSR01F"},
{ TUNER_LG_PAL_FM, "LG TPI8PSB01D"},
{ TUNER_LG_PAL, "LG TPI8PSB11D"},
{ TUNER_LG_PAL_I_FM, "LG TAPC-I001D"},
{ TUNER_LG_PAL_I, "LG TAPC-I701D"}
};
 
static void hauppauge_eeprom(struct bttv *btv)
static void modtec_eeprom(struct bttv *btv)
{
int blk2,tuner,radio,model;
if( strncmp(&(eeprom_data[0x1e]),"Temic 4066 FY5",14) ==0) {
btv->tuner_type=TUNER_TEMIC_4066FY5_PAL_I;
printk("bttv Modtec: Tuner autodetected %s\n",
&eeprom_data[0x1e]);
} else {
printk("bttv Modtec: Unknown TunerString:%s\n",
&eeprom_data[0x1e]);
}
}
 
static void __devinit hauppauge_eeprom(struct bttv *btv)
{
unsigned int blk2,tuner,radio,model;
 
if (eeprom_data[0] != 0x84 || eeprom_data[2] != 0)
printk(KERN_WARNING "bttv%d: Hauppauge eeprom: invalid\n",
btv->nr);
1664,7 → 2486,7
tuner = eeprom_data[9];
radio = eeprom_data[blk2-1] & 0x01;
if (tuner < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER))
if (tuner < ARRAY_SIZE(hauppauge_tuner))
btv->tuner_type = hauppauge_tuner[tuner].id;
if (radio)
btv->has_radio = 1;
1676,137 → 2498,254
btv->tuner_type, radio ? "yes" : "no");
}
 
static void osprey_eeprom(struct bttv *btv)
static int terratec_active_radio_upgrade(struct bttv *btv)
{
int i = 0;
int detected_type = btv->type;
unsigned char *ee = eeprom_data;
unsigned long serial = 0;
if (bttv_debug) {
printk(KERN_INFO "Osprey: EEPROM dump\n");
for(;i<256; i+= 16) {
cprintf("[info ] Osprey 100:(%02X) %02X %02X %02X %02X %02X %02X %02X %02X -- %02X %02X %02X %02X %02X %02X %02X %02X\n",
i,ee[i+ 0],ee[i+ 1],ee[i+ 2],ee[i+ 3],
ee[i+ 4],ee[i+ 5],ee[i+ 6],ee[i+ 7],
ee[i+ 8],ee[i+ 9],ee[i+10],ee[i+11],
ee[i+12],ee[i+13],ee[i+14],ee[i+15] );
int freq;
 
btv->has_radio = 1;
btv->has_matchbox = 1;
btv->mbox_we = 0x10;
btv->mbox_most = 0x20;
btv->mbox_clk = 0x08;
btv->mbox_data = 0x04;
btv->mbox_mask = 0x3c;
 
btv->mbox_iow = 1 << 8;
btv->mbox_ior = 1 << 9;
btv->mbox_csel = 1 << 10;
 
freq=88000/62.5;
tea5757_write(btv, 5 * freq + 0x358); // write 0x1ed8
if (0x1ed8 == tea5757_read(btv)) {
printk("bttv%d: Terratec Active Radio Upgrade found.\n",
btv->nr);
btv->has_radio = 1;
btv->has_matchbox = 1;
} else {
btv->has_radio = 0;
btv->has_matchbox = 0;
}
return 0;
}
 
 
/* ----------------------------------------------------------------------- */
 
/*
* minimal bootstrap for the WinTV/PVR -- upload altera firmware.
*
* The hcwamc.rbf firmware file is on the Hauppauge driver CD. Have
* a look at Pvr/pvr45xxx.EXE (self-extracting zip archive, can be
* unpacked with unzip).
*/
#define PVR_GPIO_DELAY 10
 
#define BTTV_ALT_DATA 0x000001
#define BTTV_ALT_DCLK 0x100000
#define BTTV_ALT_NCONFIG 0x800000
 
static int __devinit pvr_altera_load(struct bttv *btv, u8 *micro, u32 microlen)
{
u32 n;
u8 bits;
int i;
btwrite(BTTV_ALT_DATA|BTTV_ALT_DCLK|BTTV_ALT_NCONFIG,
BT848_GPIO_OUT_EN);
btwrite(0,BT848_GPIO_DATA);
udelay(PVR_GPIO_DELAY);
btwrite(BTTV_ALT_NCONFIG,BT848_GPIO_DATA);
udelay(PVR_GPIO_DELAY);
 
for (n = 0; n < microlen; n++) {
bits = micro[n];
for ( i = 0 ; i < 8 ; i++ ) {
btand(~BTTV_ALT_DCLK,BT848_GPIO_DATA);
if (bits & 0x01)
btor(BTTV_ALT_DATA,BT848_GPIO_DATA);
else
btand(~BTTV_ALT_DATA,BT848_GPIO_DATA);
btor(BTTV_ALT_DCLK,BT848_GPIO_DATA);
bits >>= 1;
}
}
btand(~BTTV_ALT_DCLK,BT848_GPIO_DATA);
udelay(PVR_GPIO_DELAY);
/* begin Altera init loop (Not necessary,but doesn't hurt) */
for (i = 0 ; i < 30 ; i++) {
btand(~BTTV_ALT_DCLK,BT848_GPIO_DATA);
btor(BTTV_ALT_DCLK,BT848_GPIO_DATA);
}
btand(~BTTV_ALT_DCLK,BT848_GPIO_DATA);
return 0;
}
 
#ifndef CONFIG_FW_LOADER
/* old 2.4.x way -- via soundcore's mod_firmware_load */
static char *firm_altera = "/usr/lib/video4linux/hcwamc.rbf";
MODULE_PARM(firm_altera,"s");
MODULE_PARM_DESC(firm_altera,"WinTV/PVR firmware "
"(driver CD => unzip pvr45xxx.exe => hcwamc.rbf)");
 
extern int mod_firmware_load(const char *fn, char **fp);
 
int __devinit pvr_boot(struct bttv *btv)
{
u32 microlen;
u8 *micro;
int result;
 
microlen = mod_firmware_load(firm_altera, (char**) &micro);
if (!microlen) {
printk(KERN_WARNING "bttv%d: altera firmware not found [%s]\n",
btv->nr, firm_altera);
return -1;
}
printk(KERN_INFO "bttv%d: uploading altera firmware [%s] ...\n",
btv->nr, firm_altera);
result = pvr_altera_load(btv, micro, microlen);
printk(KERN_INFO "bttv%d: ... upload %s\n",
btv->nr, (result < 0) ? "failed" : "ok");
vfree(micro);
return result;
}
#else
/* new 2.5.x way -- via hotplug firmware loader */
 
int __devinit pvr_boot(struct bttv *btv)
{
const struct firmware *fw_entry;
int rc;
 
rc = request_firmware(&fw_entry, "hcwamc.rbf", &btv->dev->dev);
if (rc != 0) {
printk(KERN_WARNING "bttv%d: no altera firmware [via hotplug]\n",
btv->nr);
return rc;
}
}
rc = pvr_altera_load(btv, fw_entry->data, fw_entry->size);
printk(KERN_INFO "bttv%d: altera firmware upload %s\n",
btv->nr, (rc < 0) ? "failed" : "ok");
release_firmware(fw_entry);
return rc;
}
#endif
 
/* ----------------------------------------------------------------------- */
/* some osprey specific stuff */
 
static void __devinit osprey_eeprom(struct bttv *btv)
{
int i = 0;
unsigned char *ee = eeprom_data;
unsigned long serial = 0;
if (btv->type == 0) {
/* this might be an antique...check for MMAC label in eeprom */
if ((ee[0]=='M') && (ee[1]=='M') && (ee[2]=='A') && (ee[3]=='C')) {
unsigned char checksum = 0;
/* that looks like an old card...verify checksum */
for (i =0; i<21; i++) checksum += ee[i];
if (checksum == ee[21]) {
btv->type = BTTV_OSPREY1x0_848;
for (i = 12; i < 21; i++) serial *= 10,serial += ee[i] - '0';
}
}
} else {
/* we know this is an osprey card, find a valid eeprom descriptor */
int offset = 4*16;
if (btv->type == 0) {
/* this might be an antique... check for MMAC label in eeprom */
if ((ee[0]=='M') && (ee[1]=='M') && (ee[2]=='A') && (ee[3]=='C')) {
unsigned char checksum = 0;
for (i =0; i<21; i++)
checksum += ee[i];
if (checksum != ee[21])
return;
btv->type = BTTV_OSPREY1x0_848;
for (i = 12; i < 21; i++)
serial *= 10, serial += ee[i] - '0';
}
} else {
unsigned short type;
int offset = 4*16;
for(; offset < 8*16; offset += 16) {
unsigned short checksum = 0;
/* verify the checksum */
for(i = 0; i<14; i++) checksum += ee[i+offset];
checksum = ~checksum; /* no idea why */
if ((((checksum>>8) & 0x0FF) == ee[offset+14]) &&
((checksum & 0x0FF) == ee[offset+15])) {
break;
}
}
for(; offset < 8*16; offset += 16) {
unsigned short checksum = 0;
/* verify the checksum */
for(i = 0; i<14; i++) checksum += ee[i+offset];
checksum = ~checksum; /* no idea why */
if ((((checksum>>8)&0x0FF) == ee[offset+14]) &&
((checksum & 0x0FF) == ee[offset+15])) {
break;
}
}
if (offset < 8*16) {
/* found a valid descriptor */
unsigned short type = (ee[offset+4]<<8) | (ee[offset+5]);
switch(type) {
/* 848 based */
case 0x0004: {
btv->type = BTTV_OSPREY1x0_848;
break;
}
case 0x0005: {
btv->type = BTTV_OSPREY101_848;
break;
}
/* 878 based */
case 0x0012:
case 0x0013: {
btv->type = BTTV_OSPREY1x0;
break;
}
case 0x0014:
case 0x0015: {
btv->type = BTTV_OSPREY1x1;
break;
}
case 0x0016:
case 0x0017:
case 0x0020: {
btv->type = BTTV_OSPREY1x1_SVID;
break;
}
case 0x0018:
case 0x0019:
case 0x001E:
case 0x001F: {
btv->type = BTTV_OSPREY2xx;
break;
}
case 0x001A:
case 0x001B: {
btv->type = BTTV_OSPREY2x0_SVID;
break;
}
case 0x0060:
case 0x0070: {
btv->type = BTTV_OSPREY2x0;
//enable output on select control lines
btwrite(0x000303, BT848_GPIO_OUT_EN);
break;
}
default: {
/* unknown...leave as generic, but get a serial # */
break;
}
}
serial = (ee[offset+6] << 24)
| (ee[offset+7] << 16)
| (ee[offset+8] << 8)
| (ee[offset+9]);
}
}
if ((btv->type != detected_type) || (serial != 0)){
/* reprint which card config we are using */
sprintf(btv->video_dev.name,"BT%d%s(%.23s)",
btv->id,
(btv->id==848 && btv->revision==0x12) ? "A" : "",
bttv_tvcards[btv->type].name);
printk(KERN_INFO "bttv%d: is now:%s [card=%d,%s] Serial#: %ld\n",
btv->nr,
btv->video_dev.name,
btv->type,
(card[btv->nr] >= 0 && card[btv->nr] < bttv_num_tvcards) ?
"insmod option" : "autodetected",
serial);
}
}
if (offset >= 8*16)
return;
 
/* found a valid descriptor */
type = (ee[offset+4]<<8) | (ee[offset+5]);
switch(type) {
 
/* 848 based */
case 0x0004:
btv->type = BTTV_OSPREY1x0_848;
break;
case 0x0005:
btv->type = BTTV_OSPREY101_848;
break;
/* 878 based */
case 0x0012:
case 0x0013:
btv->type = BTTV_OSPREY1x0;
break;
case 0x0014:
case 0x0015:
btv->type = BTTV_OSPREY1x1;
break;
case 0x0016:
case 0x0017:
case 0x0020:
btv->type = BTTV_OSPREY1x1_SVID;
break;
case 0x0018:
case 0x0019:
case 0x001E:
case 0x001F:
btv->type = BTTV_OSPREY2xx;
break;
case 0x001A:
case 0x001B:
btv->type = BTTV_OSPREY2x0_SVID;
break;
case 0x0040:
btv->type = BTTV_OSPREY500;
break;
case 0x0050:
case 0x0056:
btv->type = BTTV_OSPREY540;
/* bttv_osprey_540_init(btv); */
break;
case 0x0060:
case 0x0070:
btv->type = BTTV_OSPREY2x0;
//enable output on select control lines
btwrite(0x000303, BT848_GPIO_OUT_EN);
break;
default:
/* unknown...leave generic, but get serial # */
break;
}
serial = (ee[offset+6] << 24)
| (ee[offset+7] << 16)
| (ee[offset+8] << 8)
| (ee[offset+9]);
}
printk(KERN_INFO "bttv%d: osprey eeprom: card=%d name=%s serial=%ld\n",
btv->nr, btv->type, bttv_tvcards[btv->type].name,serial);
}
 
/* ----------------------------------------------------------------------- */
/* AVermedia specific stuff, from bktr_card.c */
 
int tuner_0_table[] = {
TUNER_PHILIPS_NTSC, TUNER_PHILIPS_PAL,
TUNER_PHILIPS_NTSC, TUNER_PHILIPS_PAL /* PAL-BG*/,
TUNER_PHILIPS_PAL, TUNER_PHILIPS_PAL /* PAL-I*/,
TUNER_PHILIPS_PAL, TUNER_PHILIPS_PAL,
TUNER_PHILIPS_PAL, TUNER_PHILIPS_PAL,
TUNER_PHILIPS_SECAM, TUNER_PHILIPS_SECAM,
TUNER_PHILIPS_SECAM, TUNER_PHILIPS_PAL};
#if 0
1825,14 → 2764,14
TUNER_TEMIC_4012FY5, TUNER_TEMIC_4012FY5, //TUNER_TEMIC_SECAM
TUNER_TEMIC_4012FY5, TUNER_TEMIC_PAL};
 
static void avermedia_eeprom(struct bttv *btv)
static void __devinit avermedia_eeprom(struct bttv *btv)
{
int tuner_make,tuner_tv_fm,tuner_format,tuner=0,remote;
int tuner_make,tuner_tv_fm,tuner_format,tuner=0;
 
tuner_make = (eeprom_data[0x41] & 0x7);
tuner_tv_fm = (eeprom_data[0x41] & 0x18) >> 3;
tuner_format = (eeprom_data[0x42] & 0xf0) >> 4;
remote = (eeprom_data[0x42] & 0x01);
tuner_make = (eeprom_data[0x41] & 0x7);
tuner_tv_fm = (eeprom_data[0x41] & 0x18) >> 3;
tuner_format = (eeprom_data[0x42] & 0xf0) >> 4;
btv->has_remote = (eeprom_data[0x42] & 0x01);
 
if (tuner_make == 0 || tuner_make == 2)
if(tuner_format <=9)
1841,16 → 2780,16
if(tuner_format <=9)
tuner = tuner_1_table[tuner_format];
cprintf("[info ] bttv%d: Avermedia eeprom[0x%02x%02x]: tuner=",
printk(KERN_INFO "bttv%d: Avermedia eeprom[0x%02x%02x]: tuner=",
btv->nr,eeprom_data[0x41],eeprom_data[0x42]);
if(tuner) {
btv->tuner_type=tuner;
cprintf("%d",tuner);
printk("%d",tuner);
} else
cprintf("Unknown type");
cprintf(" radio:%s remote control:%s\n",
tuner_tv_fm?"yes":"no",
remote?"yes":"no");
printk("Unknown type");
printk(" radio:%s remote control:%s\n",
tuner_tv_fm ? "yes" : "no",
btv->has_remote ? "yes" : "no");
}
 
/* used on Voodoo TV/FM (Voodoo 200), S0 wired to 0x10000 */
1868,26 → 2807,26
dprintk("bttv_tda9880_setnorm to PAL\n");
}
// set GPIO according
gpioaor(bttv_tvcards[btv->type].audiomux[btv->audio],
~bttv_tvcards[btv->type].gpiomask);
btaor(bttv_tvcards[btv->type].audiomux[btv->audio],
~bttv_tvcards[btv->type].gpiomask, BT848_GPIO_DATA);
}
 
 
/*
* reset/enable the MSP on some Hauppauge cards
* Thanks to Ky€sti M€lkki (kmalkki@cc.hut.fi)!
* Thanks to Kyösti Mälkki (kmalkki@cc.hut.fi)!
*
* Hauppauge: pin 5
* Voodoo: pin 20
*/
static void boot_msp34xx(struct bttv *btv, int pin)
static void __devinit boot_msp34xx(struct bttv *btv, int pin)
{
int mask = (1 << pin);
 
btor(mask, BT848_GPIO_OUT_EN);
gpioand(~mask);
btaor(mask, ~mask, BT848_GPIO_OUT_EN);
btaor(0, ~mask, BT848_GPIO_DATA);
udelay(2500);
gpioor(mask);
btaor(mask, ~mask, BT848_GPIO_DATA);
if (bttv_gpio)
bttv_gpio_tracking(btv,"msp34xx");
 
1896,7 → 2835,42
"init [%d]\n", btv->nr, pin);
}
 
static void __devinit boot_bt832(struct bttv *btv)
{
int outbits,databits,resetbit=0;
 
switch (btv->type) {
case BTTV_PXELVWPLTVPAK:
resetbit = 0x400000;
break;
case BTTV_MODTEC_205:
resetbit = 1<<9;
break;
default:
BUG();
}
 
request_module("bt832");
bttv_call_i2c_clients(btv, BT832_HEXDUMP, NULL);
 
printk("bttv%d: Reset Bt832 [line=0x%x]\n",btv->nr,resetbit);
btwrite(0, BT848_GPIO_DATA);
outbits = btread(BT848_GPIO_OUT_EN);
databits= btread(BT848_GPIO_DATA);
btwrite(resetbit, BT848_GPIO_OUT_EN);
udelay(5);
btwrite(resetbit, BT848_GPIO_DATA);
udelay(5);
btwrite(0, BT848_GPIO_DATA);
udelay(5);
btwrite(outbits, BT848_GPIO_OUT_EN);
btwrite(databits, BT848_GPIO_DATA);
 
// bt832 on pixelview changes from i2c 0x8a to 0x88 after
// being reset as above. So we must follow by this:
bttv_call_i2c_clients(btv, BT832_REATTACH, NULL);
}
 
/* ----------------------------------------------------------------------- */
/* Imagenation L-Model PXC200 Framegrabber */
/* This is basically the same procedure as
1903,13 → 2877,20
* used by Alessandro Rubini in his pxc200
* driver, but using BTTV functions */
 
static void init_PXC200(struct bttv *btv)
static void __devinit init_PXC200(struct bttv *btv)
{
static int vals[] __devinitdata = { 0x08, 0x09, 0x0a, 0x0b, 0x0d, 0x0d,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x00 };
unsigned int i;
int tmp;
u32 val;
/* Initialise GPIO-connevted stuff */
btwrite(1<<13,BT848_GPIO_OUT_EN); /* Reset pin only */
gpiowrite(0);
btwrite(0,BT848_GPIO_DATA);
udelay(3);
gpiowrite(1<<13);
btwrite(1<<13,BT848_GPIO_DATA);
/* GPIO inputs are pulled up, so no need to drive
* reset pin any longer */
btwrite(0,BT848_GPIO_OUT_EN);
1923,6 → 2904,7
setting BT848_ADC_AGC_EN disable the AGC
tboult@eecs.lehigh.edu
*/
 
btwrite(BT848_ADC_RESERVED|BT848_ADC_AGC_EN, BT848_ADC);
/* Initialise MAX517 DAC */
1934,9 → 2916,36
* same chips - but the R/W bit is included in the address
* argument so the numbers are different */
 
printk(KERN_INFO "Initialising 12C508 PIC chip ...\n");
 
/* First of all, enable the clock line. This is used in the PXC200-F */
val = btread(BT848_GPIO_DMA_CTL);
val |= BT848_GPIO_DMA_CTL_GPCLKMODE;
btwrite(val, BT848_GPIO_DMA_CTL);
/* Then, push to 0 the reset pin long enough to reset the *
* device same as above for the reset line, but not the same
* value sent to the GPIO-connected stuff
* which one is the good one? */
btwrite( (1<<2), BT848_GPIO_OUT_EN); /* only the reset pin */
btwrite(0, BT848_GPIO_DATA);
udelay(10);
btwrite(1<<2, BT848_GPIO_DATA);
 
for (i = 0; i < ARRAY_SIZE(vals); i++) {
tmp=bttv_I2CWrite(btv,0x1E,0,vals[i],1);
if (tmp != -1) {
printk(KERN_INFO
"I2C Write(%2.2x) = %i\nI2C Read () = %2.2x\n\n",
vals[i],tmp,bttv_I2CRead(btv,0x1F,NULL));
}
}
 
printk(KERN_INFO "PXC200 Initialised.\n");
}
 
 
/* ----------------------------------------------------------------------- */
/* Miro Pro radio stuff -- the tea5757 is connected to some GPIO ports */
/*
1946,18 → 2955,56
* Brutally hacked by Dan Sheridan <dan.sheridan@contact.org.uk> djs52 8/3/00
*/
 
#if 0
/* bus bits on the GPIO port */
#define TEA_WE 6
#define TEA_DATA 9
#define TEA_CLK 8
#define TEA_MOST 7
#endif
void bus_low(struct bttv *btv, int bit)
{
if (btv->mbox_ior) {
btor(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
BT848_GPIO_DATA);
udelay(5);
}
 
#define BUS_LOW(bit) gpioand(~(bit))
#define BUS_HIGH(bit) gpioor((bit))
#define BUS_IN(bit) (gpioread() & (bit))
btand(~(bit), BT848_GPIO_DATA);
udelay(5);
 
if (btv->mbox_ior) {
btand(~(btv->mbox_iow | btv->mbox_csel),
BT848_GPIO_DATA);
udelay(5);
}
}
 
void bus_high(struct bttv *btv, int bit)
{
if (btv->mbox_ior) {
btor(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
BT848_GPIO_DATA);
udelay(5);
}
 
btor((bit), BT848_GPIO_DATA);
udelay(5);
 
if (btv->mbox_ior) {
btand(~(btv->mbox_iow | btv->mbox_csel),
BT848_GPIO_DATA);
udelay(5);
}
}
 
int bus_in(struct bttv *btv, int bit)
{
if (btv->mbox_ior) {
btor(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
BT848_GPIO_DATA);
udelay(5);
 
btand(~(btv->mbox_ior | btv->mbox_csel),
BT848_GPIO_DATA);
udelay(5);
}
return btread(BT848_GPIO_DATA) & (bit);
}
 
/* TEA5757 register bits */
#define TEA_FREQ 0:14
#define TEA_BUFFER 15:15
1985,6 → 3032,103
#define TEA_STATUS_TUNED 0
#define TEA_STATUS_SEARCHING 1
 
/* Low-level stuff */
static int tea5757_read(struct bttv *btv)
{
unsigned long timeout;
int value = 0;
int i;
/* better safe than sorry */
btaor((btv->mbox_clk | btv->mbox_we),
~btv->mbox_mask, BT848_GPIO_OUT_EN);
 
if (btv->mbox_ior) {
btor(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
BT848_GPIO_DATA);
udelay(5);
}
 
if (bttv_gpio)
bttv_gpio_tracking(btv,"tea5757 read");
bus_low(btv,btv->mbox_we);
bus_low(btv,btv->mbox_clk);
udelay(10);
timeout= jiffies + HZ;
 
// wait for DATA line to go low; error if it doesn't
while (bus_in(btv,btv->mbox_data) && time_before(jiffies, timeout))
schedule();
if (bus_in(btv,btv->mbox_data)) {
printk(KERN_WARNING "bttv%d: tea5757: read timeout\n",btv->nr);
return -1;
}
 
dprintk("bttv%d: tea5757:",btv->nr);
for(i = 0; i < 24; i++)
{
udelay(5);
bus_high(btv,btv->mbox_clk);
udelay(5);
dprintk("%c",(bus_in(btv,btv->mbox_most) == 0)?'T':'-');
bus_low(btv,btv->mbox_clk);
value <<= 1;
value |= (bus_in(btv,btv->mbox_data) == 0)?0:1; /* MSB first */
dprintk("%c", (bus_in(btv,btv->mbox_most) == 0)?'S':'M');
}
dprintk("\nbttv%d: tea5757: read 0x%X\n", btv->nr, value);
return value;
}
 
static int tea5757_write(struct bttv *btv, int value)
{
int i;
int reg = value;
btaor(btv->mbox_clk | btv->mbox_we | btv->mbox_data,
~btv->mbox_mask, BT848_GPIO_OUT_EN);
 
if (btv->mbox_ior) {
btor(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
BT848_GPIO_DATA);
udelay(5);
}
if (bttv_gpio)
bttv_gpio_tracking(btv,"tea5757 write");
 
dprintk("bttv%d: tea5757: write 0x%X\n", btv->nr, value);
bus_low(btv,btv->mbox_clk);
bus_high(btv,btv->mbox_we);
for(i = 0; i < 25; i++)
{
if (reg & 0x1000000)
bus_high(btv,btv->mbox_data);
else
bus_low(btv,btv->mbox_data);
reg <<= 1;
bus_high(btv,btv->mbox_clk);
udelay(10);
bus_low(btv,btv->mbox_clk);
udelay(10);
}
bus_low(btv,btv->mbox_we); /* unmute !!! */
return 0;
}
 
void tea5757_set_freq(struct bttv *btv, unsigned short freq)
{
dprintk("tea5757_set_freq %d\n",freq);
tea5757_write(btv, 5 * freq + 0x358); /* add 10.7MHz (see docs) */
#if 0
/* breaks Miro PCTV */
value = tea5757_read(btv);
dprintk("bttv%d: tea5757 readback=0x%x\n",btv->nr,value);
#endif
}
 
 
/* ----------------------------------------------------------------------- */
/* winview */
 
2006,7 → 3150,7
/* tens */
bits_out |= (PT2254_DBS_IN_10>>(vol/5));
bits_out |= PT2254_L_CHANNEL | PT2254_R_CHANNEL;
data = gpioread();
data = btread(BT848_GPIO_DATA);
data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA|
WINVIEW_PT2254_STROBE);
for (loops = 17; loops >= 0 ; loops--) {
2014,20 → 3158,20
data |= WINVIEW_PT2254_DATA;
else
data &= ~WINVIEW_PT2254_DATA;
gpiowrite(data);
btwrite(data, BT848_GPIO_DATA);
udelay(5);
data |= WINVIEW_PT2254_CLK;
gpiowrite(data);
btwrite(data, BT848_GPIO_DATA);
udelay(5);
data &= ~WINVIEW_PT2254_CLK;
gpiowrite(data);
btwrite(data, BT848_GPIO_DATA);
}
data |= WINVIEW_PT2254_STROBE;
data &= ~WINVIEW_PT2254_DATA;
gpiowrite(data);
btwrite(data, BT848_GPIO_DATA);
udelay(10);
data &= ~WINVIEW_PT2254_STROBE;
gpiowrite(data);
btwrite(data, BT848_GPIO_DATA);
}
 
/* ----------------------------------------------------------------------- */
2049,7 → 3193,7
con = 0x200;
// if (v->mode & VIDEO_SOUND_MONO)
// con = 0x100;
gpioaor(con, ~0x300);
btaor(con, ~0x300, BT848_GPIO_DATA);
} else {
v->mode = VIDEO_SOUND_STEREO |
VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
2080,7 → 3224,7
if (v->mode & VIDEO_SOUND_STEREO)
val = 0x01;
if (val) {
gpioaor(val, ~0x03);
btaor(val, ~0x03, BT848_GPIO_DATA);
if (bttv_gpio)
bttv_gpio_tracking(btv,"avermedia");
}
2097,7 → 3241,7
{
int val = 0;
 
if (gpioread() & 0x4000) {
if (btread(BT848_GPIO_DATA) & 0x4000) {
v->mode = VIDEO_SOUND_MONO;
return;
}
2110,7 → 3254,7
if ((v->mode & VIDEO_SOUND_LANG1) ||
(v->mode & VIDEO_SOUND_MONO))
val = 0;
gpioaor(val, ~0x0880);
btaor(val, ~0x0880, BT848_GPIO_DATA);
if (bttv_gpio)
bttv_gpio_tracking(btv,"lt9415");
} else {
2121,7 → 3265,7
}
}
 
 
// TDA9821 on TerraTV+ Bt848, Bt878
static void
terratv_audio(struct bttv *btv, struct video_audio *v, int set)
{
2133,7 → 3277,7
con = 0x080000;
if (v->mode & VIDEO_SOUND_STEREO)
con = 0x180000;
gpioaor(con, ~0x180000);
btaor(con, ~0x180000, BT848_GPIO_DATA);
if (bttv_gpio)
bttv_gpio_tracking(btv,"terratv");
} else {
2158,7 → 3302,7
if (v->mode & VIDEO_SOUND_STEREO) /* Stereo */
val = 0x020000;
if (val) {
gpioaor(val, ~0x430000);
btaor(val, ~0x430000, BT848_GPIO_DATA);
if (bttv_gpio)
bttv_gpio_tracking(btv,"winfast2000");
}
2172,6 → 3316,9
* Dariusz Kowalewski <darekk@automex.pl>
* sound control for Prolink PV-BT878P+9B (PixelView PlayTV Pro FM+NICAM
* revision 9B has on-board TDA9874A sound decoder).
*
* Note: There are card variants without tda9874a. Forcing the "stereo sound route"
* will mute this cards.
*/
static void
pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set)
2178,8 → 3325,13
{
unsigned int val = 0;
 
#if BTTV_VERSION_CODE > KERNEL_VERSION(0,8,0)
if (btv->radio_user)
return;
#else
if (btv->radio)
return;
#endif
 
if (set) {
if (v->mode & VIDEO_SOUND_MONO) {
2190,7 → 3342,7
val = 0x02;
}
if (val) {
gpioaor(val, ~0x03);
btaor(val, ~0x03, BT848_GPIO_DATA);
if (bttv_gpio)
bttv_gpio_tracking(btv,"pvbt878p9b");
}
2210,9 → 3362,13
{
unsigned int val = 0xffff;
 
#if BTTV_VERSION_CODE > KERNEL_VERSION(0,8,0)
if (btv->radio_user)
return;
#else
if (btv->radio)
return;
#endif
if (set) {
if (v->mode & VIDEO_SOUND_MONO) {
val = 0x0000;
2222,7 → 3378,7
val = 0x1080; //-dk-???: 0x0880, 0x0080, 0x1800 ...
}
if (val != 0xffff) {
gpioaor(val, ~0x1800);
btaor(val, ~0x1800, BT848_GPIO_DATA);
if (bttv_gpio)
bttv_gpio_tracking(btv,"fv2000s");
}
2251,7 → 3407,7
if (v->mode & VIDEO_SOUND_STEREO)
val = 0;
if (val) {
gpioaor(val, ~0x140000);
btaor(val, ~0x140000, BT848_GPIO_DATA);
if (bttv_gpio)
bttv_gpio_tracking(btv,"windvr");
}
2261,6 → 3417,38
}
}
 
/*
* sound control for AD-TVK503
* Hiroshi Takekawa <sian@big.or.jp>
*/
static void
adtvk503_audio(struct bttv *btv, struct video_audio *v, int set)
{
unsigned int con = 0xffffff;
 
//btaor(0x1e0000, ~0x1e0000, BT848_GPIO_OUT_EN);
 
if (set) {
//btor(***, BT848_GPIO_OUT_EN);
if (v->mode & VIDEO_SOUND_LANG1)
con = 0x00000000;
if (v->mode & VIDEO_SOUND_LANG2)
con = 0x00180000;
if (v->mode & VIDEO_SOUND_STEREO)
con = 0x00000000;
if (v->mode & VIDEO_SOUND_MONO)
con = 0x00060000;
if (con != 0xffffff) {
btaor(con, ~0x1e0000, BT848_GPIO_DATA);
if (bttv_gpio)
bttv_gpio_tracking(btv, "adtvk503");
}
} else {
v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
}
}
 
/* RemoteVision MX (rv605) muxsel helper [Miguel Freitas]
*
* This is needed because rv605 don't use a normal multiplex, but a crosspoint
2288,70 → 3476,169
static void rv605_muxsel(struct bttv *btv, unsigned int input)
{
/* reset all conections */
gpioaor(0x200,~0x200);
udelay(1000);
gpioaor(0x000,~0x200);
udelay(1000);
btaor(0x200,~0x200, BT848_GPIO_DATA);
mdelay(1);
btaor(0x000,~0x200, BT848_GPIO_DATA);
mdelay(1);
 
/* create a new conection */
gpioaor(0x080,~0x480);
gpioaor(0x480,~0x480);
udelay(1000);
gpioaor(0x080,~0x480);
udelay(1000);
btaor(0x080,~0x480, BT848_GPIO_DATA);
btaor(0x480,~0x480, BT848_GPIO_DATA);
mdelay(1);
btaor(0x080,~0x480, BT848_GPIO_DATA);
mdelay(1);
}
 
// The Grandtec X-Guard framegrabber card uses two Dual 4-channel
// video multiplexers to provide up to 16 video inputs. These
// multiplexers are controlled by the lower 8 GPIO pins of the
// bt878. The multiplexers probably Pericom PI5V331Q or similar.
 
// xxx0 is pin xxx of multiplexer U5,
// yyy1 is pin yyy of multiplexer U2
 
#define ENA0 0x01
#define ENB0 0x02
#define ENA1 0x04
#define ENB1 0x08
 
#define IN10 0x10
#define IN00 0x20
#define IN11 0x40
#define IN01 0x80
 
static void xguard_muxsel(struct bttv *btv, unsigned int input)
{
static const int masks[] = {
ENB0, ENB0|IN00, ENB0|IN10, ENB0|IN00|IN10,
ENA0, ENA0|IN00, ENA0|IN10, ENA0|IN00|IN10,
ENB1, ENB1|IN01, ENB1|IN11, ENB1|IN01|IN11,
ENA1, ENA1|IN01, ENA1|IN11, ENA1|IN01|IN11,
};
btwrite(masks[input%16], BT848_GPIO_DATA);
}
 
/*
* ivc120_muxsel [Added by Alan Garfield <alan@fromorbit.com>]
*
* The IVC120G security card has 4 i2c controlled TDA8540 matrix
* swichers to provide 16 channels to MUX0. The TDA8540's have
* 4 indepedant outputs and as such the IVC120G also has the
* optional "Monitor Out" bus. This allows the card to be looking
* at one input while the monitor is looking at another.
*
* Since I've couldn't be bothered figuring out how to add an
* independant muxsel for the monitor bus, I've just set it to
* whatever the card is looking at.
*
* OUT0 of the TDA8540's is connected to MUX0 (0x03)
* OUT1 of the TDA8540's is connected to "Monitor Out" (0x0C)
*
* TDA8540_ALT3 IN0-3 = Channel 13 - 16 (0x03)
* TDA8540_ALT4 IN0-3 = Channel 1 - 4 (0x03)
* TDA8540_ALT5 IN0-3 = Channel 5 - 8 (0x03)
* TDA8540_ALT6 IN0-3 = Channel 9 - 12 (0x03)
*
*/
 
/* All 7 possible sub-ids for the TDA8540 Matrix Switcher */
#define I2C_TDA8540 0x90
#define I2C_TDA8540_ALT1 0x92
#define I2C_TDA8540_ALT2 0x94
#define I2C_TDA8540_ALT3 0x96
#define I2C_TDA8540_ALT4 0x98
#define I2C_TDA8540_ALT5 0x9a
#define I2C_TDA8540_ALT6 0x9c
 
static void ivc120_muxsel(struct bttv *btv, unsigned int input)
{
// Simple maths
int key = input % 4;
int matrix = input / 4;
dprintk("bttv%d: ivc120_muxsel: Input - %02d | TDA - %02d | In - %02d\n",
btv->nr, input, matrix, key);
// Handles the input selection on the TDA8540's
bttv_I2CWrite(btv, I2C_TDA8540_ALT3, 0x00,
((matrix == 3) ? (key | key << 2) : 0x00), 1);
bttv_I2CWrite(btv, I2C_TDA8540_ALT4, 0x00,
((matrix == 0) ? (key | key << 2) : 0x00), 1);
bttv_I2CWrite(btv, I2C_TDA8540_ALT5, 0x00,
((matrix == 1) ? (key | key << 2) : 0x00), 1);
bttv_I2CWrite(btv, I2C_TDA8540_ALT6, 0x00,
((matrix == 2) ? (key | key << 2) : 0x00), 1);
// Handles the output enables on the TDA8540's
bttv_I2CWrite(btv, I2C_TDA8540_ALT3, 0x02,
((matrix == 3) ? 0x03 : 0x00), 1); // 13 - 16
bttv_I2CWrite(btv, I2C_TDA8540_ALT4, 0x02,
((matrix == 0) ? 0x03 : 0x00), 1); // 1-4
bttv_I2CWrite(btv, I2C_TDA8540_ALT5, 0x02,
((matrix == 1) ? 0x03 : 0x00), 1); // 5-8
bttv_I2CWrite(btv, I2C_TDA8540_ALT6, 0x02,
((matrix == 2) ? 0x03 : 0x00), 1); // 9-12
// Selects MUX0 for input on the 878
btaor((0)<<5, ~(3<<5), BT848_IFORM);
}
 
 
/* ----------------------------------------------------------------------- */
/* motherboard chipset specific stuff */
 
void bttv_check_chipset(void)
void __devinit bttv_check_chipset(void)
{
int pcipci_fail = 0;
struct pci_dev dev;
BYTE bus, dv;
struct pci_dev *dev = NULL;
 
triton1 = 0;
vsfx = 0;
if (pci_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, 0, &bus, &dv)) pcipci_fail = 1;
if (pci_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, 0, &bus, &dv)) pcipci_fail = 1;
if (pci_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, 0, &bus, &dv)) triton1 = 1;
if (pci_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_0, 0, &bus, &dv)) triton1 = 1;
if (pci_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, 0, &bus, &dv)) triton1 = 1;
if (pci_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576, 0, &bus, &dv)) vsfx = 1;
if (pci_pci_problems & PCIPCI_FAIL)
pcipci_fail = 1;
if (pci_pci_problems & (PCIPCI_TRITON|PCIPCI_NATOMA|PCIPCI_VIAETBF))
triton1 = 1;
if (pci_pci_problems & PCIPCI_VSFX)
vsfx = 1;
#ifdef PCIPCI_ALIMAGIK
if (pci_pci_problems & PCIPCI_ALIMAGIK)
latency = 0x0A;
#endif
 
#if 0
/* print which chipset we have */
while ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8,dev)))
printk(KERN_INFO "bttv: Host bridge is %s\n",pci_name(dev));
#endif
 
/* print warnings about any quirks found */
if (triton1)
printk(KERN_INFO "bttv: Host bridge needs ETBF enabled.\n");
if (vsfx)
printk(KERN_INFO "bttv: Host bridge needs VSFX enabled.\n");
 
if (pcipci_fail) {
printk(KERN_WARNING "bttv: BT848 and your chipset may not work together.\n");
if (-1 == no_overlay) {
if (UNSET == no_overlay) {
printk(KERN_WARNING "bttv: going to disable overlay.\n");
no_overlay = 1;
}
}
if (UNSET != latency)
printk(KERN_INFO "bttv: pci latency fixup [%d]\n",latency);
 
if(pci_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, 0, &bus, &dv)) {
while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82441, dev))) {
unsigned char b;
dev.bus->number = bus;
dev.devfn = dv;
pci_read_config_byte(&dev, 0x53, &b);
pci_read_config_byte(dev, 0x53, &b);
if (bttv_debug)
printk(KERN_INFO "bttv: Host bridge: 82441FX Natoma, "
"bufcon=0x%02x\n",b);
}
 
}
 
int bttv_handle_chipset(struct bttv *btv)
int __devinit bttv_handle_chipset(struct bttv *btv)
{
unsigned char command;
 
if (!triton1 && !vsfx)
if (!triton1 && !vsfx && UNSET == latency)
return 0;
 
if (bttv_verbose) {
2359,6 → 3646,9
printk(KERN_INFO "bttv%d: enabling ETBF (430FX/VP3 compatibilty)\n",btv->nr);
if (vsfx && btv->id >= 878)
printk(KERN_INFO "bttv%d: enabling VSFX\n",btv->nr);
if (UNSET != latency)
printk(KERN_INFO "bttv%d: setting pci timer to %d\n",
btv->nr,latency);
}
 
if (btv->id < 878) {
2374,6 → 3664,14
command |= BT878_EN_VSFX;
pci_write_config_byte(btv->dev, BT878_DEVCTRL, command);
}
if (UNSET != latency)
pci_write_config_byte(btv->dev, PCI_LATENCY_TIMER, latency);
return 0;
}
 
 
/*
* Local variables:
* c-basic-offset: 8
* End:
*/
/shark/trunk/drivers/bttv/bttv-if.c
7,7 → 7,7
 
Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
& Marcus Metzler (mocm@thp.uni-koeln.de)
(c) 1999,2000 Gerd Knorr <kraxel@goldbach.in-berlin.de>
(c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
 
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
25,29 → 25,47
*/
 
/* SHARK version by Giacomo Guidi <giacomo@gandalf.sssup.it> */
#include <linuxcomp.h>
 
#define __NO_VERSION__ 1
#include <linux/module.h>
#include <linux/init.h>
#include <linux/delay.h>
 
#include <linux/pci.h>
#include <string.h>
#include <asm/io.h>
 
#include "drivers/bttv.h"
#include "drivers/tuner.h"
#include "drivers/bttvp.h"
 
#define printk cprintf
 
static struct i2c_algo_bit_data bttv_i2c_algo_template;
static struct i2c_adapter bttv_i2c_adap_template;
static struct i2c_algo_bit_data bttv_i2c_algo_bit_template;
static struct i2c_adapter bttv_i2c_adap_sw_template;
static struct i2c_adapter bttv_i2c_adap_hw_template;
static struct i2c_client bttv_i2c_client_template;
 
#ifndef I2C_PEC
static void bttv_inc_use(struct i2c_adapter *adap);
static void bttv_dec_use(struct i2c_adapter *adap);
#endif
static int attach_inform(struct i2c_client *client);
 
EXPORT_SYMBOL(bttv_get_cardinfo);
EXPORT_SYMBOL(bttv_get_pcidev);
EXPORT_SYMBOL(bttv_get_id);
EXPORT_SYMBOL(bttv_gpio_enable);
EXPORT_SYMBOL(bttv_read_gpio);
EXPORT_SYMBOL(bttv_write_gpio);
EXPORT_SYMBOL(bttv_get_gpio_queue);
EXPORT_SYMBOL(bttv_i2c_call);
 
static int i2c_debug = 0;
static int i2c_hw = 0;
MODULE_PARM(i2c_debug,"i");
MODULE_PARM(i2c_hw,"i");
 
/* ----------------------------------------------------------------------- */
/* Exported functions - for other modules which want to access the */
/* gpio ports (IR for example) */
/* see bttv.h for comments */
 
int bttv_get_cardinfo(unsigned int card, int *type, int *cardid)
int bttv_get_cardinfo(unsigned int card, int *type, unsigned *cardid)
{
if (card >= bttv_num) {
return -1;
57,6 → 75,23
return 0;
}
 
struct pci_dev* bttv_get_pcidev(unsigned int card)
{
if (card >= bttv_num)
return NULL;
return bttvs[card].dev;
}
 
int bttv_get_id(unsigned int card)
{
printk("bttv_get_id is obsolete, use bttv_get_cardinfo instead\n");
if (card >= bttv_num) {
return -1;
}
return bttvs[card].type;
}
 
 
int bttv_gpio_enable(unsigned int card, unsigned long mask, unsigned long data)
{
struct bttv *btv;
88,7 → 123,7
 
/* prior setting BT848_GPIO_REG_INP is (probably) not needed
because we set direct input on init */
*data = gpioread();
*data = btread(BT848_GPIO_DATA);
return 0;
}
 
104,39 → 139,53
 
/* prior setting BT848_GPIO_REG_INP is (probably) not needed
because direct input is set on init */
gpioaor(data & mask, ~mask);
btaor(data & mask, ~mask, BT848_GPIO_DATA);
if (bttv_gpio)
bttv_gpio_tracking(btv,"extern write");
return 0;
}
 
wait_queue_head_t* bttv_get_gpio_queue(unsigned int card)
{
struct bttv *btv;
 
if (card >= bttv_num) {
return NULL;
}
 
btv = &bttvs[card];
if (bttvs[card].shutdown) {
return NULL;
}
return &btv->gpioq;
}
 
 
/* ----------------------------------------------------------------------- */
/* I2C functions */
/* I2C functions - bitbanging adapter (software i2c) */
 
void bttv_bit_setscl(void *data, int state)
{
struct bttv *btv = (struct bttv*)data;
unsigned long tmp;
 
if (state)
btv->i2c_state |= 0x02;
else
btv->i2c_state &= ~0x02;
btwrite(btv->i2c_state, BT848_I2C);
tmp = btread(BT848_I2C);
btread(BT848_I2C);
}
 
void bttv_bit_setsda(void *data, int state)
{
struct bttv *btv = (struct bttv*)data;
unsigned long tmp;
 
if (state)
btv->i2c_state |= 0x01;
else
btv->i2c_state &= ~0x01;
btwrite(btv->i2c_state, BT848_I2C);
tmp = btread(BT848_I2C);
btread(BT848_I2C);
}
 
static int bttv_bit_getscl(void *data)
157,88 → 206,256
return state;
}
 
static void bttv_inc_use(struct i2c_adapter *adap)
static struct i2c_algo_bit_data bttv_i2c_algo_bit_template = {
.setsda = bttv_bit_setsda,
.setscl = bttv_bit_setscl,
.getsda = bttv_bit_getsda,
.getscl = bttv_bit_getscl,
.udelay = 16,
.mdelay = 10,
.timeout = 200,
};
 
static struct i2c_adapter bttv_i2c_adap_sw_template = {
#ifdef I2C_PEC
.owner = THIS_MODULE,
#else
.inc_use = bttv_inc_use,
.dec_use = bttv_dec_use,
#endif
#ifdef I2C_ADAP_CLASS_TV_ANALOG
.class = I2C_ADAP_CLASS_TV_ANALOG,
#endif
I2C_DEVNAME("bt848"),
.id = I2C_HW_B_BT848,
.client_register = attach_inform,
};
 
/* ----------------------------------------------------------------------- */
/* I2C functions - hardware i2c */
 
static int algo_control(struct i2c_adapter *adapter,
unsigned int cmd, unsigned long arg)
{
MOD_INC_USE_COUNT;
return 0;
}
 
static void bttv_dec_use(struct i2c_adapter *adap)
static u32 functionality(struct i2c_adapter *adap)
{
MOD_DEC_USE_COUNT;
return I2C_FUNC_SMBUS_EMUL;
}
 
static int attach_inform(struct i2c_client *client)
static int
bttv_i2c_wait_done(struct bttv *btv)
{
struct bttv *btv = (struct bttv*)client->adapter->data;
int i;
u32 stat;
unsigned long timeout;
 
for (i = 0; i < I2C_CLIENTS_MAX; i++) {
if (btv->i2c_clients[i] == NULL) {
btv->i2c_clients[i] = client;
timeout = jiffies + HZ/100 + 1; /* 10ms */
for (;;) {
stat = btread(BT848_INT_STAT);
if (stat & BT848_INT_I2CDONE)
break;
if (time_after(jiffies,timeout))
return -EIO;
udelay(10);
}
btwrite(BT848_INT_I2CDONE|BT848_INT_RACK, BT848_INT_STAT);
return ((stat & BT848_INT_RACK) ? 1 : 0);
}
 
#define I2C_HW (BT878_I2C_MODE | BT848_I2C_SYNC |\
BT848_I2C_SCL | BT848_I2C_SDA)
 
static int
bttv_i2c_sendbytes(struct bttv *btv, const struct i2c_msg *msg, int last)
{
u32 xmit;
int retval,cnt;
 
/* start, address + first byte */
xmit = (msg->addr << 25) | (msg->buf[0] << 16) | I2C_HW;
if (msg->len > 1 || !last)
xmit |= BT878_I2C_NOSTOP;
btwrite(xmit, BT848_I2C);
retval = bttv_i2c_wait_done(btv);
if (retval < 0)
goto err;
if (retval == 0)
goto eio;
if (i2c_debug) {
printk(" <W %02x %02x", msg->addr << 1, msg->buf[0]);
if (!(xmit & BT878_I2C_NOSTOP))
printk(" >\n");
}
 
for (cnt = 1; cnt < msg->len; cnt++ ) {
/* following bytes */
xmit = (msg->buf[cnt] << 24) | I2C_HW | BT878_I2C_NOSTART;
if (cnt < msg->len-1 || !last)
xmit |= BT878_I2C_NOSTOP;
btwrite(xmit, BT848_I2C);
retval = bttv_i2c_wait_done(btv);
if (retval < 0)
goto err;
if (retval == 0)
goto eio;
if (i2c_debug) {
printk(" %02x", msg->buf[cnt]);
if (!(xmit & BT878_I2C_NOSTOP))
printk(" >\n");
}
}
if (btv->tuner_type != -1)
bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type);
if (bttv_verbose)
cprintf("bttv%d: i2c attach [client=%s,%s]\n",btv->nr,
client->name, (i < I2C_CLIENTS_MAX) ? "ok" : "failed");
return 0;
return msg->len;
 
eio:
retval = -EIO;
err:
if (i2c_debug)
printk(" ERR: %d\n",retval);
return retval;
}
 
static int detach_inform(struct i2c_client *client)
static int
bttv_i2c_readbytes(struct bttv *btv, const struct i2c_msg *msg, int last)
{
struct bttv *btv = (struct bttv*)client->adapter->data;
int i;
u32 xmit;
u32 cnt;
int retval;
 
for (i = 0; i < I2C_CLIENTS_MAX; i++) {
if (btv->i2c_clients[i] == client) {
btv->i2c_clients[i] = NULL;
break;
for(cnt = 0; cnt < msg->len; cnt++) {
xmit = (msg->addr << 25) | (1 << 24) | I2C_HW;
if (cnt < msg->len-1)
xmit |= BT848_I2C_W3B;
if (cnt < msg->len-1 || !last)
xmit |= BT878_I2C_NOSTOP;
if (cnt)
xmit |= BT878_I2C_NOSTART;
btwrite(xmit, BT848_I2C);
retval = bttv_i2c_wait_done(btv);
if (retval < 0)
goto err;
if (retval == 0)
goto eio;
msg->buf[cnt] = ((u32)btread(BT848_I2C) >> 8) & 0xff;
if (i2c_debug) {
if (!(xmit & BT878_I2C_NOSTART))
printk(" <R %02x", (msg->addr << 1) +1);
printk(" =%02x", msg->buf[cnt]);
if (!(xmit & BT878_I2C_NOSTOP))
printk(" >\n");
}
}
if (bttv_verbose)
cprintf("bttv%d: i2c detach [client=%s,%s]\n",btv->nr,
client->name, (i < I2C_CLIENTS_MAX) ? "ok" : "failed");
return 0;
return msg->len;
 
eio:
retval = -EIO;
err:
if (i2c_debug)
printk(" ERR: %d\n",retval);
return retval;
}
 
void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg)
int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
{
struct bttv *btv = i2c_get_adapdata(i2c_adap);
int retval = 0;
int i;
for (i = 0; i < I2C_CLIENTS_MAX; i++) {
if (NULL == btv->i2c_clients[i])
continue;
if (NULL == btv->i2c_clients[i]->driver->command)
continue;
btv->i2c_clients[i]->driver->command(
btv->i2c_clients[i],cmd,arg);
 
if (i2c_debug)
printk("bt-i2c:");
btwrite(BT848_INT_I2CDONE|BT848_INT_RACK, BT848_INT_STAT);
for (i = 0 ; i < num; i++) {
if (msgs[i].flags & I2C_M_RD) {
/* read */
retval = bttv_i2c_readbytes(btv, &msgs[i], i+1 == num);
if (retval < 0)
goto err;
} else {
/* write */
retval = bttv_i2c_sendbytes(btv, &msgs[i], i+1 == num);
if (retval < 0)
goto err;
}
}
return num;
 
err:
return retval;
}
 
static struct i2c_algo_bit_data bttv_i2c_algo_template = {
setsda: bttv_bit_setsda,
setscl: bttv_bit_setscl,
getsda: bttv_bit_getsda,
getscl: bttv_bit_getscl,
udelay: 16,
mdelay: 10,
timeout: 200,
static struct i2c_algorithm bttv_algo = {
.name = "bt878",
.id = I2C_ALGO_BIT | I2C_HW_B_BT848 /* FIXME */,
.master_xfer = bttv_i2c_xfer,
.algo_control = algo_control,
.functionality = functionality,
};
 
static struct i2c_adapter bttv_i2c_adap_template = {
name: "bt848",
id: I2C_HW_B_BT848,
inc_use: bttv_inc_use,
dec_use: bttv_dec_use,
client_register: attach_inform,
client_unregister: detach_inform,
static struct i2c_adapter bttv_i2c_adap_hw_template = {
#ifdef I2C_PEC
.owner = THIS_MODULE,
#else
.inc_use = bttv_inc_use,
.dec_use = bttv_dec_use,
#endif
#ifdef I2C_ADAP_CLASS_TV_ANALOG
.class = I2C_ADAP_CLASS_TV_ANALOG,
#endif
I2C_DEVNAME("bt878"),
.id = I2C_ALGO_BIT | I2C_HW_B_BT848 /* FIXME */,
.algo = &bttv_algo,
.client_register = attach_inform,
};
 
/* ----------------------------------------------------------------------- */
/* I2C functions - common stuff */
 
#ifndef I2C_PEC
static void bttv_inc_use(struct i2c_adapter *adap)
{
MOD_INC_USE_COUNT;
}
 
static void bttv_dec_use(struct i2c_adapter *adap)
{
MOD_DEC_USE_COUNT;
}
#endif
 
static int attach_inform(struct i2c_client *client)
{
struct bttv *btv = i2c_get_adapdata(client->adapter);
 
if (btv->tuner_type != UNSET)
bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type);
if (btv->pinnacle_id != UNSET)
bttv_call_i2c_clients(btv,AUDC_CONFIG_PINNACLE,
&btv->pinnacle_id);
 
if (bttv_debug)
printk("bttv%d: i2c attach [client=%s]\n",
btv->nr, i2c_clientname(client));
return 0;
}
 
void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg)
{
if (0 != btv->i2c_rc)
return;
i2c_clients_command(&btv->i2c_adap, cmd, arg);
}
 
void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg)
{
if (card >= bttv_num)
return;
bttv_call_i2c_clients(&bttvs[card], cmd, arg);
}
 
static struct i2c_client bttv_i2c_client_template = {
name: "bttv internal use only",
id: -1,
I2C_DEVNAME("bttv internal"),
.id = -1,
};
 
 
250,7 → 467,7
if (0 != btv->i2c_rc)
return -1;
if (bttv_verbose && NULL != probe_for)
printk("[info ] bttv%d: i2c: checking for %s @ 0x%02x... ",
printk(KERN_INFO "bttv%d: i2c: checking for %s @ 0x%02x... ",
btv->nr,probe_for,addr);
btv->i2c_client.addr = addr >> 1;
if (1 != i2c_master_recv(&btv->i2c_client, &buffer, 1)) {
258,7 → 475,7
if (bttv_verbose)
printk("not found\n");
} else
printk("bttv%d: i2c read 0x%x: error\n",
printk(KERN_WARNING "bttv%d: i2c read 0x%x: error\n",
btv->nr,addr);
return -1;
}
285,86 → 502,76
}
 
/* read EEPROM content */
void bttv_readee(struct bttv *btv, unsigned char *eedata, int addr)
void __devinit bttv_readee(struct bttv *btv, unsigned char *eedata, int addr)
{
int i;
if (bttv_I2CWrite(btv, addr, 0, -1, 0)<0) {
printk("bttv: readee error\n");
printk(KERN_WARNING "bttv: readee error\n");
return;
}
btv->i2c_client.addr = addr >> 1;
for (i=0; i<256; i+=16) {
if (16 != i2c_master_recv(&btv->i2c_client,eedata+i,16)) {
printk("bttv: readee error\n");
printk(KERN_WARNING "bttv: readee error\n");
break;
}
}
}
 
/* TODO: get an assigned bus id */
#define I2C_HW_B_BT848_OSPREY 0x0FF
/* init + register i2c algo-bit adapter */
int init_bttv_i2c(struct bttv *btv)
int __devinit init_bttv_i2c(struct bttv *btv)
{
memcpy(&btv->i2c_adap, &bttv_i2c_adap_template,
sizeof(struct i2c_adapter));
if ((btv->type == BTTV_OSPREY2000) ||
(btv->type == BTTV_OSPREY5x0)) {
/* these boards have the bt860 which conflicts with the tda7432
* which will attempt to load when this type of bus is registered.
* change the bus name to prevent this (and any other conflicts)
* from occuring */
btv->i2c_adap.id = I2C_HW_B_BT848_OSPREY;
}
memcpy(&btv->i2c_algo, &bttv_i2c_algo_template,
sizeof(struct i2c_algo_bit_data));
int use_hw = (btv->id == 878) && i2c_hw;
 
memcpy(&btv->i2c_client, &bttv_i2c_client_template,
sizeof(struct i2c_client));
sizeof(bttv_i2c_client_template));
 
sprintf(btv->i2c_adap.name+strlen(btv->i2c_adap.name),
" #%d", btv->nr);
btv->i2c_algo.data = btv;
btv->i2c_adap.data = btv;
btv->i2c_adap.algo_data = &btv->i2c_algo;
if (use_hw) {
/* bt878 */
memcpy(&btv->i2c_adap, &bttv_i2c_adap_hw_template,
sizeof(bttv_i2c_adap_hw_template));
} else {
/* bt848 */
memcpy(&btv->i2c_adap, &bttv_i2c_adap_sw_template,
sizeof(bttv_i2c_adap_sw_template));
memcpy(&btv->i2c_algo, &bttv_i2c_algo_bit_template,
sizeof(bttv_i2c_algo_bit_template));
btv->i2c_algo.data = btv;
btv->i2c_adap.algo_data = &btv->i2c_algo;
}
 
btv->i2c_adap.dev.parent = &btv->dev->dev;
snprintf(btv->i2c_adap.name, sizeof(btv->i2c_adap.name),
"bt%d #%d [%s]", btv->id, btv->nr, use_hw ? "hw" : "sw");
 
i2c_set_adapdata(&btv->i2c_adap, btv);
btv->i2c_client.adapter = &btv->i2c_adap;
 
bttv_bit_setscl(btv,1);
bttv_bit_setsda(btv,1);
 
printk("[info ] bttv: adding i2c bus to system\n");
btv->i2c_rc = i2c_bit_add_bus(&btv->i2c_adap);
printk("[info ] bttv: i2c bus added to system\n");
if (use_hw) {
btv->i2c_rc = i2c_add_adapter(&btv->i2c_adap);
} else {
bttv_bit_setscl(btv,1);
bttv_bit_setsda(btv,1);
btv->i2c_rc = i2c_bit_add_bus(&btv->i2c_adap);
}
return btv->i2c_rc;
}
 
/* find a bttv struct by matching some data from the pci bus (for audio) */
struct bttv *bttv_find_matching_card( struct pci_dev *dev )
int __devexit fini_bttv_i2c(struct bttv *btv)
{
int i;
if (dev == NULL) return NULL;
for (i = 0;i < bttv_num;i++) {
if (bttvs[i].dev == NULL) {
continue; //hmm...can this ever happen?
}
if ((dev->bus->number == bttvs[i].dev->bus->number) &&
(PCI_SLOT(dev->devfn) == PCI_SLOT(bttvs[i].dev->devfn))) {
//match! return this one.
return &(bttvs[i]);
}
int use_hw = (btv->id == 878) && i2c_hw;
 
if (0 != btv->i2c_rc)
return 0;
 
if (use_hw) {
return i2c_del_adapter(&btv->i2c_adap);
} else {
return i2c_bit_del_bus(&btv->i2c_adap);
}
return NULL;
}
 
struct gpio_adapter *bttv_get_gpio( struct bttv *btv )
{
return &(btv->gpio_adap);
}
 
/*
* Local variables:
* c-basic-offset: 8
/shark/trunk/drivers/bttv/fg.c
5,11 → 5,13
*
*/
 
#include <drivers/bttv.h>
#include <drivers/fg.h>
#include <kernel/kern.h>
#include <unistd.h>
 
#include <linuxcomp.h>
 
#include <drivers/bttv.h>
#include <drivers/bttvp.h>
 
extern void bttv_start(struct bttv *btv);
extern int bttv_ioctl(struct bttv *btv, unsigned int cmg, void *arg);
extern void bttv_close(struct bttv *btv);
20,9 → 22,6
static struct video_mmap vmm;
static void * fbuf_pointer;
 
PID refresh_PID;
HARD_TASK_MODEL ht_refresh;
 
static void (*elaborate_frame_hook)(void * ptrframe);
 
void dummy_elaborate_frame(void * ptrframe)
29,7 → 28,7
{
}
 
TASK FG_refresh(void)
void FG_refresh(void)
{
 
int err;
38,27 → 37,23
 
if (vmm.frame == 0) {
vmm.frame = 1;
fbuf_pointer = btv.fbuffer;
// fbuf_pointer = (void *)(btv.fbuffer);
/* *(BYTE *)fbuf_pointer = 255;
* *(BYTE *)(fbuf_pointer+1) = 0;
*/
} else {
vmm.frame = 0;
fbuf_pointer = btv.fbuffer+gbufsize;
//fbuf_pointer = btv.fbuffer+gbufsize;
/* *(BYTE *)fbuf_pointer = 0;
* *(BYTE *)(fbuf_pointer+1) = 255;
*/
}
 
task_testcancel();
err = bttv_ioctl(&btv, VIDIOCMCAPTURE, &vmm);
if (err) kern_printf("(BTTV_IOCTL Error: %d)",err);
if (err) //kern_printf("(BTTV_IOCTL Error: %d)",err);
elaborate_frame_hook(fbuf_pointer);
task_endcycle();
 
}
 
}
72,23 → 67,11
struct video_picture p;
struct video_channel ch;
 
hard_task_default_model(ht_refresh);
hard_task_def_wcet(ht_refresh, wcet);
hard_task_def_mit(ht_refresh, period);
hard_task_def_ctrl_jet(ht_refresh);
 
refresh_PID = task_create("FG_refresh", FG_refresh, &ht_refresh, NULL);
if (refresh_PID == -1) {
cprintf("could not create task, err no=%d\n",errno);
sys_end();
}
bttv_start(&btv);
 
err = bttv_ioctl(&btv, VIDIOCGWIN, &vw);
if (err) {
kern_printf("(BTTV_IOCTL VIDIOCGWIN Error: %d)",err);
sys_end();
//kern_printf("(BTTV_IOCTL VIDIOCGWIN Error: %d)",err);
}
vw.x = 0;
vw.y = 0;
96,14 → 79,14
vw.height = height;
err = bttv_ioctl(&btv, VIDIOCSWIN, &vw);
if (err) {
kern_printf("(BTTV_IOCTL VIDIOCSWIN Error: %d)",err);
sys_end();
//kern_printf("(BTTV_IOCTL VIDIOCSWIN Error: %d)",err);
//sys_end();
}
 
err = bttv_ioctl(&btv, VIDIOCGPICT, &p);
if (err) {
kern_printf("(BTTV_IOCTL VIDIOCGPICT Error: %d)",err);
sys_end();
//kern_printf("(BTTV_IOCTL VIDIOCGPICT Error: %d)",err);
//sys_end();
}
 
if (color == FG_RGB24) {
121,22 → 104,22
 
err = bttv_ioctl(&btv, VIDIOCSPICT, &p);
if (err) {
kern_printf("(BTTV_IOCTL VIDIOCSPICT Error: %d)",err);
sys_end();
//kern_printf("(BTTV_IOCTL VIDIOCSPICT Error: %d)",err);
//sys_end();
}
ch.channel = channel;
err = bttv_ioctl(&btv, VIDIOCGCHAN, &ch);
if (err) {
kern_printf("(BTTV_IOCTL VIDIOCGCHAN Error: %d)",err);
sys_end();
//kern_printf("(BTTV_IOCTL VIDIOCGCHAN Error: %d)",err);
//sys_end();
}
ch.norm = VIDEO_MODE_PAL;
ch.type = VIDEO_TYPE_CAMERA;
err = bttv_ioctl(&btv, VIDIOCSCHAN, &ch);
if (err) {
kern_printf("(BTTV_IOCTL VIDIOCSCHAN Error: %d)",err);
sys_end();
//kern_printf("(BTTV_IOCTL VIDIOCSCHAN Error: %d)",err);
//sys_end();
}
vmm.frame = 0;
145,13 → 128,11
vmm.format = p.palette;
err = bttv_ioctl(&btv, VIDIOCMCAPTURE, &vmm);
if (err) {
kern_printf("(BTTV_IOCTL VIDIOCMCAPTURE Error: %d)",err);
sys_end();
//kern_printf("(BTTV_IOCTL VIDIOCMCAPTURE Error: %d)",err);
//sys_end();
}
elaborate_frame_hook = dummy_elaborate_frame;
sleep(1);
return 0;
}
159,7 → 140,6
void FG_start_grabbing(void)
{
 
task_activate(refresh_PID);
}
 
166,9 → 146,6
void FG_close(void)
{
 
task_kill(refresh_PID);
/* sleep(1);
*/
bttv_close(&btv);
}
/shark/trunk/drivers/bttv/makefile
10,7 → 10,7
 
OBJS_PATH = $(BASE)/drivers/bttv
 
OBJS = gpio.o bttv-if.o bttv-cards.o bttv-driver.o fg.o
OBJS = bttv-if.o bttv-cards.o bttv-driver.o bttv-risc.o bttv-vbi.o fg.o
 
OTHERINCL += -I$(BASE)/drivers/bttv/include -I$(BASE)/drivers/linuxc26/include
 
/shark/trunk/drivers/bttv/bttv-vbi.c
0,0 → 1,230
/*
bttv - Bt848 frame grabber driver
vbi interface
(c) 2002 Gerd Knorr <kraxel@bytesex.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
 
#include <linuxcomp.h>
 
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/kdev_t.h>
#include <asm/io.h>
#include "drivers/bttvp.h"
 
#define VBI_DEFLINES 16
#define VBI_MAXLINES 32
 
static unsigned int vbibufs = 4;
static unsigned int vbi_debug = 0;
 
MODULE_PARM(vbibufs,"i");
MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32, default 4");
MODULE_PARM(vbi_debug,"i");
MODULE_PARM_DESC(vbi_debug,"vbi code debug messages, default is 0 (no)");
 
#ifdef dprintk
# undef dprintk
#endif
#define dprintk(fmt, arg...) if (vbi_debug) \
printk(KERN_DEBUG "bttv%d/vbi: " fmt, btv->nr, ## arg)
 
/* ----------------------------------------------------------------------- */
/* vbi risc code + mm */
 
static int
vbi_buffer_risc(struct bttv *btv, struct bttv_buffer *buf, int lines)
{
int bpl = 2048;
 
bttv_risc_packed(btv, &buf->top, buf->vb.dma.sglist,
0, bpl-4, 4, lines);
bttv_risc_packed(btv, &buf->bottom, buf->vb.dma.sglist,
lines * bpl, bpl-4, 4, lines);
return 0;
}
 
static int vbi_buffer_setup(struct file *file,
unsigned int *count, unsigned int *size)
{
struct bttv_fh *fh = file->private_data;
struct bttv *btv = fh->btv;
 
if (0 == *count)
*count = vbibufs;
*size = fh->lines * 2 * 2048;
dprintk("setup: lines=%d\n",fh->lines);
return 0;
}
 
static int vbi_buffer_prepare(struct file *file, struct videobuf_buffer *vb,
enum v4l2_field field)
{
struct bttv_fh *fh = file->private_data;
struct bttv *btv = fh->btv;
struct bttv_buffer *buf = (struct bttv_buffer*)vb;
int rc;
buf->vb.size = fh->lines * 2 * 2048;
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
return -EINVAL;
 
if (STATE_NEEDS_INIT == buf->vb.state) {
if (0 != (rc = videobuf_iolock(btv->dev, &buf->vb, NULL)))
goto fail;
if (0 != (rc = vbi_buffer_risc(btv,buf,fh->lines)))
goto fail;
}
buf->vb.state = STATE_PREPARED;
buf->vb.field = field;
dprintk("buf prepare %p: top=%p bottom=%p field=%s\n",
vb, &buf->top, &buf->bottom,
v4l2_field_names[buf->vb.field]);
return 0;
 
fail:
bttv_dma_free(btv,buf);
return rc;
}
 
static void
vbi_buffer_queue(struct file *file, struct videobuf_buffer *vb)
{
struct bttv_fh *fh = file->private_data;
struct bttv *btv = fh->btv;
struct bttv_buffer *buf = (struct bttv_buffer*)vb;
dprintk("queue %p\n",vb);
buf->vb.state = STATE_QUEUED;
list_add_tail(&buf->vb.queue,&btv->vcapture);
bttv_set_dma(btv,0x0c,1);
}
 
static void vbi_buffer_release(struct file *file, struct videobuf_buffer *vb)
{
struct bttv_fh *fh = file->private_data;
struct bttv *btv = fh->btv;
struct bttv_buffer *buf = (struct bttv_buffer*)vb;
dprintk("free %p\n",vb);
bttv_dma_free(fh->btv,buf);
}
 
struct videobuf_queue_ops bttv_vbi_qops = {
.buf_setup = vbi_buffer_setup,
.buf_prepare = vbi_buffer_prepare,
.buf_queue = vbi_buffer_queue,
.buf_release = vbi_buffer_release,
};
 
/* ----------------------------------------------------------------------- */
 
void bttv_vbi_setlines(struct bttv_fh *fh, struct bttv *btv, int lines)
{
int vdelay;
 
if (lines < 1)
lines = 1;
if (lines > VBI_MAXLINES)
lines = VBI_MAXLINES;
fh->lines = lines;
 
vdelay = btread(BT848_E_VDELAY_LO);
if (vdelay < lines*2) {
vdelay = lines*2;
btwrite(vdelay,BT848_E_VDELAY_LO);
btwrite(vdelay,BT848_O_VDELAY_LO);
}
}
 
void bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_format *f)
{
const struct bttv_tvnorm *tvnorm;
u32 start0,start1;
s32 count0,count1,count;
 
tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
f->type = V4L2_BUF_TYPE_VBI_CAPTURE;
f->fmt.vbi.sampling_rate = tvnorm->Fsc;
f->fmt.vbi.samples_per_line = 2048;
f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
f->fmt.vbi.offset = 244;
f->fmt.vbi.flags = 0;
switch (fh->btv->tvnorm) {
case 1: /* NTSC */
start0 = 10;
start1 = 273;
break;
case 0: /* PAL */
case 2: /* SECAM */
default:
start0 = 7;
start1 = 319;
}
 
count0 = (f->fmt.vbi.start[0] + f->fmt.vbi.count[0]) - start0;
count1 = (f->fmt.vbi.start[1] + f->fmt.vbi.count[1]) - start1;
count = max(count0,count1);
if (count > VBI_MAXLINES)
count = VBI_MAXLINES;
if (count < 1)
count = 1;
 
f->fmt.vbi.start[0] = start0;
f->fmt.vbi.start[1] = start1;
f->fmt.vbi.count[0] = count;
f->fmt.vbi.count[1] = count;
}
 
void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f)
{
const struct bttv_tvnorm *tvnorm;
 
tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
memset(f,0,sizeof(*f));
f->type = V4L2_BUF_TYPE_VBI_CAPTURE;
f->fmt.vbi.sampling_rate = tvnorm->Fsc;
f->fmt.vbi.samples_per_line = 2048;
f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
f->fmt.vbi.offset = 244;
f->fmt.vbi.count[0] = fh->lines;
f->fmt.vbi.count[1] = fh->lines;
f->fmt.vbi.flags = 0;
switch (fh->btv->tvnorm) {
case 1: /* NTSC */
f->fmt.vbi.start[0] = 10;
f->fmt.vbi.start[1] = 273;
break;
case 0: /* PAL */
case 2: /* SECAM */
default:
f->fmt.vbi.start[0] = 7;
f->fmt.vbi.start[1] = 319;
}
}
 
/* ----------------------------------------------------------------------- */
/*
* Local variables:
* c-basic-offset: 8
* End:
*/
/shark/trunk/drivers/bttv/bttv-risc.c
0,0 → 1,775
/*
bttv-risc.c -- interfaces to other kernel modules
 
bttv risc code handling
- memory management
- generation
 
(c) 2000 Gerd Knorr <kraxel@bytesex.org>
 
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
*/
 
#include <linuxcomp.h>
 
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/vmalloc.h>
#include <linux/interrupt.h>
#include <asm/page.h>
#include <asm/pgtable.h>
 
#include "drivers/bttvp.h"
 
#define VCR_HACK_LINES 4
 
/* ---------------------------------------------------------- */
/* risc code generators */
 
int
bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
struct scatterlist *sglist,
unsigned int offset, unsigned int bpl,
unsigned int padding, unsigned int lines)
{
u32 instructions,line,todo;
struct scatterlist *sg;
u32 *rp;
int rc;
 
/* estimate risc mem: worst case is one write per page border +
one write per scan line + sync + jump (all 2 dwords) */
instructions = (bpl * lines) / PAGE_SIZE + lines;
instructions += 2;
if ((rc = btcx_riscmem_alloc(btv->dev,risc,instructions*8)) < 0)
return rc;
 
/* sync instruction */
rp = risc->cpu;
*(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
*(rp++) = cpu_to_le32(0);
 
/* scan lines */
sg = sglist;
for (line = 0; line < lines; line++) {
if ((btv->opt_vcr_hack) &&
(line >= (lines - VCR_HACK_LINES)))
continue;
while (offset >= sg_dma_len(sg)) {
offset -= sg_dma_len(sg);
sg++;
}
if (bpl <= sg_dma_len(sg)-offset) {
/* fits into current chunk */
*(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
BT848_RISC_EOL|bpl);
*(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
offset+=bpl;
} else {
/* scanline needs to be splitted */
todo = bpl;
*(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
(sg_dma_len(sg)-offset));
*(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
todo -= (sg_dma_len(sg)-offset);
offset = 0;
sg++;
while (todo > sg_dma_len(sg)) {
*(rp++)=cpu_to_le32(BT848_RISC_WRITE|
sg_dma_len(sg));
*(rp++)=cpu_to_le32(sg_dma_address(sg));
todo -= sg_dma_len(sg);
sg++;
}
*(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL|
todo);
*(rp++)=cpu_to_le32(sg_dma_address(sg));
offset += todo;
}
offset += padding;
}
dprintk("bttv%d: risc planar: %d sglist elems\n", btv->nr, (int)(sg-sglist));
 
/* save pointer to jmp instruction address */
risc->jmp = rp;
return 0;
}
 
int
bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc,
struct scatterlist *sglist,
unsigned int yoffset, unsigned int ybpl,
unsigned int ypadding, unsigned int ylines,
unsigned int uoffset, unsigned int voffset,
unsigned int hshift, unsigned int vshift,
unsigned int cpadding)
{
unsigned int instructions,line,todo,ylen,chroma;
u32 *rp,ri;
struct scatterlist *ysg;
struct scatterlist *usg;
struct scatterlist *vsg;
int rc;
 
/* estimate risc mem: worst case is one write per page border +
one write per scan line (5 dwords)
plus sync + jump (2 dwords) */
instructions = (ybpl * ylines * 2) / PAGE_SIZE + ylines;
instructions += 2;
if ((rc = btcx_riscmem_alloc(btv->dev,risc,instructions*4*5)) < 0)
return rc;
 
/* sync instruction */
rp = risc->cpu;
*(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3);
*(rp++) = cpu_to_le32(0);
 
/* scan lines */
ysg = sglist;
usg = sglist;
vsg = sglist;
for (line = 0; line < ylines; line++) {
if ((btv->opt_vcr_hack) &&
(line >= (ylines - VCR_HACK_LINES)))
continue;
switch (vshift) {
case 0: chroma = 1; break;
case 1: chroma = !(line & 1); break;
case 2: chroma = !(line & 3); break;
default: chroma = 0;
}
for (todo = ybpl; todo > 0; todo -= ylen) {
/* go to next sg entry if needed */
while (yoffset >= sg_dma_len(ysg)) {
yoffset -= sg_dma_len(ysg);
ysg++;
}
while (uoffset >= sg_dma_len(usg)) {
uoffset -= sg_dma_len(usg);
usg++;
}
while (voffset >= sg_dma_len(vsg)) {
voffset -= sg_dma_len(vsg);
vsg++;
}
 
/* calculate max number of bytes we can write */
ylen = todo;
if (yoffset + ylen > sg_dma_len(ysg))
ylen = sg_dma_len(ysg) - yoffset;
if (chroma) {
if (uoffset + (ylen>>hshift) > sg_dma_len(usg))
ylen = (sg_dma_len(usg) - uoffset) << hshift;
if (voffset + (ylen>>hshift) > sg_dma_len(vsg))
ylen = (sg_dma_len(vsg) - voffset) << hshift;
ri = BT848_RISC_WRITE123;
} else {
ri = BT848_RISC_WRITE1S23;
}
if (ybpl == todo)
ri |= BT848_RISC_SOL;
if (ylen == todo)
ri |= BT848_RISC_EOL;
 
/* write risc instruction */
*(rp++)=cpu_to_le32(ri | ylen);
*(rp++)=cpu_to_le32(((ylen >> hshift) << 16) |
(ylen >> hshift));
*(rp++)=cpu_to_le32(sg_dma_address(ysg)+yoffset);
yoffset += ylen;
if (chroma) {
*(rp++)=cpu_to_le32(sg_dma_address(usg)+uoffset);
uoffset += ylen >> hshift;
*(rp++)=cpu_to_le32(sg_dma_address(vsg)+voffset);
voffset += ylen >> hshift;
}
}
yoffset += ypadding;
if (chroma) {
uoffset += cpadding;
voffset += cpadding;
}
}
 
/* save pointer to jmp instruction address */
risc->jmp = rp;
return 0;
}
 
int
bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
const struct bttv_format *fmt, struct bttv_overlay *ov,
int skip_even, int skip_odd)
{
int instructions,rc,line,maxy,start,end,skip,nskips;
struct btcx_skiplist *skips;
u32 *rp,ri,ra;
u32 addr;
 
/* skip list for window clipping */
if (NULL == (skips = kmalloc(sizeof(*skips) * ov->nclips,GFP_KERNEL)))
return -ENOMEM;
/* estimate risc mem: worst case is (clip+1) * lines instructions
+ sync + jump (all 2 dwords) */
instructions = (ov->nclips + 1) *
((skip_even || skip_odd) ? ov->w.height>>1 : ov->w.height);
instructions += 2;
if ((rc = btcx_riscmem_alloc(btv->dev,risc,instructions*8)) < 0) {
kfree(skips);
return rc;
}
 
/* sync instruction */
rp = risc->cpu;
*(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
*(rp++) = cpu_to_le32(0);
 
addr = (unsigned long)btv->fbuf.base;
addr += btv->fbuf.fmt.bytesperline * ov->w.top;
addr += (fmt->depth >> 3) * ov->w.left;
 
/* scan lines */
for (maxy = -1, line = 0; line < ov->w.height;
line++, addr += btv->fbuf.fmt.bytesperline) {
if ((btv->opt_vcr_hack) &&
(line >= (ov->w.height - VCR_HACK_LINES)))
continue;
if ((line%2) == 0 && skip_even)
continue;
if ((line%2) == 1 && skip_odd)
if ((line%2) == 0 && skip_even)
continue;
if ((line%2) == 1 && skip_odd)
continue;
 
/* calculate clipping */
if (line > maxy)
btcx_calc_skips(line, ov->w.width, &maxy,
skips, &nskips, ov->clips, ov->nclips);
 
/* write out risc code */
for (start = 0, skip = 0; start < ov->w.width; start = end) {
if (skip >= nskips) {
ri = BT848_RISC_WRITE;
end = ov->w.width;
} else if (start < skips[skip].start) {
ri = BT848_RISC_WRITE;
end = skips[skip].start;
} else {
ri = BT848_RISC_SKIP;
end = skips[skip].end;
skip++;
}
if (BT848_RISC_WRITE == ri)
ra = addr + (fmt->depth>>3)*start;
else
ra = 0;
if (0 == start)
ri |= BT848_RISC_SOL;
if (ov->w.width == end)
ri |= BT848_RISC_EOL;
ri |= (fmt->depth>>3) * (end-start);
 
*(rp++)=cpu_to_le32(ri);
if (0 != ra)
*(rp++)=cpu_to_le32(ra);
}
}
 
/* save pointer to jmp instruction address */
risc->jmp = rp;
kfree(skips);
return 0;
}
 
/* ---------------------------------------------------------- */
 
void
bttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo,
int width, int height, int interleaved, int norm)
{
const struct bttv_tvnorm *tvnorm = &bttv_tvnorms[norm];
u32 xsf, sr;
int vdelay;
 
int swidth = tvnorm->swidth;
int totalwidth = tvnorm->totalwidth;
int scaledtwidth = tvnorm->scaledtwidth;
 
if (bttv_tvcards[btv->type].muxsel[btv->input] < 0) {
swidth = 720;
totalwidth = 858;
scaledtwidth = 858;
}
 
vdelay = tvnorm->vdelay;
#if 0 /* FIXME */
if (vdelay < btv->vbi.lines*2)
vdelay = btv->vbi.lines*2;
#endif
 
xsf = (width*scaledtwidth)/swidth;
geo->hscale = ((totalwidth*4096UL)/xsf-4096);
geo->hdelay = tvnorm->hdelayx1;
geo->hdelay = (geo->hdelay*width)/swidth;
geo->hdelay &= 0x3fe;
sr = ((tvnorm->sheight >> (interleaved?0:1))*512)/height - 512;
geo->vscale = (0x10000UL-sr) & 0x1fff;
geo->crop = ((width>>8)&0x03) | ((geo->hdelay>>6)&0x0c) |
((tvnorm->sheight>>4)&0x30) | ((vdelay>>2)&0xc0);
geo->vscale |= interleaved ? (BT848_VSCALE_INT<<8) : 0;
geo->vdelay = vdelay;
geo->width = width;
geo->sheight = tvnorm->sheight;
geo->vtotal = tvnorm->vtotal;
 
if (btv->opt_combfilter) {
geo->vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
geo->comb = (width < 769) ? 1 : 0;
} else {
geo->vtc = 0;
geo->comb = 0;
}
}
 
void
bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd)
{
int off = odd ? 0x80 : 0x00;
 
if (geo->comb)
btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
else
btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
 
btwrite(geo->vtc, BT848_E_VTC+off);
btwrite(geo->hscale >> 8, BT848_E_HSCALE_HI+off);
btwrite(geo->hscale & 0xff, BT848_E_HSCALE_LO+off);
btaor((geo->vscale>>8), 0xe0, BT848_E_VSCALE_HI+off);
btwrite(geo->vscale & 0xff, BT848_E_VSCALE_LO+off);
btwrite(geo->width & 0xff, BT848_E_HACTIVE_LO+off);
btwrite(geo->hdelay & 0xff, BT848_E_HDELAY_LO+off);
btwrite(geo->sheight & 0xff, BT848_E_VACTIVE_LO+off);
btwrite(geo->vdelay & 0xff, BT848_E_VDELAY_LO+off);
btwrite(geo->crop, BT848_E_CROP+off);
btwrite(geo->vtotal>>8, BT848_VTOTAL_HI);
btwrite(geo->vtotal & 0xff, BT848_VTOTAL_LO);
}
 
/* ---------------------------------------------------------- */
/* risc group / risc main loop / dma management */
 
void
bttv_set_dma(struct bttv *btv, int override, int irqflags)
{
unsigned long cmd;
int capctl;
 
btv->cap_ctl = 0;
if (NULL != btv->curr.top) btv->cap_ctl |= 0x02;
if (NULL != btv->curr.bottom) btv->cap_ctl |= 0x01;
if (NULL != btv->curr.vbi) btv->cap_ctl |= 0x0c;
 
capctl = 0;
capctl |= (btv->cap_ctl & 0x03) ? 0x03 : 0x00; /* capture */
capctl |= (btv->cap_ctl & 0x0c) ? 0x0c : 0x00; /* vbi data */
capctl |= override;
 
d2printk(KERN_DEBUG
"bttv%d: capctl=%x irq=%d top=%08Lx/%08Lx even=%08Lx/%08Lx\n",
btv->nr,capctl,irqflags,
btv->curr.vbi ? (unsigned long long)btv->curr.vbi->top.dma : 0,
btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0,
btv->curr.vbi ? (unsigned long long)btv->curr.vbi->bottom.dma : 0,
btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0);
cmd = BT848_RISC_JUMP;
if (irqflags) {
cmd |= BT848_RISC_IRQ;
cmd |= (irqflags & 0x0f) << 16;
cmd |= (~irqflags & 0x0f) << 20;
mod_timer(&btv->timeout, jiffies+BTTV_TIMEOUT);
} else {
del_timer(&btv->timeout);
}
btv->main.cpu[RISC_SLOT_LOOP] = cpu_to_le32(cmd);
btaor(capctl, ~0x0f, BT848_CAP_CTL);
if (capctl) {
if (btv->dma_on)
return;
btwrite(btv->main.dma, BT848_RISC_STRT_ADD);
btor(3, BT848_GPIO_DMA_CTL);
btv->dma_on = 1;
} else {
if (!btv->dma_on)
return;
btand(~3, BT848_GPIO_DMA_CTL);
btv->dma_on = 0;
}
return;
}
 
int
bttv_risc_init_main(struct bttv *btv)
{
int rc;
if ((rc = btcx_riscmem_alloc(btv->dev,&btv->main,PAGE_SIZE)) < 0)
return rc;
dprintk(KERN_DEBUG "bttv%d: risc main @ %08Lx\n",
btv->nr,(unsigned long long)btv->main.dma);
 
btv->main.cpu[0] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
BT848_FIFO_STATUS_VRE);
btv->main.cpu[1] = cpu_to_le32(0);
btv->main.cpu[2] = cpu_to_le32(BT848_RISC_JUMP);
btv->main.cpu[3] = cpu_to_le32(btv->main.dma + (4<<2));
 
/* top field */
btv->main.cpu[4] = cpu_to_le32(BT848_RISC_JUMP);
btv->main.cpu[5] = cpu_to_le32(btv->main.dma + (6<<2));
btv->main.cpu[6] = cpu_to_le32(BT848_RISC_JUMP);
btv->main.cpu[7] = cpu_to_le32(btv->main.dma + (8<<2));
 
btv->main.cpu[8] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
BT848_FIFO_STATUS_VRO);
btv->main.cpu[9] = cpu_to_le32(0);
 
/* bottom field */
btv->main.cpu[10] = cpu_to_le32(BT848_RISC_JUMP);
btv->main.cpu[11] = cpu_to_le32(btv->main.dma + (12<<2));
btv->main.cpu[12] = cpu_to_le32(BT848_RISC_JUMP);
btv->main.cpu[13] = cpu_to_le32(btv->main.dma + (14<<2));
 
/* jump back to top field */
btv->main.cpu[14] = cpu_to_le32(BT848_RISC_JUMP);
btv->main.cpu[15] = cpu_to_le32(btv->main.dma + (0<<2));
 
return 0;
}
 
int
bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc,
int irqflags)
{
unsigned long cmd;
unsigned long next = btv->main.dma + ((slot+2) << 2);
 
if (NULL == risc) {
d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=NULL\n",
btv->nr,risc,slot);
btv->main.cpu[slot+1] = cpu_to_le32(next);
} else {
d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=%08Lx irq=%d\n",
btv->nr,risc,slot,(unsigned long long)risc->dma,irqflags);
cmd = BT848_RISC_JUMP;
if (irqflags) {
cmd |= BT848_RISC_IRQ;
cmd |= (irqflags & 0x0f) << 16;
cmd |= (~irqflags & 0x0f) << 20;
}
risc->jmp[0] = cpu_to_le32(cmd);
risc->jmp[1] = cpu_to_le32(next);
btv->main.cpu[slot+1] = cpu_to_le32(risc->dma);
}
return 0;
}
 
void
bttv_dma_free(struct bttv *btv, struct bttv_buffer *buf)
{
if (in_interrupt())
BUG();
videobuf_waiton(&buf->vb,0,0);
videobuf_dma_pci_unmap(btv->dev, &buf->vb.dma);
videobuf_dma_free(&buf->vb.dma);
btcx_riscmem_free(btv->dev,&buf->bottom);
btcx_riscmem_free(btv->dev,&buf->top);
buf->vb.state = STATE_NEEDS_INIT;
}
 
int
bttv_buffer_set_activate(struct bttv *btv,
struct bttv_buffer_set *set)
{
/* vbi capture */
if (set->vbi) {
set->vbi->vb.state = STATE_ACTIVE;
list_del(&set->vbi->vb.queue);
bttv_risc_hook(btv, RISC_SLOT_O_VBI, &set->vbi->top, 0);
bttv_risc_hook(btv, RISC_SLOT_E_VBI, &set->vbi->bottom, 0);
} else {
bttv_risc_hook(btv, RISC_SLOT_O_VBI, NULL, 0);
bttv_risc_hook(btv, RISC_SLOT_E_VBI, NULL, 0);
}
 
/* video capture */
if (NULL != set->top && NULL != set->bottom) {
if (set->top == set->bottom) {
set->top->vb.state = STATE_ACTIVE;
if (set->top->vb.queue.next)
list_del(&set->top->vb.queue);
} else {
set->top->vb.state = STATE_ACTIVE;
set->bottom->vb.state = STATE_ACTIVE;
if (set->top->vb.queue.next)
list_del(&set->top->vb.queue);
if (set->bottom->vb.queue.next)
list_del(&set->bottom->vb.queue);
}
bttv_apply_geo(btv, &set->top->geo, 1);
bttv_apply_geo(btv, &set->bottom->geo,0);
bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top, set->topirq);
bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom, 0);
btaor((set->top->btformat & 0xf0) | (set->bottom->btformat & 0x0f),
~0xff, BT848_COLOR_FMT);
btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05),
~0x0f, BT848_COLOR_CTL);
} else if (NULL != set->top) {
set->top->vb.state = STATE_ACTIVE;
if (set->top->vb.queue.next)
list_del(&set->top->vb.queue);
bttv_apply_geo(btv, &set->top->geo,1);
bttv_apply_geo(btv, &set->top->geo,0);
bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top, 0);
bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0);
btaor(set->top->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
btaor(set->top->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL);
} else if (NULL != set->bottom) {
set->bottom->vb.state = STATE_ACTIVE;
if (set->bottom->vb.queue.next)
list_del(&set->bottom->vb.queue);
bttv_apply_geo(btv, &set->bottom->geo,1);
bttv_apply_geo(btv, &set->bottom->geo,0);
bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom, 0);
btaor(set->bottom->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
btaor(set->bottom->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL);
} else {
bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0);
}
return 0;
}
 
/* ---------------------------------------------------------- */
 
/* calculate geometry, build risc code */
int
bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
{
const struct bttv_tvnorm *tvnorm = bttv_tvnorms + buf->tvnorm;
 
dprintk(KERN_DEBUG
"bttv%d: buffer field: %s format: %s size: %dx%d\n",
btv->nr, v4l2_field_names[buf->vb.field],
buf->fmt->name, buf->vb.width, buf->vb.height);
 
/* packed pixel modes */
if (buf->fmt->flags & FORMAT_FLAGS_PACKED) {
int bpl = (buf->fmt->depth >> 3) * buf->vb.width;
int bpf = bpl * (buf->vb.height >> 1);
 
bttv_calc_geo(btv,&buf->geo,buf->vb.width,buf->vb.height,
V4L2_FIELD_HAS_BOTH(buf->vb.field),buf->tvnorm);
switch (buf->vb.field) {
case V4L2_FIELD_TOP:
bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
0,bpl,0,buf->vb.height);
break;
case V4L2_FIELD_BOTTOM:
bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
0,bpl,0,buf->vb.height);
break;
case V4L2_FIELD_INTERLACED:
bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
0,bpl,bpl,buf->vb.height >> 1);
bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
bpl,bpl,bpl,buf->vb.height >> 1);
break;
case V4L2_FIELD_SEQ_TB:
bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
0,bpl,0,buf->vb.height >> 1);
bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
bpf,bpl,0,buf->vb.height >> 1);
break;
default:
BUG();
}
}
 
/* planar modes */
if (buf->fmt->flags & FORMAT_FLAGS_PLANAR) {
int uoffset, voffset;
int ypadding, cpadding, lines;
 
/* calculate chroma offsets */
uoffset = buf->vb.width * buf->vb.height;
voffset = buf->vb.width * buf->vb.height;
if (buf->fmt->flags & FORMAT_FLAGS_CrCb) {
/* Y-Cr-Cb plane order */
uoffset >>= buf->fmt->hshift;
uoffset >>= buf->fmt->vshift;
uoffset += voffset;
} else {
/* Y-Cb-Cr plane order */
voffset >>= buf->fmt->hshift;
voffset >>= buf->fmt->vshift;
voffset += uoffset;
}
 
switch (buf->vb.field) {
case V4L2_FIELD_TOP:
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
buf->vb.height,0,buf->tvnorm);
bttv_risc_planar(btv, &buf->top, buf->vb.dma.sglist,
0,buf->vb.width,0,buf->vb.height,
uoffset,voffset,buf->fmt->hshift,
buf->fmt->vshift,0);
break;
case V4L2_FIELD_BOTTOM:
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
buf->vb.height,0,buf->tvnorm);
bttv_risc_planar(btv, &buf->bottom, buf->vb.dma.sglist,
0,buf->vb.width,0,buf->vb.height,
uoffset,voffset,buf->fmt->hshift,
buf->fmt->vshift,0);
break;
case V4L2_FIELD_INTERLACED:
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
buf->vb.height,1,buf->tvnorm);
lines = buf->vb.height >> 1;
ypadding = buf->vb.width;
cpadding = buf->vb.width >> buf->fmt->hshift;
bttv_risc_planar(btv,&buf->top,
buf->vb.dma.sglist,
0,buf->vb.width,ypadding,lines,
uoffset,voffset,
buf->fmt->hshift,
buf->fmt->vshift,
cpadding);
bttv_risc_planar(btv,&buf->bottom,
buf->vb.dma.sglist,
ypadding,buf->vb.width,ypadding,lines,
uoffset+cpadding,
voffset+cpadding,
buf->fmt->hshift,
buf->fmt->vshift,
cpadding);
break;
case V4L2_FIELD_SEQ_TB:
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
buf->vb.height,1,buf->tvnorm);
lines = buf->vb.height >> 1;
ypadding = buf->vb.width;
cpadding = buf->vb.width >> buf->fmt->hshift;
bttv_risc_planar(btv,&buf->top,
buf->vb.dma.sglist,
0,buf->vb.width,0,lines,
uoffset >> 1,
voffset >> 1,
buf->fmt->hshift,
buf->fmt->vshift,
0);
bttv_risc_planar(btv,&buf->bottom,
buf->vb.dma.sglist,
lines * ypadding,buf->vb.width,0,lines,
lines * ypadding + (uoffset >> 1),
lines * ypadding + (voffset >> 1),
buf->fmt->hshift,
buf->fmt->vshift,
0);
break;
default:
BUG();
}
}
 
/* raw data */
if (buf->fmt->flags & FORMAT_FLAGS_RAW) {
/* build risc code */
buf->vb.field = V4L2_FIELD_SEQ_TB;
bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight,
1,buf->tvnorm);
bttv_risc_packed(btv, &buf->top, buf->vb.dma.sglist,
0, RAW_BPL, 0, RAW_LINES);
bttv_risc_packed(btv, &buf->bottom, buf->vb.dma.sglist,
buf->vb.size/2 , RAW_BPL, 0, RAW_LINES);
}
 
/* copy format info */
buf->btformat = buf->fmt->btformat;
buf->btswap = buf->fmt->btswap;
return 0;
}
 
/* ---------------------------------------------------------- */
 
/* calculate geometry, build risc code */
int
bttv_overlay_risc(struct bttv *btv,
struct bttv_overlay *ov,
const struct bttv_format *fmt,
struct bttv_buffer *buf)
{
/* check interleave, bottom+top fields */
dprintk(KERN_DEBUG
"bttv%d: overlay fields: %s format: %s size: %dx%d\n",
btv->nr, v4l2_field_names[buf->vb.field],
fmt->name,ov->w.width,ov->w.height);
 
/* calculate geometry */
bttv_calc_geo(btv,&buf->geo,ov->w.width,ov->w.height,
V4L2_FIELD_HAS_BOTH(ov->field), ov->tvnorm);
 
/* build risc code */
switch (ov->field) {
case V4L2_FIELD_TOP:
bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 0);
break;
case V4L2_FIELD_BOTTOM:
bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 0, 0);
break;
case V4L2_FIELD_INTERLACED:
#if 0
bttv_risc_overlay(btv, &buf->top, fmt, ov, 1, 0);
bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 0, 1);
#else
bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 1);
bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 1, 0);
#endif
break;
default:
BUG();
}
 
/* copy format info */
buf->btformat = fmt->btformat;
buf->btswap = fmt->btswap;
buf->vb.field = ov->field;
return 0;
}
 
/*
* Local variables:
* c-basic-offset: 8
* End:
*/