Subversion Repositories shark

Compare Revisions

Ignore whitespace Rev 427 → 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:
*/
/shark/trunk/drivers/newpci/access.c
0,0 → 1,62
#include <linux/pci.h>
#include <linux/module.h>
#include <linux/ioport.h>
 
/*
* This interrupt-safe spinlock protects all accesses to PCI
* configuration space.
*/
 
static spinlock_t pci_lock = SPIN_LOCK_UNLOCKED;
 
/*
* Wrappers for all PCI configuration access functions. They just check
* alignment, do locking and call the low-level functions pointed to
* by pci_dev->ops.
*/
 
#define PCI_byte_BAD 0
#define PCI_word_BAD (pos & 1)
#define PCI_dword_BAD (pos & 3)
 
#define PCI_OP_READ(size,type,len) \
int pci_bus_read_config_##size \
(struct pci_bus *bus, unsigned int devfn, int pos, type *value) \
{ \
int res; \
unsigned long flags; \
u32 data = 0; \
if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \
spin_lock_irqsave(&pci_lock, flags); \
res = bus->ops->read(bus, devfn, pos, len, &data); \
*value = (type)data; \
spin_unlock_irqrestore(&pci_lock, flags); \
return res; \
}
 
#define PCI_OP_WRITE(size,type,len) \
int pci_bus_write_config_##size \
(struct pci_bus *bus, unsigned int devfn, int pos, type value) \
{ \
int res; \
unsigned long flags; \
if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \
spin_lock_irqsave(&pci_lock, flags); \
res = bus->ops->write(bus, devfn, pos, len, value); \
spin_unlock_irqrestore(&pci_lock, flags); \
return res; \
}
 
PCI_OP_READ(byte, u8, 1)
PCI_OP_READ(word, u16, 2)
PCI_OP_READ(dword, u32, 4)
PCI_OP_WRITE(byte, u8, 1)
PCI_OP_WRITE(word, u16, 2)
PCI_OP_WRITE(dword, u32, 4)
 
EXPORT_SYMBOL(pci_bus_read_config_byte);
EXPORT_SYMBOL(pci_bus_read_config_word);
EXPORT_SYMBOL(pci_bus_read_config_dword);
EXPORT_SYMBOL(pci_bus_write_config_byte);
EXPORT_SYMBOL(pci_bus_write_config_word);
EXPORT_SYMBOL(pci_bus_write_config_dword);
/shark/trunk/drivers/newpci/names.c
0,0 → 1,138
/*
* PCI Class and Device Name Tables
*
* Copyright 1993--1999 Drew Eckhardt, Frederic Potter,
* David Mosberger-Tang, Martin Mares
*/
 
#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/init.h>
 
#ifdef CONFIG_PCI_NAMES
 
struct pci_device_info {
unsigned short device;
unsigned short seen;
const char *name;
};
 
struct pci_vendor_info {
unsigned short vendor;
unsigned short nr;
const char *name;
struct pci_device_info *devices;
};
 
/*
* This is ridiculous, but we want the strings in
* the .init section so that they don't take up
* real memory.. Parse the same file multiple times
* to get all the info.
*/
#define VENDOR( vendor, name ) static char __vendorstr_##vendor[] __devinitdata = name;
#define ENDVENDOR()
#define DEVICE( vendor, device, name ) static char __devicestr_##vendor##device[] __devinitdata = name;
#include "devlist.h"
 
 
#define VENDOR( vendor, name ) static struct pci_device_info __devices_##vendor[] __devinitdata = {
#define ENDVENDOR() };
#define DEVICE( vendor, device, name ) { 0x##device, 0, __devicestr_##vendor##device },
#include "devlist.h"
 
static struct pci_vendor_info __devinitdata pci_vendor_list[] = {
#define VENDOR( vendor, name ) { 0x##vendor, sizeof(__devices_##vendor) / sizeof(struct pci_device_info), __vendorstr_##vendor, __devices_##vendor },
#define ENDVENDOR()
#define DEVICE( vendor, device, name )
#include "devlist.h"
};
 
#define VENDORS (sizeof(pci_vendor_list)/sizeof(struct pci_vendor_info))
 
void __devinit pci_name_device(struct pci_dev *dev)
{
const struct pci_vendor_info *vendor_p = pci_vendor_list;
int i = VENDORS;
char *name = dev->pretty_name;
 
do {
if (vendor_p->vendor == dev->vendor)
goto match_vendor;
vendor_p++;
} while (--i);
 
/* Couldn't find either the vendor nor the device */
sprintf(name, "PCI device %04x:%04x", dev->vendor, dev->device);
return;
 
match_vendor: {
struct pci_device_info *device_p = vendor_p->devices;
int i = vendor_p->nr;
 
while (i > 0) {
if (device_p->device == dev->device)
goto match_device;
device_p++;
i--;
}
 
/* Ok, found the vendor, but unknown device */
sprintf(name, "PCI device %04x:%04x (%." PCI_NAME_HALF "s)",
dev->vendor, dev->device, vendor_p->name);
return;
 
/* Full match */
match_device: {
char *n = name + sprintf(name, "%." PCI_NAME_HALF
"s %." PCI_NAME_HALF "s",
vendor_p->name, device_p->name);
int nr = device_p->seen + 1;
device_p->seen = nr;
if (nr > 1)
sprintf(n, " (#%d)", nr);
}
}
}
 
/*
* Class names. Not in .init section as they are needed in runtime.
*/
 
static u16 pci_class_numbers[] = {
#define CLASS(x,y) 0x##x,
#include "classlist.h"
};
 
static char *pci_class_names[] = {
#define CLASS(x,y) y,
#include "classlist.h"
};
 
char *
pci_class_name(u32 class)
{
int i;
 
for(i=0; i<sizeof(pci_class_numbers)/sizeof(pci_class_numbers[0]); i++)
if (pci_class_numbers[i] == class)
return pci_class_names[i];
return NULL;
}
 
#else
 
void __devinit pci_name_device(struct pci_dev *dev)
{
}
 
char *
pci_class_name(u32 class)
{
return NULL;
}
 
#endif /* CONFIG_PCI_NAMES */
 
/shark/trunk/drivers/newpci/proc.c
0,0 → 1,615
/*
* $Id: proc.c,v 1.1 2004-01-28 18:32:17 giacomo Exp $
*
* Procfs interface for the PCI bus.
*
* Copyright (c) 1997--1999 Martin Mares <mj@ucw.cz>
*/
 
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/smp_lock.h>
 
#include <asm/uaccess.h>
#include <asm/byteorder.h>
 
#define PCI_CFG_SPACE_SIZE 256
 
static int proc_initialized; /* = 0 */
 
static loff_t
proc_bus_pci_lseek(struct file *file, loff_t off, int whence)
{
loff_t new = -1;
 
lock_kernel();
switch (whence) {
case 0:
new = off;
break;
case 1:
new = file->f_pos + off;
break;
case 2:
new = PCI_CFG_SPACE_SIZE + off;
break;
}
unlock_kernel();
if (new < 0 || new > PCI_CFG_SPACE_SIZE)
return -EINVAL;
return (file->f_pos = new);
}
 
static ssize_t
proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
{
const struct inode *ino = file->f_dentry->d_inode;
const struct proc_dir_entry *dp = PDE(ino);
struct pci_dev *dev = dp->data;
unsigned int pos = *ppos;
unsigned int cnt, size;
 
/*
* Normal users can read only the standardized portion of the
* configuration space as several chips lock up when trying to read
* undefined locations (think of Intel PIIX4 as a typical example).
*/
 
if (capable(CAP_SYS_ADMIN))
size = PCI_CFG_SPACE_SIZE;
else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
size = 128;
else
size = 64;
 
if (pos >= size)
return 0;
if (nbytes >= size)
nbytes = size;
if (pos + nbytes > size)
nbytes = size - pos;
cnt = nbytes;
 
if (!access_ok(VERIFY_WRITE, buf, cnt))
return -EINVAL;
 
if ((pos & 1) && cnt) {
unsigned char val;
pci_read_config_byte(dev, pos, &val);
__put_user(val, buf);
buf++;
pos++;
cnt--;
}
 
if ((pos & 3) && cnt > 2) {
unsigned short val;
pci_read_config_word(dev, pos, &val);
__put_user(cpu_to_le16(val), (unsigned short *) buf);
buf += 2;
pos += 2;
cnt -= 2;
}
 
while (cnt >= 4) {
unsigned int val;
pci_read_config_dword(dev, pos, &val);
__put_user(cpu_to_le32(val), (unsigned int *) buf);
buf += 4;
pos += 4;
cnt -= 4;
}
 
if (cnt >= 2) {
unsigned short val;
pci_read_config_word(dev, pos, &val);
__put_user(cpu_to_le16(val), (unsigned short *) buf);
buf += 2;
pos += 2;
cnt -= 2;
}
 
if (cnt) {
unsigned char val;
pci_read_config_byte(dev, pos, &val);
__put_user(val, buf);
buf++;
pos++;
cnt--;
}
 
*ppos = pos;
return nbytes;
}
 
static ssize_t
proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, loff_t *ppos)
{
const struct inode *ino = file->f_dentry->d_inode;
const struct proc_dir_entry *dp = PDE(ino);
struct pci_dev *dev = dp->data;
int pos = *ppos;
int cnt;
 
if (pos >= PCI_CFG_SPACE_SIZE)
return 0;
if (nbytes >= PCI_CFG_SPACE_SIZE)
nbytes = PCI_CFG_SPACE_SIZE;
if (pos + nbytes > PCI_CFG_SPACE_SIZE)
nbytes = PCI_CFG_SPACE_SIZE - pos;
cnt = nbytes;
 
if (!access_ok(VERIFY_READ, buf, cnt))
return -EINVAL;
 
if ((pos & 1) && cnt) {
unsigned char val;
__get_user(val, buf);
pci_write_config_byte(dev, pos, val);
buf++;
pos++;
cnt--;
}
 
if ((pos & 3) && cnt > 2) {
unsigned short val;
__get_user(val, (unsigned short *) buf);
pci_write_config_word(dev, pos, le16_to_cpu(val));
buf += 2;
pos += 2;
cnt -= 2;
}
 
while (cnt >= 4) {
unsigned int val;
__get_user(val, (unsigned int *) buf);
pci_write_config_dword(dev, pos, le32_to_cpu(val));
buf += 4;
pos += 4;
cnt -= 4;
}
 
if (cnt >= 2) {
unsigned short val;
__get_user(val, (unsigned short *) buf);
pci_write_config_word(dev, pos, le16_to_cpu(val));
buf += 2;
pos += 2;
cnt -= 2;
}
 
if (cnt) {
unsigned char val;
__get_user(val, buf);
pci_write_config_byte(dev, pos, val);
buf++;
pos++;
cnt--;
}
 
*ppos = pos;
return nbytes;
}
 
struct pci_filp_private {
enum pci_mmap_state mmap_state;
int write_combine;
};
 
static int proc_bus_pci_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
const struct proc_dir_entry *dp = PDE(inode);
struct pci_dev *dev = dp->data;
#ifdef HAVE_PCI_MMAP
struct pci_filp_private *fpriv = file->private_data;
#endif /* HAVE_PCI_MMAP */
int ret = 0;
 
switch (cmd) {
case PCIIOC_CONTROLLER:
ret = pci_domain_nr(dev->bus);
break;
 
#ifdef HAVE_PCI_MMAP
case PCIIOC_MMAP_IS_IO:
fpriv->mmap_state = pci_mmap_io;
break;
 
case PCIIOC_MMAP_IS_MEM:
fpriv->mmap_state = pci_mmap_mem;
break;
 
case PCIIOC_WRITE_COMBINE:
if (arg)
fpriv->write_combine = 1;
else
fpriv->write_combine = 0;
break;
 
#endif /* HAVE_PCI_MMAP */
 
default:
ret = -EINVAL;
break;
};
 
return ret;
}
 
#ifdef HAVE_PCI_MMAP
static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma)
{
struct inode *inode = file->f_dentry->d_inode;
const struct proc_dir_entry *dp = PDE(inode);
struct pci_dev *dev = dp->data;
struct pci_filp_private *fpriv = file->private_data;
int ret;
 
if (!capable(CAP_SYS_RAWIO))
return -EPERM;
 
ret = pci_mmap_page_range(dev, vma,
fpriv->mmap_state,
fpriv->write_combine);
if (ret < 0)
return ret;
 
return 0;
}
 
static int proc_bus_pci_open(struct inode *inode, struct file *file)
{
struct pci_filp_private *fpriv = kmalloc(sizeof(*fpriv), GFP_KERNEL);
 
if (!fpriv)
return -ENOMEM;
 
fpriv->mmap_state = pci_mmap_io;
fpriv->write_combine = 0;
 
file->private_data = fpriv;
 
return 0;
}
 
static int proc_bus_pci_release(struct inode *inode, struct file *file)
{
kfree(file->private_data);
file->private_data = NULL;
 
return 0;
}
#endif /* HAVE_PCI_MMAP */
 
static struct file_operations proc_bus_pci_operations = {
.llseek = proc_bus_pci_lseek,
.read = proc_bus_pci_read,
.write = proc_bus_pci_write,
.ioctl = proc_bus_pci_ioctl,
#ifdef HAVE_PCI_MMAP
.open = proc_bus_pci_open,
.release = proc_bus_pci_release,
.mmap = proc_bus_pci_mmap,
#ifdef HAVE_ARCH_PCI_GET_UNMAPPED_AREA
.get_unmapped_area = get_pci_unmapped_area,
#endif /* HAVE_ARCH_PCI_GET_UNMAPPED_AREA */
#endif /* HAVE_PCI_MMAP */
};
 
#if BITS_PER_LONG == 32
#define LONG_FORMAT "\t%08lx"
#else
#define LONG_FORMAT "\t%16lx"
#endif
 
/* iterator */
static void *pci_seq_start(struct seq_file *m, loff_t *pos)
{
struct pci_dev *dev = NULL;
loff_t n = *pos;
 
dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
while (n--) {
dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
if (dev == NULL)
goto exit;
}
exit:
return dev;
}
 
static void *pci_seq_next(struct seq_file *m, void *v, loff_t *pos)
{
struct pci_dev *dev = v;
 
(*pos)++;
dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
return dev;
}
 
static void pci_seq_stop(struct seq_file *m, void *v)
{
if (v) {
struct pci_dev *dev = v;
pci_dev_put(dev);
}
}
 
static int show_device(struct seq_file *m, void *v)
{
const struct pci_dev *dev = v;
const struct pci_driver *drv;
int i;
 
if (dev == NULL)
return 0;
 
drv = pci_dev_driver(dev);
seq_printf(m, "%02x%02x\t%04x%04x\t%x",
dev->bus->number,
dev->devfn,
dev->vendor,
dev->device,
dev->irq);
/* Here should be 7 and not PCI_NUM_RESOURCES as we need to preserve compatibility */
for(i=0; i<7; i++)
seq_printf(m, LONG_FORMAT,
dev->resource[i].start |
(dev->resource[i].flags & PCI_REGION_FLAG_MASK));
for(i=0; i<7; i++)
seq_printf(m, LONG_FORMAT,
dev->resource[i].start < dev->resource[i].end ?
dev->resource[i].end - dev->resource[i].start + 1 : 0);
seq_putc(m, '\t');
if (drv)
seq_printf(m, "%s", drv->name);
seq_putc(m, '\n');
return 0;
}
 
static struct seq_operations proc_bus_pci_devices_op = {
.start = pci_seq_start,
.next = pci_seq_next,
.stop = pci_seq_stop,
.show = show_device
};
 
struct proc_dir_entry *proc_bus_pci_dir;
 
int pci_proc_attach_device(struct pci_dev *dev)
{
struct pci_bus *bus = dev->bus;
struct proc_dir_entry *de, *e;
char name[16];
 
if (!proc_initialized)
return -EACCES;
 
if (!(de = bus->procdir)) {
if (pci_name_bus(name, bus))
return -EEXIST;
de = bus->procdir = proc_mkdir(name, proc_bus_pci_dir);
if (!de)
return -ENOMEM;
}
sprintf(name, "%02x.%x", PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
e = dev->procent = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR, de);
if (!e)
return -ENOMEM;
e->proc_fops = &proc_bus_pci_operations;
e->data = dev;
e->size = PCI_CFG_SPACE_SIZE;
 
return 0;
}
 
int pci_proc_detach_device(struct pci_dev *dev)
{
struct proc_dir_entry *e;
 
if ((e = dev->procent)) {
if (atomic_read(&e->count))
return -EBUSY;
remove_proc_entry(e->name, dev->bus->procdir);
dev->procent = NULL;
}
return 0;
}
 
int pci_proc_attach_bus(struct pci_bus* bus)
{
struct proc_dir_entry *de = bus->procdir;
 
if (!proc_initialized)
return -EACCES;
 
if (!de) {
char name[16];
sprintf(name, "%02x", bus->number);
de = bus->procdir = proc_mkdir(name, proc_bus_pci_dir);
if (!de)
return -ENOMEM;
}
return 0;
}
 
int pci_proc_detach_bus(struct pci_bus* bus)
{
struct proc_dir_entry *de = bus->procdir;
if (de)
remove_proc_entry(de->name, proc_bus_pci_dir);
return 0;
}
 
#ifdef CONFIG_PCI_LEGACY_PROC
 
/*
* Backward compatible /proc/pci interface.
*/
 
/*
* Convert some of the configuration space registers of the device at
* address (bus,devfn) into a string (possibly several lines each).
* The configuration string is stored starting at buf[len]. If the
* string would exceed the size of the buffer (SIZE), 0 is returned.
*/
static int show_dev_config(struct seq_file *m, void *v)
{
struct pci_dev *dev = v;
struct pci_dev *first_dev;
struct pci_driver *drv;
u32 class_rev;
unsigned char latency, min_gnt, max_lat, *class;
int reg;
 
first_dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
if (dev == first_dev)
seq_puts(m, "PCI devices found:\n");
pci_dev_put(first_dev);
 
drv = pci_dev_driver(dev);
 
pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency);
pci_read_config_byte (dev, PCI_MIN_GNT, &min_gnt);
pci_read_config_byte (dev, PCI_MAX_LAT, &max_lat);
seq_printf(m, " Bus %2d, device %3d, function %2d:\n",
dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
class = pci_class_name(class_rev >> 16);
if (class)
seq_printf(m, " %s", class);
else
seq_printf(m, " Class %04x", class_rev >> 16);
#ifdef CONFIG_PCI_NAMES
seq_printf(m, ": %s", dev->pretty_name);
#else
seq_printf(m, ": PCI device %04x:%04x", dev->vendor, dev->device);
#endif
seq_printf(m, " (rev %d).\n", class_rev & 0xff);
 
if (dev->irq)
seq_printf(m, " IRQ %d.\n", dev->irq);
 
if (latency || min_gnt || max_lat) {
seq_printf(m, " Master Capable. ");
if (latency)
seq_printf(m, "Latency=%d. ", latency);
else
seq_puts(m, "No bursts. ");
if (min_gnt)
seq_printf(m, "Min Gnt=%d.", min_gnt);
if (max_lat)
seq_printf(m, "Max Lat=%d.", max_lat);
seq_putc(m, '\n');
}
 
for (reg = 0; reg < 6; reg++) {
struct resource *res = dev->resource + reg;
unsigned long base, end, flags;
 
base = res->start;
end = res->end;
flags = res->flags;
if (!end)
continue;
 
if (flags & PCI_BASE_ADDRESS_SPACE_IO) {
seq_printf(m, " I/O at 0x%lx [0x%lx].\n",
base, end);
} else {
const char *pref, *type = "unknown";
 
if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH)
pref = "P";
else
pref = "Non-p";
switch (flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK) {
case PCI_BASE_ADDRESS_MEM_TYPE_32:
type = "32 bit"; break;
case PCI_BASE_ADDRESS_MEM_TYPE_1M:
type = "20 bit"; break;
case PCI_BASE_ADDRESS_MEM_TYPE_64:
type = "64 bit"; break;
}
seq_printf(m, " %srefetchable %s memory at "
"0x%lx [0x%lx].\n", pref, type,
base,
end);
}
}
return 0;
}
 
static struct seq_operations proc_pci_op = {
.start = pci_seq_start,
.next = pci_seq_next,
.stop = pci_seq_stop,
.show = show_dev_config
};
 
static int proc_pci_open(struct inode *inode, struct file *file)
{
return seq_open(file, &proc_pci_op);
}
static struct file_operations proc_pci_operations = {
.open = proc_pci_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
 
static void legacy_proc_init(void)
{
struct proc_dir_entry * entry = create_proc_entry("pci", 0, NULL);
if (entry)
entry->proc_fops = &proc_pci_operations;
}
 
#else
 
static void legacy_proc_init(void)
{
 
}
 
#endif /* CONFIG_PCI_LEGACY_PROC */
 
static int proc_bus_pci_dev_open(struct inode *inode, struct file *file)
{
return seq_open(file, &proc_bus_pci_devices_op);
}
static struct file_operations proc_bus_pci_dev_operations = {
.open = proc_bus_pci_dev_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
 
static int __init pci_proc_init(void)
{
struct proc_dir_entry *entry;
struct pci_dev *dev = NULL;
proc_bus_pci_dir = proc_mkdir("pci", proc_bus);
entry = create_proc_entry("devices", 0, proc_bus_pci_dir);
if (entry)
entry->proc_fops = &proc_bus_pci_dev_operations;
proc_initialized = 1;
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
pci_proc_attach_device(dev);
}
legacy_proc_init();
return 0;
}
 
__initcall(pci_proc_init);
 
#ifdef CONFIG_HOTPLUG
EXPORT_SYMBOL(pci_proc_attach_device);
EXPORT_SYMBOL(pci_proc_attach_bus);
EXPORT_SYMBOL(pci_proc_detach_bus);
EXPORT_SYMBOL(proc_bus_pci_dir);
#endif
 
/shark/trunk/drivers/newpci/pci-driver.c
0,0 → 1,535
/*
* drivers/pci/pci-driver.c
*
*/
 
#include <linux/pci.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/pci-dynids.h>
#include "pci.h"
 
/*
* Registration of PCI drivers and handling of hot-pluggable devices.
*/
 
/**
* pci_match_one_device - Tell if a PCI device structure has a matching
* PCI device id structure
* @id: single PCI device id structure to match
* @dev: the PCI device structure to match against
*
* Returns the matching pci_device_id structure or %NULL if there is no match.
*/
 
static inline const struct pci_device_id *
pci_match_one_device(const struct pci_device_id *id, const struct pci_dev *dev)
{
if ((id->vendor == PCI_ANY_ID || id->vendor == dev->vendor) &&
(id->device == PCI_ANY_ID || id->device == dev->device) &&
(id->subvendor == PCI_ANY_ID || id->subvendor == dev->subsystem_vendor) &&
(id->subdevice == PCI_ANY_ID || id->subdevice == dev->subsystem_device) &&
!((id->class ^ dev->class) & id->class_mask))
return id;
return NULL;
}
 
/*
* Dynamic device IDs are disabled for !CONFIG_HOTPLUG
*/
 
#ifdef CONFIG_HOTPLUG
/**
* pci_device_probe_dynamic()
*
* Walk the dynamic ID list looking for a match.
* returns 0 and sets pci_dev->driver when drv claims pci_dev, else error.
*/
static int
pci_device_probe_dynamic(struct pci_driver *drv, struct pci_dev *pci_dev)
{
int error = -ENODEV;
struct list_head *pos;
struct dynid *dynid;
 
spin_lock(&drv->dynids.lock);
list_for_each(pos, &drv->dynids.list) {
dynid = list_entry(pos, struct dynid, node);
if (pci_match_one_device(&dynid->id, pci_dev)) {
spin_unlock(&drv->dynids.lock);
error = drv->probe(pci_dev, &dynid->id);
if (error >= 0) {
pci_dev->driver = drv;
return 0;
}
return error;
}
}
spin_unlock(&drv->dynids.lock);
return error;
}
 
static inline void
dynid_init(struct dynid *dynid)
{
memset(dynid, 0, sizeof(*dynid));
INIT_LIST_HEAD(&dynid->node);
}
 
/**
* store_new_id
*
* Adds a new dynamic pci device ID to this driver,
* and causes the driver to probe for all devices again.
*/
static inline ssize_t
store_new_id(struct device_driver *driver, const char *buf, size_t count)
{
struct dynid *dynid;
struct bus_type * bus;
struct pci_driver *pdrv = to_pci_driver(driver);
__u32 vendor=PCI_ANY_ID, device=PCI_ANY_ID, subvendor=PCI_ANY_ID,
subdevice=PCI_ANY_ID, class=0, class_mask=0;
unsigned long driver_data=0;
int fields=0;
 
fields = sscanf(buf, "%x %x %x %x %x %x %lux",
&vendor, &device, &subvendor, &subdevice,
&class, &class_mask, &driver_data);
if (fields < 0)
return -EINVAL;
 
dynid = kmalloc(sizeof(*dynid), GFP_KERNEL);
if (!dynid)
return -ENOMEM;
dynid_init(dynid);
 
dynid->id.vendor = vendor;
dynid->id.device = device;
dynid->id.subvendor = subvendor;
dynid->id.subdevice = subdevice;
dynid->id.class = class;
dynid->id.class_mask = class_mask;
dynid->id.driver_data = pdrv->dynids.use_driver_data ?
driver_data : 0UL;
 
spin_lock(&pdrv->dynids.lock);
list_add_tail(&pdrv->dynids.list, &dynid->node);
spin_unlock(&pdrv->dynids.lock);
 
bus = get_bus(pdrv->driver.bus);
if (bus) {
if (get_driver(&pdrv->driver)) {
down_write(&bus->subsys.rwsem);
driver_attach(&pdrv->driver);
up_write(&bus->subsys.rwsem);
put_driver(&pdrv->driver);
}
put_bus(bus);
}
 
return count;
}
 
static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
static inline void
pci_init_dynids(struct pci_dynids *dynids)
{
memset(dynids, 0, sizeof(*dynids));
spin_lock_init(&dynids->lock);
INIT_LIST_HEAD(&dynids->list);
}
 
static void
pci_free_dynids(struct pci_driver *drv)
{
struct list_head *pos, *n;
struct dynid *dynid;
 
spin_lock(&drv->dynids.lock);
list_for_each_safe(pos, n, &drv->dynids.list) {
dynid = list_entry(pos, struct dynid, node);
list_del(&dynid->node);
kfree(dynid);
}
spin_unlock(&drv->dynids.lock);
}
 
static int
pci_create_newid_file(struct pci_driver *drv)
{
int error = 0;
if (drv->probe != NULL)
error = sysfs_create_file(&drv->driver.kobj,
&driver_attr_new_id.attr);
return error;
}
 
static int
pci_bus_match_dynids(const struct pci_dev *pci_dev, struct pci_driver *pci_drv)
{
struct list_head *pos;
struct dynid *dynid;
 
spin_lock(&pci_drv->dynids.lock);
list_for_each(pos, &pci_drv->dynids.list) {
dynid = list_entry(pos, struct dynid, node);
if (pci_match_one_device(&dynid->id, pci_dev)) {
spin_unlock(&pci_drv->dynids.lock);
return 1;
}
}
spin_unlock(&pci_drv->dynids.lock);
return 0;
}
 
#else /* !CONFIG_HOTPLUG */
static inline int pci_device_probe_dynamic(struct pci_driver *drv, struct pci_dev *pci_dev)
{
return -ENODEV;
}
static inline void dynid_init(struct dynid *dynid) {}
static inline void pci_init_dynids(struct pci_dynids *dynids) {}
static inline void pci_free_dynids(struct pci_driver *drv) {}
static inline int pci_create_newid_file(struct pci_driver *drv)
{
return 0;
}
static inline int pci_bus_match_dynids(const struct pci_dev *pci_dev, struct pci_driver *pci_drv)
{
return 0;
}
#endif
 
/**
* pci_match_device - Tell if a PCI device structure has a matching
* PCI device id structure
* @ids: array of PCI device id structures to search in
* @dev: the PCI device structure to match against
*
* Used by a driver to check whether a PCI device present in the
* system is in its list of supported devices.Returns the matching
* pci_device_id structure or %NULL if there is no match.
*/
const struct pci_device_id *
pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev)
{
while (ids->vendor || ids->subvendor || ids->class_mask) {
if (pci_match_one_device(ids, dev))
return ids;
ids++;
}
return NULL;
}
 
/**
* pci_device_probe_static()
*
* returns 0 and sets pci_dev->driver when drv claims pci_dev, else error.
*/
static int
pci_device_probe_static(struct pci_driver *drv, struct pci_dev *pci_dev)
{
int error = -ENODEV;
const struct pci_device_id *id;
 
if (!drv->id_table)
return error;
id = pci_match_device(drv->id_table, pci_dev);
if (id)
error = drv->probe(pci_dev, id);
if (error >= 0) {
pci_dev->driver = drv;
return 0;
}
return error;
}
 
/**
* __pci_device_probe()
*
* returns 0 on success, else error.
* side-effect: pci_dev->driver is set to drv when drv claims pci_dev.
*/
static int
__pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev)
{
int error = 0;
 
if (!pci_dev->driver && drv->probe) {
error = pci_device_probe_static(drv, pci_dev);
if (error == -ENODEV)
error = pci_device_probe_dynamic(drv, pci_dev);
}
return error;
}
 
static int pci_device_probe(struct device * dev)
{
int error = 0;
struct pci_driver *drv;
struct pci_dev *pci_dev;
 
drv = to_pci_driver(dev->driver);
pci_dev = to_pci_dev(dev);
pci_dev_get(pci_dev);
error = __pci_device_probe(drv, pci_dev);
if (error)
pci_dev_put(pci_dev);
 
return error;
}
 
static int pci_device_remove(struct device * dev)
{
struct pci_dev * pci_dev = to_pci_dev(dev);
struct pci_driver * drv = pci_dev->driver;
 
if (drv) {
if (drv->remove)
drv->remove(pci_dev);
pci_dev->driver = NULL;
}
pci_dev_put(pci_dev);
return 0;
}
 
static int pci_device_suspend(struct device * dev, u32 state)
{
struct pci_dev * pci_dev = to_pci_dev(dev);
struct pci_driver * drv = pci_dev->driver;
 
if (drv && drv->suspend)
return drv->suspend(pci_dev,state);
return 0;
}
 
static int pci_device_resume(struct device * dev)
{
struct pci_dev * pci_dev = to_pci_dev(dev);
struct pci_driver * drv = pci_dev->driver;
 
if (drv && drv->resume)
drv->resume(pci_dev);
return 0;
}
 
 
#define kobj_to_pci_driver(obj) container_of(obj, struct device_driver, kobj)
#define attr_to_driver_attribute(obj) container_of(obj, struct driver_attribute, attr)
 
static ssize_t
pci_driver_attr_show(struct kobject * kobj, struct attribute *attr, char *buf)
{
struct device_driver *driver = kobj_to_pci_driver(kobj);
struct driver_attribute *dattr = attr_to_driver_attribute(attr);
ssize_t ret = 0;
 
if (get_driver(driver)) {
if (dattr->show)
ret = dattr->show(driver, buf);
put_driver(driver);
}
return ret;
}
 
static ssize_t
pci_driver_attr_store(struct kobject * kobj, struct attribute *attr,
const char *buf, size_t count)
{
struct device_driver *driver = kobj_to_pci_driver(kobj);
struct driver_attribute *dattr = attr_to_driver_attribute(attr);
ssize_t ret = 0;
 
if (get_driver(driver)) {
if (dattr->store)
ret = dattr->store(driver, buf, count);
put_driver(driver);
}
return ret;
}
 
static struct sysfs_ops pci_driver_sysfs_ops = {
.show = pci_driver_attr_show,
.store = pci_driver_attr_store,
};
static struct kobj_type pci_driver_kobj_type = {
.sysfs_ops = &pci_driver_sysfs_ops,
};
 
static int
pci_populate_driver_dir(struct pci_driver *drv)
{
return pci_create_newid_file(drv);
}
 
/**
* pci_register_driver - register a new pci driver
* @drv: the driver structure to register
*
* Adds the driver structure to the list of registered drivers
* Returns the number of pci devices which were claimed by the driver
* during registration. The driver remains registered even if the
* return value is zero.
*/
int
pci_register_driver(struct pci_driver *drv)
{
int count = 0;
 
/* initialize common driver fields */
drv->driver.name = drv->name;
drv->driver.bus = &pci_bus_type;
drv->driver.probe = pci_device_probe;
drv->driver.remove = pci_device_remove;
drv->driver.kobj.ktype = &pci_driver_kobj_type;
pci_init_dynids(&drv->dynids);
 
/* register with core */
count = driver_register(&drv->driver);
 
if (count >= 0) {
pci_populate_driver_dir(drv);
}
 
return count ? count : 1;
}
 
/**
* pci_unregister_driver - unregister a pci driver
* @drv: the driver structure to unregister
*
* Deletes the driver structure from the list of registered PCI drivers,
* gives it a chance to clean up by calling its remove() function for
* each device it was responsible for, and marks those devices as
* driverless.
*/
 
void
pci_unregister_driver(struct pci_driver *drv)
{
driver_unregister(&drv->driver);
pci_free_dynids(drv);
}
 
static struct pci_driver pci_compat_driver = {
.name = "compat"
};
 
/**
* pci_dev_driver - get the pci_driver of a device
* @dev: the device to query
*
* Returns the appropriate pci_driver structure or %NULL if there is no
* registered driver for the device.
*/
struct pci_driver *
pci_dev_driver(const struct pci_dev *dev)
{
if (dev->driver)
return dev->driver;
else {
int i;
for(i=0; i<=PCI_ROM_RESOURCE; i++)
if (dev->resource[i].flags & IORESOURCE_BUSY)
return &pci_compat_driver;
}
return NULL;
}
 
/**
* pci_bus_match - Tell if a PCI device structure has a matching PCI device id structure
* @ids: array of PCI device id structures to search in
* @dev: the PCI device structure to match against
*
* Used by a driver to check whether a PCI device present in the
* system is in its list of supported devices.Returns the matching
* pci_device_id structure or %NULL if there is no match.
*/
static int pci_bus_match(struct device * dev, struct device_driver * drv)
{
const struct pci_dev * pci_dev = to_pci_dev(dev);
struct pci_driver * pci_drv = to_pci_driver(drv);
const struct pci_device_id * ids = pci_drv->id_table;
const struct pci_device_id *found_id;
 
if (!ids)
return 0;
 
found_id = pci_match_device(ids, pci_dev);
if (found_id)
return 1;
 
return pci_bus_match_dynids(pci_dev, pci_drv);
}
 
/**
* pci_dev_get - increments the reference count of the pci device structure
* @dev: the device being referenced
*
* Each live reference to a device should be refcounted.
*
* Drivers for PCI devices should normally record such references in
* their probe() methods, when they bind to a device, and release
* them by calling pci_dev_put(), in their disconnect() methods.
*
* A pointer to the device with the incremented reference counter is returned.
*/
struct pci_dev *pci_dev_get(struct pci_dev *dev)
{
struct device *tmp;
 
if (!dev)
return NULL;
 
tmp = get_device(&dev->dev);
if (tmp)
return to_pci_dev(tmp);
else
return NULL;
}
 
/**
* pci_dev_put - release a use of the pci device structure
* @dev: device that's been disconnected
*
* Must be called when a user of a device is finished with it. When the last
* user of the device calls this function, the memory of the device is freed.
*/
void pci_dev_put(struct pci_dev *dev)
{
if (dev)
put_device(&dev->dev);
}
 
#ifndef CONFIG_HOTPLUG
int pci_hotplug (struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size)
{
return -ENODEV;
}
#endif
 
struct bus_type pci_bus_type = {
.name = "pci",
.match = pci_bus_match,
.hotplug = pci_hotplug,
.suspend = pci_device_suspend,
.resume = pci_device_resume,
};
 
static int __init pci_driver_init(void)
{
return bus_register(&pci_bus_type);
}
 
postcore_initcall(pci_driver_init);
 
EXPORT_SYMBOL(pci_match_device);
EXPORT_SYMBOL(pci_register_driver);
EXPORT_SYMBOL(pci_unregister_driver);
EXPORT_SYMBOL(pci_dev_driver);
EXPORT_SYMBOL(pci_bus_type);
EXPORT_SYMBOL(pci_dev_get);
EXPORT_SYMBOL(pci_dev_put);
/shark/trunk/drivers/newpci/search.c
0,0 → 1,321
/*
* PCI searching functions.
*
* Copyright 1993 -- 1997 Drew Eckhardt, Frederic Potter,
* David Mosberger-Tang
* Copyright 1997 -- 2000 Martin Mares <mj@ucw.cz>
* Copyright 2003 -- Greg Kroah-Hartman <greg@kroah.com>
*/
 
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/module.h>
#include <linux/interrupt.h>
 
spinlock_t pci_bus_lock = SPIN_LOCK_UNLOCKED;
 
static struct pci_bus * __devinit
pci_do_find_bus(struct pci_bus* bus, unsigned char busnr)
{
struct pci_bus* child;
struct list_head *tmp;
 
if(bus->number == busnr)
return bus;
 
list_for_each(tmp, &bus->children) {
child = pci_do_find_bus(pci_bus_b(tmp), busnr);
if(child)
return child;
}
return NULL;
}
 
/**
* pci_find_bus - locate PCI bus from a given domain and bus number
* @domain: number of PCI domain to search
* @busnr: number of desired PCI bus
*
* Given a PCI bus number and domain number, the desired PCI bus is located
* in the global list of PCI buses. If the bus is found, a pointer to its
* data structure is returned. If no bus is found, %NULL is returned.
*/
struct pci_bus * __devinit pci_find_bus(int domain, int busnr)
{
struct pci_bus *bus = NULL;
struct pci_bus *tmp_bus;
 
while ((bus = pci_find_next_bus(bus)) != NULL) {
if (pci_domain_nr(bus) != domain)
continue;
tmp_bus = pci_do_find_bus(bus, busnr);
if (tmp_bus)
return tmp_bus;
}
return NULL;
}
 
/**
* pci_find_next_bus - begin or continue searching for a PCI bus
* @from: Previous PCI bus found, or %NULL for new search.
*
* Iterates through the list of known PCI busses. A new search is
* initiated by passing %NULL to the @from argument. Otherwise if
* @from is not %NULL, searches continue from next device on the
* global list.
*/
struct pci_bus *
pci_find_next_bus(const struct pci_bus *from)
{
struct list_head *n;
struct pci_bus *b = NULL;
 
WARN_ON(in_interrupt());
spin_lock(&pci_bus_lock);
n = from ? from->node.next : pci_root_buses.next;
if (n != &pci_root_buses)
b = pci_bus_b(n);
spin_unlock(&pci_bus_lock);
return b;
}
 
/**
* pci_find_slot - locate PCI device from a given PCI slot
* @bus: number of PCI bus on which desired PCI device resides
* @devfn: encodes number of PCI slot in which the desired PCI
* device resides and the logical device number within that slot
* in case of multi-function devices.
*
* Given a PCI bus and slot/function number, the desired PCI device
* is located in system global list of PCI devices. If the device
* is found, a pointer to its data structure is returned. If no
* device is found, %NULL is returned.
*/
struct pci_dev *
pci_find_slot(unsigned int bus, unsigned int devfn)
{
struct pci_dev *dev = NULL;
 
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
if (dev->bus->number == bus && dev->devfn == devfn)
return dev;
}
return NULL;
}
 
/**
* pci_find_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id
* @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
* @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
* @ss_vendor: PCI subsystem vendor id to match, or %PCI_ANY_ID to match all vendor ids
* @ss_device: PCI subsystem device id to match, or %PCI_ANY_ID to match all device ids
* @from: Previous PCI device found in search, or %NULL for new search.
*
* Iterates through the list of known PCI devices. If a PCI device is
* found with a matching @vendor, @device, @ss_vendor and @ss_device, a pointer to its
* device structure is returned. Otherwise, %NULL is returned.
* A new search is initiated by passing %NULL to the @from argument.
* Otherwise if @from is not %NULL, searches continue from next device on the global list.
*
* NOTE: Do not use this function anymore, use pci_get_subsys() instead, as
* the pci device returned by this function can disappear at any moment in
* time.
*/
struct pci_dev *
pci_find_subsys(unsigned int vendor, unsigned int device,
unsigned int ss_vendor, unsigned int ss_device,
const struct pci_dev *from)
{
struct list_head *n;
struct pci_dev *dev;
 
WARN_ON(in_interrupt());
spin_lock(&pci_bus_lock);
n = from ? from->global_list.next : pci_devices.next;
 
while (n && (n != &pci_devices)) {
dev = pci_dev_g(n);
if ((vendor == PCI_ANY_ID || dev->vendor == vendor) &&
(device == PCI_ANY_ID || dev->device == device) &&
(ss_vendor == PCI_ANY_ID || dev->subsystem_vendor == ss_vendor) &&
(ss_device == PCI_ANY_ID || dev->subsystem_device == ss_device))
goto exit;
n = n->next;
}
dev = NULL;
exit:
spin_unlock(&pci_bus_lock);
return dev;
}
 
/**
* pci_find_device - begin or continue searching for a PCI device by vendor/device id
* @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
* @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
* @from: Previous PCI device found in search, or %NULL for new search.
*
* Iterates through the list of known PCI devices. If a PCI device is
* found with a matching @vendor and @device, a pointer to its device structure is
* returned. Otherwise, %NULL is returned.
* A new search is initiated by passing %NULL to the @from argument.
* Otherwise if @from is not %NULL, searches continue from next device on the global list.
*
* NOTE: Do not use this function anymore, use pci_get_device() instead, as
* the pci device returned by this function can disappear at any moment in
* time.
*/
struct pci_dev *
pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *from)
{
return pci_find_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);
}
 
/**
* pci_get_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id
* @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
* @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
* @ss_vendor: PCI subsystem vendor id to match, or %PCI_ANY_ID to match all vendor ids
* @ss_device: PCI subsystem device id to match, or %PCI_ANY_ID to match all device ids
* @from: Previous PCI device found in search, or %NULL for new search.
*
* Iterates through the list of known PCI devices. If a PCI device is
* found with a matching @vendor, @device, @ss_vendor and @ss_device, a pointer to its
* device structure is returned, and the reference count to the device is
* incremented. Otherwise, %NULL is returned. A new search is initiated by
* passing %NULL to the @from argument. Otherwise if @from is not %NULL,
* searches continue from next device on the global list.
* The reference count for @from is always decremented if it is not %NULL.
*/
struct pci_dev *
pci_get_subsys(unsigned int vendor, unsigned int device,
unsigned int ss_vendor, unsigned int ss_device,
struct pci_dev *from)
{
struct list_head *n;
struct pci_dev *dev;
 
WARN_ON(in_interrupt());
spin_lock(&pci_bus_lock);
n = from ? from->global_list.next : pci_devices.next;
 
while (n && (n != &pci_devices)) {
dev = pci_dev_g(n);
if ((vendor == PCI_ANY_ID || dev->vendor == vendor) &&
(device == PCI_ANY_ID || dev->device == device) &&
(ss_vendor == PCI_ANY_ID || dev->subsystem_vendor == ss_vendor) &&
(ss_device == PCI_ANY_ID || dev->subsystem_device == ss_device))
goto exit;
n = n->next;
}
dev = NULL;
exit:
pci_dev_put(from);
dev = pci_dev_get(dev);
spin_unlock(&pci_bus_lock);
return dev;
}
 
/**
* pci_get_device - begin or continue searching for a PCI device by vendor/device id
* @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
* @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
* @from: Previous PCI device found in search, or %NULL for new search.
*
* Iterates through the list of known PCI devices. If a PCI device is
* found with a matching @vendor and @device, a pointer to its device structure is
* returned. Otherwise, %NULL is returned.
* A new search is initiated by passing %NULL to the @from argument.
* Otherwise if @from is not %NULL, searches continue from next device on the global list.
*
* Iterates through the list of known PCI devices. If a PCI device is
* found with a matching @vendor and @device, the reference count to the
* device is incremented and a pointer to its device structure is returned.
* Otherwise, %NULL is returned. A new search is initiated by passing %NULL
* to the @from argument. Otherwise if @from is not %NULL, searches continue
* from next device on the global list. The reference count for @from is
* always decremented if it is not %NULL.
*/
struct pci_dev *
pci_get_device(unsigned int vendor, unsigned int device, struct pci_dev *from)
{
return pci_get_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);
}
 
 
/**
* pci_find_device_reverse - begin or continue searching for a PCI device by vendor/device id
* @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
* @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
* @from: Previous PCI device found in search, or %NULL for new search.
*
* Iterates through the list of known PCI devices in the reverse order of pci_find_device().
* If a PCI device is found with a matching @vendor and @device, a pointer to
* its device structure is returned. Otherwise, %NULL is returned.
* A new search is initiated by passing %NULL to the @from argument.
* Otherwise if @from is not %NULL, searches continue from previous device on the global list.
*/
struct pci_dev *
pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct pci_dev *from)
{
struct list_head *n;
struct pci_dev *dev;
 
WARN_ON(in_interrupt());
spin_lock(&pci_bus_lock);
n = from ? from->global_list.prev : pci_devices.prev;
 
while (n && (n != &pci_devices)) {
dev = pci_dev_g(n);
if ((vendor == PCI_ANY_ID || dev->vendor == vendor) &&
(device == PCI_ANY_ID || dev->device == device))
goto exit;
n = n->prev;
}
dev = NULL;
exit:
spin_unlock(&pci_bus_lock);
return dev;
}
 
 
/**
* pci_find_class - begin or continue searching for a PCI device by class
* @class: search for a PCI device with this class designation
* @from: Previous PCI device found in search, or %NULL for new search.
*
* Iterates through the list of known PCI devices. If a PCI device is
* found with a matching @class, a pointer to its device structure is
* returned. Otherwise, %NULL is returned.
* A new search is initiated by passing %NULL to the @from argument.
* Otherwise if @from is not %NULL, searches continue from next device
* on the global list.
*/
struct pci_dev *
pci_find_class(unsigned int class, const struct pci_dev *from)
{
struct list_head *n;
struct pci_dev *dev;
 
spin_lock(&pci_bus_lock);
n = from ? from->global_list.next : pci_devices.next;
 
while (n && (n != &pci_devices)) {
dev = pci_dev_g(n);
if (dev->class == class)
goto exit;
n = n->next;
}
dev = NULL;
exit:
spin_unlock(&pci_bus_lock);
return dev;
}
 
EXPORT_SYMBOL(pci_find_bus);
EXPORT_SYMBOL(pci_find_class);
EXPORT_SYMBOL(pci_find_device);
EXPORT_SYMBOL(pci_find_device_reverse);
EXPORT_SYMBOL(pci_find_slot);
EXPORT_SYMBOL(pci_find_subsys);
EXPORT_SYMBOL(pci_get_device);
EXPORT_SYMBOL(pci_get_subsys);
/shark/trunk/drivers/newpci/probe.c
0,0 → 1,683
/*
* probe.c - PCI detection and setup code
*/
 
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/module.h>
 
#undef DEBUG
 
#ifdef DEBUG
#define DBG(x...) printk(x)
#else
#define DBG(x...)
#endif
 
#define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */
#define CARDBUS_RESERVE_BUSNR 3
 
/* Ugh. Need to stop exporting this to modules. */
LIST_HEAD(pci_root_buses);
EXPORT_SYMBOL(pci_root_buses);
 
LIST_HEAD(pci_devices);
 
/*
* Translate the low bits of the PCI base
* to the resource type
*/
static inline unsigned int pci_calc_resource_flags(unsigned int flags)
{
if (flags & PCI_BASE_ADDRESS_SPACE_IO)
return IORESOURCE_IO;
 
if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH)
return IORESOURCE_MEM | IORESOURCE_PREFETCH;
 
return IORESOURCE_MEM;
}
 
/*
* Find the extent of a PCI decode..
*/
static u32 pci_size(u32 base, u32 maxbase, unsigned long mask)
{
u32 size = mask & maxbase; /* Find the significant bits */
if (!size)
return 0;
 
/* Get the lowest of them to find the decode size, and
from that the extent. */
size = (size & ~(size-1)) - 1;
 
/* base == maxbase can be valid only if the BAR has
already been programmed with all 1s. */
if (base == maxbase && ((base | size) & mask) != mask)
return 0;
 
return size;
}
 
static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
{
unsigned int pos, reg, next;
u32 l, sz;
struct resource *res;
 
for(pos=0; pos<howmany; pos = next) {
next = pos+1;
res = &dev->resource[pos];
res->name = pci_name(dev);
reg = PCI_BASE_ADDRESS_0 + (pos << 2);
pci_read_config_dword(dev, reg, &l);
pci_write_config_dword(dev, reg, ~0);
pci_read_config_dword(dev, reg, &sz);
pci_write_config_dword(dev, reg, l);
if (!sz || sz == 0xffffffff)
continue;
if (l == 0xffffffff)
l = 0;
if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) {
sz = pci_size(l, sz, PCI_BASE_ADDRESS_MEM_MASK);
if (!sz)
continue;
res->start = l & PCI_BASE_ADDRESS_MEM_MASK;
res->flags |= l & ~PCI_BASE_ADDRESS_MEM_MASK;
} else {
sz = pci_size(l, sz, PCI_BASE_ADDRESS_IO_MASK & 0xffff);
if (!sz)
continue;
res->start = l & PCI_BASE_ADDRESS_IO_MASK;
res->flags |= l & ~PCI_BASE_ADDRESS_IO_MASK;
}
res->end = res->start + (unsigned long) sz;
res->flags |= pci_calc_resource_flags(l);
if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK))
== (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) {
pci_read_config_dword(dev, reg+4, &l);
next++;
#if BITS_PER_LONG == 64
res->start |= ((unsigned long) l) << 32;
res->end = res->start + sz;
pci_write_config_dword(dev, reg+4, ~0);
pci_read_config_dword(dev, reg+4, &sz);
pci_write_config_dword(dev, reg+4, l);
if (~sz)
res->end = res->start + 0xffffffff +
(((unsigned long) ~sz) << 32);
#else
if (l) {
printk(KERN_ERR "PCI: Unable to handle 64-bit address for device %s\n", pci_name(dev));
res->start = 0;
res->flags = 0;
continue;
}
#endif
}
}
if (rom) {
dev->rom_base_reg = rom;
res = &dev->resource[PCI_ROM_RESOURCE];
res->name = pci_name(dev);
pci_read_config_dword(dev, rom, &l);
pci_write_config_dword(dev, rom, ~PCI_ROM_ADDRESS_ENABLE);
pci_read_config_dword(dev, rom, &sz);
pci_write_config_dword(dev, rom, l);
if (l == 0xffffffff)
l = 0;
if (sz && sz != 0xffffffff) {
sz = pci_size(l, sz, PCI_ROM_ADDRESS_MASK);
if (sz) {
res->flags = (l & PCI_ROM_ADDRESS_ENABLE) |
IORESOURCE_MEM | IORESOURCE_PREFETCH |
IORESOURCE_READONLY | IORESOURCE_CACHEABLE;
res->start = l & PCI_ROM_ADDRESS_MASK;
res->end = res->start + (unsigned long) sz;
}
}
}
}
 
void __devinit pci_read_bridge_bases(struct pci_bus *child)
{
struct pci_dev *dev = child->self;
u8 io_base_lo, io_limit_lo;
u16 mem_base_lo, mem_limit_lo;
unsigned long base, limit;
struct resource *res;
int i;
 
if (!dev) /* It's a host bus, nothing to read */
return;
 
if (dev->transparent) {
printk("Transparent bridge - %s\n", pci_name(dev));
for(i = 0; i < PCI_BUS_NUM_RESOURCES; i++)
child->resource[i] = child->parent->resource[i];
return;
}
 
for(i=0; i<3; i++)
child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
 
res = child->resource[0];
pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo);
pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo);
base = (io_base_lo & PCI_IO_RANGE_MASK) << 8;
limit = (io_limit_lo & PCI_IO_RANGE_MASK) << 8;
 
if ((io_base_lo & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) {
u16 io_base_hi, io_limit_hi;
pci_read_config_word(dev, PCI_IO_BASE_UPPER16, &io_base_hi);
pci_read_config_word(dev, PCI_IO_LIMIT_UPPER16, &io_limit_hi);
base |= (io_base_hi << 16);
limit |= (io_limit_hi << 16);
}
 
if (base && base <= limit) {
res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO;
res->start = base;
res->end = limit + 0xfff;
}
 
res = child->resource[1];
pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base_lo);
pci_read_config_word(dev, PCI_MEMORY_LIMIT, &mem_limit_lo);
base = (mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16;
limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16;
if (base && base <= limit) {
res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM;
res->start = base;
res->end = limit + 0xfffff;
}
 
res = child->resource[2];
pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo);
pci_read_config_word(dev, PCI_PREF_MEMORY_LIMIT, &mem_limit_lo);
base = (mem_base_lo & PCI_PREF_RANGE_MASK) << 16;
limit = (mem_limit_lo & PCI_PREF_RANGE_MASK) << 16;
 
if ((mem_base_lo & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) {
u32 mem_base_hi, mem_limit_hi;
pci_read_config_dword(dev, PCI_PREF_BASE_UPPER32, &mem_base_hi);
pci_read_config_dword(dev, PCI_PREF_LIMIT_UPPER32, &mem_limit_hi);
#if BITS_PER_LONG == 64
base |= ((long) mem_base_hi) << 32;
limit |= ((long) mem_limit_hi) << 32;
#else
if (mem_base_hi || mem_limit_hi) {
printk(KERN_ERR "PCI: Unable to handle 64-bit address space for %s\n", child->name);
return;
}
#endif
}
if (base && base <= limit) {
res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM | IORESOURCE_PREFETCH;
res->start = base;
res->end = limit + 0xfffff;
}
}
 
static struct pci_bus * __devinit pci_alloc_bus(void)
{
struct pci_bus *b;
 
b = kmalloc(sizeof(*b), GFP_KERNEL);
if (b) {
memset(b, 0, sizeof(*b));
INIT_LIST_HEAD(&b->node);
INIT_LIST_HEAD(&b->children);
INIT_LIST_HEAD(&b->devices);
}
return b;
}
 
static struct pci_bus * __devinit
pci_alloc_child_bus(struct pci_bus *parent, struct pci_dev *bridge, int busnr)
{
struct pci_bus *child;
 
/*
* Allocate a new bus, and inherit stuff from the parent..
*/
child = pci_alloc_bus();
 
if (child) {
int i;
 
child->self = bridge;
child->parent = parent;
child->ops = parent->ops;
child->sysdata = parent->sysdata;
child->dev = &bridge->dev;
 
/*
* Set up the primary, secondary and subordinate
* bus numbers.
*/
child->number = child->secondary = busnr;
child->primary = parent->secondary;
child->subordinate = 0xff;
 
/* Set up default resource pointers and names.. */
for (i = 0; i < 4; i++) {
child->resource[i] = &bridge->resource[PCI_BRIDGE_RESOURCES+i];
child->resource[i]->name = child->name;
}
 
bridge->subordinate = child;
}
 
return child;
}
 
struct pci_bus * __devinit pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr)
{
struct pci_bus *child;
 
child = pci_alloc_child_bus(parent, dev, busnr);
if (child)
list_add_tail(&child->node, &parent->children);
return child;
}
 
static unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus);
 
/*
* If it's a bridge, configure it and scan the bus behind it.
* For CardBus bridges, we don't scan behind as the devices will
* be handled by the bridge driver itself.
*
* We need to process bridges in two passes -- first we scan those
* already configured by the BIOS and after we are done with all of
* them, we proceed to assigning numbers to the remaining buses in
* order to avoid overlaps between old and new bus numbers.
*/
int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass)
{
struct pci_bus *child;
int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS);
u32 buses;
 
pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
 
DBG("Scanning behind PCI bridge %s, config %06x, pass %d\n",
pci_name(dev), buses & 0xffffff, pass);
 
if ((buses & 0xffff00) && !pcibios_assign_all_busses() && !is_cardbus) {
unsigned int cmax;
/*
* Bus already configured by firmware, process it in the first
* pass and just note the configuration.
*/
if (pass)
return max;
child = pci_alloc_child_bus(bus, dev, 0);
child->primary = buses & 0xFF;
child->secondary = (buses >> 8) & 0xFF;
child->subordinate = (buses >> 16) & 0xFF;
child->number = child->secondary;
cmax = pci_scan_child_bus(child);
if (cmax > max) max = cmax;
} else {
/*
* We need to assign a number to this bus which we always
* do in the second pass.
*/
if (!pass)
return max;
 
/* Clear errors */
pci_write_config_word(dev, PCI_STATUS, 0xffff);
 
child = pci_alloc_child_bus(bus, dev, ++max);
buses = (buses & 0xff000000)
| ((unsigned int)(child->primary) << 0)
| ((unsigned int)(child->secondary) << 8)
| ((unsigned int)(child->subordinate) << 16);
 
/*
* yenta.c forces a secondary latency timer of 176.
* Copy that behaviour here.
*/
if (is_cardbus) {
buses &= ~0xff000000;
buses |= CARDBUS_LATENCY_TIMER << 24;
}
/*
* We need to blast all three values with a single write.
*/
pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses);
 
if (!is_cardbus) {
/* Now we can scan all subordinate buses... */
max = pci_scan_child_bus(child);
} else {
/*
* For CardBus bridges, we leave 4 bus numbers
* as cards with a PCI-to-PCI bridge can be
* inserted later.
*/
max += CARDBUS_RESERVE_BUSNR;
}
/*
* Set the subordinate bus number to its real value.
*/
child->subordinate = max;
pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max);
}
 
sprintf(child->name, (is_cardbus ? "PCI CardBus #%02x" : "PCI Bus #%02x"), child->number);
 
return max;
}
 
/*
* Read interrupt line and base address registers.
* The architecture-dependent code can tweak these, of course.
*/
static void pci_read_irq(struct pci_dev *dev)
{
unsigned char irq;
 
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq);
if (irq)
pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
dev->irq = irq;
}
 
/**
* pci_setup_device - fill in class and map information of a device
* @dev: the device structure to fill
*
* Initialize the device structure with information about the device's
* vendor,class,memory and IO-space addresses,IRQ lines etc.
* Called at initialisation of the PCI subsystem and by CardBus services.
* Returns 0 on success and -1 if unknown type of device (not normal, bridge
* or CardBus).
*/
static int pci_setup_device(struct pci_dev * dev)
{
u32 class;
 
dev->slot_name = dev->dev.bus_id;
sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(dev->bus),
dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
 
INIT_LIST_HEAD(&dev->pools);
 
pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
class >>= 8; /* upper 3 bytes */
dev->class = class;
class >>= 8;
 
DBG("Found %02x:%02x [%04x/%04x] %06x %02x\n", dev->bus->number,
dev->devfn, dev->vendor, dev->device, class, dev->hdr_type);
 
/* "Unknown power state" */
dev->current_state = 4;
 
switch (dev->hdr_type) { /* header type */
case PCI_HEADER_TYPE_NORMAL: /* standard header */
if (class == PCI_CLASS_BRIDGE_PCI)
goto bad;
pci_read_irq(dev);
pci_read_bases(dev, 6, PCI_ROM_ADDRESS);
pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor);
pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &dev->subsystem_device);
break;
 
case PCI_HEADER_TYPE_BRIDGE: /* bridge header */
if (class != PCI_CLASS_BRIDGE_PCI)
goto bad;
/* The PCI-to-PCI bridge spec requires that subtractive
decoding (i.e. transparent) bridge must have programming
interface code of 0x01. */
dev->transparent = ((dev->class & 0xff) == 1);
pci_read_bases(dev, 2, PCI_ROM_ADDRESS1);
break;
 
case PCI_HEADER_TYPE_CARDBUS: /* CardBus bridge header */
if (class != PCI_CLASS_BRIDGE_CARDBUS)
goto bad;
pci_read_irq(dev);
pci_read_bases(dev, 1, 0);
pci_read_config_word(dev, PCI_CB_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor);
pci_read_config_word(dev, PCI_CB_SUBSYSTEM_ID, &dev->subsystem_device);
break;
 
default: /* unknown header */
printk(KERN_ERR "PCI: device %s has unknown header type %02x, ignoring.\n",
pci_name(dev), dev->hdr_type);
return -1;
 
bad:
printk(KERN_ERR "PCI: %s: class %x doesn't match header type %02x. Ignoring class.\n",
pci_name(dev), class, dev->hdr_type);
dev->class = PCI_CLASS_NOT_DEFINED;
}
 
/* We found a fine healthy device, go go go... */
return 0;
}
 
/**
* pci_release_dev - free a pci device structure when all users of it are finished.
* @dev: device that's been disconnected
*
* Will be called only by the device core when all users of this pci device are
* done.
*/
static void pci_release_dev(struct device *dev)
{
struct pci_dev *pci_dev;
 
pci_dev = to_pci_dev(dev);
kfree(pci_dev);
}
 
/*
* Read the config data for a PCI device, sanity-check it
* and fill in the dev structure...
*/
static struct pci_dev * __devinit
pci_scan_device(struct pci_bus *bus, int devfn)
{
struct pci_dev *dev;
u32 l;
u8 hdr_type;
 
if (pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type))
return NULL;
 
if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l))
return NULL;
 
/* some broken boards return 0 or ~0 if a slot is empty: */
if (l == 0xffffffff || l == 0x00000000 ||
l == 0x0000ffff || l == 0xffff0000)
return NULL;
 
dev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL);
if (!dev)
return NULL;
 
memset(dev, 0, sizeof(struct pci_dev));
dev->bus = bus;
dev->sysdata = bus->sysdata;
dev->dev.parent = bus->dev;
dev->dev.bus = &pci_bus_type;
dev->devfn = devfn;
dev->hdr_type = hdr_type & 0x7f;
dev->multifunction = !!(hdr_type & 0x80);
dev->vendor = l & 0xffff;
dev->device = (l >> 16) & 0xffff;
 
/* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
set this higher, assuming the system even supports it. */
dev->dma_mask = 0xffffffff;
dev->consistent_dma_mask = 0xffffffff;
if (pci_setup_device(dev) < 0) {
kfree(dev);
return NULL;
}
device_initialize(&dev->dev);
dev->dev.release = pci_release_dev;
pci_dev_get(dev);
 
pci_name_device(dev);
 
dev->dev.dma_mask = &dev->dma_mask;
 
return dev;
}
 
/**
* pci_scan_slot - scan a PCI slot on a bus for devices.
* @bus: PCI bus to scan
* @devfn: slot number to scan (must have zero function.)
*
* Scan a PCI slot on the specified PCI bus for devices, adding
* discovered devices to the @bus->devices list. New devices
* will have an empty dev->global_list head.
*/
int __devinit pci_scan_slot(struct pci_bus *bus, int devfn)
{
int func, nr = 0;
 
for (func = 0; func < 8; func++, devfn++) {
struct pci_dev *dev;
 
dev = pci_scan_device(bus, devfn);
if (func == 0) {
if (!dev)
break;
} else {
if (!dev)
continue;
dev->multifunction = 1;
}
 
/* Fix up broken headers */
pci_fixup_device(PCI_FIXUP_HEADER, dev);
 
/*
* Add the device to our list of discovered devices
* and the bus list for fixup functions, etc.
*/
INIT_LIST_HEAD(&dev->global_list);
list_add_tail(&dev->bus_list, &bus->devices);
nr++;
 
/*
* If this is a single function device,
* don't scan past the first function.
*/
if (!dev->multifunction)
break;
}
return nr;
}
 
static unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus)
{
unsigned int devfn, pass, max = bus->secondary;
struct pci_dev *dev;
 
DBG("Scanning bus %02x\n", bus->number);
 
/* Go find them, Rover! */
for (devfn = 0; devfn < 0x100; devfn += 8)
pci_scan_slot(bus, devfn);
 
/*
* After performing arch-dependent fixup of the bus, look behind
* all PCI-to-PCI bridges on this bus.
*/
DBG("Fixups for bus %02x\n", bus->number);
pcibios_fixup_bus(bus);
for (pass=0; pass < 2; pass++)
list_for_each_entry(dev, &bus->devices, bus_list) {
if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
max = pci_scan_bridge(bus, dev, max, pass);
}
 
/*
* We've scanned the bus and so we know all about what's on
* the other side of any bridges that may be on this bus plus
* any devices.
*
* Return how far we've got finding sub-buses.
*/
DBG("Bus scan for %02x returning with max=%02x\n", bus->number, max);
return max;
}
 
unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus)
{
unsigned int max;
 
max = pci_scan_child_bus(bus);
 
/*
* Make the discovered devices available.
*/
pci_bus_add_devices(bus);
 
return max;
}
 
struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent, int bus, struct pci_ops *ops, void *sysdata)
{
struct pci_bus *b;
 
b = pci_alloc_bus();
if (!b)
return NULL;
 
b->dev = kmalloc(sizeof(*(b->dev)),GFP_KERNEL);
if (!b->dev){
kfree(b);
return NULL;
}
 
b->sysdata = sysdata;
b->ops = ops;
 
if (pci_find_bus(pci_domain_nr(b), bus)) {
/* If we already got to this bus through a different bridge, ignore it */
DBG("PCI: Bus %02x already known\n", bus);
kfree(b->dev);
kfree(b);
return NULL;
}
 
list_add_tail(&b->node, &pci_root_buses);
 
memset(b->dev,0,sizeof(*(b->dev)));
b->dev->parent = parent;
sprintf(b->dev->bus_id,"pci%04x:%02x", pci_domain_nr(b), bus);
device_register(b->dev);
 
b->number = b->secondary = bus;
b->resource[0] = &ioport_resource;
b->resource[1] = &iomem_resource;
 
b->subordinate = pci_scan_child_bus(b);
 
pci_bus_add_devices(b);
 
return b;
}
EXPORT_SYMBOL(pci_scan_bus_parented);
 
#ifdef CONFIG_HOTPLUG
EXPORT_SYMBOL(pci_add_new_bus);
EXPORT_SYMBOL(pci_do_scan_bus);
EXPORT_SYMBOL(pci_scan_slot);
EXPORT_SYMBOL(pci_scan_bridge);
#endif
/shark/trunk/drivers/newpci/pool.c
0,0 → 1,404
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/module.h>
 
/*
* Pool allocator ... wraps the pci_alloc_consistent page allocator, so
* small blocks are easily used by drivers for bus mastering controllers.
* This should probably be sharing the guts of the slab allocator.
*/
 
struct pci_pool { /* the pool */
struct list_head page_list;
spinlock_t lock;
size_t blocks_per_page;
size_t size;
struct pci_dev *dev;
size_t allocation;
char name [32];
wait_queue_head_t waitq;
struct list_head pools;
};
 
struct pci_page { /* cacheable header for 'allocation' bytes */
struct list_head page_list;
void *vaddr;
dma_addr_t dma;
unsigned in_use;
unsigned long bitmap [0];
};
 
#define POOL_TIMEOUT_JIFFIES ((100 /* msec */ * HZ) / 1000)
#define POOL_POISON_FREED 0xa7 /* !inuse */
#define POOL_POISON_ALLOCATED 0xa9 /* !initted */
 
static DECLARE_MUTEX (pools_lock);
 
static ssize_t
show_pools (struct device *dev, char *buf)
{
struct pci_dev *pdev;
unsigned temp, size;
char *next;
struct list_head *i, *j;
 
pdev = container_of (dev, struct pci_dev, dev);
next = buf;
size = PAGE_SIZE;
 
temp = snprintf (next, size, "poolinfo - 0.1\n");
size -= temp;
next += temp;
 
down (&pools_lock);
list_for_each (i, &pdev->pools) {
struct pci_pool *pool;
unsigned pages = 0, blocks = 0;
 
pool = list_entry (i, struct pci_pool, pools);
 
list_for_each (j, &pool->page_list) {
struct pci_page *page;
 
page = list_entry (j, struct pci_page, page_list);
pages++;
blocks += page->in_use;
}
 
/* per-pool info, no real statistics yet */
temp = snprintf (next, size, "%-16s %4u %4Zu %4Zu %2u\n",
pool->name,
blocks, pages * pool->blocks_per_page,
pool->size, pages);
size -= temp;
next += temp;
}
up (&pools_lock);
 
return PAGE_SIZE - size;
}
static DEVICE_ATTR (pools, S_IRUGO, show_pools, NULL);
 
/**
* pci_pool_create - Creates a pool of pci consistent memory blocks, for dma.
* @name: name of pool, for diagnostics
* @pdev: pci device that will be doing the DMA
* @size: size of the blocks in this pool.
* @align: alignment requirement for blocks; must be a power of two
* @allocation: returned blocks won't cross this boundary (or zero)
* Context: !in_interrupt()
*
* Returns a pci allocation pool with the requested characteristics, or
* null if one can't be created. Given one of these pools, pci_pool_alloc()
* may be used to allocate memory. Such memory will all have "consistent"
* DMA mappings, accessible by the device and its driver without using
* cache flushing primitives. The actual size of blocks allocated may be
* larger than requested because of alignment.
*
* If allocation is nonzero, objects returned from pci_pool_alloc() won't
* cross that size boundary. This is useful for devices which have
* addressing restrictions on individual DMA transfers, such as not crossing
* boundaries of 4KBytes.
*/
struct pci_pool *
pci_pool_create (const char *name, struct pci_dev *pdev,
size_t size, size_t align, size_t allocation)
{
struct pci_pool *retval;
 
if (align == 0)
align = 1;
if (size == 0)
return 0;
else if (size < align)
size = align;
else if ((size % align) != 0) {
size += align + 1;
size &= ~(align - 1);
}
 
if (allocation == 0) {
if (PAGE_SIZE < size)
allocation = size;
else
allocation = PAGE_SIZE;
// FIXME: round up for less fragmentation
} else if (allocation < size)
return 0;
 
if (!(retval = kmalloc (sizeof *retval, SLAB_KERNEL)))
return retval;
 
strlcpy (retval->name, name, sizeof retval->name);
 
retval->dev = pdev;
 
INIT_LIST_HEAD (&retval->page_list);
spin_lock_init (&retval->lock);
retval->size = size;
retval->allocation = allocation;
retval->blocks_per_page = allocation / size;
init_waitqueue_head (&retval->waitq);
 
if (pdev) {
down (&pools_lock);
if (list_empty (&pdev->pools))
device_create_file (&pdev->dev, &dev_attr_pools);
/* note: not currently insisting "name" be unique */
list_add (&retval->pools, &pdev->pools);
up (&pools_lock);
} else
INIT_LIST_HEAD (&retval->pools);
 
return retval;
}
 
 
static struct pci_page *
pool_alloc_page (struct pci_pool *pool, int mem_flags)
{
struct pci_page *page;
int mapsize;
 
mapsize = pool->blocks_per_page;
mapsize = (mapsize + BITS_PER_LONG - 1) / BITS_PER_LONG;
mapsize *= sizeof (long);
 
page = (struct pci_page *) kmalloc (mapsize + sizeof *page, mem_flags);
if (!page)
return 0;
page->vaddr = pci_alloc_consistent (pool->dev,
pool->allocation,
&page->dma);
if (page->vaddr) {
memset (page->bitmap, 0xff, mapsize); // bit set == free
#ifdef CONFIG_DEBUG_SLAB
memset (page->vaddr, POOL_POISON_FREED, pool->allocation);
#endif
list_add (&page->page_list, &pool->page_list);
page->in_use = 0;
} else {
kfree (page);
page = 0;
}
return page;
}
 
 
static inline int
is_page_busy (int blocks, unsigned long *bitmap)
{
while (blocks > 0) {
if (*bitmap++ != ~0UL)
return 1;
blocks -= BITS_PER_LONG;
}
return 0;
}
 
static void
pool_free_page (struct pci_pool *pool, struct pci_page *page)
{
dma_addr_t dma = page->dma;
 
#ifdef CONFIG_DEBUG_SLAB
memset (page->vaddr, POOL_POISON_FREED, pool->allocation);
#endif
pci_free_consistent (pool->dev, pool->allocation, page->vaddr, dma);
list_del (&page->page_list);
kfree (page);
}
 
 
/**
* pci_pool_destroy - destroys a pool of pci memory blocks.
* @pool: pci pool that will be destroyed
* Context: !in_interrupt()
*
* Caller guarantees that no more memory from the pool is in use,
* and that nothing will try to use the pool after this call.
*/
void
pci_pool_destroy (struct pci_pool *pool)
{
down (&pools_lock);
list_del (&pool->pools);
if (pool->dev && list_empty (&pool->dev->pools))
device_remove_file (&pool->dev->dev, &dev_attr_pools);
up (&pools_lock);
 
while (!list_empty (&pool->page_list)) {
struct pci_page *page;
page = list_entry (pool->page_list.next,
struct pci_page, page_list);
if (is_page_busy (pool->blocks_per_page, page->bitmap)) {
printk (KERN_ERR "pci_pool_destroy %s/%s, %p busy\n",
pool->dev ? pci_name(pool->dev) : NULL,
pool->name, page->vaddr);
/* leak the still-in-use consistent memory */
list_del (&page->page_list);
kfree (page);
} else
pool_free_page (pool, page);
}
 
kfree (pool);
}
 
 
/**
* pci_pool_alloc - get a block of consistent memory
* @pool: pci pool that will produce the block
* @mem_flags: SLAB_KERNEL or SLAB_ATOMIC
* @handle: pointer to dma address of block
*
* This returns the kernel virtual address of a currently unused block,
* and reports its dma address through the handle.
* If such a memory block can't be allocated, null is returned.
*/
void *
pci_pool_alloc (struct pci_pool *pool, int mem_flags, dma_addr_t *handle)
{
unsigned long flags;
struct list_head *entry;
struct pci_page *page;
int map, block;
size_t offset;
void *retval;
 
restart:
spin_lock_irqsave (&pool->lock, flags);
list_for_each (entry, &pool->page_list) {
int i;
page = list_entry (entry, struct pci_page, page_list);
/* only cachable accesses here ... */
for (map = 0, i = 0;
i < pool->blocks_per_page;
i += BITS_PER_LONG, map++) {
if (page->bitmap [map] == 0)
continue;
block = ffz (~ page->bitmap [map]);
if ((i + block) < pool->blocks_per_page) {
clear_bit (block, &page->bitmap [map]);
offset = (BITS_PER_LONG * map) + block;
offset *= pool->size;
goto ready;
}
}
}
if (!(page = pool_alloc_page (pool, SLAB_ATOMIC))) {
if (mem_flags == SLAB_KERNEL) {
DECLARE_WAITQUEUE (wait, current);
 
current->state = TASK_INTERRUPTIBLE;
add_wait_queue (&pool->waitq, &wait);
spin_unlock_irqrestore (&pool->lock, flags);
 
schedule_timeout (POOL_TIMEOUT_JIFFIES);
 
remove_wait_queue (&pool->waitq, &wait);
goto restart;
}
retval = 0;
goto done;
}
 
clear_bit (0, &page->bitmap [0]);
offset = 0;
ready:
page->in_use++;
retval = offset + page->vaddr;
*handle = offset + page->dma;
#ifdef CONFIG_DEBUG_SLAB
memset (retval, POOL_POISON_ALLOCATED, pool->size);
#endif
done:
spin_unlock_irqrestore (&pool->lock, flags);
return retval;
}
 
 
static struct pci_page *
pool_find_page (struct pci_pool *pool, dma_addr_t dma)
{
unsigned long flags;
struct list_head *entry;
struct pci_page *page;
 
spin_lock_irqsave (&pool->lock, flags);
list_for_each (entry, &pool->page_list) {
page = list_entry (entry, struct pci_page, page_list);
if (dma < page->dma)
continue;
if (dma < (page->dma + pool->allocation))
goto done;
}
page = 0;
done:
spin_unlock_irqrestore (&pool->lock, flags);
return page;
}
 
 
/**
* pci_pool_free - put block back into pci pool
* @pool: the pci pool holding the block
* @vaddr: virtual address of block
* @dma: dma address of block
*
* Caller promises neither device nor driver will again touch this block
* unless it is first re-allocated.
*/
void
pci_pool_free (struct pci_pool *pool, void *vaddr, dma_addr_t dma)
{
struct pci_page *page;
unsigned long flags;
int map, block;
 
if ((page = pool_find_page (pool, dma)) == 0) {
printk (KERN_ERR "pci_pool_free %s/%s, %p/%lx (bad dma)\n",
pool->dev ? pci_name(pool->dev) : NULL,
pool->name, vaddr, (unsigned long) dma);
return;
}
 
block = dma - page->dma;
block /= pool->size;
map = block / BITS_PER_LONG;
block %= BITS_PER_LONG;
 
#ifdef CONFIG_DEBUG_SLAB
if (((dma - page->dma) + (void *)page->vaddr) != vaddr) {
printk (KERN_ERR "pci_pool_free %s/%s, %p (bad vaddr)/%Lx\n",
pool->dev ? pci_name(pool->dev) : NULL,
pool->name, vaddr, (unsigned long long) dma);
return;
}
if (page->bitmap [map] & (1UL << block)) {
printk (KERN_ERR "pci_pool_free %s/%s, dma %Lx already free\n",
pool->dev ? pci_name(pool->dev) : NULL,
pool->name, (unsigned long long)dma);
return;
}
memset (vaddr, POOL_POISON_FREED, pool->size);
#endif
 
spin_lock_irqsave (&pool->lock, flags);
page->in_use--;
set_bit (block, &page->bitmap [map]);
if (waitqueue_active (&pool->waitq))
wake_up (&pool->waitq);
/*
* Resist a temptation to do
* if (!is_page_busy(bpp, page->bitmap)) pool_free_page(pool, page);
* it is not interrupt safe. Better have empty pages hang around.
*/
spin_unlock_irqrestore (&pool->lock, flags);
}
 
 
EXPORT_SYMBOL (pci_pool_create);
EXPORT_SYMBOL (pci_pool_destroy);
EXPORT_SYMBOL (pci_pool_alloc);
EXPORT_SYMBOL (pci_pool_free);
/shark/trunk/drivers/newpci/syscall.c
0,0 → 1,142
/*
* pci_syscall.c
*
* For architectures where we want to allow direct access
* to the PCI config stuff - it would probably be preferable
* on PCs too, but there people just do it by hand with the
* magic northbridge registers..
*/
 
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/pci.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
 
 
asmlinkage long
sys_pciconfig_read(unsigned long bus, unsigned long dfn,
unsigned long off, unsigned long len, void *buf)
{
struct pci_dev *dev;
u8 byte;
u16 word;
u32 dword;
long err, cfg_ret;
 
err = -EPERM;
if (!capable(CAP_SYS_ADMIN))
goto error;
 
err = -ENODEV;
dev = pci_find_slot(bus, dfn);
if (!dev)
goto error;
 
lock_kernel();
switch (len) {
case 1:
cfg_ret = pci_read_config_byte(dev, off, &byte);
break;
case 2:
cfg_ret = pci_read_config_word(dev, off, &word);
break;
case 4:
cfg_ret = pci_read_config_dword(dev, off, &dword);
break;
default:
err = -EINVAL;
unlock_kernel();
goto error;
};
unlock_kernel();
 
err = -EIO;
if (cfg_ret != PCIBIOS_SUCCESSFUL)
goto error;
 
switch (len) {
case 1:
err = put_user(byte, (unsigned char *)buf);
break;
case 2:
err = put_user(word, (unsigned short *)buf);
break;
case 4:
err = put_user(dword, (unsigned int *)buf);
break;
};
return err;
 
error:
/* ??? XFree86 doesn't even check the return value. They
just look for 0xffffffff in the output, since that's what
they get instead of a machine check on x86. */
switch (len) {
case 1:
put_user(-1, (unsigned char *)buf);
break;
case 2:
put_user(-1, (unsigned short *)buf);
break;
case 4:
put_user(-1, (unsigned int *)buf);
break;
};
return err;
}
 
asmlinkage long
sys_pciconfig_write(unsigned long bus, unsigned long dfn,
unsigned long off, unsigned long len, void *buf)
{
struct pci_dev *dev;
u8 byte;
u16 word;
u32 dword;
int err = 0;
 
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
 
dev = pci_find_slot(bus, dfn);
if (!dev)
return -ENODEV;
 
lock_kernel();
switch(len) {
case 1:
err = get_user(byte, (u8 *)buf);
if (err)
break;
err = pci_write_config_byte(dev, off, byte);
if (err != PCIBIOS_SUCCESSFUL)
err = -EIO;
break;
 
case 2:
err = get_user(word, (u16 *)buf);
if (err)
break;
err = pci_write_config_word(dev, off, word);
if (err != PCIBIOS_SUCCESSFUL)
err = -EIO;
break;
 
case 4:
err = get_user(dword, (u32 *)buf);
if (err)
break;
err = pci_write_config_dword(dev, off, dword);
if (err != PCIBIOS_SUCCESSFUL)
err = -EIO;
break;
 
default:
err = -EINVAL;
break;
};
unlock_kernel();
 
return err;
}
/shark/trunk/drivers/newpci/pci.c
0,0 → 1,780
/*
* $Id: pci.c,v 1.1 2004-01-28 18:32:16 giacomo Exp $
*
* PCI Bus Services, see include/linux/pci.h for further explanation.
*
* Copyright 1993 -- 1997 Drew Eckhardt, Frederic Potter,
* David Mosberger-Tang
*
* Copyright 1997 -- 2000 Martin Mares <mj@ucw.cz>
*/
 
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <asm/dma.h> /* isa_dma_bridge_buggy */
 
#undef DEBUG
 
#ifdef DEBUG
#define DBG(x...) printk(x)
#else
#define DBG(x...)
#endif
 
/**
* pci_bus_max_busnr - returns maximum PCI bus number of given bus' children
* @bus: pointer to PCI bus structure to search
*
* Given a PCI bus, returns the highest PCI bus number present in the set
* including the given PCI bus and its list of child PCI buses.
*/
unsigned char __devinit
pci_bus_max_busnr(struct pci_bus* bus)
{
struct list_head *tmp;
unsigned char max, n;
 
max = bus->number;
list_for_each(tmp, &bus->children) {
n = pci_bus_max_busnr(pci_bus_b(tmp));
if(n > max)
max = n;
}
return max;
}
 
/**
* pci_max_busnr - returns maximum PCI bus number
*
* Returns the highest PCI bus number present in the system global list of
* PCI buses.
*/
unsigned char __devinit
pci_max_busnr(void)
{
struct pci_bus *bus = NULL;
unsigned char max, n;
 
max = 0;
while ((bus = pci_find_next_bus(bus)) != NULL) {
n = pci_bus_max_busnr(bus);
if(n > max)
max = n;
}
return max;
}
 
/**
* pci_find_capability - query for devices' capabilities
* @dev: PCI device to query
* @cap: capability code
*
* Tell if a device supports a given PCI capability.
* Returns the address of the requested capability structure within the
* device's PCI configuration space or 0 in case the device does not
* support it. Possible values for @cap:
*
* %PCI_CAP_ID_PM Power Management
*
* %PCI_CAP_ID_AGP Accelerated Graphics Port
*
* %PCI_CAP_ID_VPD Vital Product Data
*
* %PCI_CAP_ID_SLOTID Slot Identification
*
* %PCI_CAP_ID_MSI Message Signalled Interrupts
*
* %PCI_CAP_ID_CHSWP CompactPCI HotSwap
*
* %PCI_CAP_ID_PCIX PCI-X
*/
int
pci_find_capability(struct pci_dev *dev, int cap)
{
u16 status;
u8 pos, id;
int ttl = 48;
 
pci_read_config_word(dev, PCI_STATUS, &status);
if (!(status & PCI_STATUS_CAP_LIST))
return 0;
switch (dev->hdr_type) {
case PCI_HEADER_TYPE_NORMAL:
case PCI_HEADER_TYPE_BRIDGE:
pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &pos);
break;
case PCI_HEADER_TYPE_CARDBUS:
pci_read_config_byte(dev, PCI_CB_CAPABILITY_LIST, &pos);
break;
default:
return 0;
}
while (ttl-- && pos >= 0x40) {
pos &= ~3;
pci_read_config_byte(dev, pos + PCI_CAP_LIST_ID, &id);
if (id == 0xff)
break;
if (id == cap)
return pos;
pci_read_config_byte(dev, pos + PCI_CAP_LIST_NEXT, &pos);
}
return 0;
}
 
/**
* pci_bus_find_capability - query for devices' capabilities
* @bus: the PCI bus to query
* @devfn: PCI device to query
* @cap: capability code
*
* Like pci_find_capability() but works for pci devices that do not have a
* pci_dev structure set up yet.
*
* Returns the address of the requested capability structure within the
* device's PCI configuration space or 0 in case the device does not
* support it.
*/
int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap)
{
u16 status;
u8 pos, id;
int ttl = 48;
struct pci_dev *dev = bus->self;
 
pci_bus_read_config_word(bus, devfn, PCI_STATUS, &status);
if (!(status & PCI_STATUS_CAP_LIST))
return 0;
switch (dev->hdr_type) {
case PCI_HEADER_TYPE_NORMAL:
case PCI_HEADER_TYPE_BRIDGE:
pci_bus_read_config_byte(bus, devfn, PCI_CAPABILITY_LIST, &pos);
break;
case PCI_HEADER_TYPE_CARDBUS:
pci_bus_read_config_byte(bus, devfn, PCI_CB_CAPABILITY_LIST, &pos);
break;
default:
return 0;
}
while (ttl-- && pos >= 0x40) {
pos &= ~3;
pci_bus_read_config_byte(bus, devfn, pos + PCI_CAP_LIST_ID, &id);
if (id == 0xff)
break;
if (id == cap)
return pos;
pci_bus_read_config_byte(bus, devfn, pos + PCI_CAP_LIST_NEXT, &pos);
}
return 0;
}
 
/**
* pci_find_parent_resource - return resource region of parent bus of given region
* @dev: PCI device structure contains resources to be searched
* @res: child resource record for which parent is sought
*
* For given resource region of given device, return the resource
* region of parent bus the given region is contained in or where
* it should be allocated from.
*/
struct resource *
pci_find_parent_resource(const struct pci_dev *dev, struct resource *res)
{
const struct pci_bus *bus = dev->bus;
int i;
struct resource *best = NULL;
 
for(i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
struct resource *r = bus->resource[i];
if (!r)
continue;
if (res->start && !(res->start >= r->start && res->end <= r->end))
continue; /* Not contained */
if ((res->flags ^ r->flags) & (IORESOURCE_IO | IORESOURCE_MEM))
continue; /* Wrong type */
if (!((res->flags ^ r->flags) & IORESOURCE_PREFETCH))
return r; /* Exact match */
if ((res->flags & IORESOURCE_PREFETCH) && !(r->flags & IORESOURCE_PREFETCH))
best = r; /* Approximating prefetchable by non-prefetchable */
}
return best;
}
 
/**
* pci_set_power_state - Set the power state of a PCI device
* @dev: PCI device to be suspended
* @state: Power state we're entering
*
* Transition a device to a new power state, using the Power Management
* Capabilities in the device's config space.
*
* RETURN VALUE:
* -EINVAL if trying to enter a lower state than we're already in.
* 0 if we're already in the requested state.
* -EIO if device does not support PCI PM.
* 0 if we can successfully change the power state.
*/
 
int
pci_set_power_state(struct pci_dev *dev, int state)
{
int pm;
u16 pmcsr;
 
/* bound the state we're entering */
if (state > 3) state = 3;
 
/* Validate current state:
* Can enter D0 from any state, but if we can only go deeper
* to sleep if we're already in a low power state
*/
if (state > 0 && dev->current_state > state)
return -EINVAL;
else if (dev->current_state == state)
return 0; /* we're already there */
 
/* find PCI PM capability in list */
pm = pci_find_capability(dev, PCI_CAP_ID_PM);
/* abort if the device doesn't support PM capabilities */
if (!pm) return -EIO;
 
/* check if this device supports the desired state */
if (state == 1 || state == 2) {
u16 pmc;
pci_read_config_word(dev,pm + PCI_PM_PMC,&pmc);
if (state == 1 && !(pmc & PCI_PM_CAP_D1)) return -EIO;
else if (state == 2 && !(pmc & PCI_PM_CAP_D2)) return -EIO;
}
 
/* If we're in D3, force entire word to 0.
* This doesn't affect PME_Status, disables PME_En, and
* sets PowerState to 0.
*/
if (dev->current_state >= 3)
pmcsr = 0;
else {
pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr);
pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
pmcsr |= state;
}
 
/* enter specified state */
pci_write_config_word(dev, pm + PCI_PM_CTRL, pmcsr);
 
/* Mandatory power management transition delays */
/* see PCI PM 1.1 5.6.1 table 18 */
if(state == 3 || dev->current_state == 3)
{
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ/100);
}
else if(state == 2 || dev->current_state == 2)
udelay(200);
dev->current_state = state;
 
return 0;
}
 
/**
* pci_save_state - save the PCI configuration space of a device before suspending
* @dev: - PCI device that we're dealing with
* @buffer: - buffer to hold config space context
*
* @buffer must be large enough to hold the entire PCI 2.2 config space
* (>= 64 bytes).
*/
int
pci_save_state(struct pci_dev *dev, u32 *buffer)
{
int i;
if (buffer) {
/* XXX: 100% dword access ok here? */
for (i = 0; i < 16; i++)
pci_read_config_dword(dev, i * 4,&buffer[i]);
}
return 0;
}
 
/**
* pci_restore_state - Restore the saved state of a PCI device
* @dev: - PCI device that we're dealing with
* @buffer: - saved PCI config space
*
*/
int
pci_restore_state(struct pci_dev *dev, u32 *buffer)
{
int i;
 
if (buffer) {
for (i = 0; i < 16; i++)
pci_write_config_dword(dev,i * 4, buffer[i]);
}
/*
* otherwise, write the context information we know from bootup.
* This works around a problem where warm-booting from Windows
* combined with a D3(hot)->D0 transition causes PCI config
* header data to be forgotten.
*/
else {
for (i = 0; i < 6; i ++)
pci_write_config_dword(dev,
PCI_BASE_ADDRESS_0 + (i * 4),
dev->resource[i].start);
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
}
return 0;
}
 
/**
* pci_enable_device_bars - Initialize some of a device for use
* @dev: PCI device to be initialized
* @bars: bitmask of BAR's that must be configured
*
* Initialize device before it's used by a driver. Ask low-level code
* to enable selected I/O and memory resources. Wake up the device if it
* was suspended. Beware, this function can fail.
*/
int
pci_enable_device_bars(struct pci_dev *dev, int bars)
{
int err;
 
pci_set_power_state(dev, 0);
if ((err = pcibios_enable_device(dev, bars)) < 0)
return err;
return 0;
}
 
/**
* pci_enable_device - Initialize device before it's used by a driver.
* @dev: PCI device to be initialized
*
* Initialize device before it's used by a driver. Ask low-level code
* to enable I/O and memory. Wake up the device if it was suspended.
* Beware, this function can fail.
*/
int
pci_enable_device(struct pci_dev *dev)
{
return pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1);
}
 
/**
* pci_disable_device - Disable PCI device after use
* @dev: PCI device to be disabled
*
* Signal to the system that the PCI device is not in use by the system
* anymore. This only involves disabling PCI bus-mastering, if active.
*/
void
pci_disable_device(struct pci_dev *dev)
{
u16 pci_command;
 
pci_read_config_word(dev, PCI_COMMAND, &pci_command);
if (pci_command & PCI_COMMAND_MASTER) {
pci_command &= ~PCI_COMMAND_MASTER;
pci_write_config_word(dev, PCI_COMMAND, pci_command);
}
}
 
/**
* pci_enable_wake - enable device to generate PME# when suspended
* @dev: - PCI device to operate on
* @state: - Current state of device.
* @enable: - Flag to enable or disable generation
*
* Set the bits in the device's PM Capabilities to generate PME# when
* the system is suspended.
*
* -EIO is returned if device doesn't have PM Capabilities.
* -EINVAL is returned if device supports it, but can't generate wake events.
* 0 if operation is successful.
*
*/
int pci_enable_wake(struct pci_dev *dev, u32 state, int enable)
{
int pm;
u16 value;
 
/* find PCI PM capability in list */
pm = pci_find_capability(dev, PCI_CAP_ID_PM);
 
/* If device doesn't support PM Capabilities, but request is to disable
* wake events, it's a nop; otherwise fail */
if (!pm)
return enable ? -EIO : 0;
 
/* Check device's ability to generate PME# */
pci_read_config_word(dev,pm+PCI_PM_PMC,&value);
 
value &= PCI_PM_CAP_PME_MASK;
value >>= ffs(value); /* First bit of mask */
 
/* Check if it can generate PME# from requested state. */
if (!value || !(value & (1 << state)))
return enable ? -EINVAL : 0;
 
pci_read_config_word(dev, pm + PCI_PM_CTRL, &value);
 
/* Clear PME_Status by writing 1 to it and enable PME# */
value |= PCI_PM_CTRL_PME_STATUS | PCI_PM_CTRL_PME_ENABLE;
 
if (!enable)
value &= ~PCI_PM_CTRL_PME_ENABLE;
 
pci_write_config_word(dev, pm + PCI_PM_CTRL, value);
return 0;
}
 
int
pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)
{
u8 pin;
 
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
if (!pin)
return -1;
pin--;
while (dev->bus->self) {
pin = (pin + PCI_SLOT(dev->devfn)) % 4;
dev = dev->bus->self;
}
*bridge = dev;
return pin;
}
 
/**
* pci_release_region - Release a PCI bar
* @pdev: PCI device whose resources were previously reserved by pci_request_region
* @bar: BAR to release
*
* Releases the PCI I/O and memory resources previously reserved by a
* successful call to pci_request_region. Call this function only
* after all use of the PCI regions has ceased.
*/
void pci_release_region(struct pci_dev *pdev, int bar)
{
if (pci_resource_len(pdev, bar) == 0)
return;
if (pci_resource_flags(pdev, bar) & IORESOURCE_IO)
release_region(pci_resource_start(pdev, bar),
pci_resource_len(pdev, bar));
else if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM)
release_mem_region(pci_resource_start(pdev, bar),
pci_resource_len(pdev, bar));
}
 
/**
* pci_request_region - Reserved PCI I/O and memory resource
* @pdev: PCI device whose resources are to be reserved
* @bar: BAR to be reserved
* @res_name: Name to be associated with resource.
*
* Mark the PCI region associated with PCI device @pdev BR @bar as
* being reserved by owner @res_name. Do not access any
* address inside the PCI regions unless this call returns
* successfully.
*
* Returns 0 on success, or %EBUSY on error. A warning
* message is also printed on failure.
*/
int pci_request_region(struct pci_dev *pdev, int bar, char *res_name)
{
if (pci_resource_len(pdev, bar) == 0)
return 0;
if (pci_resource_flags(pdev, bar) & IORESOURCE_IO) {
if (!request_region(pci_resource_start(pdev, bar),
pci_resource_len(pdev, bar), res_name))
goto err_out;
}
else if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) {
if (!request_mem_region(pci_resource_start(pdev, bar),
pci_resource_len(pdev, bar), res_name))
goto err_out;
}
return 0;
 
err_out:
printk (KERN_WARNING "PCI: Unable to reserve %s region #%d:%lx@%lx for device %s\n",
pci_resource_flags(pdev, bar) & IORESOURCE_IO ? "I/O" : "mem",
bar + 1, /* PCI BAR # */
pci_resource_len(pdev, bar), pci_resource_start(pdev, bar),
pci_name(pdev));
return -EBUSY;
}
 
 
/**
* pci_release_regions - Release reserved PCI I/O and memory resources
* @pdev: PCI device whose resources were previously reserved by pci_request_regions
*
* Releases all PCI I/O and memory resources previously reserved by a
* successful call to pci_request_regions. Call this function only
* after all use of the PCI regions has ceased.
*/
 
void pci_release_regions(struct pci_dev *pdev)
{
int i;
for (i = 0; i < 6; i++)
pci_release_region(pdev, i);
}
 
/**
* pci_request_regions - Reserved PCI I/O and memory resources
* @pdev: PCI device whose resources are to be reserved
* @res_name: Name to be associated with resource.
*
* Mark all PCI regions associated with PCI device @pdev as
* being reserved by owner @res_name. Do not access any
* address inside the PCI regions unless this call returns
* successfully.
*
* Returns 0 on success, or %EBUSY on error. A warning
* message is also printed on failure.
*/
int pci_request_regions(struct pci_dev *pdev, char *res_name)
{
int i;
for (i = 0; i < 6; i++)
if(pci_request_region(pdev, i, res_name))
goto err_out;
return 0;
 
err_out:
printk (KERN_WARNING "PCI: Unable to reserve %s region #%d:%lx@%lx for device %s\n",
pci_resource_flags(pdev, i) & IORESOURCE_IO ? "I/O" : "mem",
i + 1, /* PCI BAR # */
pci_resource_len(pdev, i), pci_resource_start(pdev, i),
pci_name(pdev));
while(--i >= 0)
pci_release_region(pdev, i);
return -EBUSY;
}
 
/**
* pci_set_master - enables bus-mastering for device dev
* @dev: the PCI device to enable
*
* Enables bus-mastering on the device and calls pcibios_set_master()
* to do the needed arch specific settings.
*/
void
pci_set_master(struct pci_dev *dev)
{
u16 cmd;
 
pci_read_config_word(dev, PCI_COMMAND, &cmd);
if (! (cmd & PCI_COMMAND_MASTER)) {
DBG("PCI: Enabling bus mastering for device %s\n", pci_name(dev));
cmd |= PCI_COMMAND_MASTER;
pci_write_config_word(dev, PCI_COMMAND, cmd);
}
pcibios_set_master(dev);
}
 
#ifndef HAVE_ARCH_PCI_MWI
/* This can be overridden by arch code. */
u8 pci_cache_line_size = L1_CACHE_BYTES >> 2;
 
/**
* pci_generic_prep_mwi - helper function for pci_set_mwi
* @dev: the PCI device for which MWI is enabled
*
* Helper function for generic implementation of pcibios_prep_mwi
* function. Originally copied from drivers/net/acenic.c.
* Copyright 1998-2001 by Jes Sorensen, <jes@trained-monkey.org>.
*
* RETURNS: An appropriate -ERRNO error value on error, or zero for success.
*/
static int
pci_generic_prep_mwi(struct pci_dev *dev)
{
u8 cacheline_size;
 
if (!pci_cache_line_size)
return -EINVAL; /* The system doesn't support MWI. */
 
/* Validate current setting: the PCI_CACHE_LINE_SIZE must be
equal to or multiple of the right value. */
pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &cacheline_size);
if (cacheline_size >= pci_cache_line_size &&
(cacheline_size % pci_cache_line_size) == 0)
return 0;
 
/* Write the correct value. */
pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, pci_cache_line_size);
/* Read it back. */
pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &cacheline_size);
if (cacheline_size == pci_cache_line_size)
return 0;
 
printk(KERN_WARNING "PCI: cache line size of %d is not supported "
"by device %s\n", pci_cache_line_size << 2, pci_name(dev));
 
return -EINVAL;
}
#endif /* !HAVE_ARCH_PCI_MWI */
 
/**
* pci_set_mwi - enables memory-write-invalidate PCI transaction
* @dev: the PCI device for which MWI is enabled
*
* Enables the Memory-Write-Invalidate transaction in %PCI_COMMAND,
* and then calls @pcibios_set_mwi to do the needed arch specific
* operations or a generic mwi-prep function.
*
* RETURNS: An appropriate -ERRNO error value on error, or zero for success.
*/
int
pci_set_mwi(struct pci_dev *dev)
{
int rc;
u16 cmd;
 
#ifdef HAVE_ARCH_PCI_MWI
rc = pcibios_prep_mwi(dev);
#else
rc = pci_generic_prep_mwi(dev);
#endif
 
if (rc)
return rc;
 
pci_read_config_word(dev, PCI_COMMAND, &cmd);
if (! (cmd & PCI_COMMAND_INVALIDATE)) {
DBG("PCI: Enabling Mem-Wr-Inval for device %s\n", pci_name(dev));
cmd |= PCI_COMMAND_INVALIDATE;
pci_write_config_word(dev, PCI_COMMAND, cmd);
}
return 0;
}
 
/**
* pci_clear_mwi - disables Memory-Write-Invalidate for device dev
* @dev: the PCI device to disable
*
* Disables PCI Memory-Write-Invalidate transaction on the device
*/
void
pci_clear_mwi(struct pci_dev *dev)
{
u16 cmd;
 
pci_read_config_word(dev, PCI_COMMAND, &cmd);
if (cmd & PCI_COMMAND_INVALIDATE) {
cmd &= ~PCI_COMMAND_INVALIDATE;
pci_write_config_word(dev, PCI_COMMAND, cmd);
}
}
 
int
pci_set_dma_mask(struct pci_dev *dev, u64 mask)
{
if (!pci_dma_supported(dev, mask))
return -EIO;
 
dev->dma_mask = mask;
 
return 0;
}
int
pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask)
{
if (!pci_dac_dma_supported(dev, mask))
return -EIO;
 
dev->dma_mask = mask;
 
return 0;
}
 
int
pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask)
{
if (!pci_dma_supported(dev, mask))
return -EIO;
 
dev->consistent_dma_mask = mask;
 
return 0;
}
static int __devinit pci_init(void)
{
struct pci_dev *dev = NULL;
 
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
pci_fixup_device(PCI_FIXUP_FINAL, dev);
}
return 0;
}
 
static int __devinit pci_setup(char *str)
{
while (str) {
char *k = strchr(str, ',');
if (k)
*k++ = 0;
if (*str && (str = pcibios_setup(str)) && *str) {
/* PCI layer options should be handled here */
printk(KERN_ERR "PCI: Unknown option `%s'\n", str);
}
str = k;
}
return 1;
}
 
device_initcall(pci_init);
 
__setup("pci=", pci_setup);
 
#if defined(CONFIG_ISA) || defined(CONFIG_EISA)
/* FIXME: Some boxes have multiple ISA bridges! */
struct pci_dev *isa_bridge;
EXPORT_SYMBOL(isa_bridge);
#endif
 
EXPORT_SYMBOL(pci_enable_device_bars);
EXPORT_SYMBOL(pci_enable_device);
EXPORT_SYMBOL(pci_disable_device);
EXPORT_SYMBOL(pci_max_busnr);
EXPORT_SYMBOL(pci_bus_max_busnr);
EXPORT_SYMBOL(pci_find_capability);
EXPORT_SYMBOL(pci_bus_find_capability);
EXPORT_SYMBOL(pci_release_regions);
EXPORT_SYMBOL(pci_request_regions);
EXPORT_SYMBOL(pci_release_region);
EXPORT_SYMBOL(pci_request_region);
EXPORT_SYMBOL(pci_set_master);
EXPORT_SYMBOL(pci_set_mwi);
EXPORT_SYMBOL(pci_clear_mwi);
EXPORT_SYMBOL(pci_set_dma_mask);
EXPORT_SYMBOL(pci_dac_set_dma_mask);
EXPORT_SYMBOL(pci_set_consistent_dma_mask);
EXPORT_SYMBOL(pci_assign_resource);
EXPORT_SYMBOL(pci_find_parent_resource);
 
EXPORT_SYMBOL(pci_set_power_state);
EXPORT_SYMBOL(pci_save_state);
EXPORT_SYMBOL(pci_restore_state);
EXPORT_SYMBOL(pci_enable_wake);
 
/* Quirk info */
 
EXPORT_SYMBOL(isa_dma_bridge_buggy);
EXPORT_SYMBOL(pci_pci_problems);
/shark/trunk/drivers/newpci/quirks.c
0,0 → 1,978
/*
* $Id: quirks.c,v 1.1 2004-01-28 18:32:17 giacomo Exp $
*
* This file contains work-arounds for many known PCI hardware
* bugs. Devices present only on certain architectures (host
* bridges et cetera) should be handled in arch-specific code.
*
* Copyright (c) 1999 Martin Mares <mj@ucw.cz>
*
* The bridge optimization stuff has been removed. If you really
* have a silly BIOS which is unable to set your host bridge right,
* use the PowerTweak utility (see http://powertweak.sourceforge.net).
*/
 
#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/delay.h>
 
#undef DEBUG
 
/* Deal with broken BIOS'es that neglect to enable passive release,
which can cause problems in combination with the 82441FX/PPro MTRRs */
static void __devinit quirk_passive_release(struct pci_dev *dev)
{
struct pci_dev *d = NULL;
unsigned char dlc;
 
/* We have to make sure a particular bit is set in the PIIX3
ISA bridge, so we have to go out and find it. */
while ((d = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, d))) {
pci_read_config_byte(d, 0x82, &dlc);
if (!(dlc & 1<<1)) {
printk(KERN_ERR "PCI: PIIX3: Enabling Passive Release on %s\n", pci_name(d));
dlc |= 1<<1;
pci_write_config_byte(d, 0x82, dlc);
}
}
}
 
/* The VIA VP2/VP3/MVP3 seem to have some 'features'. There may be a workaround
but VIA don't answer queries. If you happen to have good contacts at VIA
ask them for me please -- Alan
This appears to be BIOS not version dependent. So presumably there is a
chipset level fix */
 
int isa_dma_bridge_buggy; /* Exported */
static void __devinit quirk_isa_dma_hangs(struct pci_dev *dev)
{
if (!isa_dma_bridge_buggy) {
isa_dma_bridge_buggy=1;
printk(KERN_INFO "Activating ISA DMA hang workarounds.\n");
}
}
 
int pci_pci_problems;
 
/*
* Chipsets where PCI->PCI transfers vanish or hang
*/
 
static void __devinit quirk_nopcipci(struct pci_dev *dev)
{
if((pci_pci_problems&PCIPCI_FAIL)==0)
{
printk(KERN_INFO "Disabling direct PCI/PCI transfers.\n");
pci_pci_problems|=PCIPCI_FAIL;
}
}
 
/*
* Triton requires workarounds to be used by the drivers
*/
static void __devinit quirk_triton(struct pci_dev *dev)
{
if((pci_pci_problems&PCIPCI_TRITON)==0)
{
printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n");
pci_pci_problems|=PCIPCI_TRITON;
}
}
 
/*
* VIA Apollo KT133 needs PCI latency patch
* Made according to a windows driver based patch by George E. Breese
* see PCI Latency Adjust on http://www.viahardware.com/download/viatweak.shtm
* Also see http://www.au-ja.org/review-kt133a-1-en.phtml for
* the info on which Mr Breese based his work.
*
* Updated based on further information from the site and also on
* information provided by VIA
*/
static void __devinit quirk_vialatency(struct pci_dev *dev)
{
struct pci_dev *p;
u8 rev;
u8 busarb;
/* Ok we have a potential problem chipset here. Now see if we have
a buggy southbridge */
p=pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, NULL);
if(p!=NULL)
{
pci_read_config_byte(p, PCI_CLASS_REVISION, &rev);
/* 0x40 - 0x4f == 686B, 0x10 - 0x2f == 686A; thanks Dan Hollis */
/* Check for buggy part revisions */
if (rev < 0x40 || rev > 0x42)
return;
}
else
{
p = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231, NULL);
if(p==NULL) /* No problem parts */
return;
pci_read_config_byte(p, PCI_CLASS_REVISION, &rev);
/* Check for buggy part revisions */
if (rev < 0x10 || rev > 0x12)
return;
}
/*
* Ok we have the problem. Now set the PCI master grant to
* occur every master grant. The apparent bug is that under high
* PCI load (quite common in Linux of course) you can get data
* loss when the CPU is held off the bus for 3 bus master requests
* This happens to include the IDE controllers....
*
* VIA only apply this fix when an SB Live! is present but under
* both Linux and Windows this isnt enough, and we have seen
* corruption without SB Live! but with things like 3 UDMA IDE
* controllers. So we ignore that bit of the VIA recommendation..
*/
 
pci_read_config_byte(dev, 0x76, &busarb);
/* Set bit 4 and bi 5 of byte 76 to 0x01
"Master priority rotation on every PCI master grant */
busarb &= ~(1<<5);
busarb |= (1<<4);
pci_write_config_byte(dev, 0x76, busarb);
printk(KERN_INFO "Applying VIA southbridge workaround.\n");
}
 
/*
* VIA Apollo VP3 needs ETBF on BT848/878
*/
static void __devinit quirk_viaetbf(struct pci_dev *dev)
{
if((pci_pci_problems&PCIPCI_VIAETBF)==0)
{
printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n");
pci_pci_problems|=PCIPCI_VIAETBF;
}
}
static void __devinit quirk_vsfx(struct pci_dev *dev)
{
if((pci_pci_problems&PCIPCI_VSFX)==0)
{
printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n");
pci_pci_problems|=PCIPCI_VSFX;
}
}
 
/*
* Ali Magik requires workarounds to be used by the drivers
* that DMA to AGP space. Latency must be set to 0xA and triton
* workaround applied too
* [Info kindly provided by ALi]
*/
static void __init quirk_alimagik(struct pci_dev *dev)
{
if((pci_pci_problems&PCIPCI_ALIMAGIK)==0)
{
printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n");
pci_pci_problems|=PCIPCI_ALIMAGIK|PCIPCI_TRITON;
}
}
 
 
/*
* Natoma has some interesting boundary conditions with Zoran stuff
* at least
*/
static void __devinit quirk_natoma(struct pci_dev *dev)
{
if((pci_pci_problems&PCIPCI_NATOMA)==0)
{
printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n");
pci_pci_problems|=PCIPCI_NATOMA;
}
}
 
/*
* S3 868 and 968 chips report region size equal to 32M, but they decode 64M.
* If it's needed, re-allocate the region.
*/
 
static void __devinit quirk_s3_64M(struct pci_dev *dev)
{
struct resource *r = &dev->resource[0];
 
if ((r->start & 0x3ffffff) || r->end != r->start + 0x3ffffff) {
r->start = 0;
r->end = 0x3ffffff;
}
}
 
static void __devinit quirk_io_region(struct pci_dev *dev, unsigned region, unsigned size, int nr)
{
region &= ~(size-1);
if (region) {
struct resource *res = dev->resource + nr;
 
res->name = pci_name(dev);
res->start = region;
res->end = region + size - 1;
res->flags = IORESOURCE_IO;
pci_claim_resource(dev, nr);
}
}
 
/*
* ATI Northbridge setups MCE the processor if you even
* read somewhere between 0x3b0->0x3bb or read 0x3d3
*/
static void __devinit quirk_ati_exploding_mce(struct pci_dev *dev)
{
printk(KERN_INFO "ATI Northbridge, reserving I/O ports 0x3b0 to 0x3bb.\n");
/* Mae rhaid i ni beidio ag edrych ar y lleoliadiau I/O hyn */
request_region(0x3b0, 0x0C, "RadeonIGP");
request_region(0x3d3, 0x01, "RadeonIGP");
}
 
/*
* Let's make the southbridge information explicit instead
* of having to worry about people probing the ACPI areas,
* for example.. (Yes, it happens, and if you read the wrong
* ACPI register it will put the machine to sleep with no
* way of waking it up again. Bummer).
*
* ALI M7101: Two IO regions pointed to by words at
* 0xE0 (64 bytes of ACPI registers)
* 0xE2 (32 bytes of SMB registers)
*/
static void __devinit quirk_ali7101_acpi(struct pci_dev *dev)
{
u16 region;
 
pci_read_config_word(dev, 0xE0, &region);
quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES);
pci_read_config_word(dev, 0xE2, &region);
quirk_io_region(dev, region, 32, PCI_BRIDGE_RESOURCES+1);
}
 
/*
* PIIX4 ACPI: Two IO regions pointed to by longwords at
* 0x40 (64 bytes of ACPI registers)
* 0x90 (32 bytes of SMB registers)
*/
static void __devinit quirk_piix4_acpi(struct pci_dev *dev)
{
u32 region;
 
pci_read_config_dword(dev, 0x40, &region);
quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES);
pci_read_config_dword(dev, 0x90, &region);
quirk_io_region(dev, region, 32, PCI_BRIDGE_RESOURCES+1);
}
 
/*
* ICH4, ICH4-M, ICH5, ICH5-M ACPI: Three IO regions pointed to by longwords at
* 0x40 (128 bytes of ACPI, GPIO & TCO registers)
* 0x58 (64 bytes of GPIO I/O space)
*/
static void __devinit quirk_ich4_lpc_acpi(struct pci_dev *dev)
{
u32 region;
 
pci_read_config_dword(dev, 0x40, &region);
quirk_io_region(dev, region, 128, PCI_BRIDGE_RESOURCES);
 
pci_read_config_dword(dev, 0x58, &region);
quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES+1);
}
 
/*
* VIA ACPI: One IO region pointed to by longword at
* 0x48 or 0x20 (256 bytes of ACPI registers)
*/
static void __devinit quirk_vt82c586_acpi(struct pci_dev *dev)
{
u8 rev;
u32 region;
 
pci_read_config_byte(dev, PCI_CLASS_REVISION, &rev);
if (rev & 0x10) {
pci_read_config_dword(dev, 0x48, &region);
region &= PCI_BASE_ADDRESS_IO_MASK;
quirk_io_region(dev, region, 256, PCI_BRIDGE_RESOURCES);
}
}
 
/*
* VIA VT82C686 ACPI: Three IO region pointed to by (long)words at
* 0x48 (256 bytes of ACPI registers)
* 0x70 (128 bytes of hardware monitoring register)
* 0x90 (16 bytes of SMB registers)
*/
static void __devinit quirk_vt82c686_acpi(struct pci_dev *dev)
{
u16 hm;
u32 smb;
 
quirk_vt82c586_acpi(dev);
 
pci_read_config_word(dev, 0x70, &hm);
hm &= PCI_BASE_ADDRESS_IO_MASK;
quirk_io_region(dev, hm, 128, PCI_BRIDGE_RESOURCES + 1);
 
pci_read_config_dword(dev, 0x90, &smb);
smb &= PCI_BASE_ADDRESS_IO_MASK;
quirk_io_region(dev, smb, 16, PCI_BRIDGE_RESOURCES + 2);
}
 
 
#ifdef CONFIG_X86_IO_APIC
 
#include <asm/io_apic.h>
 
/*
* VIA 686A/B: If an IO-APIC is active, we need to route all on-chip
* devices to the external APIC.
*
* TODO: When we have device-specific interrupt routers,
* this code will go away from quirks.
*/
static void __devinit quirk_via_ioapic(struct pci_dev *dev)
{
u8 tmp;
if (nr_ioapics < 1)
tmp = 0; /* nothing routed to external APIC */
else
tmp = 0x1f; /* all known bits (4-0) routed to external APIC */
printk(KERN_INFO "PCI: %sbling Via external APIC routing\n",
tmp == 0 ? "Disa" : "Ena");
 
/* Offset 0x58: External APIC IRQ output control */
pci_write_config_byte (dev, 0x58, tmp);
}
 
/*
* The AMD io apic can hang the box when an apic irq is masked.
* We check all revs >= B0 (yet not in the pre production!) as the bug
* is currently marked NoFix
*
* We have multiple reports of hangs with this chipset that went away with
* noapic specified. For the moment we assume its the errata. We may be wrong
* of course. However the advice is demonstrably good even if so..
*/
static void __devinit quirk_amd_ioapic(struct pci_dev *dev)
{
u8 rev;
 
pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
if(rev >= 0x02)
{
printk(KERN_WARNING "I/O APIC: AMD Errata #22 may be present. In the event of instability try\n");
printk(KERN_WARNING " : booting with the \"noapic\" option.\n");
}
}
 
static void __init quirk_ioapic_rmw(struct pci_dev *dev)
{
if (dev->devfn == 0 && dev->bus->number == 0)
sis_apic_bug = 1;
}
 
#define AMD8131_revA0 0x01
#define AMD8131_revB0 0x11
#define AMD8131_MISC 0x40
#define AMD8131_NIOAMODE_BIT 0
 
static void __init quirk_amd_8131_ioapic(struct pci_dev *dev)
{
unsigned char revid, tmp;
if (nr_ioapics == 0)
return;
 
pci_read_config_byte(dev, PCI_REVISION_ID, &revid);
if (revid == AMD8131_revA0 || revid == AMD8131_revB0) {
printk(KERN_INFO "Fixing up AMD8131 IOAPIC mode\n");
pci_read_config_byte( dev, AMD8131_MISC, &tmp);
tmp &= ~(1 << AMD8131_NIOAMODE_BIT);
pci_write_config_byte( dev, AMD8131_MISC, tmp);
}
}
 
#endif /* CONFIG_X86_IO_APIC */
 
 
/*
* Via 686A/B: The PCI_INTERRUPT_LINE register for the on-chip
* devices, USB0/1, AC97, MC97, and ACPI, has an unusual feature:
* when written, it makes an internal connection to the PIC.
* For these devices, this register is defined to be 4 bits wide.
* Normally this is fine. However for IO-APIC motherboards, or
* non-x86 architectures (yes Via exists on PPC among other places),
* we must mask the PCI_INTERRUPT_LINE value versus 0xf to get
* interrupts delivered properly.
*
* TODO: When we have device-specific interrupt routers,
* quirk_via_irqpic will go away from quirks.
*/
 
/*
* FIXME: it is questionable that quirk_via_acpi
* is needed. It shows up as an ISA bridge, and does not
* support the PCI_INTERRUPT_LINE register at all. Therefore
* it seems like setting the pci_dev's 'irq' to the
* value of the ACPI SCI interrupt is only done for convenience.
* -jgarzik
*/
static void __devinit quirk_via_acpi(struct pci_dev *d)
{
/*
* VIA ACPI device: SCI IRQ line in PCI config byte 0x42
*/
u8 irq;
pci_read_config_byte(d, 0x42, &irq);
irq &= 0xf;
if (irq && (irq != 2))
d->irq = irq;
}
 
static void __devinit quirk_via_irqpic(struct pci_dev *dev)
{
u8 irq, new_irq = dev->irq & 0xf;
 
pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
 
if (new_irq != irq) {
printk(KERN_INFO "PCI: Via IRQ fixup for %s, from %d to %d\n",
pci_name(dev), irq, new_irq);
 
udelay(15);
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, new_irq);
}
}
 
 
/*
* PIIX3 USB: We have to disable USB interrupts that are
* hardwired to PIRQD# and may be shared with an
* external device.
*
* Legacy Support Register (LEGSUP):
* bit13: USB PIRQ Enable (USBPIRQDEN),
* bit4: Trap/SMI On IRQ Enable (USBSMIEN).
*
* We mask out all r/wc bits, too.
*/
static void __devinit quirk_piix3_usb(struct pci_dev *dev)
{
u16 legsup;
 
pci_read_config_word(dev, 0xc0, &legsup);
legsup &= 0x50ef;
pci_write_config_word(dev, 0xc0, legsup);
}
 
/*
* VIA VT82C598 has its device ID settable and many BIOSes
* set it to the ID of VT82C597 for backward compatibility.
* We need to switch it off to be able to recognize the real
* type of the chip.
*/
static void __devinit quirk_vt82c598_id(struct pci_dev *dev)
{
pci_write_config_byte(dev, 0xfc, 0);
pci_read_config_word(dev, PCI_DEVICE_ID, &dev->device);
}
 
/*
* CardBus controllers have a legacy base address that enables them
* to respond as i82365 pcmcia controllers. We don't want them to
* do this even if the Linux CardBus driver is not loaded, because
* the Linux i82365 driver does not (and should not) handle CardBus.
*/
static void __devinit quirk_cardbus_legacy(struct pci_dev *dev)
{
if ((PCI_CLASS_BRIDGE_CARDBUS << 8) ^ dev->class)
return;
pci_write_config_dword(dev, PCI_CB_LEGACY_MODE_BASE, 0);
}
 
/*
* Following the PCI ordering rules is optional on the AMD762. I'm not
* sure what the designers were smoking but let's not inhale...
*
* To be fair to AMD, it follows the spec by default, its BIOS people
* who turn it off!
*/
static void __devinit quirk_amd_ordering(struct pci_dev *dev)
{
u32 pcic;
pci_read_config_dword(dev, 0x4C, &pcic);
if((pcic&6)!=6)
{
pcic |= 6;
printk(KERN_WARNING "BIOS failed to enable PCI standards compliance, fixing this error.\n");
pci_write_config_dword(dev, 0x4C, pcic);
pci_read_config_dword(dev, 0x84, &pcic);
pcic |= (1<<23); /* Required in this mode */
pci_write_config_dword(dev, 0x84, pcic);
}
}
 
/*
* DreamWorks provided workaround for Dunord I-3000 problem
*
* This card decodes and responds to addresses not apparently
* assigned to it. We force a larger allocation to ensure that
* nothing gets put too close to it.
*/
 
static void __devinit quirk_dunord ( struct pci_dev * dev )
{
struct resource * r = & dev -> resource [ 1 ];
r -> start = 0;
r -> end = 0xffffff;
}
 
static void __devinit quirk_transparent_bridge(struct pci_dev *dev)
{
dev->transparent = 1;
}
 
/*
* Common misconfiguration of the MediaGX/Geode PCI master that will
* reduce PCI bandwidth from 70MB/s to 25MB/s. See the GXM/GXLV/GX1
* datasheets found at http://www.national.com/ds/GX for info on what
* these bits do. <christer@weinigel.se>
*/
static void __init quirk_mediagx_master(struct pci_dev *dev)
{
u8 reg;
pci_read_config_byte(dev, 0x41, &reg);
if (reg & 2) {
reg &= ~2;
printk(KERN_INFO "PCI: Fixup for MediaGX/Geode Slave Disconnect Boundary (0x41=0x%02x)\n", reg);
pci_write_config_byte(dev, 0x41, reg);
}
}
 
/*
* As per PCI spec, ignore base address registers 0-3 of the IDE controllers
* running in Compatible mode (bits 0 and 2 in the ProgIf for primary and
* secondary channels respectively). If the device reports Compatible mode
* but does use BAR0-3 for address decoding, we assume that firmware has
* programmed these BARs with standard values (0x1f0,0x3f4 and 0x170,0x374).
* Exceptions (if they exist) must be handled in chip/architecture specific
* fixups.
*
* Note: for non x86 people. You may need an arch specific quirk to handle
* moving IDE devices to native mode as well. Some plug in card devices power
* up in compatible mode and assume the BIOS will adjust them.
*
* Q: should we load the 0x1f0,0x3f4 into the registers or zap them as
* we do now ? We don't want is pci_enable_device to come along
* and assign new resources. Both approaches work for that.
*/
 
static void __devinit quirk_ide_bases(struct pci_dev *dev)
{
struct resource *res;
int first_bar = 2, last_bar = 0;
 
if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE)
return;
 
res = &dev->resource[0];
 
/* primary channel: ProgIf bit 0, BAR0, BAR1 */
if (!(dev->class & 1) && (res[0].flags || res[1].flags)) {
res[0].start = res[0].end = res[0].flags = 0;
res[1].start = res[1].end = res[1].flags = 0;
first_bar = 0;
last_bar = 1;
}
 
/* secondary channel: ProgIf bit 2, BAR2, BAR3 */
if (!(dev->class & 4) && (res[2].flags || res[3].flags)) {
res[2].start = res[2].end = res[2].flags = 0;
res[3].start = res[3].end = res[3].flags = 0;
last_bar = 3;
}
 
if (!last_bar)
return;
 
printk(KERN_INFO "PCI: Ignoring BAR%d-%d of IDE controller %s\n",
first_bar, last_bar, pci_name(dev));
}
 
/*
* Ensure C0 rev restreaming is off. This is normally done by
* the BIOS but in the odd case it is not the results are corruption
* hence the presence of a Linux check
*/
static void __init quirk_disable_pxb(struct pci_dev *pdev)
{
u16 config;
u8 rev;
pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
if(rev != 0x04) /* Only C0 requires this */
return;
pci_read_config_word(pdev, 0x40, &config);
if(config & (1<<6))
{
config &= ~(1<<6);
pci_write_config_word(pdev, 0x40, config);
printk(KERN_INFO "PCI: C0 revision 450NX. Disabling PCI restreaming.\n");
}
}
 
/*
* VIA northbridges care about PCI_INTERRUPT_LINE
*/
int interrupt_line_quirk;
 
static void __devinit quirk_via_bridge(struct pci_dev *pdev)
{
if(pdev->devfn == 0)
interrupt_line_quirk = 1;
}
 
/*
* Serverworks CSB5 IDE does not fully support native mode
*/
static void __init quirk_svwks_csb5ide(struct pci_dev *pdev)
{
u8 prog;
pci_read_config_byte(pdev, PCI_CLASS_PROG, &prog);
if (prog & 5) {
prog &= ~5;
pdev->class &= ~5;
pci_write_config_byte(pdev, PCI_CLASS_PROG, prog);
/* need to re-assign BARs for compat mode */
quirk_ide_bases(pdev);
}
}
 
/* This was originally an Alpha specific thing, but it really fits here.
* The i82375 PCI/EISA bridge appears as non-classified. Fix that.
*/
 
static void __init quirk_eisa_bridge(struct pci_dev *dev)
{
dev->class = PCI_CLASS_BRIDGE_EISA << 8;
}
 
/*
* On ASUS P4B boards, the SMBus PCI Device within the ICH2/4 southbridge
* is not activated. The myth is that Asus said that they do not want the
* users to be irritated by just another PCI Device in the Win98 device
* manager. (see the file prog/hotplug/README.p4b in the lm_sensors
* package 2.7.0 for details)
*
* The SMBus PCI Device can be activated by setting a bit in the ICH LPC
* bridge. Unfortunately, this device has no subvendor/subdevice ID. So it
* becomes necessary to do this tweak in two steps -- I've chosen the Host
* bridge as trigger.
*/
 
static int __initdata asus_hides_smbus = 0;
 
static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
{
if (likely(dev->subsystem_vendor != PCI_VENDOR_ID_ASUSTEK))
return;
 
if (dev->device == PCI_DEVICE_ID_INTEL_82845_HB)
switch(dev->subsystem_device) {
case 0x8070: /* P4B */
case 0x8088: /* P4B533 */
asus_hides_smbus = 1;
}
if ((dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) &&
(dev->subsystem_device == 0x80b2)) /* P4PE */
asus_hides_smbus = 1;
if ((dev->device == PCI_DEVICE_ID_INTEL_82850_HB) &&
(dev->subsystem_device == 0x8030)) /* P4T533 */
asus_hides_smbus = 1;
if ((dev->device == PCI_DEVICE_ID_INTEL_7205_0) &&
(dev->subsystem_device == 0x8070)) /* P4G8X Deluxe */
asus_hides_smbus = 1;
return;
}
 
static void __init asus_hides_smbus_lpc(struct pci_dev *dev)
{
u16 val;
if (likely(!asus_hides_smbus))
return;
 
pci_read_config_word(dev, 0xF2, &val);
if (val & 0x8) {
pci_write_config_word(dev, 0xF2, val & (~0x8));
pci_read_config_word(dev, 0xF2, &val);
if(val & 0x8)
printk(KERN_INFO "PCI: i801 SMBus device continues to play 'hide and seek'! 0x%x\n", val);
else
printk(KERN_INFO "PCI: Enabled i801 SMBus device\n");
}
}
 
/*
* SiS 96x south bridge: BIOS typically hides SMBus device...
*/
static void __init quirk_sis_96x_smbus(struct pci_dev *dev)
{
u8 val = 0;
printk(KERN_INFO "Enabling SiS 96x SMBus.\n");
pci_read_config_byte(dev, 0x77, &val);
pci_write_config_byte(dev, 0x77, val & ~0x10);
pci_read_config_byte(dev, 0x77, &val);
}
 
/*
* ... This is further complicated by the fact that some SiS96x south
* bridges pretend to be 85C503/5513 instead. In that case see if we
* spotted a compatible north bridge to make sure.
* (pci_find_device doesn't work yet)
*
* We can also enable the sis96x bit in the discovery register..
*/
static int __devinitdata sis_96x_compatible = 0;
 
#define SIS_DETECT_REGISTER 0x40
 
static void __init quirk_sis_503_smbus(struct pci_dev *dev)
{
u8 reg;
u16 devid;
 
pci_read_config_byte(dev, SIS_DETECT_REGISTER, &reg);
pci_write_config_byte(dev, SIS_DETECT_REGISTER, reg | (1 << 6));
pci_read_config_word(dev, PCI_DEVICE_ID, &devid);
if ((devid & 0xfff0) != 0x0960) {
pci_write_config_byte(dev, SIS_DETECT_REGISTER, reg);
return;
}
 
/* Make people aware that we changed the config.. */
printk(KERN_WARNING "Uncovering SIS%x that hid as a SIS503 (compatible=%d)\n", devid, sis_96x_compatible);
 
/*
* Ok, it now shows up as a 96x.. The 96x quirks are after
* the 503 quirk in the quirk table, so they'll automatically
* run and enable things like the SMBus device
*/
dev->device = devid;
}
 
static void __init quirk_sis_96x_compatible(struct pci_dev *dev)
{
sis_96x_compatible = 1;
}
 
#ifdef CONFIG_SCSI_SATA
static void __init quirk_intel_ide_combined(struct pci_dev *pdev)
{
u8 prog, comb, tmp;
 
/*
* Narrow down to Intel SATA PCI devices.
*/
switch (pdev->device) {
/* PCI ids taken from drivers/scsi/ata_piix.c */
case 0x24d1:
case 0x24df:
case 0x25a3:
case 0x25b0:
break;
default:
/* we do not handle this PCI device */
return;
}
 
/*
* Read combined mode register.
*/
pci_read_config_byte(pdev, 0x90, &tmp); /* combined mode reg */
tmp &= 0x6; /* interesting bits 2:1, PATA primary/secondary */
if (tmp == 0x4) /* bits 10x */
comb = (1 << 0); /* SATA port 0, PATA port 1 */
else if (tmp == 0x6) /* bits 11x */
comb = (1 << 2); /* PATA port 0, SATA port 1 */
else
return; /* not in combined mode */
 
/*
* Read programming interface register.
* (Tells us if it's legacy or native mode)
*/
pci_read_config_byte(pdev, PCI_CLASS_PROG, &prog);
 
/* if SATA port is in native mode, we're ok. */
if (prog & comb)
return;
 
/* SATA port is in legacy mode. Reserve port so that
* IDE driver does not attempt to use it. If request_region
* fails, it will be obvious at boot time, so we don't bother
* checking return values.
*/
if (comb == (1 << 0))
request_region(0x1f0, 8, "libata"); /* port 0 */
else
request_region(0x170, 8, "libata"); /* port 1 */
}
#endif /* CONFIG_SCSI_SATA */
 
/*
* The main table of quirks.
*
* Note: any hooks for hotpluggable devices in this table must _NOT_
* be declared __init.
*/
 
static struct pci_fixup pci_fixups[] __devinitdata = {
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_DUNORD, PCI_DEVICE_ID_DUNORD_I3000, quirk_dunord },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release },
/*
* Its not totally clear which chipsets are the problematic ones
* We know 82C586 and 82C596 variants are affected.
*/
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, quirk_isa_dma_hangs },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596, quirk_isa_dma_hangs },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, quirk_isa_dma_hangs },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, quirk_disable_pxb },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_1, quirk_isa_dma_hangs },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_2, quirk_isa_dma_hangs },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_3, quirk_isa_dma_hangs },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_868, quirk_s3_64M },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_968, quirk_s3_64M },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, quirk_triton },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437VX, quirk_triton },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439, quirk_triton },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439TX, quirk_triton },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_natoma },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443LX_0, quirk_natoma },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443LX_1, quirk_natoma },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_0, quirk_natoma },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_1, quirk_natoma },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_2, quirk_natoma },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, quirk_nopcipci },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, quirk_nopcipci },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503_smbus },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_645, quirk_sis_96x_compatible },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_646, quirk_sis_96x_compatible },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_648, quirk_sis_96x_compatible },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_650, quirk_sis_96x_compatible },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_651, quirk_sis_96x_compatible },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1647, quirk_alimagik },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1651, quirk_alimagik },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, quirk_vialatency },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8371_1, quirk_vialatency },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, quirk_vialatency },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576, quirk_vsfx },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_viaetbf },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_vt82c598_id },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_vt82c586_acpi },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_vt82c686_acpi },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, quirk_piix4_acpi },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, quirk_ich4_lpc_acpi },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, quirk_ali7101_acpi },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_2, quirk_piix3_usb },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_2, quirk_piix3_usb },
{ PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, quirk_ide_bases },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_bridge },
{ PCI_FIXUP_FINAL, PCI_ANY_ID, PCI_ANY_ID, quirk_cardbus_legacy },
 
#ifdef CONFIG_X86_IO_APIC
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_ioapic },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, quirk_amd_ioapic },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_SI, PCI_ANY_ID, quirk_ioapic_rmw },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_APIC,
quirk_amd_8131_ioapic },
#endif
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_via_acpi },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_via_acpi },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_2, quirk_via_irqpic },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, quirk_via_irqpic },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_6, quirk_via_irqpic },
 
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS100, quirk_ati_exploding_mce },
/*
* i82380FB mobile docking controller: its PCI-to-PCI bridge
* is subtractive decoding (transparent), and does indicate this
* in the ProgIf. Unfortunately, the ProgIf value is wrong - 0x80
* instead of 0x01.
*/
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82380FB, quirk_transparent_bridge },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_TOSHIBA, 0x605, quirk_transparent_bridge },
 
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master },
 
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, quirk_svwks_csb5ide },
 
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82375, quirk_eisa_bridge },
 
/*
* on Asus P4B boards, the i801SMBus device is disabled at startup.
*/
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845_HB, asus_hides_smbus_hostbridge },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845G_HB, asus_hides_smbus_hostbridge },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82850_HB, asus_hides_smbus_hostbridge },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_7205_0, asus_hides_smbus_hostbridge },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, asus_hides_smbus_lpc },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, asus_hides_smbus_lpc },
 
#ifdef CONFIG_SCSI_SATA
/* Fixup BIOSes that configure Parallel ATA (PATA / IDE) and
* Serial ATA (SATA) into the same PCI ID.
*/
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_ANY_ID,
quirk_intel_ide_combined },
#endif /* CONFIG_SCSI_SATA */
 
{ 0 }
};
 
 
static void pci_do_fixups(struct pci_dev *dev, int pass, struct pci_fixup *f)
{
while (f->pass) {
if (f->pass == pass &&
(f->vendor == dev->vendor || f->vendor == (u16) PCI_ANY_ID) &&
(f->device == dev->device || f->device == (u16) PCI_ANY_ID)) {
#ifdef DEBUG
printk(KERN_INFO "PCI: Calling quirk %p for %s\n", f->hook, pci_name(dev));
#endif
f->hook(dev);
}
f++;
}
}
 
void pci_fixup_device(int pass, struct pci_dev *dev)
{
pci_do_fixups(dev, pass, pcibios_fixups);
pci_do_fixups(dev, pass, pci_fixups);
}
/shark/trunk/drivers/newpci/pci-sysfs.c
0,0 → 1,182
/*
* drivers/pci/pci-sysfs.c
*
* (C) Copyright 2002 Greg Kroah-Hartman
* (C) Copyright 2002 IBM Corp.
* (C) Copyright 2003 Matthew Wilcox
* (C) Copyright 2003 Hewlett-Packard
*
* File attributes for PCI devices
*
* Modeled after usb's driverfs.c
*
*/
 
 
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/stat.h>
 
#include "pci.h"
 
/* show configuration fields */
#define pci_config_attr(field, format_string) \
static ssize_t \
show_##field (struct device *dev, char *buf) \
{ \
struct pci_dev *pdev; \
\
pdev = to_pci_dev (dev); \
return sprintf (buf, format_string, pdev->field); \
} \
static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
 
pci_config_attr(vendor, "0x%04x\n");
pci_config_attr(device, "0x%04x\n");
pci_config_attr(subsystem_vendor, "0x%04x\n");
pci_config_attr(subsystem_device, "0x%04x\n");
pci_config_attr(class, "0x%06x\n");
pci_config_attr(irq, "%u\n");
 
/* show resources */
static ssize_t
pci_show_resources(struct device * dev, char * buf)
{
struct pci_dev * pci_dev = to_pci_dev(dev);
char * str = buf;
int i;
int max = 7;
 
if (pci_dev->subordinate)
max = DEVICE_COUNT_RESOURCE;
 
for (i = 0; i < max; i++) {
str += sprintf(str,"0x%016lx 0x%016lx 0x%016lx\n",
pci_resource_start(pci_dev,i),
pci_resource_end(pci_dev,i),
pci_resource_flags(pci_dev,i));
}
return (str - buf);
}
 
static DEVICE_ATTR(resource,S_IRUGO,pci_show_resources,NULL);
 
static ssize_t
pci_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count)
{
struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj));
unsigned int size = 64;
loff_t init_off = off;
 
/* Several chips lock up trying to read undefined config space */
if (capable(CAP_SYS_ADMIN)) {
size = 256;
} else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
size = 128;
}
 
if (off > size)
return 0;
if (off + count > size) {
size -= off;
count = size;
} else {
size = count;
}
 
while (off & 3) {
unsigned char val;
pci_read_config_byte(dev, off, &val);
buf[off - init_off] = val;
off++;
if (--size == 0)
break;
}
 
while (size > 3) {
unsigned int val;
pci_read_config_dword(dev, off, &val);
buf[off - init_off] = val & 0xff;
buf[off - init_off + 1] = (val >> 8) & 0xff;
buf[off - init_off + 2] = (val >> 16) & 0xff;
buf[off - init_off + 3] = (val >> 24) & 0xff;
off += 4;
size -= 4;
}
 
while (size > 0) {
unsigned char val;
pci_read_config_byte(dev, off, &val);
buf[off - init_off] = val;
off++;
--size;
}
 
return count;
}
 
static ssize_t
pci_write_config(struct kobject *kobj, char *buf, loff_t off, size_t count)
{
struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj));
unsigned int size = count;
loff_t init_off = off;
 
if (off > 256)
return 0;
if (off + count > 256) {
size = 256 - off;
count = size;
}
 
while (off & 3) {
pci_write_config_byte(dev, off, buf[off - init_off]);
off++;
if (--size == 0)
break;
}
 
while (size > 3) {
unsigned int val = buf[off - init_off];
val |= (unsigned int) buf[off - init_off + 1] << 8;
val |= (unsigned int) buf[off - init_off + 2] << 16;
val |= (unsigned int) buf[off - init_off + 3] << 24;
pci_write_config_dword(dev, off, val);
off += 4;
size -= 4;
}
 
while (size > 0) {
pci_write_config_byte(dev, off, buf[off - init_off]);
off++;
--size;
}
 
return count;
}
 
static struct bin_attribute pci_config_attr = {
.attr = {
.name = "config",
.mode = S_IRUGO | S_IWUSR,
},
.size = 256,
.read = pci_read_config,
.write = pci_write_config,
};
 
void pci_create_sysfs_dev_files (struct pci_dev *pdev)
{
struct device *dev = &pdev->dev;
 
/* current configuration's attributes */
device_create_file (dev, &dev_attr_vendor);
device_create_file (dev, &dev_attr_device);
device_create_file (dev, &dev_attr_subsystem_vendor);
device_create_file (dev, &dev_attr_subsystem_device);
device_create_file (dev, &dev_attr_class);
device_create_file (dev, &dev_attr_irq);
device_create_file (dev, &dev_attr_resource);
sysfs_create_bin_file(&dev->kobj, &pci_config_attr);
}
/shark/trunk/drivers/newpci/gen-devlist.c
0,0 → 1,130
/*
* Generate devlist.h and classlist.h from the PCI ID file.
*
* (c) 1999--2002 Martin Mares <mj@ucw.cz>
*/
 
#include <stdio.h>
#include <string.h>
 
#define MAX_NAME_SIZE 79
 
static void
pq(FILE *f, const char *c)
{
while (*c) {
if (*c == '"')
fprintf(f, "\\\"");
else {
fputc(*c, f);
if (*c == '?' && c[1] == '?') {
/* Avoid trigraphs */
fprintf(f, "\" \"");
}
}
c++;
}
}
 
int
main(void)
{
char line[1024], *c, *bra, vend[8];
int vendors = 0;
int mode = 0;
int lino = 0;
int vendor_len = 0;
FILE *devf, *clsf;
 
devf = fopen("devlist.h", "w");
clsf = fopen("classlist.h", "w");
if (!devf || !clsf) {
fprintf(stderr, "Cannot create output file!\n");
return 1;
}
 
while (fgets(line, sizeof(line)-1, stdin)) {
lino++;
if ((c = strchr(line, '\n')))
*c = 0;
if (!line[0] || line[0] == '#')
continue;
if (line[1] == ' ') {
if (line[0] == 'C' && strlen(line) > 4 && line[4] == ' ') {
vend[0] = line[2];
vend[1] = line[3];
vend[2] = 0;
mode = 2;
} else goto err;
}
else if (line[0] == '\t') {
if (line[1] == '\t')
continue;
switch (mode) {
case 1:
if (strlen(line) > 5 && line[5] == ' ') {
c = line + 5;
while (*c == ' ')
*c++ = 0;
if (vendor_len + strlen(c) + 1 > MAX_NAME_SIZE) {
/* Too long, try cutting off long description */
bra = strchr(c, '[');
if (bra && bra > c && bra[-1] == ' ')
bra[-1] = 0;
if (vendor_len + strlen(c) + 1 > MAX_NAME_SIZE) {
fprintf(stderr, "Line %d: Device name too long\n", lino);
fprintf(stderr, "%s\n", c);
return 1;
}
}
fprintf(devf, "\tDEVICE(%s,%s,\"", vend, line+1);
pq(devf, c);
fputs("\")\n", devf);
} else goto err;
break;
case 2:
if (strlen(line) > 3 && line[3] == ' ') {
c = line + 3;
while (*c == ' ')
*c++ = 0;
fprintf(clsf, "CLASS(%s%s, \"%s\")\n", vend, line+1, c);
} else goto err;
break;
default:
goto err;
}
} else if (strlen(line) > 4 && line[4] == ' ') {
c = line + 4;
while (*c == ' ')
*c++ = 0;
if (vendors)
fputs("ENDVENDOR()\n\n", devf);
vendors++;
strcpy(vend, line);
vendor_len = strlen(c);
if (vendor_len + 24 > MAX_NAME_SIZE) {
fprintf(stderr, "Line %d: Vendor name too long\n", lino);
return 1;
}
fprintf(devf, "VENDOR(%s,\"", vend);
pq(devf, c);
fputs("\")\n", devf);
mode = 1;
} else {
err:
fprintf(stderr, "Line %d: Syntax error in mode %d: %s\n", lino, mode, line);
return 1;
}
}
fputs("ENDVENDOR()\n\
\n\
#undef VENDOR\n\
#undef DEVICE\n\
#undef ENDVENDOR\n", devf);
fputs("\n#undef CLASS\n", clsf);
 
fclose(devf);
fclose(clsf);
 
return 0;
}
/shark/trunk/drivers/newpci/hotplug.c
0,0 → 1,172
#include <linux/pci.h>
#include <linux/module.h>
#include "pci.h"
 
#undef DEBUG
 
#ifdef DEBUG
#define DBG(x...) printk(x)
#else
#define DBG(x...)
#endif
 
int pci_hotplug (struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size)
{
struct pci_dev *pdev;
char *scratch;
int i = 0;
int length = 0;
 
if (!dev)
return -ENODEV;
 
pdev = to_pci_dev(dev);
if (!pdev)
return -ENODEV;
 
scratch = buffer;
 
/* stuff we want to pass to /sbin/hotplug */
envp[i++] = scratch;
length += snprintf (scratch, buffer_size - length, "PCI_CLASS=%04X",
pdev->class);
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
++length;
scratch += length;
 
envp[i++] = scratch;
length += snprintf (scratch, buffer_size - length, "PCI_ID=%04X:%04X",
pdev->vendor, pdev->device);
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
++length;
scratch += length;
 
envp[i++] = scratch;
length += snprintf (scratch, buffer_size - length,
"PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor,
pdev->subsystem_device);
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
++length;
scratch += length;
 
envp[i++] = scratch;
length += snprintf (scratch, buffer_size - length, "PCI_SLOT_NAME=%s",
pci_name(pdev));
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
 
envp[i] = 0;
 
return 0;
}
 
static int pci_visit_bus (struct pci_visit * fn, struct pci_bus_wrapped *wrapped_bus, struct pci_dev_wrapped *wrapped_parent)
{
struct list_head *ln;
struct pci_dev *dev;
struct pci_dev_wrapped wrapped_dev;
int result = 0;
 
DBG("scanning bus %02x\n", wrapped_bus->bus->number);
 
if (fn->pre_visit_pci_bus) {
result = fn->pre_visit_pci_bus(wrapped_bus, wrapped_parent);
if (result)
return result;
}
 
ln = wrapped_bus->bus->devices.next;
while (ln != &wrapped_bus->bus->devices) {
dev = pci_dev_b(ln);
ln = ln->next;
 
memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped));
wrapped_dev.dev = dev;
 
result = pci_visit_dev(fn, &wrapped_dev, wrapped_bus);
if (result)
return result;
}
 
if (fn->post_visit_pci_bus)
result = fn->post_visit_pci_bus(wrapped_bus, wrapped_parent);
 
return result;
}
 
static int pci_visit_bridge (struct pci_visit * fn,
struct pci_dev_wrapped *wrapped_dev,
struct pci_bus_wrapped *wrapped_parent)
{
struct pci_bus *bus;
struct pci_bus_wrapped wrapped_bus;
int result = 0;
 
DBG("scanning bridge %02x, %02x\n", PCI_SLOT(wrapped_dev->dev->devfn),
PCI_FUNC(wrapped_dev->dev->devfn));
 
if (fn->visit_pci_dev) {
result = fn->visit_pci_dev(wrapped_dev, wrapped_parent);
if (result)
return result;
}
 
bus = wrapped_dev->dev->subordinate;
if(bus) {
memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped));
wrapped_bus.bus = bus;
 
result = pci_visit_bus(fn, &wrapped_bus, wrapped_dev);
}
return result;
}
 
/**
* pci_visit_dev - scans the pci buses.
* Every bus and every function is presented to a custom
* function that can act upon it.
*/
int pci_visit_dev (struct pci_visit *fn, struct pci_dev_wrapped *wrapped_dev,
struct pci_bus_wrapped *wrapped_parent)
{
struct pci_dev* dev = wrapped_dev ? wrapped_dev->dev : NULL;
int result = 0;
 
if (!dev)
return 0;
 
if (fn->pre_visit_pci_dev) {
result = fn->pre_visit_pci_dev(wrapped_dev, wrapped_parent);
if (result)
return result;
}
 
switch (dev->class >> 8) {
case PCI_CLASS_BRIDGE_PCI:
result = pci_visit_bridge(fn, wrapped_dev,
wrapped_parent);
if (result)
return result;
break;
default:
DBG("scanning device %02x, %02x\n",
PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
if (fn->visit_pci_dev) {
result = fn->visit_pci_dev (wrapped_dev,
wrapped_parent);
if (result)
return result;
}
}
 
if (fn->post_visit_pci_dev)
result = fn->post_visit_pci_dev(wrapped_dev, wrapped_parent);
 
return result;
}
EXPORT_SYMBOL(pci_visit_dev);
 
/shark/trunk/drivers/newpci/setup-bus.c
0,0 → 1,549
/*
* drivers/pci/setup-bus.c
*
* Extruded from code written by
* Dave Rusling (david.rusling@reo.mts.dec.com)
* David Mosberger (davidm@cs.arizona.edu)
* David Miller (davem@redhat.com)
*
* Support routines for initializing a PCI subsystem.
*/
 
/*
* Nov 2000, Ivan Kokshaysky <ink@jurassic.park.msu.ru>
* PCI-PCI bridges cleanup, sorted resource allocation.
* Feb 2002, Ivan Kokshaysky <ink@jurassic.park.msu.ru>
* Converted to allocation in 3 passes, which gives
* tighter packing. Prefetchable range support.
*/
 
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/cache.h>
#include <linux/slab.h>
 
 
#define DEBUG_CONFIG 1
#if DEBUG_CONFIG
# define DBGC(args) printk args
#else
# define DBGC(args)
#endif
 
#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1))
 
/*
* FIXME: IO should be max 256 bytes. However, since we may
* have a P2P bridge below a cardbus bridge, we need 4K.
*/
#define CARDBUS_IO_SIZE (4096)
#define CARDBUS_MEM_SIZE (32*1024*1024)
 
static int __devinit
pbus_assign_resources_sorted(struct pci_bus *bus)
{
struct pci_dev *dev;
struct resource *res;
struct resource_list head, *list, *tmp;
int idx, found_vga = 0;
 
head.next = NULL;
list_for_each_entry(dev, &bus->devices, bus_list) {
u16 class = dev->class >> 8;
 
if (class == PCI_CLASS_DISPLAY_VGA
|| class == PCI_CLASS_NOT_DEFINED_VGA)
found_vga = 1;
 
pdev_sort_resources(dev, &head);
}
 
for (list = head.next; list;) {
res = list->res;
idx = res - &list->dev->resource[0];
pci_assign_resource(list->dev, idx);
tmp = list;
list = list->next;
kfree(tmp);
}
 
return found_vga;
}
 
static void __devinit
pci_setup_cardbus(struct pci_bus *bus)
{
struct pci_dev *bridge = bus->self;
struct pci_bus_region region;
 
printk("PCI: Bus %d, cardbus bridge: %s\n",
bus->number, pci_name(bridge));
 
pcibios_resource_to_bus(bridge, &region, bus->resource[0]);
if (bus->resource[0]->flags & IORESOURCE_IO) {
/*
* The IO resource is allocated a range twice as large as it
* would normally need. This allows us to set both IO regs.
*/
printk(" IO window: %08lx-%08lx\n",
region.start, region.end);
pci_write_config_dword(bridge, PCI_CB_IO_BASE_0,
region.start);
pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_0,
region.end);
}
 
pcibios_resource_to_bus(bridge, &region, bus->resource[1]);
if (bus->resource[1]->flags & IORESOURCE_IO) {
printk(" IO window: %08lx-%08lx\n",
region.start, region.end);
pci_write_config_dword(bridge, PCI_CB_IO_BASE_1,
region.start);
pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_1,
region.end);
}
 
pcibios_resource_to_bus(bridge, &region, bus->resource[2]);
if (bus->resource[2]->flags & IORESOURCE_MEM) {
printk(" PREFETCH window: %08lx-%08lx\n",
region.start, region.end);
pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_0,
region.start);
pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_0,
region.end);
}
 
pcibios_resource_to_bus(bridge, &region, bus->resource[3]);
if (bus->resource[3]->flags & IORESOURCE_MEM) {
printk(" MEM window: %08lx-%08lx\n",
region.start, region.end);
pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_1,
region.start);
pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_1,
region.end);
}
}
 
/* Initialize bridges with base/limit values we have collected.
PCI-to-PCI Bridge Architecture Specification rev. 1.1 (1998)
requires that if there is no I/O ports or memory behind the
bridge, corresponding range must be turned off by writing base
value greater than limit to the bridge's base/limit registers.
 
Note: care must be taken when updating I/O base/limit registers
of bridges which support 32-bit I/O. This update requires two
config space writes, so it's quite possible that an I/O window of
the bridge will have some undesirable address (e.g. 0) after the
first write. Ditto 64-bit prefetchable MMIO. */
static void __devinit
pci_setup_bridge(struct pci_bus *bus)
{
struct pci_dev *bridge = bus->self;
struct pci_bus_region region;
u32 l, io_upper16;
 
DBGC((KERN_INFO "PCI: Bus %d, bridge: %s\n",
bus->number, pci_name(bridge)));
 
/* Set up the top and bottom of the PCI I/O segment for this bus. */
pcibios_resource_to_bus(bridge, &region, bus->resource[0]);
if (bus->resource[0]->flags & IORESOURCE_IO) {
pci_read_config_dword(bridge, PCI_IO_BASE, &l);
l &= 0xffff0000;
l |= (region.start >> 8) & 0x00f0;
l |= region.end & 0xf000;
/* Set up upper 16 bits of I/O base/limit. */
io_upper16 = (region.end & 0xffff0000) | (region.start >> 16);
DBGC((KERN_INFO " IO window: %04lx-%04lx\n",
region.start, region.end));
}
else {
/* Clear upper 16 bits of I/O base/limit. */
io_upper16 = 0;
l = 0x00f0;
DBGC((KERN_INFO " IO window: disabled.\n"));
}
/* Temporarily disable the I/O range before updating PCI_IO_BASE. */
pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0x0000ffff);
/* Update lower 16 bits of I/O base/limit. */
pci_write_config_dword(bridge, PCI_IO_BASE, l);
/* Update upper 16 bits of I/O base/limit. */
pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, io_upper16);
 
/* Set up the top and bottom of the PCI Memory segment
for this bus. */
pcibios_resource_to_bus(bridge, &region, bus->resource[1]);
if (bus->resource[1]->flags & IORESOURCE_MEM) {
l = (region.start >> 16) & 0xfff0;
l |= region.end & 0xfff00000;
DBGC((KERN_INFO " MEM window: %08lx-%08lx\n",
region.start, region.end));
}
else {
l = 0x0000fff0;
DBGC((KERN_INFO " MEM window: disabled.\n"));
}
pci_write_config_dword(bridge, PCI_MEMORY_BASE, l);
 
/* Clear out the upper 32 bits of PREF limit.
If PCI_PREF_BASE_UPPER32 was non-zero, this temporarily
disables PREF range, which is ok. */
pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0);
 
/* Set up PREF base/limit. */
pcibios_resource_to_bus(bridge, &region, bus->resource[2]);
if (bus->resource[2]->flags & IORESOURCE_PREFETCH) {
l = (region.start >> 16) & 0xfff0;
l |= region.end & 0xfff00000;
DBGC((KERN_INFO " PREFETCH window: %08lx-%08lx\n",
region.start, region.end));
}
else {
l = 0x0000fff0;
DBGC((KERN_INFO " PREFETCH window: disabled.\n"));
}
pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
 
/* Clear out the upper 32 bits of PREF base. */
pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, 0);
 
/* Check if we have VGA behind the bridge.
Enable ISA in either case (FIXME!). */
l = (bus->resource[0]->flags & IORESOURCE_BUS_HAS_VGA) ? 0x0c : 0x04;
pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, l);
}
 
/* Check whether the bridge supports optional I/O and
prefetchable memory ranges. If not, the respective
base/limit registers must be read-only and read as 0. */
static void __devinit
pci_bridge_check_ranges(struct pci_bus *bus)
{
u16 io;
u32 pmem;
struct pci_dev *bridge = bus->self;
struct resource *b_res;
 
b_res = &bridge->resource[PCI_BRIDGE_RESOURCES];
b_res[1].flags |= IORESOURCE_MEM;
 
pci_read_config_word(bridge, PCI_IO_BASE, &io);
if (!io) {
pci_write_config_word(bridge, PCI_IO_BASE, 0xf0f0);
pci_read_config_word(bridge, PCI_IO_BASE, &io);
pci_write_config_word(bridge, PCI_IO_BASE, 0x0);
}
if (io)
b_res[0].flags |= IORESOURCE_IO;
/* DECchip 21050 pass 2 errata: the bridge may miss an address
disconnect boundary by one PCI data phase.
Workaround: do not use prefetching on this device. */
if (bridge->vendor == PCI_VENDOR_ID_DEC && bridge->device == 0x0001)
return;
pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem);
if (!pmem) {
pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE,
0xfff0fff0);
pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem);
pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, 0x0);
}
if (pmem)
b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH;
}
 
/* Helper function for sizing routines: find first available
bus resource of a given type. Note: we intentionally skip
the bus resources which have already been assigned (that is,
have non-NULL parent resource). */
static struct resource * __devinit
find_free_bus_resource(struct pci_bus *bus, unsigned long type)
{
int i;
struct resource *r;
unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
IORESOURCE_PREFETCH;
 
for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
r = bus->resource[i];
if (r && (r->flags & type_mask) == type && !r->parent)
return r;
}
return NULL;
}
 
/* Sizing the IO windows of the PCI-PCI bridge is trivial,
since these windows have 4K granularity and the IO ranges
of non-bridge PCI devices are limited to 256 bytes.
We must be careful with the ISA aliasing though. */
static void __devinit
pbus_size_io(struct pci_bus *bus)
{
struct pci_dev *dev;
struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO);
unsigned long size = 0, size1 = 0;
 
if (!b_res)
return;
 
list_for_each_entry(dev, &bus->devices, bus_list) {
int i;
 
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
struct resource *r = &dev->resource[i];
unsigned long r_size;
 
if (r->parent || !(r->flags & IORESOURCE_IO))
continue;
r_size = r->end - r->start + 1;
 
if (r_size < 0x400)
/* Might be re-aligned for ISA */
size += r_size;
else
size1 += r_size;
}
}
/* To be fixed in 2.5: we should have sort of HAVE_ISA
flag in the struct pci_bus. */
#if defined(CONFIG_ISA) || defined(CONFIG_EISA)
size = (size & 0xff) + ((size & ~0xffUL) << 2);
#endif
size = ROUND_UP(size + size1, 4096);
if (!size) {
b_res->flags = 0;
return;
}
/* Alignment of the IO window is always 4K */
b_res->start = 4096;
b_res->end = b_res->start + size - 1;
}
 
/* Calculate the size of the bus and minimal alignment which
guarantees that all child resources fit in this size. */
static int __devinit
pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long type)
{
struct pci_dev *dev;
unsigned long min_align, align, size;
unsigned long aligns[12]; /* Alignments from 1Mb to 2Gb */
int order, max_order;
struct resource *b_res = find_free_bus_resource(bus, type);
 
if (!b_res)
return 0;
 
memset(aligns, 0, sizeof(aligns));
max_order = 0;
size = 0;
 
list_for_each_entry(dev, &bus->devices, bus_list) {
int i;
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
struct resource *r = &dev->resource[i];
unsigned long r_size;
 
if (r->parent || (r->flags & mask) != type)
continue;
r_size = r->end - r->start + 1;
/* For bridges size != alignment */
align = (i < PCI_BRIDGE_RESOURCES) ? r_size : r->start;
order = __ffs(align) - 20;
if (order > 11) {
printk(KERN_WARNING "PCI: region %s/%d "
"too large: %lx-%lx\n",
pci_name(dev), i, r->start, r->end);
r->flags = 0;
continue;
}
size += r_size;
if (order < 0)
order = 0;
/* Exclude ranges with size > align from
calculation of the alignment. */
if (r_size == align)
aligns[order] += align;
if (order > max_order)
max_order = order;
}
}
 
align = 0;
min_align = 0;
for (order = 0; order <= max_order; order++) {
unsigned long align1 = 1UL << (order + 20);
 
if (!align)
min_align = align1;
else if (ROUND_UP(align + min_align, min_align) < align1)
min_align = align1 >> 1;
align += aligns[order];
}
size = ROUND_UP(size, min_align);
if (!size) {
b_res->flags = 0;
return 1;
}
b_res->start = min_align;
b_res->end = size + min_align - 1;
return 1;
}
 
static void __devinit
pci_bus_size_cardbus(struct pci_bus *bus)
{
struct pci_dev *bridge = bus->self;
struct resource *b_res = &bridge->resource[PCI_BRIDGE_RESOURCES];
u16 ctrl;
 
/*
* Reserve some resources for CardBus. We reserve
* a fixed amount of bus space for CardBus bridges.
*/
b_res[0].start = CARDBUS_IO_SIZE;
b_res[0].end = b_res[0].start + CARDBUS_IO_SIZE - 1;
b_res[0].flags |= IORESOURCE_IO;
 
b_res[1].start = CARDBUS_IO_SIZE;
b_res[1].end = b_res[1].start + CARDBUS_IO_SIZE - 1;
b_res[1].flags |= IORESOURCE_IO;
 
/*
* Check whether prefetchable memory is supported
* by this bridge.
*/
pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
if (!(ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0)) {
ctrl |= PCI_CB_BRIDGE_CTL_PREFETCH_MEM0;
pci_write_config_word(bridge, PCI_CB_BRIDGE_CONTROL, ctrl);
pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
}
 
/*
* If we have prefetchable memory support, allocate
* two regions. Otherwise, allocate one region of
* twice the size.
*/
if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0) {
b_res[2].start = CARDBUS_MEM_SIZE;
b_res[2].end = b_res[2].start + CARDBUS_MEM_SIZE - 1;
b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH;
 
b_res[3].start = CARDBUS_MEM_SIZE;
b_res[3].end = b_res[3].start + CARDBUS_MEM_SIZE - 1;
b_res[3].flags |= IORESOURCE_MEM;
} else {
b_res[3].start = CARDBUS_MEM_SIZE * 2;
b_res[3].end = b_res[3].start + CARDBUS_MEM_SIZE * 2 - 1;
b_res[3].flags |= IORESOURCE_MEM;
}
}
 
void __devinit
pci_bus_size_bridges(struct pci_bus *bus)
{
struct pci_dev *dev;
unsigned long mask, prefmask;
 
list_for_each_entry(dev, &bus->devices, bus_list) {
struct pci_bus *b = dev->subordinate;
if (!b)
continue;
 
switch (dev->class >> 8) {
case PCI_CLASS_BRIDGE_CARDBUS:
pci_bus_size_cardbus(b);
break;
 
case PCI_CLASS_BRIDGE_PCI:
default:
pci_bus_size_bridges(b);
break;
}
}
 
/* The root bus? */
if (!bus->self)
return;
 
switch (bus->self->class >> 8) {
case PCI_CLASS_BRIDGE_CARDBUS:
/* don't size cardbuses yet. */
break;
 
case PCI_CLASS_BRIDGE_PCI:
pci_bridge_check_ranges(bus);
default:
pbus_size_io(bus);
/* If the bridge supports prefetchable range, size it
separately. If it doesn't, or its prefetchable window
has already been allocated by arch code, try
non-prefetchable range for both types of PCI memory
resources. */
mask = IORESOURCE_MEM;
prefmask = IORESOURCE_MEM | IORESOURCE_PREFETCH;
if (pbus_size_mem(bus, prefmask, prefmask))
mask = prefmask; /* Success, size non-prefetch only. */
pbus_size_mem(bus, mask, IORESOURCE_MEM);
break;
}
}
EXPORT_SYMBOL(pci_bus_size_bridges);
 
void __devinit
pci_bus_assign_resources(struct pci_bus *bus)
{
struct pci_bus *b;
int found_vga = pbus_assign_resources_sorted(bus);
struct pci_dev *dev;
 
if (found_vga) {
/* Propagate presence of the VGA to upstream bridges */
for (b = bus; b->parent; b = b->parent) {
b->resource[0]->flags |= IORESOURCE_BUS_HAS_VGA;
}
}
list_for_each_entry(dev, &bus->devices, bus_list) {
b = dev->subordinate;
if (!b)
continue;
 
pci_bus_assign_resources(b);
 
switch (dev->class >> 8) {
case PCI_CLASS_BRIDGE_PCI:
pci_setup_bridge(b);
break;
 
case PCI_CLASS_BRIDGE_CARDBUS:
pci_setup_cardbus(b);
break;
 
default:
printk(KERN_INFO "PCI: not setting up bridge %s "
"for bus %d\n", pci_name(dev), b->number);
break;
}
}
}
EXPORT_SYMBOL(pci_bus_assign_resources);
 
void __init
pci_assign_unassigned_resources(void)
{
struct list_head *ln;
 
/* Depth first, calculate sizes and alignments of all
subordinate buses. */
for(ln=pci_root_buses.next; ln != &pci_root_buses; ln=ln->next)
pci_bus_size_bridges(pci_bus_b(ln));
/* Depth last, allocate resources and update the hardware. */
for(ln=pci_root_buses.next; ln != &pci_root_buses; ln=ln->next) {
pci_bus_assign_resources(pci_bus_b(ln));
pci_enable_bridges(pci_bus_b(ln));
}
}
/shark/trunk/drivers/newpci/setup-res.c
0,0 → 1,198
/*
* drivers/pci/setup-res.c
*
* Extruded from code written by
* Dave Rusling (david.rusling@reo.mts.dec.com)
* David Mosberger (davidm@cs.arizona.edu)
* David Miller (davem@redhat.com)
*
* Support routines for initializing a PCI subsystem.
*/
 
/* fixed for multiple pci buses, 1999 Andrea Arcangeli <andrea@suse.de> */
 
/*
* Nov 2000, Ivan Kokshaysky <ink@jurassic.park.msu.ru>
* Resource sorting
*/
 
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/cache.h>
#include <linux/slab.h>
#include "pci.h"
 
#define DEBUG_CONFIG 0
#if DEBUG_CONFIG
# define DBGC(args) printk args
#else
# define DBGC(args)
#endif
 
 
static void
pci_update_resource(struct pci_dev *dev, struct resource *res, int resno)
{
struct pci_bus_region region;
u32 new, check, mask;
int reg;
 
pcibios_resource_to_bus(dev, &region, res);
 
DBGC((KERN_ERR " got res [%lx:%lx] bus [%lx:%lx] flags %lx for "
"BAR %d of %s\n", res->start, res->end,
region.start, region.end, res->flags,
resno, pci_name(dev)));
 
new = region.start | (res->flags & PCI_REGION_FLAG_MASK);
if (res->flags & IORESOURCE_IO)
mask = (u32)PCI_BASE_ADDRESS_IO_MASK;
else
mask = (u32)PCI_BASE_ADDRESS_MEM_MASK;
 
if (resno < 6) {
reg = PCI_BASE_ADDRESS_0 + 4 * resno;
} else if (resno == PCI_ROM_RESOURCE) {
new |= res->flags & PCI_ROM_ADDRESS_ENABLE;
reg = dev->rom_base_reg;
} else {
/* Hmm, non-standard resource. */
BUG();
return; /* kill uninitialised var warning */
}
 
pci_write_config_dword(dev, reg, new);
pci_read_config_dword(dev, reg, &check);
 
if ((new ^ check) & mask) {
printk(KERN_ERR "PCI: Error while updating region "
"%s/%d (%08x != %08x)\n", pci_name(dev), resno,
new, check);
}
 
if ((new & (PCI_BASE_ADDRESS_SPACE|PCI_BASE_ADDRESS_MEM_TYPE_MASK)) ==
(PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64)) {
new = 0; /* currently everyone zeros the high address */
pci_write_config_dword(dev, reg + 4, new);
pci_read_config_dword(dev, reg + 4, &check);
if (check != new) {
printk(KERN_ERR "PCI: Error updating region "
"%s/%d (high %08x != %08x)\n",
pci_name(dev), resno, new, check);
}
}
}
 
int __init
pci_claim_resource(struct pci_dev *dev, int resource)
{
struct resource *res = &dev->resource[resource];
struct resource *root = pci_find_parent_resource(dev, res);
char *dtype = resource < PCI_BRIDGE_RESOURCES ? "device" : "bridge";
int err;
 
err = -EINVAL;
if (root != NULL)
err = request_resource(root, res);
 
if (err) {
printk(KERN_ERR "PCI: %s region %d of %s %s [%lx:%lx]\n",
root ? "Address space collision on" :
"No parent found for",
resource, dtype, pci_name(dev), res->start, res->end);
}
 
return err;
}
 
int pci_assign_resource(struct pci_dev *dev, int resno)
{
struct pci_bus *bus = dev->bus;
struct resource *res = dev->resource + resno;
unsigned long size, min, align;
int ret;
 
size = res->end - res->start + 1;
min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM;
/* The bridge resources are special, as their
size != alignment. Sizing routines return
required alignment in the "start" field. */
align = (resno < PCI_BRIDGE_RESOURCES) ? size : res->start;
 
/* First, try exact prefetching match.. */
ret = pci_bus_alloc_resource(bus, res, size, align, min,
IORESOURCE_PREFETCH,
pcibios_align_resource, dev);
 
if (ret < 0 && (res->flags & IORESOURCE_PREFETCH)) {
/*
* That failed.
*
* But a prefetching area can handle a non-prefetching
* window (it will just not perform as well).
*/
ret = pci_bus_alloc_resource(bus, res, size, align, min, 0,
pcibios_align_resource, dev);
}
 
if (ret) {
printk(KERN_ERR "PCI: Failed to allocate resource %d(%lx-%lx) for %s\n",
resno, res->start, res->end, pci_name(dev));
} else if (resno < PCI_BRIDGE_RESOURCES) {
pci_update_resource(dev, res, resno);
}
 
return ret;
}
 
/* Sort resources by alignment */
void __devinit
pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
{
int i;
 
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
struct resource *r;
struct resource_list *list, *tmp;
unsigned long r_align;
 
r = &dev->resource[i];
r_align = r->end - r->start;
if (!(r->flags) || r->parent)
continue;
if (!r_align) {
printk(KERN_WARNING "PCI: Ignore bogus resource %d "
"[%lx:%lx] of %s\n",
i, r->start, r->end, pci_name(dev));
continue;
}
r_align = (i < PCI_BRIDGE_RESOURCES) ? r_align + 1 : r->start;
for (list = head; ; list = list->next) {
unsigned long align = 0;
struct resource_list *ln = list->next;
int idx;
 
if (ln) {
idx = ln->res - &ln->dev->resource[0];
align = (idx < PCI_BRIDGE_RESOURCES) ?
ln->res->end - ln->res->start + 1 :
ln->res->start;
}
if (r_align > align) {
tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
if (!tmp)
panic("pdev_sort_resources(): "
"kmalloc() failed!\n");
tmp->next = ln;
tmp->res = r;
tmp->dev = dev;
list->next = tmp;
break;
}
}
}
}
/shark/trunk/drivers/newpci/bus.c
0,0 → 1,137
/*
* drivers/pci/bus.c
*
* From setup-res.c, by:
* Dave Rusling (david.rusling@reo.mts.dec.com)
* David Mosberger (davidm@cs.arizona.edu)
* David Miller (davem@redhat.com)
* Ivan Kokshaysky (ink@jurassic.park.msu.ru)
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
 
#include "pci.h"
 
/**
* pci_bus_alloc_resource - allocate a resource from a parent bus
* @bus: PCI bus
* @res: resource to allocate
* @size: size of resource to allocate
* @align: alignment of resource to allocate
* @min: minimum /proc/iomem address to allocate
* @type_mask: IORESOURCE_* type flags
* @alignf: resource alignment function
* @alignf_data: data argument for resource alignment function
*
* Given the PCI bus a device resides on, the size, minimum address,
* alignment and type, try to find an acceptable resource allocation
* for a specific device resource.
*/
int
pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
unsigned long size, unsigned long align, unsigned long min,
unsigned int type_mask,
void (*alignf)(void *, struct resource *,
unsigned long, unsigned long),
void *alignf_data)
{
int i, ret = -ENOMEM;
 
type_mask |= IORESOURCE_IO | IORESOURCE_MEM;
 
for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
struct resource *r = bus->resource[i];
if (!r)
continue;
 
/* type_mask must match */
if ((res->flags ^ r->flags) & type_mask)
continue;
 
/* We cannot allocate a non-prefetching resource
from a pre-fetching area */
if ((r->flags & IORESOURCE_PREFETCH) &&
!(res->flags & IORESOURCE_PREFETCH))
continue;
 
/* Ok, try it out.. */
ret = allocate_resource(r, res, size, min, -1, align,
alignf, alignf_data);
if (ret == 0)
break;
}
return ret;
}
 
/**
* pci_bus_add_devices - insert newly discovered PCI devices
* @bus: bus to check for new devices
*
* Add newly discovered PCI devices (which are on the bus->devices
* list) to the global PCI device list, add the sysfs and procfs
* entries. Where a bridge is found, add the discovered bus to
* the parents list of child buses, and recurse (breadth-first
* to be compatible with 2.4)
*
* Call hotplug for each new devices.
*/
void __devinit pci_bus_add_devices(struct pci_bus *bus)
{
struct pci_dev *dev;
 
list_for_each_entry(dev, &bus->devices, bus_list) {
/*
* Skip already-present devices (which are on the
* global device list.)
*/
if (!list_empty(&dev->global_list))
continue;
 
device_add(&dev->dev);
 
spin_lock(&pci_bus_lock);
list_add_tail(&dev->global_list, &pci_devices);
spin_unlock(&pci_bus_lock);
 
pci_proc_attach_device(dev);
pci_create_sysfs_dev_files(dev);
 
}
 
list_for_each_entry(dev, &bus->devices, bus_list) {
 
BUG_ON(list_empty(&dev->global_list));
 
/*
* If there is an unattached subordinate bus, attach
* it and then scan for unattached PCI devices.
*/
if (dev->subordinate && list_empty(&dev->subordinate->node)) {
spin_lock(&pci_bus_lock);
list_add_tail(&dev->subordinate->node, &dev->bus->children);
spin_unlock(&pci_bus_lock);
pci_bus_add_devices(dev->subordinate);
}
}
}
 
void pci_enable_bridges(struct pci_bus *bus)
{
struct pci_dev *dev;
 
list_for_each_entry(dev, &bus->devices, bus_list) {
if (dev->subordinate) {
pci_enable_device(dev);
pci_set_master(dev);
pci_enable_bridges(dev->subordinate);
}
}
}
 
EXPORT_SYMBOL(pci_bus_add_devices);
EXPORT_SYMBOL(pci_enable_bridges);
/shark/trunk/drivers/newpci/setup-irq.c
0,0 → 1,71
/*
* drivers/pci/setup-irq.c
*
* Extruded from code written by
* Dave Rusling (david.rusling@reo.mts.dec.com)
* David Mosberger (davidm@cs.arizona.edu)
* David Miller (davem@redhat.com)
*
* Support routines for initializing a PCI subsystem.
*/
 
 
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/cache.h>
 
 
#define DEBUG_CONFIG 0
#if DEBUG_CONFIG
# define DBGC(args) printk args
#else
# define DBGC(args)
#endif
 
 
static void __init
pdev_fixup_irq(struct pci_dev *dev,
u8 (*swizzle)(struct pci_dev *, u8 *),
int (*map_irq)(struct pci_dev *, u8, u8))
{
u8 pin, slot;
int irq;
 
/* If this device is not on the primary bus, we need to figure out
which interrupt pin it will come in on. We know which slot it
will come in on 'cos that slot is where the bridge is. Each
time the interrupt line passes through a PCI-PCI bridge we must
apply the swizzle function. */
 
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
/* Cope with 0 and illegal. */
if (pin == 0 || pin > 4)
pin = 1;
 
/* Follow the chain of bridges, swizzling as we go. */
slot = (*swizzle)(dev, &pin);
 
irq = (*map_irq)(dev, slot, pin);
if (irq == -1)
irq = 0;
dev->irq = irq;
 
DBGC((KERN_ERR "PCI fixup irq: (%s) got %d\n", dev->dev.name, dev->irq));
 
/* Always tell the device, so the driver knows what is
the real IRQ to use; the device does not use it. */
pcibios_update_irq(dev, irq);
}
 
void __init
pci_fixup_irqs(u8 (*swizzle)(struct pci_dev *, u8 *),
int (*map_irq)(struct pci_dev *, u8, u8))
{
struct pci_dev *dev = NULL;
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
pdev_fixup_irq(dev, swizzle, map_irq);
}
}
/shark/trunk/drivers/newpci/remove.c
0,0 → 1,113
#include <linux/pci.h>
#include <linux/module.h>
#include "pci.h"
 
#undef DEBUG
 
#ifdef DEBUG
#define DBG(x...) printk(x)
#else
#define DBG(x...)
#endif
 
static void pci_free_resources(struct pci_dev *dev)
{
int i;
 
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
struct resource *res = dev->resource + i;
if (res->parent)
release_resource(res);
}
}
 
static void pci_destroy_dev(struct pci_dev *dev)
{
pci_proc_detach_device(dev);
device_unregister(&dev->dev);
 
/* Remove the device from the device lists, and prevent any further
* list accesses from this device */
spin_lock(&pci_bus_lock);
list_del(&dev->bus_list);
list_del(&dev->global_list);
dev->bus_list.next = dev->bus_list.prev = NULL;
dev->global_list.next = dev->global_list.prev = NULL;
spin_unlock(&pci_bus_lock);
 
pci_free_resources(dev);
pci_dev_put(dev);
}
 
/**
* pci_remove_device_safe - remove an unused hotplug device
* @dev: the device to remove
*
* Delete the device structure from the device lists and
* notify userspace (/sbin/hotplug), but only if the device
* in question is not being used by a driver.
* Returns 0 on success.
*/
int pci_remove_device_safe(struct pci_dev *dev)
{
if (pci_dev_driver(dev))
return -EBUSY;
pci_destroy_dev(dev);
return 0;
}
EXPORT_SYMBOL(pci_remove_device_safe);
 
/**
* pci_remove_bus_device - remove a PCI device and any children
* @dev: the device to remove
*
* Remove a PCI device from the device lists, informing the drivers
* that the device has been removed. We also remove any subordinate
* buses and children in a depth-first manner.
*
* For each device we remove, delete the device structure from the
* device lists, remove the /proc entry, and notify userspace
* (/sbin/hotplug).
*/
void pci_remove_bus_device(struct pci_dev *dev)
{
if (dev->subordinate) {
struct pci_bus *b = dev->subordinate;
 
pci_remove_behind_bridge(dev);
pci_proc_detach_bus(b);
 
spin_lock(&pci_bus_lock);
list_del(&b->node);
spin_unlock(&pci_bus_lock);
 
kfree(b);
dev->subordinate = NULL;
}
 
pci_destroy_dev(dev);
}
 
/**
* pci_remove_behind_bridge - remove all devices behind a PCI bridge
* @dev: PCI bridge device
*
* Remove all devices on the bus, except for the parent bridge.
* This also removes any child buses, and any devices they may
* contain in a depth-first manner.
*/
void pci_remove_behind_bridge(struct pci_dev *dev)
{
struct list_head *l, *n;
 
if (dev->subordinate) {
list_for_each_safe(l, n, &dev->subordinate->devices) {
struct pci_dev *dev = pci_dev_b(l);
 
pci_remove_bus_device(dev);
}
}
}
 
EXPORT_SYMBOL(pci_remove_bus_device);
EXPORT_SYMBOL(pci_remove_behind_bridge);
/shark/trunk/drivers/linuxc26/include/linux/kernel.h
15,12 → 15,12
#include <asm/byteorder.h>
#include <asm/bug.h>
 
#define INT_MAX ((int)(~0U>>1))
#define INT_MIN (-INT_MAX - 1)
#define UINT_MAX (~0U)
#define LONG_MAX ((long)(~0UL>>1))
#define LONG_MIN (-LONG_MAX - 1)
#define ULONG_MAX (~0UL)
//#define INT_MAX ((int)(~0U>>1))
//#define INT_MIN (-INT_MAX - 1)
//#define UINT_MAX (~0U)
//#define LONG_MAX ((long)(~0UL>>1))
//#define LONG_MIN (-LONG_MAX - 1)
//#define ULONG_MAX (~0UL)
 
#define STACK_MAGIC 0xdeadbeef
 
171,6 → 171,8
(void) (&_x == &_y); \
_x > _y ? _x : _y; })
 
 
 
/*
* ..and if you can't take the strict
* types, you can specify one yourself.
/shark/trunk/drivers/linuxc26/include/linux/types.h
91,10 → 91,10
#endif
 
/* bsd */
typedef unsigned char u_char;
typedef unsigned short u_short;
typedef unsigned int u_int;
typedef unsigned long u_long;
//typedef unsigned char u_char;
//typedef unsigned short u_short;
//typedef unsigned int u_int;
//typedef unsigned long u_long;
 
/* sysv */
typedef unsigned char unchar;
/shark/trunk/drivers/linuxc26/include/linux/limits.h
1,22 → 1,4
#ifndef _LINUX_LIMITS_H
#define _LINUX_LIMITS_H
 
#define NR_OPEN 1024
 
#define NGROUPS_MAX 32 /* supplemental group IDs are available */
#define ARG_MAX 131072 /* # bytes of args + environ for exec() */
#define CHILD_MAX 999 /* no limit :-) */
#define OPEN_MAX 256 /* # open files a process may have */
#define LINK_MAX 127 /* # links a file may have */
#define MAX_CANON 255 /* size of the canonical input queue */
#define MAX_INPUT 255 /* size of the type-ahead buffer */
#define NAME_MAX 255 /* # chars in a file name */
#define PATH_MAX 4096 /* # chars in a path name including nul */
#define PIPE_BUF 4096 /* # bytes in atomic write to a pipe */
#define XATTR_NAME_MAX 255 /* # chars in an extended attribute name */
#define XATTR_SIZE_MAX 65536 /* size of an extended attribute value (64k) */
#define XATTR_LIST_MAX 65536 /* size of extended attribute namelist (64k) */
 
#define RTSIG_MAX 32
 
#endif
/shark/trunk/drivers/linuxc26/include/asm/string.h
3,482 → 3,7
 
#ifdef __KERNEL__
#include <linux/config.h>
/*
* On a 486 or Pentium, we are better off not using the
* byte string operations. But on a 386 or a PPro the
* byte string ops are faster than doing it by hand
* (MUCH faster on a Pentium).
*/
 
/*
* This string-include defines all string functions as inline
* functions. Use gcc. It also assumes ds=es=data space, this should be
* normal. Most of the string-functions are rather heavily hand-optimized,
* see especially strsep,strstr,str[c]spn. They should work, but are not
* very easy to understand. Everything is done entirely within the register
* set, making the functions fast and clean. String instructions have been
* used through-out, making for "slightly" unclear code :-)
*
* NO Copyright (C) 1991, 1992 Linus Torvalds,
* consider these trivial functions to be PD.
*/
 
#define __HAVE_ARCH_STRCPY
static inline char * strcpy(char * dest,const char *src)
{
int d0, d1, d2;
__asm__ __volatile__(
"1:\tlodsb\n\t"
"stosb\n\t"
"testb %%al,%%al\n\t"
"jne 1b"
: "=&S" (d0), "=&D" (d1), "=&a" (d2)
:"0" (src),"1" (dest) : "memory");
return dest;
}
 
#define __HAVE_ARCH_STRNCPY
static inline char * strncpy(char * dest,const char *src,size_t count)
{
int d0, d1, d2, d3;
__asm__ __volatile__(
"1:\tdecl %2\n\t"
"js 2f\n\t"
"lodsb\n\t"
"stosb\n\t"
"testb %%al,%%al\n\t"
"jne 1b\n\t"
"rep\n\t"
"stosb\n"
"2:"
: "=&S" (d0), "=&D" (d1), "=&c" (d2), "=&a" (d3)
:"0" (src),"1" (dest),"2" (count) : "memory");
return dest;
}
 
#define __HAVE_ARCH_STRCAT
static inline char * strcat(char * dest,const char * src)
{
int d0, d1, d2, d3;
__asm__ __volatile__(
"repne\n\t"
"scasb\n\t"
"decl %1\n"
"1:\tlodsb\n\t"
"stosb\n\t"
"testb %%al,%%al\n\t"
"jne 1b"
: "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
: "0" (src), "1" (dest), "2" (0), "3" (0xffffffffu):"memory");
return dest;
}
 
#define __HAVE_ARCH_STRNCAT
static inline char * strncat(char * dest,const char * src,size_t count)
{
int d0, d1, d2, d3;
__asm__ __volatile__(
"repne\n\t"
"scasb\n\t"
"decl %1\n\t"
"movl %8,%3\n"
"1:\tdecl %3\n\t"
"js 2f\n\t"
"lodsb\n\t"
"stosb\n\t"
"testb %%al,%%al\n\t"
"jne 1b\n"
"2:\txorl %2,%2\n\t"
"stosb"
: "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
: "0" (src),"1" (dest),"2" (0),"3" (0xffffffffu), "g" (count)
: "memory");
return dest;
}
 
#define __HAVE_ARCH_STRCMP
static inline int strcmp(const char * cs,const char * ct)
{
int d0, d1;
register int __res;
__asm__ __volatile__(
"1:\tlodsb\n\t"
"scasb\n\t"
"jne 2f\n\t"
"testb %%al,%%al\n\t"
"jne 1b\n\t"
"xorl %%eax,%%eax\n\t"
"jmp 3f\n"
"2:\tsbbl %%eax,%%eax\n\t"
"orb $1,%%al\n"
"3:"
:"=a" (__res), "=&S" (d0), "=&D" (d1)
:"1" (cs),"2" (ct));
return __res;
}
 
#define __HAVE_ARCH_STRNCMP
static inline int strncmp(const char * cs,const char * ct,size_t count)
{
register int __res;
int d0, d1, d2;
__asm__ __volatile__(
"1:\tdecl %3\n\t"
"js 2f\n\t"
"lodsb\n\t"
"scasb\n\t"
"jne 3f\n\t"
"testb %%al,%%al\n\t"
"jne 1b\n"
"2:\txorl %%eax,%%eax\n\t"
"jmp 4f\n"
"3:\tsbbl %%eax,%%eax\n\t"
"orb $1,%%al\n"
"4:"
:"=a" (__res), "=&S" (d0), "=&D" (d1), "=&c" (d2)
:"1" (cs),"2" (ct),"3" (count));
return __res;
}
 
#define __HAVE_ARCH_STRCHR
static inline char * strchr(const char * s, int c)
{
int d0;
register char * __res;
__asm__ __volatile__(
"movb %%al,%%ah\n"
"1:\tlodsb\n\t"
"cmpb %%ah,%%al\n\t"
"je 2f\n\t"
"testb %%al,%%al\n\t"
"jne 1b\n\t"
"movl $1,%1\n"
"2:\tmovl %1,%0\n\t"
"decl %0"
:"=a" (__res), "=&S" (d0) : "1" (s),"0" (c));
return __res;
}
 
#define __HAVE_ARCH_STRRCHR
static inline char * strrchr(const char * s, int c)
{
int d0, d1;
register char * __res;
__asm__ __volatile__(
"movb %%al,%%ah\n"
"1:\tlodsb\n\t"
"cmpb %%ah,%%al\n\t"
"jne 2f\n\t"
"leal -1(%%esi),%0\n"
"2:\ttestb %%al,%%al\n\t"
"jne 1b"
:"=g" (__res), "=&S" (d0), "=&a" (d1) :"0" (0),"1" (s),"2" (c));
return __res;
}
 
#define __HAVE_ARCH_STRLEN
static inline size_t strlen(const char * s)
{
int d0;
register int __res;
__asm__ __volatile__(
"repne\n\t"
"scasb\n\t"
"notl %0\n\t"
"decl %0"
:"=c" (__res), "=&D" (d0) :"1" (s),"a" (0), "0" (0xffffffffu));
return __res;
}
 
static inline void * __memcpy(void * to, const void * from, size_t n)
{
int d0, d1, d2;
__asm__ __volatile__(
"rep ; movsl\n\t"
"testb $2,%b4\n\t"
"je 1f\n\t"
"movsw\n"
"1:\ttestb $1,%b4\n\t"
"je 2f\n\t"
"movsb\n"
"2:"
: "=&c" (d0), "=&D" (d1), "=&S" (d2)
:"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from)
: "memory");
return (to);
}
 
/*
* This looks horribly ugly, but the compiler can optimize it totally,
* as the count is constant.
*/
static inline void * __constant_memcpy(void * to, const void * from, size_t n)
{
if (n <= 128)
return __builtin_memcpy(to, from, n);
 
#define COMMON(x) \
__asm__ __volatile__( \
"rep ; movsl" \
x \
: "=&c" (d0), "=&D" (d1), "=&S" (d2) \
: "0" (n/4),"1" ((long) to),"2" ((long) from) \
: "memory");
{
int d0, d1, d2;
switch (n % 4) {
case 0: COMMON(""); return to;
case 1: COMMON("\n\tmovsb"); return to;
case 2: COMMON("\n\tmovsw"); return to;
default: COMMON("\n\tmovsw\n\tmovsb"); return to;
}
}
#undef COMMON
}
 
#define __HAVE_ARCH_MEMCPY
 
#ifdef CONFIG_X86_USE_3DNOW
 
#include <asm/mmx.h>
 
/*
* This CPU favours 3DNow strongly (eg AMD Athlon)
*/
 
static inline void * __constant_memcpy3d(void * to, const void * from, size_t len)
{
if (len < 512)
return __constant_memcpy(to, from, len);
return _mmx_memcpy(to, from, len);
}
 
static __inline__ void *__memcpy3d(void *to, const void *from, size_t len)
{
if (len < 512)
return __memcpy(to, from, len);
return _mmx_memcpy(to, from, len);
}
 
#define memcpy(t, f, n) \
(__builtin_constant_p(n) ? \
__constant_memcpy3d((t),(f),(n)) : \
__memcpy3d((t),(f),(n)))
 
#else
 
/*
* No 3D Now!
*/
#define memcpy(t, f, n) \
(__builtin_constant_p(n) ? \
__constant_memcpy((t),(f),(n)) : \
__memcpy((t),(f),(n)))
 
#endif
 
/*
* struct_cpy(x,y), copy structure *x into (matching structure) *y.
*
* We get link-time errors if the structure sizes do not match.
* There is no runtime overhead, it's all optimized away at
* compile time.
*/
extern void __struct_cpy_bug (void);
 
#define struct_cpy(x,y) \
({ \
if (sizeof(*(x)) != sizeof(*(y))) \
__struct_cpy_bug; \
memcpy(x, y, sizeof(*(x))); \
})
 
#define __HAVE_ARCH_MEMMOVE
static inline void * memmove(void * dest,const void * src, size_t n)
{
int d0, d1, d2;
if (dest<src)
__asm__ __volatile__(
"rep\n\t"
"movsb"
: "=&c" (d0), "=&S" (d1), "=&D" (d2)
:"0" (n),"1" (src),"2" (dest)
: "memory");
else
__asm__ __volatile__(
"std\n\t"
"rep\n\t"
"movsb\n\t"
"cld"
: "=&c" (d0), "=&S" (d1), "=&D" (d2)
:"0" (n),
"1" (n-1+(const char *)src),
"2" (n-1+(char *)dest)
:"memory");
return dest;
}
 
#define memcmp __builtin_memcmp
 
#define __HAVE_ARCH_MEMCHR
static inline void * memchr(const void * cs,int c,size_t count)
{
int d0;
register void * __res;
if (!count)
return NULL;
__asm__ __volatile__(
"repne\n\t"
"scasb\n\t"
"je 1f\n\t"
"movl $1,%0\n"
"1:\tdecl %0"
:"=D" (__res), "=&c" (d0) : "a" (c),"0" (cs),"1" (count));
return __res;
}
 
static inline void * __memset_generic(void * s, char c,size_t count)
{
int d0, d1;
__asm__ __volatile__(
"rep\n\t"
"stosb"
: "=&c" (d0), "=&D" (d1)
:"a" (c),"1" (s),"0" (count)
:"memory");
return s;
}
 
/* we might want to write optimized versions of these later */
#define __constant_count_memset(s,c,count) __memset_generic((s),(c),(count))
 
/*
* memset(x,0,y) is a reasonably common thing to do, so we want to fill
* things 32 bits at a time even when we don't know the size of the
* area at compile-time..
*/
static inline void * __constant_c_memset(void * s, unsigned long c, size_t count)
{
int d0, d1;
__asm__ __volatile__(
"rep ; stosl\n\t"
"testb $2,%b3\n\t"
"je 1f\n\t"
"stosw\n"
"1:\ttestb $1,%b3\n\t"
"je 2f\n\t"
"stosb\n"
"2:"
: "=&c" (d0), "=&D" (d1)
:"a" (c), "q" (count), "0" (count/4), "1" ((long) s)
:"memory");
return (s);
}
 
/* Added by Gertjan van Wingerde to make minix and sysv module work */
#define __HAVE_ARCH_STRNLEN
static inline size_t strnlen(const char * s, size_t count)
{
int d0;
register int __res;
__asm__ __volatile__(
"movl %2,%0\n\t"
"jmp 2f\n"
"1:\tcmpb $0,(%0)\n\t"
"je 3f\n\t"
"incl %0\n"
"2:\tdecl %1\n\t"
"cmpl $-1,%1\n\t"
"jne 1b\n"
"3:\tsubl %2,%0"
:"=a" (__res), "=&d" (d0)
:"c" (s),"1" (count));
return __res;
}
/* end of additional stuff */
 
#define __HAVE_ARCH_STRSTR
 
extern char *strstr(const char *cs, const char *ct);
 
/*
* This looks horribly ugly, but the compiler can optimize it totally,
* as we by now know that both pattern and count is constant..
*/
static inline void * __constant_c_and_count_memset(void * s, unsigned long pattern, size_t count)
{
switch (count) {
case 0:
return s;
case 1:
*(unsigned char *)s = pattern;
return s;
case 2:
*(unsigned short *)s = pattern;
return s;
case 3:
*(unsigned short *)s = pattern;
*(2+(unsigned char *)s) = pattern;
return s;
case 4:
*(unsigned long *)s = pattern;
return s;
}
#define COMMON(x) \
__asm__ __volatile__( \
"rep ; stosl" \
x \
: "=&c" (d0), "=&D" (d1) \
: "a" (pattern),"0" (count/4),"1" ((long) s) \
: "memory")
{
int d0, d1;
switch (count % 4) {
case 0: COMMON(""); return s;
case 1: COMMON("\n\tstosb"); return s;
case 2: COMMON("\n\tstosw"); return s;
default: COMMON("\n\tstosw\n\tstosb"); return s;
}
}
#undef COMMON
}
 
#define __constant_c_x_memset(s, c, count) \
(__builtin_constant_p(count) ? \
__constant_c_and_count_memset((s),(c),(count)) : \
__constant_c_memset((s),(c),(count)))
 
#define __memset(s, c, count) \
(__builtin_constant_p(count) ? \
__constant_count_memset((s),(c),(count)) : \
__memset_generic((s),(c),(count)))
 
#define __HAVE_ARCH_MEMSET
#define memset(s, c, count) \
(__builtin_constant_p(c) ? \
__constant_c_x_memset((s),(0x01010101UL*(unsigned char)(c)),(count)) : \
__memset((s),(c),(count)))
 
/*
* find the first occurrence of byte 'c', or 1 past the area if none
*/
#define __HAVE_ARCH_MEMSCAN
static inline void * memscan(void * addr, int c, size_t size)
{
if (!size)
return addr;
__asm__("repnz; scasb\n\t"
"jnz 1f\n\t"
"dec %%edi\n"
"1:"
: "=D" (addr), "=c" (size)
: "0" (addr), "1" (size), "a" (c));
return addr;
}
 
#endif /* __KERNEL__ */
 
#endif
/shark/trunk/drivers/linuxc26/include/linuxcomp.h
12,4 → 12,18
#define NR_IRQS 15
#define NR_IRQ_VECTORS 15
 
#define __BIT_TYPES_DEFINED__
 
#include <ll/i386/mem.h>
 
#define _SIZE_T
#define _SSIZE_T
 
#define __HAVE_ARCH_MEMSET
#define __HAVE_ARCH_MEMCPY
#define __HAVE_ARCH_MEMMOVE
#define __HAVE_ARCH_MEMSCAN
#define __HAVE_ARCH_MEMCMP
#define __HAVE_ARCH_MEMCHR
 
#endif