patch-2.1.118 linux/drivers/char/bttv.c
Next file: linux/drivers/char/bttv.h
Previous file: linux/drivers/char/bt848.h
Back to the patch index
Back to the overall index
- Lines: 1699
- Date:
Sun Aug 23 13:32:25 1998
- Orig file:
v2.1.117/linux/drivers/char/bttv.c
- Orig date:
Thu Aug 20 17:05:15 1998
diff -u --recursive --new-file v2.1.117/linux/drivers/char/bttv.c linux/drivers/char/bttv.c
@@ -65,18 +65,12 @@
#define DEBUG(x) /* Debug driver */
#define IDEBUG(x) /* Debug interrupt handler */
-static unsigned int remap=0; /* remap Bt848 */
-static unsigned int vidmem=0; /* manually set video mem address */
-static int triton1=0;
-static int radio=0;
-
-static unsigned int card=0;
-
-MODULE_PARM(remap,"i");
MODULE_PARM(vidmem,"i");
MODULE_PARM(triton1,"i");
-MODULE_PARM(radio,"i");
-MODULE_PARM(card,"i");
+MODULE_PARM(remap,"1-4i");
+MODULE_PARM(radio,"1-4i");
+MODULE_PARM(card,"1-4i");
+MODULE_PARM(pll,"1-4i");
static int find_vga(void);
static void bt848_set_risc_jmps(struct bttv *btv);
@@ -84,12 +78,19 @@
/* Anybody who uses more than four? */
#define BTTV_MAX 4
+static unsigned int vidmem=0; /* manually set video mem address */
+static int triton1=0;
+
+static unsigned int remap[BTTV_MAX]; /* remap Bt848 */
+static unsigned int radio[BTTV_MAX];
+static unsigned int card[BTTV_MAX] = { 0, 0,
+ 0, 0 };
+static unsigned int pll[BTTV_MAX] = { 0, 0, 0, 0 };
+
static int bttv_num; /* number of Bt848s in use */
static struct bttv bttvs[BTTV_MAX];
#define I2C_TIMING (0x7<<4)
-#define I2C_COMMAND (I2C_TIMING | BT848_I2C_SCL | BT848_I2C_SDA)
-
#define I2C_DELAY 10
#define I2C_SET(CTRL,DATA) \
{ btwrite((CTRL<<1)|(DATA), BT848_I2C); udelay(I2C_DELAY); }
@@ -128,10 +129,6 @@
static inline unsigned long uvirt_to_bus(unsigned long adr)
{
- /* printk("adr: 0x%8x, ",adr);
- printk("phys: 0x%8x, ",(uvirt_to_phys(adr)));
- printk("bus: 0x%8x\n",virt_to_bus(phys_to_virt(uvirt_to_phys(adr))));
- */
return virt_to_bus(phys_to_virt(uvirt_to_phys(adr)));
}
@@ -199,7 +196,8 @@
if(!btv->fbuffer)
btv->fbuffer=(unsigned char *) rvmalloc(2*BTTV_MAX_FBUF);
else
- printk(KERN_ERR "bttv: Double alloc of fbuffer!\n");
+ printk(KERN_ERR "bttv%d: Double alloc of fbuffer!\n",
+ btv->nr);
if(!btv->fbuffer)
return -ENOBUFS;
return 0;
@@ -236,7 +234,7 @@
/* clear status bit ; BT848_INT_RACK is ro */
btwrite(BT848_INT_I2CDONE, BT848_INT_STAT);
- btwrite(((addr & 0xff) << 24) | I2C_COMMAND, BT848_I2C);
+ btwrite(((addr & 0xff) << 24) | btv->i2c_command, BT848_I2C);
/*
* Timeout for I2CRead is 1 second (this should be enough, really!)
@@ -251,7 +249,8 @@
if (!i)
{
- printk(KERN_DEBUG "bttv: I2CRead timeout\n");
+ printk(KERN_DEBUG "bttv%d: I2CRead timeout\n",
+ btv->nr);
return -1;
}
if (!(stat & BT848_INT_RACK))
@@ -274,7 +273,7 @@
/* clear status bit; BT848_INT_RACK is ro */
btwrite(BT848_INT_I2CDONE, BT848_INT_STAT);
- data=((addr & 0xff) << 24) | ((b1 & 0xff) << 16) | I2C_COMMAND;
+ data=((addr & 0xff) << 24) | ((b1 & 0xff) << 16) | btv->i2c_command;
if (both)
{
data|=((b2 & 0xff) << 8);
@@ -293,7 +292,8 @@
if (!i)
{
- printk(KERN_DEBUG "bttv: I2CWrite timeout\n");
+ printk(KERN_DEBUG "bttv%d: I2CWrite timeout\n",
+ btv->nr);
return -1;
}
if (!(stat & BT848_INT_RACK))
@@ -356,9 +356,10 @@
if (btv->tuner_type != -1)
{
tunertype=btv->tuner_type;
- i2c_control_device(&(btv->i2c), I2C_DRIVERID_TUNER,
- TUNER_SET_TYPE,&tunertype);
- }
+ i2c_control_device(&(btv->i2c),
+ I2C_DRIVERID_TUNER,
+ TUNER_SET_TYPE,&tunertype);
+ }
break;
}
}
@@ -406,6 +407,7 @@
u32 gpiomask;
u32 muxsel[8];
u32 audiomux[6]; /* Tuner, Radio, internal, external, mute, stereo */
+ u32 gpiomask2; /* GPIO MUX mask */
};
static struct tvcard tvcards[] =
@@ -423,12 +425,14 @@
/* Diamond DTV2000 */
{ 3, 0, 2, 3, { 2, 3, 1, 1}, { 0, 1, 0, 1, 3}},
/* AVerMedia TVPhone */
- { 3, 0, 2,15, { 2, 3, 1, 1}, {12, 0,11,11, 0}},
+ { 3, 0, 3,15, { 2, 3, 1, 1}, {12, 0,11,11, 0}},
/* Matrix Vision MV-Delta */
- { 5,-1, 4, 0, { 2, 3, 1, 0, 0}},
+ { 5,-1, 3, 0, { 2, 3, 1, 0, 0}},
/* Fly Video II */
{ 3, 0, 2, 0xc00, { 2, 3, 1, 1},
{0, 0xc00, 0x800, 0x400, 0xc00, 0}},
+ /* TurboTV */
+ { 3, 0, 2, 3, { 2, 3, 1, 1}, { 1, 1, 2, 3, 0}},
};
#define TVCARDS (sizeof(tvcards)/sizeof(tvcard))
@@ -503,12 +507,46 @@
/* 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)
+ PLL_I = Integer input
+ PLL_F = Fractional input
+
+ F_input = 28.636363 MHz:
+ PAL (CLKx2 = 35.46895 MHz): PLL_X = 1, PLL_I = 0x0E, PLL_F = 0xDCF9, PLL_C = 0
+*/
+
+static void set_pll_freq(struct bttv *btv, unsigned int fin, unsigned int fout)
+{
+ unsigned char fl, fh, fi;
+
+ /* prevent overflows */
+ fin/=4;
+ fout/=4;
+
+ fout*=12;
+ fi=fout/fin;
+
+ fout=(fout-fin*fi)*256;
+ fh=fout/fin;
+
+ fout=(fout-fin*fh)*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)
{
int i;
+ unsigned long tv;
- if (!btv->pll)
- return 0;
+ if (!btv->pll)
+ return 0;
if ((btread(BT848_IFORM)&BT848_IFORM_XT0))
{
/* printk ("switching PLL off\n");*/
@@ -524,13 +562,24 @@
/* printk ("setting PLL for PAL/SECAM\n");*/
+ set_pll_freq(btv, 28636363, 35468950);
+/*
btwrite(0x00,BT848_TGCTRL);
btwrite(0xf9,BT848_PLL_F_LO);
btwrite(0xdc,BT848_PLL_F_HI);
- btwrite(0x8e,BT848_PLL_XCI);
+ btwrite(14|BT848_PLL_X,BT848_PLL_XCI);
+*/
+ /*
+ * Let other people run while the PLL stabilizes
+ */
+
+ tv=jiffies+HZ/10; /* .1 seconds */
+ do
+ {
+ schedule();
+ }
+ while(time_before(jiffies,tv));
- /* Ugh ugh ugh .. schedule ? */
- udelay(100000);
for (i=0; i<100; i++)
{
if ((btread(BT848_DSTATUS)&BT848_DSTATUS_PLOCK))
@@ -548,7 +597,8 @@
static void bt848_muxsel(struct bttv *btv, unsigned int input)
{
- btwrite(tvcards[btv->type].gpiomask, BT848_GPIO_OUT_EN);
+ btaor(tvcards[btv->type].gpiomask2,~tvcards[btv->type].gpiomask2,
+ BT848_GPIO_OUT_EN);
/* This seems to get rid of some synchronization problems */
btand(~(3<<5), BT848_IFORM);
@@ -569,23 +619,7 @@
audio(btv, (input!=tvcards[btv->type].tuner) ?
AUDIO_EXTERN : AUDIO_TUNER);
btaor(tvcards[btv->type].muxsel[input]>>4,
- ~tvcards[btv->type].gpiomask, BT848_GPIO_DATA);
-#if 0
- if (input==3)
- {
- btor(BT848_CONTROL_COMP, BT848_E_CONTROL);
- btor(BT848_CONTROL_COMP, BT848_O_CONTROL);
- }
- else
- {
- btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
- btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
- }
- if (input==2)
- input=3;
- btaor(((input+2)&3)<<5, ~(3<<5), BT848_IFORM);
- audio(btv, input ? AUDIO_EXTERN : AUDIO_TUNER);
-#endif
+ ~tvcards[btv->type].gpiomask2, BT848_GPIO_DATA);
}
@@ -645,27 +679,28 @@
BT848_COLOR_FMT_RGB15,
BT848_COLOR_FMT_YUY2,
BT848_COLOR_FMT_BtYUV,
- -1,
- -1,
- -1,
+ 0,
+ 0,
+ 0,
BT848_COLOR_FMT_RAW,
BT848_COLOR_FMT_YCrCb422,
BT848_COLOR_FMT_YCrCb411,
};
#define PALETTEFMT_MAX 11
-static int make_rawrisctab(struct bttv *btv, unsigned int *ro,
+static int make_rawrisctab(struct bttv *btv, unsigned int *ro,
unsigned int *re, unsigned int *vbuf)
{
unsigned long line;
- unsigned long bpl=1024;
+ unsigned long bpl=1024; /* bytes per line */
unsigned long vadr=(unsigned long) vbuf;
*(ro++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(ro++)=0;
*(re++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(re++)=0;
/* In PAL 650 blocks of 256 DWORDs are sampled, but only if VDELAY
- is 2. We'll have to handle this inside the IRQ handler ... */
+ is 2 and without separate VBI grabbing.
+ We'll have to handle this inside the IRQ handler ... */
for (line=0; line < 640; line++)
{
@@ -802,6 +837,152 @@
*x+=dx;
}
+static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr)
+{
+ int i,t;
+ int yy, y, x, dx;
+ struct video_clip first, *cur, *cur2, *nx, first2, *prev, *nx2;
+ int bpp, bpl, width, height, inter;
+ unsigned int **rp,*ro,*re;
+ unsigned long adr;
+ int cx,cx2,cy,cy2;
+
+ inter=(btv->win.interlace&1)^1;
+ bpp=btv->win.bpp;
+ bpl=btv->win.bpl;
+ ro=btv->risc_odd;
+ re=btv->risc_even;
+ width=btv->win.width;
+ height=btv->win.height;
+ adr=btv->win.vidadr+btv->win.x*bpp+btv->win.y*bpl;
+
+ /* clip clipping rects against viewing window AND screen
+ so we do not have to rely on the user program
+ */
+ cx=(btv->win.x<0) ? (-btv->win.x) : 0;
+ cy=(btv->win.y<0) ? (-btv->win.y) : 0;
+ cx2=(btv->win.x+width>btv->win.swidth) ?
+ (btv->win.swidth-btv->win.x) : width;
+ cy2=(btv->win.y+height>btv->win.sheight) ?
+ (btv->win.sheight-btv->win.y) : height;
+ first.next=NULL;
+ for (i=0; i<ncr; i++)
+ {
+ if ((t=cy-cr[i].y)>0)
+ {
+ if (cr[i].height<=t)
+ continue;
+ cr[i].height-=t;
+ cr[i].y=cy;
+ }
+ if ((t=cy2-cr[i].y)<cr[i].height)
+ {
+ if (t<=0)
+ continue;
+ cr[i].height=t;
+ }
+ if ((t=cx-cr[i].x)>0)
+ {
+ if (cr[i].width<=t)
+ continue;
+ cr[i].width-=t;
+ cr[i].x=cx;
+ }
+ if ((t=cx2-cr[i].x)<cr[i].width)
+ {
+ if (t<=0)
+ continue;
+ cr[i].width=t;
+ }
+ cur=&first;
+ while ((nx=cur->next) && (cr[i].y > cur->next->y))
+ cur=nx;
+ cur->next=&(cr[i]);
+ cr[i].next=nx;
+ }
+ first2.next=NULL;
+
+ *(ro++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(ro++)=0;
+ *(re++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(re++)=0;
+
+ /* loop through all lines */
+ for (yy=0; yy<(height<<inter); yy++)
+ {
+ y=yy>>inter;
+ rp= (yy&1) ? &re : &ro;
+
+ /* remove rects with y2 > y */
+ if ((cur=first2.next))
+ {
+ prev=&first2;
+ do
+ {
+ if (cur->y+cur->height <= y)
+ prev->next=cur->next;
+ else
+ prev=cur;
+ }
+ while ((cur=cur->next));
+ }
+
+ /* add rect to second (x-sorted) list if rect.y == y */
+ if ((cur=first.next))
+ {
+ while ((cur) && (cur->y == y))
+ {
+ first.next=cur->next;
+ cur2=&first2;
+ while ((nx2=cur2->next) && (cur->x > cur2->next->x))
+ cur2=nx2;
+ cur2->next=cur;
+ cur->next=nx2;
+ cur=first.next;
+ }
+ }
+ x=0;
+ if ((btv->win.y+y<=0)||(btv->win.y+y>=btv->win.sheight))
+ write_risc_segment(rp, adr, BT848_RISC_SKIP, &x,
+ width, bpp, width);
+ else
+ {
+ dx=cx;
+ for (cur2=first2.next; cur2; cur2=cur2->next)
+ {
+ if (x+dx < cur2->x)
+ {
+ write_risc_segment(rp, adr, BT848_RISC_SKIP,
+ &x, dx, bpp, width);
+ dx=cur2->x-x;
+ write_risc_segment(rp, adr, BT848_RISC_WRITEC,
+ &x, dx, bpp, width);
+ dx=cur2->width;
+ }
+ else if (x+dx < cur2->x+cur2->width)
+ dx=cur2->x+cur2->width-x;
+ }
+ if (cx2<width)
+ {
+ write_risc_segment(rp, adr, BT848_RISC_SKIP,
+ &x, dx, bpp, width);
+ write_risc_segment(rp, adr, BT848_RISC_WRITEC,
+ &x, cx2-x, bpp, width);
+ dx=width-x;
+ }
+ write_risc_segment(rp, adr, BT848_RISC_SKIP,
+ &x, dx, bpp, width);
+ write_risc_segment(rp, adr, BT848_RISC_WRITEC,
+ &x, width-x, bpp, width);
+ }
+ if ((!inter)||(yy&1))
+ adr+=bpl;
+ }
+
+ *(ro++)=BT848_RISC_JUMP;
+ *(ro++)=btv->bus_vbi_even;
+ *(re++)=BT848_RISC_JUMP;
+ *(re++)=btv->bus_vbi_odd;
+}
+
/*
* Set the registers for the size we have specified. Don't bother
@@ -814,36 +995,50 @@
struct tvnorm
{
- u16 cropwidth, cropheight;
+ u32 Fsc;
+ u16 swidth, sheight; /* scaled standard width, height */
u16 totalwidth;
u8 adelay, bdelay, iform;
u32 scaledtwidth;
u16 hdelayx1, hactivex1;
- u16 vdelay;
+ u16 vdelay, fporch;
};
static struct tvnorm tvnorms[] = {
/* PAL-BDGHI */
- { 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
- 944, 186, 922, 0x20},
+ /* max. active video is actually 922, but 924 is divisible by 4 and 3! */
+ { 35468950,
+ 924, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
+ 1135, 186, 924, 0x20},
+/*
+ { 35468950,
+ 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
+ 944, 186, 922, 0x20},
+*/
/* NTSC */
- { 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC|BT848_IFORM_XT0),
- 780, 135, 754, 0x16},
+ { 28636363,
+ 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC|BT848_IFORM_XT0),
+ 780, 135, 754, 0x1a},
/* SECAM */
- { 768, 576, 1135, 0x7f, 0xb0, (BT848_IFORM_SECAM|BT848_IFORM_XT1),
- 944, 186, 922, 0x20},
+ { 28636363,
+ 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
+ 780, 135, 754, 0x16},
/* PAL-M */
- { 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
- 780, 135, 754, 0x16},
+ { 28636363,
+ 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
+ 780, 135, 754, 0x16},
/* PAL-N */
- { 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_N|BT848_IFORM_XT1),
- 944, 186, 922, 0x20},
+ { 35468950,
+ 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_N|BT848_IFORM_XT1),
+ 944, 186, 922, 0x20},
/* PAL-NC */
- { 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_NC|BT848_IFORM_XT0),
- 944, 186, 922, 0x20},
+ { 35468950,
+ 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_NC|BT848_IFORM_XT0),
+ 944, 186, 922, 0x20},
/* NTSC-Japan */
- { 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC_J|BT848_IFORM_XT0),
- 780, 135, 754, 0x16},
+ { 28636363,
+ 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC_J|BT848_IFORM_XT0),
+ 780, 135, 754, 0x16},
};
#define TVNORMS (sizeof(tvnorms)/sizeof(tvnorm))
@@ -891,6 +1086,10 @@
tvn=&tvnorms[btv->win.norm];
+ btv->win.cropheight=tvn->sheight;
+ btv->win.cropwidth=tvn->swidth;
+
+/*
if (btv->win.cropwidth>tvn->cropwidth)
btv->win.cropwidth=tvn->cropwidth;
if (btv->win.cropheight>tvn->cropheight)
@@ -900,7 +1099,7 @@
width=btv->win.cropwidth;
if (height>btv->win.cropheight)
height=btv->win.cropheight;
-
+*/
btwrite(tvn->adelay, BT848_ADELAY);
btwrite(tvn->bdelay, BT848_BDELAY);
btaor(tvn->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH), BT848_IFORM);
@@ -916,12 +1115,13 @@
btv->win.interlace = (height>btv->win.cropheight/2) ? 1 : 0;
inter=(btv->win.interlace&1)^1;
+ vdelay=btv->win.cropy+tvn->vdelay;
+
xsf = (hactive*tvn->scaledtwidth)/btv->win.cropwidth;
hscale = ((tvn->totalwidth*4096UL)/xsf-4096);
- vdelay=btv->win.cropy+tvn->vdelay;
- hdelay=(tvn->hdelayx1*tvn->scaledtwidth)/tvn->totalwidth;
- hdelay=((hdelay+btv->win.cropx)*hactive)/btv->win.cropwidth;
+ hdelay=tvn->hdelayx1+btv->win.cropx;
+ hdelay=(hdelay*hactive)/btv->win.cropwidth;
hdelay&=0x3fe;
sr=((btv->win.cropheight>>inter)*512)/height-512;
@@ -948,22 +1148,23 @@
{
unsigned short format;
- btv->win.color_fmt=format= (btv->win.depth==15) ? BT848_COLOR_FMT_RGB15 :
- bpp2fmt[(btv->win.bpp-1)&3];
-
+ btv->win.color_fmt = format =
+ (btv->win.depth==15) ? BT848_COLOR_FMT_RGB15 :
+ bpp2fmt[(btv->win.bpp-1)&3];
+
/* 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.
*/
-#if 0
+
if (format==BT848_COLOR_FMT_RGB8)
- btand(~0x10, BT848_CAP_CTL);
+ btand(~BT848_CAP_CTL_DITH_FRAME, BT848_CAP_CTL);
else
- btor(0x10, BT848_CAP_CTL);
-#endif
- bt848_set_geo(btv,btv->win.width, btv->win.height, format);
+ btor(BT848_CAP_CTL_DITH_FRAME, BT848_CAP_CTL);
+
+ bt848_set_geo(btv, btv->win.width, btv->win.height, format);
}
/*
@@ -978,7 +1179,7 @@
audio(btv, AUDIO_MUTE);
udelay(AUDIO_MUTE_DELAY);
- if (btv->radio)
+ if (radio[btv->nr])
{
if (btv->have_tuner)
i2c_control_device(&(btv->i2c), I2C_DRIVERID_TUNER,
@@ -1027,7 +1228,7 @@
if(fbuffer_alloc(btv))
return -ENOBUFS;
}
- if(btv->grabbing>1)
+ if(btv->grabbing >= MAX_GBUFFERS)
return -ENOBUFS;
/*
@@ -1040,9 +1241,16 @@
if(mp->height <0 || mp->width <0)
return -EINVAL;
+/* This doesn´t work like this for NTSC anyway.
+ So, better check the total image size ...
+*/
+/*
if(mp->height>576 || mp->width>768)
return -EINVAL;
-
+*/
+ if (mp->height*mp->width*fmtbppx2[mp->format&0x0f]/2>BTTV_MAX_FBUF)
+ return -EINVAL;
+
/*
* FIXME: Check the format of the grab here. This is probably
* also less restrictive than the normal overlay grabs. Stuff
@@ -1055,27 +1263,31 @@
vbuf=(unsigned int *)(btv->fbuffer+BTTV_MAX_FBUF*mp->frame);
/* if (!(btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC))
- return -EAGAIN; */
+ return -EAGAIN;*/
ro=btv->grisc+(((btv->grabcount++)&1) ? 4096 :0);
re=ro+2048;
btv->gwidth=mp->width;
btv->gheight=mp->height;
+
if (mp->format > PALETTEFMT_MAX)
return -EINVAL;
btv->gfmt=palette2fmt[mp->format];
- if(btv->gfmt==-1)
+ if(btv->gfmt==0)
return -EINVAL;
make_vrisctab(btv, ro, re, vbuf, btv->gwidth, btv->gheight, btv->gfmt);
/* bt848_set_risc_jmps(btv); */
btor(3, BT848_CAP_CTL);
btor(3, BT848_GPIO_DMA_CTL);
+ btv->frame_stat[mp->frame] = GBUFFER_GRABBING;
if (btv->grabbing) {
btv->gro_next=virt_to_bus(ro);
btv->gre_next=virt_to_bus(re);
+ btv->grf_next=mp->frame;
} else {
btv->gro=virt_to_bus(ro);
btv->gre=virt_to_bus(re);
+ btv->grf=mp->frame;
}
if (!(btv->grabbing++))
btv->risc_jmp[12]=BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ;
@@ -1159,7 +1371,12 @@
btv->user--;
return -EINVAL;
}
- break;
+ btv->grabbing = 0;
+ btv->grab = 0;
+ btv->lastgrab = 0;
+ for (i = 0; i < MAX_GBUFFERS; i++)
+ btv->frame_stat[i] = GBUFFER_UNUSED;
+ break;
case 1:
break;
}
@@ -1227,265 +1444,6 @@
btaor(datahi, ~1, BT848_O_CONTROL);
}
-
-/*
- * Cliprect -> risc table.
- *
- * FIXME: This is generating wrong code when we have some kinds of
- * rectangle lists. If you generate overlapped rectangles then it
- * gets a bit confused. Since we add the frame buffer clip rectangles
- * we need to fix this. Better yet to rewrite this function.
- */
-
-static void write_risc_data(struct bttv *btv, struct video_clip *vp, int count)
-{
- int i;
- u32 yy, y, x, dx, ox;
- u32 *rmem, *rmem2;
- struct video_clip first, *cur, *cur2, *nx, first2, *prev, *nx2;
- u32 *rp, rpo=0, rpe=0, p, bpsl;
- u32 *rpp;
- u32 mask;
- int interlace;
- int depth;
-
- rmem=(u32 *)btv->risc_odd;
- rmem2=(u32 *)btv->risc_even;
- depth=btv->win.bpp;
-
- /* create y-sorted list */
-
- first.next=NULL;
- for (i=0; i<count; i++)
- {
- cur=&first;
- while ((nx=cur->next) && (vp[i].y > cur->next->y))
- cur=nx;
- cur->next=&(vp[i]);
- vp[i].next=nx;
- }
- first2.next=NULL;
-
- rmem[rpo++]=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1|(0xf<<20);
- rmem[rpo++]=0;
-
- rmem2[rpe++]=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1;
- rmem2[rpe++]=0;
-
-
- /*
- * 32bit depth frame buffers need extra flags setting
- */
-
- if (depth==4)
- mask=BT848_RISC_BYTE3;
- else
- mask=0;
-
- bpsl=btv->win.width*btv->win.bpp;
- p=btv->win.vidadr+btv->win.x*btv->win.bpp+
- btv->win.y*btv->win.bpl;
-
- interlace=btv->win.interlace;
-
- /*
- * Loop through all lines
- */
-
- for (yy=0; yy<(btv->win.height<<(1^interlace)); yy++)
- {
- y=yy>>(1^interlace);
-
- /*
- * Even or odd frame generation. We have to
- * write the RISC instructions to the right stream.
- */
-
- if(!(y&1))
- {
- rp=&rpo;
- rpp=rmem;
- }
- else
- {
- rp=&rpe;
- rpp=rmem2;
- }
-
-
- /*
- * first2 is the header of a list of "active" rectangles. We add
- * rectangles as we hit their top and remove them as they fall off
- * the bottom
- */
-
- /* remove rects with y2 > y */
- if ((cur=first2.next))
- {
- prev=&first2;
- do
- {
- if (cur->y+cur->height < y)
- prev->next=cur->next;
- else
- prev=cur;
- }
- while ((cur=cur->next));
- }
-
- /*
- * Fixme - we have to handle overlapped rectangles
- * here, but the overlap might be partial
- */
-
- /* add rect to second (x-sorted) list if rect.y == y */
- if ((cur=first.next))
- {
- while ((cur) && (cur->y == y))
- {
- first.next=cur->next;
- cur2=&first2;
- while ((nx2=cur2->next) && (cur->x > cur2->next->x))
- cur2=nx2;
- cur2->next=cur;
- cur->next=nx2;
- cur=first.next;
- }
- }
-
-
- /*
- * Begin writing the RISC script
- */
-
- dx=x=0;
-
- /*
- * Starting at x position 0 on a new scan line
- * write to location p, don't yet write the number
- * of pixels for the instruction
- */
-
- rpp[(*rp)++]=BT848_RISC_WRITE|BT848_RISC_SOL;
- rpp[(*rp)++]=p;
-
- /*
- * For each rectangle we have in the "active" list - sorted left to
- * right..
- */
-
- for (cur2=first2.next; cur2; cur2=cur2->next)
- {
- /*
- * If we are to the left of the first drawing area
- */
-
- if (x+dx < cur2->x)
- {
- /* Bytes pending ? */
- if (dx)
- {
- /* For a delta away from the start we need to write a SKIP */
- if (x)
- rpp[(*rp)++]=BT848_RISC_SKIP|(dx*depth);
- else
- /* Rewrite the start of line WRITE to a SKIP */
- rpp[(*rp)-2]|=BT848_RISC_BYTE_ALL|(dx*depth);
- /* Move X to the next point (drawing start) */
- x=x+dx;
- }
- /* Ok how far are we from the start of the next rectangle ? */
- dx=cur2->x-x;
- /* dx is now the size of data to write */
-
- /* If this isnt the left edge generate a "write continue" */
- if (x)
- rpp[(*rp)++]=BT848_RISC_WRITEC|(dx*depth)|mask;
- else
- /* Fill in the byte count on the initial WRITE */
- rpp[(*rp)-2]|=(dx*depth)|mask;
- /* Move to the start of the rectangle */
- x=cur2->x;
- /* x is our left dx is byte size of hole */
- dx=cur2->width+1;
- }
- else
- /* Already in a clip zone.. set dx */
- if (x+dx < cur2->x+cur2->width)
- dx=cur2->x+cur2->width-x+1;
- }
- /* now treat the rest of the line */
- ox=x;
- if (dx)
- {
- /* Complete the SKIP to eat to the end of the gap */
- if (x)
- rpp[(*rp)++]=BT848_RISC_SKIP|(dx*depth);
- else
- /* Rewrite to SKIP start to this point */
- rpp[(*rp)-2]|=BT848_RISC_BYTE_ALL|(dx*depth);
- x=x+dx;
- }
-
- /*
- * Not at the right hand edge ?
- */
-
- if ((dx=btv->win.width-x)!=0)
- {
- /* Write to edge of display */
- if (x)
- rpp[(*rp)++]=BT848_RISC_WRITEC|(dx*depth)|BT848_RISC_EOL|mask;
- else
- /* Entire frame is a write - patch first order */
- rpp[(*rp)-2]|=(dx*depth)|BT848_RISC_EOL|mask;
- }
- else
- {
- /* End of line if needed */
- if (ox)
- rpp[(*rp)-1]|=BT848_RISC_EOL|mask;
- else
- {
- /* Skip the line : write a SKIP + start/end of line marks */
- (*rp)--;
- rpp[(*rp)-1]=BT848_RISC_SKIP|
- (btv->win.width*depth)|
- BT848_RISC_EOL|BT848_RISC_SOL;
- }
- }
- /*
- * Move the video render pointer on a line
- */
- if (interlace||(y&1))
- p+=btv->win.bpl;
- }
-
- /*
- * Attach the interframe jumps
- */
-
- rmem[rpo++]=BT848_RISC_JUMP;
- rmem[rpo++]=btv->bus_vbi_even;
-
- rmem2[rpe++]=BT848_RISC_JUMP;
- rmem2[rpe++]=btv->bus_vbi_odd;
-}
-
-/*
- * Helper for adding clips.
- */
-
-static void new_risc_clip(struct video_window *vw, struct video_clip *vcp, int x, int y, int w, int h)
-{
- vcp[vw->clipcount].x=x;
- vcp[vw->clipcount].y=y;
- vcp[vw->clipcount].width=w;
- vcp[vw->clipcount].height=h;
- vw->clipcount++;
-}
-
-
/*
* ioctl routine
*/
@@ -1495,7 +1453,7 @@
{
unsigned char eedata[256];
struct bttv *btv=(struct bttv *)dev;
- static int lastchan=0;
+ int i;
switch (cmd)
{
@@ -1510,8 +1468,8 @@
VID_TYPE_CLIPPING|
VID_TYPE_FRAMERAM|
VID_TYPE_SCALES;
- b.channels = 4; /* tv , input, svhs */
- b.audios = 4; /* tv, input, svhs */
+ b.channels = tvcards[btv->type].inputs;
+ b.audios = tvcards[btv->type].inputs;
b.maxwidth = 768;
b.maxheight = 576;
b.minwidth = 32;
@@ -1528,26 +1486,21 @@
v.flags=VIDEO_VC_AUDIO;
v.tuners=0;
v.type=VIDEO_TYPE_CAMERA;
- switch(v.channel)
- {
- case 0:
- strcpy(v.name,"Television");
- v.flags|=VIDEO_VC_TUNER;
- v.type=VIDEO_TYPE_TV;
- v.tuners=1;
- break;
- case 1:
- strcpy(v.name,"Composite1");
- break;
- case 2:
- strcpy(v.name,"Composite2");
- break;
- case 3:
- strcpy(v.name,"SVHS");
- break;
- default:
- return -EINVAL;
- }
+ v.norm = btv->win.norm;
+ if (v.channel>=tvcards[btv->type].inputs)
+ return -EINVAL;
+ if(v.channel==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==tvcards[btv->type].svhs)
+ strcpy(v.name,"SVHS");
+ else
+ sprintf(v.name,"Composite%d",v.channel);
+
if(copy_to_user(arg,&v,sizeof(v)))
return -EFAULT;
return 0;
@@ -1557,11 +1510,19 @@
*/
case VIDIOCSCHAN:
{
- int v;
- if(copy_from_user(&v, arg, sizeof(v)))
+ struct video_channel v;
+ if(copy_from_user(&v, arg,sizeof(v)))
return -EFAULT;
- bt848_muxsel(btv, v);
- lastchan=v;
+
+ if (v.channel>tvcards[btv->type].inputs)
+ return -EINVAL;
+ bt848_muxsel(btv, v.channel);
+ if(v.norm!=VIDEO_MODE_PAL&&v.norm!=VIDEO_MODE_NTSC
+ &&v.norm!=VIDEO_MODE_SECAM)
+ return -EOPNOTSUPP;
+ btv->win.norm = v.norm;
+ bt848_set_winsize(btv);
+ btv->channel=v.channel;
return 0;
}
case VIDIOCGTUNER:
@@ -1569,7 +1530,7 @@
struct video_tuner v;
if(copy_from_user(&v,arg,sizeof(v))!=0)
return -EFAULT;
- if(v.tuner||lastchan) /* Only tuner 0 */
+ if(v.tuner||btv->channel) /* Only tuner 0 */
return -EINVAL;
strcpy(v.name, "Television");
v.rangelow=0;
@@ -1581,23 +1542,22 @@
return -EFAULT;
return 0;
}
- /* We have but tuner 0 */
+ /* We have but one tuner */
case VIDIOCSTUNER:
{
struct video_tuner v;
if(copy_from_user(&v, arg, sizeof(v)))
return -EFAULT;
- /* Only channel 0 has a tuner */
- if(v.tuner!=0 || lastchan)
- return -EINVAL;
+
+ /* Only one channel has a tuner */
+ if(v.tuner!=tvcards[btv->type].tuner)
+ return -EINVAL;
+
if(v.mode!=VIDEO_MODE_PAL&&v.mode!=VIDEO_MODE_NTSC
&&v.mode!=VIDEO_MODE_SECAM)
return -EOPNOTSUPP;
- /* FIXME: norm should be in video_channel struct
- composite source can have different norms too
- */
- btv->win.norm = v.mode;
- bt848_set_winsize(btv);
+ btv->win.norm = v.mode;
+ bt848_set_winsize(btv);
return 0;
}
case VIDIOCGPICT:
@@ -1682,24 +1642,7 @@
return -ENOMEM;
if(vw.clipcount && copy_from_user(vcp,vw.clips,sizeof(struct video_clip)*vw.clipcount))
return -EFAULT;
- /*
- * Impose display clips
- */
- if(btv->win.x<0)
- new_risc_clip(&vw, vcp, 0, 0, -btv->win.x, btv->win.height-1);
- if(btv->win.y<0)
- new_risc_clip(&vw, vcp, 0, 0, btv->win.width-1,-btv->win.y);
- if(btv->win.x+btv->win.width> btv->win.swidth)
- new_risc_clip(&vw, vcp, btv->win.swidth-btv->win.x, 0, btv->win.width-1, btv->win.height-1);
- if(btv->win.y+btv->win.height > btv->win.sheight)
- new_risc_clip(&vw, vcp, 0, btv->win.sheight-btv->win.y, btv->win.width-1, btv->win.height-1);
- /*
- * Question: Do we need to walk the clip list
- * and saw off any clips outside the window
- * frame or will write_risc_tab do the right
- * thing ?
- */
- write_risc_data(btv,vcp, vw.clipcount);
+ make_clip_tab(btv,vcp, vw.clipcount);
vfree(vcp);
if(on && btv->win.vidadr!=0)
bt848_cap(btv,1);
@@ -1764,7 +1707,7 @@
btv->win.vidadr=(unsigned long)v.base;
btv->win.sheight=v.height;
btv->win.swidth=v.width;
- btv->win.bpp=((v.depth+1)&0x38)/8;
+ btv->win.bpp=((v.depth+7)&0x38)/8;
btv->win.depth=v.depth;
btv->win.bpl=v.bytesperline;
@@ -1832,8 +1775,8 @@
return -EFAULT;
if(v.flags&VIDEO_AUDIO_MUTE)
audio(btv, AUDIO_MUTE);
- /* One audio source per tuner */
- if(v.audio!=0)
+ /* One audio source per tuner */
+ if(v.audio!=0)
return -EINVAL;
bt848_muxsel(btv,v.audio);
if(!(v.flags&VIDEO_AUDIO_MUTE))
@@ -1858,12 +1801,19 @@
}
case VIDIOCSYNC:
- if (!btv->grabbing)
- return -EAGAIN;
- if (btv->grab==btv->lastgrab)
- interruptible_sleep_on(&btv->capq);
- btv->lastgrab++;
- return 0;
+ if(copy_from_user((void *)&i,arg,sizeof(int)))
+ return -EFAULT;
+ switch (btv->frame_stat[i]) {
+ case GBUFFER_UNUSED:
+ return -EINVAL;
+ case GBUFFER_GRABBING:
+ interruptible_sleep_on(&btv->capq);
+ /* fall */
+ case GBUFFER_DONE:
+ btv->frame_stat[i] = GBUFFER_UNUSED;
+ break;
+ }
+ return 0;
case BTTV_WRITEE:
if(!capable(CAP_SYS_ADMIN))
@@ -1881,11 +1831,19 @@
return -EFAULT;
break;
+ case BTTV_FIELDNR:
+ if(copy_to_user((void *) arg, (void *) &btv->last_field,
+ sizeof(btv->last_field)))
+ return -EFAULT;
+ break;
+
case VIDIOCMCAPTURE:
{
struct video_mmap vm;
if(copy_from_user((void *) &vm, (void *) arg, sizeof(vm)))
return -EFAULT;
+ if (btv->frame_stat[vm.frame] == GBUFFER_GRABBING)
+ return -EBUSY;
return vgrab(btv, &vm);
}
@@ -2127,21 +2085,34 @@
static int radio_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
{
struct bttv *btv=(struct bttv *)(dev-1);
- static int lastchan=0;
switch (cmd) {
case VIDIOCGCAP:
- /* XXX */
+ {
+ struct video_capability v;
+ strcpy(v.name,btv->video_dev.name);
+ v.type = VID_TYPE_TUNER;
+ v.channels = 1;
+ v.audios = 1;
+ /* No we don't do pictures */
+ v.maxwidth = 0;
+ v.maxheight = 0;
+ v.minwidth = 0;
+ v.minheight = 0;
+ if (copy_to_user(arg, &v, sizeof(v)))
+ return -EFAULT;
+ return 0;
break;
+ }
case VIDIOCGTUNER:
{
struct video_tuner v;
if(copy_from_user(&v,arg,sizeof(v))!=0)
return -EFAULT;
- if(v.tuner||lastchan) /* Only tuner 0 */
+ if(v.tuner||btv->channel) /* Only tuner 0 */
return -EINVAL;
strcpy(v.name, "Radio");
v.rangelow=(int)(87.5*16);
- v.rangehigh=(int)(108.0*16);
+ v.rangehigh=(int)(108*16);
v.flags= 0; /* XXX */
v.mode = 0; /* XXX */
if(copy_to_user(arg,&v,sizeof(v)))
@@ -2154,7 +2125,7 @@
if(copy_from_user(&v, arg, sizeof(v)))
return -EFAULT;
/* Only channel 0 has a tuner */
- if(v.tuner!=0 || lastchan)
+ if(v.tuner!=0 || btv->channel)
return -EINVAL;
/* XXX anything to do ??? */
return 0;
@@ -2198,6 +2169,8 @@
};
static struct vidbases vbs[] = {
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_215CT222,
+ "ATI MACH64 CT", PCI_BASE_ADDRESS_0},
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_210888GX,
"ATI MACH64 Winturbo", PCI_BASE_ADDRESS_0},
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_215GT,
@@ -2214,8 +2187,12 @@
{ PCI_VENDOR_ID_MATROX, 0x051a, "Matrox Mystique", PCI_BASE_ADDRESS_1},
{ PCI_VENDOR_ID_N9, PCI_DEVICE_ID_N9_I128,
"Number Nine Imagine 128", PCI_BASE_ADDRESS_0},
+ { PCI_VENDOR_ID_N9, PCI_DEVICE_ID_N9_I128_2,
+ "Number Nine Imagine 128 Series 2", PCI_BASE_ADDRESS_0},
{ PCI_VENDOR_ID_S3, 0, "S3", PCI_BASE_ADDRESS_0},
{ PCI_VENDOR_ID_TSENG, 0, "TSENG", PCI_BASE_ADDRESS_0},
+ { PCI_VENDOR_ID_NVIDIA_SGS, PCI_DEVICE_ID_NVIDIA_SGS_RIVA128,
+ "Riva128", PCI_BASE_ADDRESS_1},
};
@@ -2409,13 +2386,16 @@
/* Figure out card and tuner type */
-static void idcard(struct bttv *btv)
+static void idcard(int i)
{
+ struct bttv *btv = &bttvs[i];
+
+ int tunertype;
btwrite(0, BT848_GPIO_OUT_EN);
- DEBUG(printk(KERN_DEBUG "bttv: GPIO: 0x%08x\n", btread(BT848_GPIO_DATA)));
+ DEBUG(printk(KERN_DEBUG "bttv%d: GPIO: 0x%08x\n", i, btread(BT848_GPIO_DATA)));
/* Default the card to the user-selected one. */
- btv->type=card;
+ btv->type=card[i];
btv->tuner_type=-1; /* use default tuner type */
/* If we were asked to auto-detect, then do so!
@@ -2440,13 +2420,13 @@
if (I2CRead(&(btv->i2c), I2C_TDA9850) >=0)
{
btv->audio_chip = TDA9850;
- printk(KERN_INFO "bttv: audio chip: TDA9850\n");
+ printk(KERN_INFO "bttv%d: audio chip: TDA9850\n", i);
}
if (I2CRead(&(btv->i2c), I2C_TDA8425) >=0)
{
btv->audio_chip = TDA8425;
- printk("bttv: audio chip: TDA8425\n");
+ printk("bttv%d: audio chip: TDA8425\n", i);
}
switch(btv->audio_chip)
@@ -2460,11 +2440,18 @@
}
/* How do I detect the tuner type for other cards but Miro ??? */
- printk(KERN_INFO "bttv: model: ");
+ printk(KERN_INFO "bttv%d: model: ", btv->nr);
switch (btv->type)
{
case BTTV_MIRO:
printk("MIRO\n");
+ if (btv->have_tuner)
+ {
+ tunertype=((btread(BT848_GPIO_DATA)>>10)-1)&7;
+ i2c_control_device(&(btv->i2c),
+ I2C_DRIVERID_TUNER,
+ TUNER_SET_TYPE,&tunertype);
+ }
strcpy(btv->video_dev.name,"BT848(Miro)");
break;
case BTTV_HAUPPAUGE:
@@ -2558,8 +2545,18 @@
/* reset the bt848 */
btwrite(0, BT848_SRESET);
+ DEBUG(printk(KERN_DEBUG "bttv%d: bt848_mem: 0x%08x\n",i,(unsigned int) btv->bt848_mem));
- DEBUG(printk(KERN_DEBUG "bttv: bt848_mem: 0x%08x\n",(unsigned int) btv->bt848_mem));
+#ifdef RESET_MSP_HAUPPAUGE
+ /* Reset the MSP on some Hauppauge cards */
+ /* Thanks to Kyösti Mälkki (kmalkki@cc.hut.fi)! */
+ /* Can this hurt cards without one? What about Miros with MSP? */
+ btaor(32, ~32, BT848_GPIO_OUT_EN);
+ btaor(0, ~32, BT848_GPIO_DATA);
+ udelay(2500);
+ btaor(32, ~32, BT848_GPIO_DATA);
+ btaor(0, ~32, BT848_GPIO_OUT_EN);
+#endif
/* default setup for max. PAL size in a 1024xXXX hicolor framebuffer */
@@ -2591,6 +2588,7 @@
btv->grabcount=0;
btv->grab=0;
btv->lastgrab=0;
+ btv->field=btv->last_field=0;
/* i2c */
memcpy(&(btv->i2c),&bttv_i2c_bus_template,sizeof(struct i2c_bus));
@@ -2642,8 +2640,8 @@
btwrite(0xd8, BT848_CONTRAST_LO);
bt848_bright(btv, 0x10);
- btwrite(0x60, BT848_E_VSCALE_HI);
- btwrite(0x60, BT848_O_VSCALE_HI);
+ btwrite(0x20, BT848_E_VSCALE_HI);
+ btwrite(0x20, BT848_O_VSCALE_HI);
btwrite(/*BT848_ADC_SYNC_T|*/
BT848_ADC_RESERVED|BT848_ADC_CRUSH, BT848_ADC);
@@ -2662,9 +2660,10 @@
btwrite(0xfffffUL, BT848_INT_STAT);
/* set interrupt mask */
- btwrite(triton1|
-/* BT848_INT_PABORT|BT848_INT_RIPERR|BT848_INT_PPERR|
- BT848_INT_FDSR|BT848_INT_FTRGT|BT848_INT_FBUS|*/
+ btwrite(btv->triton1|
+ /*BT848_INT_PABORT|BT848_INT_RIPERR|BT848_INT_PPERR|
+ BT848_INT_FDSR|BT848_INT_FTRGT|BT848_INT_FBUS|*/
+ BT848_INT_VSYNC|
BT848_INT_SCERR|
BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES|
BT848_INT_FMTCHG|BT848_INT_HLOCK,
@@ -2680,7 +2679,7 @@
memcpy(&btv->video_dev,&bttv_template, sizeof(bttv_template));
memcpy(&btv->vbi_dev,&vbi_template, sizeof(vbi_template));
memcpy(&btv->radio_dev,&radio_template,sizeof(radio_template));
- idcard(btv);
+ idcard(i);
if(video_register_device(&btv->video_dev,VFL_TYPE_GRABBER)<0)
return -1;
@@ -2689,7 +2688,7 @@
video_unregister_device(&btv->video_dev);
return -1;
}
- if (radio)
+ if (radio[i])
{
if(video_register_device(&btv->radio_dev, VFL_TYPE_RADIO)<0)
{
@@ -2720,28 +2719,28 @@
if (!astat)
return;
btwrite(astat,BT848_INT_STAT);
- IDEBUG(printk ("bttv: astat %08x\n",astat));
- IDEBUG(printk ("bttv: stat %08x\n",stat));
+ IDEBUG(printk ("bttv%d: astat %08x\n", btv->nr, astat));
+ IDEBUG(printk ("bttv%d: stat %08x\n", btv->nr, stat));
/* get device status bits */
dstat=btread(BT848_DSTATUS);
if (astat&BT848_INT_FMTCHG)
{
- IDEBUG(printk ("bttv: IRQ_FMTCHG\n"));
+ IDEBUG(printk ("bttv%d: IRQ_FMTCHG\n", btv->nr));
/*btv->win.norm&=
(dstat&BT848_DSTATUS_NUML) ? (~1) : (~0); */
}
if (astat&BT848_INT_VPRES)
{
- IDEBUG(printk ("bttv: IRQ_VPRES\n"));
+ IDEBUG(printk ("bttv%d: IRQ_VPRES\n", btv->nr));
}
if (astat&BT848_INT_VSYNC)
{
- IDEBUG(printk ("bttv: IRQ_VSYNC\n"));
+ IDEBUG(printk ("bttv%d: IRQ_VSYNC\n", btv->nr));
}
if (astat&BT848_INT_SCERR) {
- IDEBUG(printk ("bttv: IRQ_SCERR\n"));
+ IDEBUG(printk ("bttv%d: IRQ_SCERR\n", btv->nr));
bt848_dma(btv, 0);
bt848_dma(btv, 1);
wake_up_interruptible(&btv->vbiq);
@@ -2750,7 +2749,7 @@
}
if (astat&BT848_INT_RISCI)
{
- IDEBUG(printk ("bttv: IRQ_RISCI\n"));
+ IDEBUG(printk ("bttv%d: IRQ_RISCI\n", btv->nr));
/* captured VBI frame */
if (stat&(1<<28))
@@ -2763,10 +2762,14 @@
if (stat&(2<<28))
{
wake_up_interruptible(&btv->capq);
+ btv->last_field=btv->field;
+ btv->grab++;
+ btv->frame_stat[btv->grf] = GBUFFER_DONE;
if ((--btv->grabbing))
{
btv->gro = btv->gro_next;
btv->gre = btv->gre_next;
+ btv->grf = btv->grf_next;
btv->risc_jmp[5]=btv->gro;
btv->risc_jmp[11]=btv->gre;
bt848_set_geo(btv, btv->gwidth,
@@ -2792,31 +2795,31 @@
}
if (astat&BT848_INT_OCERR)
{
- IDEBUG(printk ("bttv: IRQ_OCERR\n"));
+ IDEBUG(printk ("bttv%d: IRQ_OCERR\n", btv->nr));
}
if (astat&BT848_INT_PABORT)
{
- IDEBUG(printk ("bttv: IRQ_PABORT\n"));
+ IDEBUG(printk ("bttv%d: IRQ_PABORT\n", btv->nr));
}
if (astat&BT848_INT_RIPERR)
{
- IDEBUG(printk ("bttv: IRQ_RIPERR\n"));
+ IDEBUG(printk ("bttv%d: IRQ_RIPERR\n", btv->nr));
}
if (astat&BT848_INT_PPERR)
{
- IDEBUG(printk ("bttv: IRQ_PPERR\n"));
+ IDEBUG(printk ("bttv%d: IRQ_PPERR\n", btv->nr));
}
if (astat&BT848_INT_FDSR)
{
- IDEBUG(printk ("bttv: IRQ_FDSR\n"));
+ IDEBUG(printk ("bttv%d: IRQ_FDSR\n", btv->nr));
}
if (astat&BT848_INT_FTRGT)
{
- IDEBUG(printk ("bttv: IRQ_FTRGT\n"));
+ IDEBUG(printk ("bttv%d: IRQ_FTRGT\n", btv->nr));
}
if (astat&BT848_INT_FBUS)
{
- IDEBUG(printk ("bttv: IRQ_FBUS\n"));
+ IDEBUG(printk ("bttv%d: IRQ_FBUS\n", btv->nr));
}
if (astat&BT848_INT_HLOCK)
{
@@ -2832,12 +2835,12 @@
count++;
if (count > 10)
- printk (KERN_WARNING "bttv: irq loop %d\n", count);
+ printk (KERN_WARNING "bttv%d: irq loop %d\n", btv->nr, count);
if (count > 20)
{
btwrite(0, BT848_INT_MASK);
printk(KERN_ERR
- "bttv: IRQ lockup, cleared int mask\n");
+ "bttv%d: IRQ lockup, cleared int mask\n", btv->nr);
}
}
}
@@ -2847,120 +2850,132 @@
/*
* Scan for a Bt848 card, request the irq and map the io memory
*/
-
-static int find_bt848(void)
+
+int configure_bt848(struct pci_dev *dev, int bttv_num)
{
- unsigned char command, latency;
int result;
+ unsigned char bus, devfn, command;
struct bttv *btv;
- struct pci_dev *dev;
- bttv_num=0;
+ btv=&bttvs[bttv_num];
+ btv->dev=dev;
+ btv->nr = bttv_num;
+ btv->bus=bus=dev->bus->number;
+ btv->devfn=devfn=dev->devfn;
+ btv->bt848_mem=NULL;
+ btv->vbibuf=NULL;
+ btv->risc_jmp=NULL;
+ btv->vbi_odd=NULL;
+ btv->vbi_even=NULL;
+ btv->vbiq=NULL;
+ btv->capq=NULL;
+ btv->capqo=NULL;
+ btv->capqe=NULL;
+ btv->vbip=VBIBUF_SIZE;
+
+ btv->id=dev->device;
+ btv->irq=dev->irq;
+ btv->bt848_adr=dev->base_address[0];
+ if (btv->id >= 878)
+ btv->i2c_command = 0x83;
+ else
+ btv->i2c_command=(I2C_TIMING | BT848_I2C_SCL | BT848_I2C_SDA);
- if (!pcibios_present())
- {
- DEBUG(printk(KERN_DEBUG "bttv: PCI-BIOS not present or not accessible!\n"));
- return 0;
- }
- for (dev = pci_devices; dev != NULL; dev = dev->next)
- {
- if (dev->vendor != PCI_VENDOR_ID_BROOKTREE)
- continue;
- if (dev->device != PCI_DEVICE_ID_BT849 &&
- dev->device != PCI_DEVICE_ID_BT848)
- continue;
-
- /* Ok, Bt848 or Bt849 found! */
- btv=&bttvs[bttv_num];
- btv->dev=dev;
- btv->bt848_mem=NULL;
- btv->vbibuf=NULL;
- btv->risc_jmp=NULL;
- btv->vbi_odd=NULL;
- btv->vbi_even=NULL;
- btv->vbiq=NULL;
- btv->capq=NULL;
- btv->capqo=NULL;
- btv->capqe=NULL;
-
- btv->vbip=VBIBUF_SIZE;
+ if (remap[bttv_num])
+ {
+ if (remap[bttv_num] < 0x1000)
+ remap[bttv_num]<<=20;
+ remap[bttv_num]&=PCI_BASE_ADDRESS_MEM_MASK;
+ printk(KERN_INFO "bttv%d: remapping to : 0x%08x.\n",
+ bttv_num,remap[bttv_num]);
+ remap[bttv_num]|=btv->bt848_adr&(~PCI_BASE_ADDRESS_MEM_MASK);
+ pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, remap[bttv_num]);
+ pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &btv->bt848_adr);
+ btv->dev->base_address[0] = btv->bt848_adr;
+ }
+ btv->bt848_adr&=PCI_BASE_ADDRESS_MEM_MASK;
+ pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
+ printk(KERN_INFO "bttv%d: Brooktree Bt%d (rev %d) ",
+ bttv_num,btv->id, btv->revision);
+ printk("bus: %d, devfn: %d, ",
+ btv->bus, btv->devfn);
+ printk("irq: %d, ",btv->irq);
+ printk("memory: 0x%08x.\n", btv->bt848_adr);
+
+ btv->pll=0;
+ if(pll[btv->nr])
+ if (!(btv->id==848 && btv->revision==0x11))
+ {
+ printk(KERN_INFO "bttv%d: internal PLL, single crystal operation enabled\n",bttv_num);
+ btv->pll=1;
+ }
+
+ btv->bt848_mem=ioremap(btv->bt848_adr, 0x1000);
+
+ /* clear interrupt mask */
+ btwrite(0, BT848_INT_MASK);
- pci_read_config_word (btv->dev, PCI_DEVICE_ID, &btv->id);
+ result = request_irq(btv->irq, bttv_irq,
+ SA_SHIRQ | SA_INTERRUPT,"bttv",(void *)btv);
+ if (result==-EINVAL)
+ {
+ printk(KERN_ERR "bttv%d: Bad irq number or handler\n",
+ bttv_num);
+ return -EINVAL;
+ }
+ if (result==-EBUSY)
+ {
+ printk(KERN_ERR "bttv%d: IRQ %d busy, change your PnP config in BIOS\n",bttv_num,btv->irq);
+ return result;
+ }
+ if (result < 0)
+ return result;
+
+ pci_set_master(dev);
- /* pci_read_config_dword(btv->dev, PCI_BASE_ADDRESS_0, &btv->bt848_adr); */
- btv->bt848_adr = btv->dev->base_address[0];
-
- if (remap&&(!bttv_num))
- {
- remap<<=20;
- remap&=PCI_BASE_ADDRESS_MEM_MASK;
- printk(KERN_INFO "Remapping to : 0x%08x.\n", remap);
- remap|=btv->bt848_adr&(~PCI_BASE_ADDRESS_MEM_MASK);
- pci_write_config_dword(btv->dev, PCI_BASE_ADDRESS_0, remap);
- pci_read_config_dword(btv->dev, PCI_BASE_ADDRESS_0, &btv->bt848_adr);
- btv->dev->base_address[0] = btv->bt848_adr;
- }
-
- btv->bt848_adr&=PCI_BASE_ADDRESS_MEM_MASK;
- pci_read_config_byte(btv->dev, PCI_CLASS_REVISION,
- &btv->revision);
- printk(KERN_INFO "bttv: Brooktree Bt%d (rev %d) ",
- btv->id, btv->revision);
- printk("bus: %d, devfn: %d, ",
- btv->dev->bus->number, btv->dev->devfn);
- printk("irq: %d, ",btv->dev->irq);
- printk("memory: 0x%08x.\n", btv->bt848_adr);
-
- btv->pll = 0;
-#ifdef USE_PLL
- if (btv->id==849 || (btv->id==848 && btv->revision==0x12))
+ btv->triton1=triton1 ? BT848_INT_ETBF : 0;
+ if (triton1 && btv->id >= 878)
+ {
+ btv->triton1 = 0;
+ printk("bttv: Enabling 430FX compatibilty for bt878\n");
+ pci_read_config_byte(dev, BT878_DEVCTRL, &command);
+ command|=BT878_EN_TBFX;
+ pci_write_config_byte(dev, BT878_DEVCTRL, command);
+ pci_read_config_byte(dev, BT878_DEVCTRL, &command);
+ if (!(command&BT878_EN_TBFX))
{
- printk(KERN_INFO "bttv: internal PLL, single crystal operation enabled.\n");
- btv->pll=1;
+ printk("bttv: 430FX compatibility could not be enabled\n");
+ return -1;
}
-#endif
-
- btv->bt848_mem=ioremap(btv->bt848_adr, 0x1000);
+ }
+
+ return 0;
+}
- result = request_irq(btv->dev->irq, bttv_irq,
- SA_SHIRQ | SA_INTERRUPT,"bttv",(void *)btv);
- if (result==-EINVAL)
- {
- printk(KERN_ERR "bttv: Bad irq number or handler\n");
- return -EINVAL;
- }
- if (result==-EBUSY)
- {
- printk(KERN_ERR "bttv: IRQ %d busy, change your PnP config in BIOS\n",btv->dev->irq);
- return result;
- }
- if (result < 0)
- return result;
+static int find_bt848(void)
+{
+ struct pci_dev *dev = pci_devices;
+ int result=0;
- /* Enable bus-mastering */
- pci_read_config_byte(btv->dev, PCI_COMMAND, &command);
- command|=PCI_COMMAND_MASTER;
- pci_write_config_byte(btv->dev, PCI_COMMAND, command);
- pci_read_config_byte(btv->dev, PCI_COMMAND, &command);
- if (!(command&PCI_COMMAND_MASTER))
- {
- printk(KERN_ERR "bttv: PCI bus-mastering could not be enabled\n");
- return -1;
- }
- pci_read_config_byte(btv->dev, PCI_LATENCY_TIMER, &latency);
- if (!latency)
- {
- latency=32;
- pci_write_config_byte(btv->dev, PCI_LATENCY_TIMER, latency);
- }
- DEBUG(printk(KERN_DEBUG "bttv: latency: %02x\n", latency));
- bttv_num++;
- }
+ bttv_num=0;
+
+ while (dev)
+ {
+ if (dev->vendor == PCI_VENDOR_ID_BROOKTREE)
+ if ((dev->device == PCI_DEVICE_ID_BT848)||
+ (dev->device == PCI_DEVICE_ID_BT849)||
+ (dev->device == PCI_DEVICE_ID_BT878)||
+ (dev->device == PCI_DEVICE_ID_BT879))
+ result=configure_bt848(dev,bttv_num++);
+ if (result)
+ return result;
+ dev = dev->next;
+ }
if(bttv_num)
printk(KERN_INFO "bttv: %d Bt848 card(s) found.\n", bttv_num);
return bttv_num;
}
-
+
static void release_bttv(void)
{
@@ -3009,7 +3024,7 @@
vfree((void *) btv->vbibuf);
- free_irq(btv->dev->irq,btv);
+ free_irq(btv->irq,btv);
DEBUG(printk(KERN_DEBUG "bt848_mem: 0x%08x.\n", btv->bt848_mem));
if (btv->bt848_mem)
iounmap(btv->bt848_mem);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov