aboutsummaryrefslogtreecommitdiffstats
path: root/bttv
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2010-04-01 11:24:35 +0200
committerGerd Hoffmann <kraxel@redhat.com>2010-04-01 11:24:35 +0200
commite258bb27135e755ea57c6d1e83e298d640913fc1 (patch)
tree0ae705962f55de0a13318168a6589c14d6f408e5 /bttv
parentbb218f6ab257e1ced214fcc815a2357313ac1e38 (diff)
v2.14
Diffstat (limited to 'bttv')
-rw-r--r--bttv/driver/bt848.h6
-rw-r--r--bttv/driver/bttv.c496
-rw-r--r--bttv/driver/bttv.h4
-rw-r--r--bttv/driver/i2c.c541
-rw-r--r--bttv/driver/i2c.h81
-rw-r--r--bttv/driver/linux-2.0.33.diff10
-rw-r--r--bttv/driver/msp3400.c93
-rw-r--r--bttv/driver/tuner.c172
-rw-r--r--bttv/driver/update4
-rw-r--r--bttv/driver/videodev.c57
-rw-r--r--bttv/driver/videodev.h8
-rw-r--r--bttv/experimental/Makefile61
-rw-r--r--bttv/experimental/README12
-rw-r--r--bttv/experimental/algo-bit.c893
-rw-r--r--bttv/experimental/algo-bit.h38
-rw-r--r--bttv/experimental/bt848.h348
-rw-r--r--bttv/experimental/bttv.c3261
-rw-r--r--bttv/experimental/bttv.h212
-rw-r--r--bttv/experimental/i2c.c385
-rw-r--r--bttv/experimental/i2c.h246
-rw-r--r--bttv/experimental/tuner.c270
-rw-r--r--bttv/experimental/tuner.h49
-rw-r--r--bttv/experimental/update40
-rw-r--r--bttv/experimental/videodev.c375
-rw-r--r--bttv/experimental/videodev.h214
25 files changed, 7176 insertions, 700 deletions
diff --git a/bttv/driver/bt848.h b/bttv/driver/bt848.h
index a50e31a..0956360 100644
--- a/bttv/driver/bt848.h
+++ b/bttv/driver/bt848.h
@@ -30,6 +30,12 @@
#ifndef PCI_DEVICE_ID_BT849
#define PCI_DEVICE_ID_BT849 0x351
#endif
+#ifndef PCI_DEVICE_ID_BT878
+#define PCI_DEVICE_ID_BT878 0x36e
+#endif
+#ifndef PCI_DEVICE_ID_BT879
+#define PCI_DEVICE_ID_BT879 0x36f
+#endif
/* Brooktree 848 registers */
diff --git a/bttv/driver/bttv.c b/bttv/driver/bttv.c
index d858dcd..7d1185b 100644
--- a/bttv/driver/bttv.c
+++ b/bttv/driver/bttv.c
@@ -30,9 +30,12 @@
* mmap VBI data?
* use new PCI routines
* fix RAW Composite grabbing for NTSC
- * allow for different VDELAY in RAW grabbing?
+ * allow for different VDELAYs
+ (larger to get Videodat in VBI and smaller to get the whole
+ picture in RAW grabbing)
* extra modules for tda9850, tda8425, any volunteers???
- * support 15bpp
+ * right border clipping is still buggy
+ (decide which clipping code to use and throw the other out ...)
*/
#include <linux/module.h>
@@ -86,13 +89,6 @@ copy_from_user(void *to, const void *from, unsigned long n)
#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=CARD_DEFAULT;
-
#if LINUX_VERSION_CODE >= 0x020117
MODULE_PARM(remap,"i");
MODULE_PARM(vidmem,"i");
@@ -107,6 +103,13 @@ static void bt848_set_risc_jmps(struct bttv *btv);
/* 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] = { CARD_DEFAULT };
+
static int bttv_num; /* number of Bt848s in use */
static struct bttv bttvs[BTTV_MAX];
@@ -221,7 +224,8 @@ static int fbuffer_alloc(struct bttv *btv)
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;
@@ -268,12 +272,17 @@ static int I2CRead(struct i2c_bus *bus, unsigned char addr)
stat=btread(BT848_INT_STAT);
if (stat & BT848_INT_I2CDONE)
break;
+#if LINUX_VERSION_CODE >= 0x020199
+ mdelay(1);
+#else
udelay(1000);
+#endif
}
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))
@@ -310,12 +319,17 @@ static int I2CWrite(struct i2c_bus *bus, unsigned char addr, unsigned char b1,
stat=btread(BT848_INT_STAT);
if (stat & BT848_INT_I2CDONE)
break;
+#if LINUX_VERSION_CODE >= 0x020199
+ mdelay(1);
+#else
udelay(1000);
+#endif
}
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))
@@ -430,7 +444,7 @@ struct tvcard
u32 gpiomask;
u32 muxsel[8];
u32 audiomux[6]; /* Tuner, Radio, internal, external, mute, stereo */
-
+ u32 gpiomask2; /* GPIO MUX mask */
};
static struct tvcard tvcards[] =
@@ -450,34 +464,18 @@ static struct tvcard tvcards[] =
/* AVerMedia TVPhone */
{ 3, 0, 2,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}},
};
#define TVCARDS (sizeof(tvcards)/sizeof(tvcard))
-/*
- * Tuner, Radio, internal, external and mute
- */
-
-static unsigned char audiomuxs[][5] =
-{
- { 0x00, 0x00, 0x00, 0x00, 0x00}, /* unknown */
- { 0x02, 0x00, 0x00, 0x00, 0x0a}, /* MIRO */
- { 0x00, 0x01, 0x02, 0x03, 0x04}, /* Hauppauge */
- { 0x04, 0x00, 0x02, 0x03, 0x01}, /* STB */
- { 0x00, 0x01, 0x02, 0x03, 0x04}, /* Intel??? */
- { 0x00, 0x01, 0x00, 0x01, 0x03}, /* Diamond DTV2000 */
- { 0x0c, 0x00, 0x0b, 0x0b, 0x00}, /* AVerMedia TVPhone */
-};
-
static void audio(struct bttv *btv, int mode)
{
btaor(tvcards[btv->type].gpiomask, ~tvcards[btv->type].gpiomask,
BT848_GPIO_OUT_EN);
-
switch (mode)
{
case AUDIO_MUTE:
@@ -499,8 +497,12 @@ static void audio(struct bttv *btv, int mode)
break;
}
/* if audio mute or not in H-lock, turn audio off */
- if ((btv->audio&AUDIO_MUTE) ||
- (!btv->radio && !(btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)))
+ if ((btv->audio&AUDIO_MUTE)
+#if 0
+ ||
+ (!btv->radio && !(btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC))
+#endif
+ )
mode=AUDIO_OFF;
if ((mode == 0) && (btv->radio))
mode = 1;
@@ -561,6 +563,7 @@ static int set_pll(struct bttv *btv)
btwrite(0xdc,BT848_PLL_F_HI);
btwrite(0x8e,BT848_PLL_XCI);
+ /* Ugh ugh ugh .. schedule ? */
udelay(100000);
for (i=0; i<100; i++)
{
@@ -572,14 +575,19 @@ static int set_pll(struct bttv *btv)
btv->pll|=2;
return 1;
}
+#if LINUX_VERSION_CODE >= 0x020199
+ mdelay(10);
+#else
udelay(10000);
+#endif
}
return -1;
}
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);
@@ -601,24 +609,7 @@ static void bt848_muxsel(struct bttv *btv, unsigned int input)
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 (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);
-*/
+ ~tvcards[btv->type].gpiomask2, BT848_GPIO_DATA);
}
@@ -681,14 +672,15 @@ 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++)
{
@@ -894,77 +886,77 @@ static void make_clip_tab(struct bttv *btv, struct cliprec *cr, int count)
*(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;
+ 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->y2 < 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->x2-x+1;
- }
- else
- if (x+dx < cur2->x2)
- dx=cur2->x2-x+1;
- }
- 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;
+ /* remove rects with y2 > y */
+ if ((cur=first2.next))
+ {
+ prev=&first2;
+ do
+ {
+ if (cur->y2 < 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->x2-x+1;
+ }
+ else if (x+dx < cur2->x2)
+ dx=cur2->x2-x+1;
+ }
+ 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;
@@ -982,7 +974,7 @@ static void make_clip_tab(struct bttv *btv, struct cliprec *cr, int count)
struct tvnorm
{
- u16 cropwidth, cropheight;
+ u16 swidth, sheight; /* scaled standard width, height */
u16 totalwidth;
u8 adelay, bdelay, iform;
u32 scaledtwidth;
@@ -992,8 +984,15 @@ struct tvnorm
static struct tvnorm tvnorms[] = {
/* PAL-BDGHI */
+ //{ 1024, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
+ // 1135, 100, 1024, 0x20},
+
+ { 914, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
+ 1135, 186+16, 914, 0x20},
+/*
{ 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},
@@ -1059,6 +1058,10 @@ static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, u16 fmt)
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)
@@ -1068,7 +1071,7 @@ static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, u16 fmt)
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);
@@ -1115,35 +1118,23 @@ int bpp2fmt[4] = {
static void bt848_set_winsize(struct bttv *btv)
{
unsigned short format;
- int bpp;
- btv->win.color_fmt=format= (btv->win.depth==15) ? BT848_COLOR_FMT_RGB15 :
- bpp2fmt[(btv->win.bpp-1)&3];
-/*
- bpp=fmtbppx2[btv->win.color_fmt&0x0f]/2;
- if (btv->win.bpp == 0)
- {
- btv->win.bpp=bpp;
- format=btv->win.color_fmt;
- }
- else if (btv->win.bpp!=bpp)
- btv->win.color_fmt=format=bpp2fmt[(btv->win.bpp-1)&3];
- else
- format=btv->win.color_fmt;
-*/
+ 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
* datasheet??? [AC - because its a standard format so I guess
* it never occured them]
* Enable dithering in this mode
*/
-/*
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);
-*/
- 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);
}
/*
@@ -1709,7 +1700,9 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
v.flags=VIDEO_VC_AUDIO;
v.tuners=0;
v.type=VIDEO_TYPE_CAMERA;
+#if 0
v.mode = btv->win.norm;
+#endif
switch(v.channel)
{
case 0:
@@ -1739,15 +1732,11 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
*/
case VIDIOCSCHAN:
{
- struct video_channel v;
+ int v;
if(copy_from_user(&v, arg, sizeof(v)))
return -EFAULT;
- bt848_muxsel(btv, v.channel);
- lastchan=v.channel;
-#if 0
- btv->win.norm = v.mode;
- bt848_set_winsize(btv);
-#endif
+ bt848_muxsel(btv, v);
+ lastchan=v;
return 0;
}
case VIDIOCGTUNER:
@@ -1760,8 +1749,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
strcpy(v.name, "Television");
v.rangelow=0;
v.rangehigh=0xFFFFFFFF;
- v.flags=VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|
- VIDEO_TUNER_SECAM;
+ v.flags=VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC;
v.mode = btv->win.norm;
if(copy_to_user(arg,&v,sizeof(v)))
return -EFAULT;
@@ -1770,18 +1758,19 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
/* We have but tuner 0 */
case VIDIOCSTUNER:
{
+ /* FIXME: norm should be in video_channel struct
+ composite source can have different norms too
+ */
+
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 1 channel has a tuner */
+ /*if(v.tuner!=tvcards[btv->type].tuner || lastchan)
+ 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);
return 0;
@@ -1819,7 +1808,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
bt848_hue(btv, (p.hue>>8)-128);
/* 0-511 */
bt848_contrast(btv, p.contrast>>7);
- btv->picture=p;
+ btv->picture = p;
/* set palette if bpp matches */
if (p.palette < sizeof(palette2fmt)/sizeof(int)) {
@@ -1941,23 +1930,33 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
case VIDIOCSFBUF:
{
struct video_buffer v;
+#if LINUX_VERSION_CODE >= 0x020100
+ if(!capable(CAP_SYS_ADMIN))
+#else
if(!suser())
+#endif
return -EPERM;
if(copy_from_user(&v, arg,sizeof(v)))
return -EFAULT;
if(v.depth!=8 && v.depth!=16 && v.depth!=15
&& v.depth!=24 && v.depth!=32)
return -EINVAL;
- if (v.base)
+ if (v.base)
+ {
/* also handle virtual base addresses */
if ((unsigned int)v.base>=0xe0000000UL)
btv->win.vidadr=(uint)v.base;
else
- btv->win.vidadr=PAGE_OFFSET|
- uvirt_to_bus((uint)v.base);
+ btv->win.vidadr=
+#if LINUX_VERSION_CODE >= 0x020199
+ __va(uvirt_to_bus((uint)v.base));
+#else
+ PAGE_OFFSET|uvirt_to_bus((uint)v.base);
+#endif
+ }
btv->win.sheight=v.height;
btv->win.swidth=v.width;
- btv->win.bpp=((v.depth+1)&0x18)/8;
+ btv->win.bpp=((v.depth+7)&0x38)/8;
btv->win.depth=v.depth;
btv->win.bpl=v.bytesperline;
@@ -2023,11 +2022,12 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
struct video_audio v;
if(copy_from_user(&v,arg, sizeof(v)))
return -EFAULT;
- if(v.audio<0||v.audio>2)
- return -EINVAL;
- bt848_muxsel(btv,v.audio);
if(v.flags&VIDEO_AUDIO_MUTE)
audio(btv, AUDIO_MUTE);
+ /* One audio source per tuner */
+ if(v.audio!=0)
+ return -EINVAL;
+ bt848_muxsel(btv,v.audio);
if(!(v.flags&VIDEO_AUDIO_MUTE))
audio(btv, AUDIO_UNMUTE);
if (btv->have_msp3400)
@@ -2073,7 +2073,11 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
return 0;
case BTTV_WRITEE:
+#if LINUX_VERSION_CODE >= 0x020100
+ if(!capable(CAP_SYS_ADMIN))
+#else
if(!suser())
+#endif
return -EPERM;
if(copy_from_user((void *) eedata, (void *) arg, 256))
return -EFAULT;
@@ -2081,13 +2085,23 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
return 0;
case BTTV_READEE:
+#if LINUX_VERSION_CODE >= 0x020100
+ if(!capable(CAP_SYS_ADMIN))
+#else
if(!suser())
+#endif
return -EPERM;
readee(&(btv->i2c), eedata);
if(copy_to_user((void *) arg, (void *) eedata, 256))
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;
@@ -2358,7 +2372,6 @@ static struct vidbases vbs[] = {
/* This id is not defined in pci.h but this entry was mailed to me?!?
{ PCI_VENDOR_ID_ALLIANCE, PCI_DEVICE_ID_ALLIANCE_AT25,
"Alliance AT25", PCI_BASE_ADDRESS_0},
-
*/
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_210888GX,
"ATI MACH64 Winturbo", PCI_BASE_ADDRESS_0},
@@ -2372,6 +2385,8 @@ static struct vidbases vbs[] = {
{ 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},
};
@@ -2429,6 +2444,8 @@ static int find_vga(void)
break;
}
}
+ if (NR_CARDS == i)
+ printk("UNKNOWN.\n");
if (!badr)
{
printk(KERN_ERR "bttv: Unknown video memory base address.\n");
@@ -2444,7 +2461,7 @@ static int find_vga(void)
vidadr &= PCI_BASE_ADDRESS_MEM_MASK;
if (!vidadr)
{
- printk(KERN_ERR "bttv: Memory @ 0, must be something wrong!");
+ printk(KERN_ERR "bttv: Memory @ 0, must be something wrong!\n");
continue;
}
@@ -2468,7 +2485,10 @@ static int find_vga(void)
if (vidmem)
{
- vidadr=vidmem<<20;
+ if (vidmem < 0x1000)
+ vidadr=vidmem<<20;
+ else
+ vidadr=vidmem;
printk(KERN_INFO "bttv: Video memory override: 0x%08x\n", vidadr);
found=1;
}
@@ -2562,7 +2582,8 @@ static void handle_chipset(void)
}
-static void init_tda8425(struct i2c_bus *bus) {
+static void init_tda8425(struct i2c_bus *bus)
+{
I2CWrite(bus, I2C_TDA8425, TDA8425_VL, 0xFC, 1); /* volume left 0dB */
I2CWrite(bus, I2C_TDA8425, TDA8425_VR, 0xFC, 1); /* volume right 0dB */
I2CWrite(bus, I2C_TDA8425, TDA8425_BA, 0xF6, 1); /* bass 0dB */
@@ -2587,14 +2608,16 @@ static void init_tda9850(struct i2c_bus *bus)
/* 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];
/* If we were asked to auto-detect, then do so!
Right now this will only recognize Miro, Hauppauge or STB
@@ -2612,28 +2635,28 @@ static void idcard(struct bttv *btv)
if (I2CRead(&(btv->i2c), I2C_TDA9850) >=0)
{
- btv->audio_chip = TDA9850;
- printk("bttv: audio chip: TDA9850\n");
+ btv->audio_chip = TDA9850;
+ printk(KERN_INFO "bttv%d: audio chip: TDA9850\n",btv->nr);
}
if (I2CRead(&(btv->i2c), I2C_TDA8425) >=0)
{
- btv->audio_chip = TDA8425;
- printk("bttv: audio chip: TDA8425\n");
+ btv->audio_chip = TDA8425;
+ printk(KERN_INFO "bttv%d: audio chip: TDA8425\n",btv->nr);
}
switch(btv->audio_chip)
{
case TDA9850:
init_tda9850(&(btv->i2c));
- break;
+ break;
case TDA8425:
init_tda8425(&(btv->i2c));
break;
}
-
+
/* 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:
@@ -2729,8 +2752,6 @@ static void bt848_set_risc_jmps(struct bttv *btv)
bt848_dma(btv, 0);
}
-
-
static int init_bt848(int i)
{
struct bttv *btv = &bttvs[i];
@@ -2739,15 +2760,9 @@ static int init_bt848(int i)
/* reset the bt848 */
btwrite(0, BT848_SRESET);
-
-
- //set_pll(btv);
-
- DEBUG(printk(KERN_DEBUG "bttv: bt848_mem: 0x%08x\n",(unsigned int) btv->bt848_mem));
-
+ DEBUG(printk(KERN_DEBUG "bttv%d: bt848_mem: 0x%08x\n",i,(unsigned int) btv->bt848_mem));
/* 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;
@@ -2776,6 +2791,7 @@ static int init_bt848(int i)
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));
@@ -2825,8 +2841,8 @@ static int init_bt848(int i)
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);
@@ -2846,11 +2862,12 @@ static int init_bt848(int i)
/* set interrupt mask */
btwrite(triton1|
-/* BT848_INT_PABORT|BT848_INT_RIPERR|BT848_INT_PPERR|
- BT848_INT_FDSR|BT848_INT_FTRGT|BT848_INT_FBUS|*/
+ /*BT848_INT_PABORT|BT848_INT_RIPERR|BT848_INT_PPERR|
+ BT848_INT_FDSR|BT848_INT_FTRGT|eBT848_INT_FBUS|*/
+ BT848_INT_VSYNC|
BT848_INT_SCERR|
BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES|
- BT848_INT_FMTCHG|BT848_INT_HLOCK,
+ BT848_INT_FMTCHG|BT848_INT_HLOCK,
BT848_INT_MASK);
make_vbitab(btv);
@@ -2863,7 +2880,7 @@ static int init_bt848(int i)
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;
@@ -2903,28 +2920,29 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
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));
+ btv->field++;
}
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);
@@ -2933,7 +2951,7 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
}
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))
@@ -2945,6 +2963,7 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
/* captured full frame */
if (stat&(2<<28))
{
+ btv->last_field=btv->field;
btv->grab++;
btv->frame_stat[btv->grf] = GBUFFER_DONE;
if ((--btv->grabbing))
@@ -2977,31 +2996,31 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
}
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)
{
@@ -3017,12 +3036,14 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
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);
}
}
}
@@ -3045,18 +3066,23 @@ static int find_bt848(void)
if (!pcibios_present())
{
- DEBUG(printk(KERN_DEBUG "bttv: PCI-BIOS not present or not accessable!\n"));
+ DEBUG(printk(KERN_DEBUG "bttv%d: PCI-BIOS not present or not accessable!\n",bttv_num));
return 0;
}
for (pci_index = 0;
!pcibios_find_device(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849,
- pci_index, &bus, &devfn)
- ||!pcibios_find_device(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
- pci_index, &bus, &devfn);
- ++pci_index)
+ pci_index, &bus, &devfn)
+ ||!pcibios_find_device(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
+ pci_index, &bus, &devfn)
+ ||!pcibios_find_device(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878,
+ pci_index, &bus, &devfn)
+ ||!pcibios_find_device(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879,
+ pci_index, &bus, &devfn);
+ ++pci_index)
{
btv=&bttvs[bttv_num];
+ btv->nr = bttv_num;
btv->bus=bus;
btv->devfn=devfn;
btv->bt848_mem=NULL;
@@ -3078,14 +3104,16 @@ static int find_bt848(void)
pcibios_read_config_dword(btv->bus, btv->devfn, PCI_BASE_ADDRESS_0,
&btv->bt848_adr);
- 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);
+ 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);
pcibios_write_config_dword(btv->bus, btv->devfn, PCI_BASE_ADDRESS_0,
- remap);
+ remap[bttv_num]);
pcibios_read_config_dword(btv->bus, btv->devfn, PCI_BASE_ADDRESS_0,
&btv->bt848_adr);
}
@@ -3093,18 +3121,18 @@ static int find_bt848(void)
btv->bt848_adr&=PCI_BASE_ADDRESS_MEM_MASK;
pcibios_read_config_byte(btv->bus, btv->devfn, PCI_CLASS_REVISION,
&btv->revision);
- printk(KERN_INFO "bttv: Brooktree Bt%d (rev %d) ",
- btv->id, 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);
+ btv->bus, btv->devfn);
printk("irq: %d, ",btv->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))
+ if (!(btv->id==848 && btv->revision==0x11))
{
- printk("bttv: internal PLL, single crystal operation enabled\n");
+ printk(KERN_INFO "bttv%d: internal PLL, single crystal operation enabled\n",bttv_num);
btv->pll=1;
}
#endif
@@ -3115,12 +3143,13 @@ static int find_bt848(void)
SA_SHIRQ | SA_INTERRUPT,"bttv",(void *)btv);
if (result==-EINVAL)
{
- printk(KERN_ERR "bttv: Bad irq number or handler\n");
+ printk(KERN_ERR "bttv%d: Bad irq number or handler\n",
+ bttv_num);
return -EINVAL;
}
if (result==-EBUSY)
{
- printk(KERN_ERR "bttv: IRQ %d busy, change your PnP config in BIOS\n",btv->irq);
+ printk(KERN_ERR "bttv%d: IRQ %d busy, change your PnP config in BIOS\n",bttv_num,btv->irq);
return result;
}
if (result < 0)
@@ -3133,7 +3162,7 @@ static int find_bt848(void)
pcibios_read_config_byte(btv->bus, btv->devfn, PCI_COMMAND, &command);
if (!(command&PCI_COMMAND_MASTER))
{
- printk(KERN_ERR "bttv: PCI bus-mastering could not be enabled\n");
+ printk(KERN_ERR "bttv%d: PCI bus-mastering could not be enabled\n",bttv_num);
return -1;
}
pcibios_read_config_byte(btv->bus, btv->devfn, PCI_LATENCY_TIMER,
@@ -3144,7 +3173,8 @@ static int find_bt848(void)
pcibios_write_config_byte(btv->bus, btv->devfn,
PCI_LATENCY_TIMER, latency);
}
- DEBUG(printk(KERN_DEBUG "bttv: latency: %02x\n", latency));
+ DEBUG(printk(KERN_DEBUG "bttv%d: latency: %02x\n",
+ bttv_num, latency));
bttv_num++;
}
if(bttv_num)
diff --git a/bttv/driver/bttv.h b/bttv/driver/bttv.h
index c202f5e..73bdcf0 100644
--- a/bttv/driver/bttv.h
+++ b/bttv/driver/bttv.h
@@ -77,6 +77,7 @@ struct bttv
int have_msp3400;
int have_tuner;
+ unsigned int nr;
unsigned short id;
unsigned char bus; /* PCI bus the Bt848 is on */
unsigned char devfn;
@@ -136,6 +137,8 @@ struct bttv
int grabcount;
int pll;
+ unsigned int field;
+ unsigned int last_field; /* number of last grabbed field */
};
#endif
@@ -160,6 +163,7 @@ struct bttv
#define BTTV_READEE _IOW('v', BASE_VIDIOCPRIVATE+0, char [256])
#define BTTV_WRITEE _IOR('v', BASE_VIDIOCPRIVATE+1, char [256])
#define BTTV_GRAB _IOR('v' , BASE_VIDIOCPRIVATE+2, struct gbuf)
+#define BTTV_FIELDNR _IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int)
#define BTTV_UNKNOWN 0x00
diff --git a/bttv/driver/i2c.c b/bttv/driver/i2c.c
index 736ddc5..f8c8d55 100644
--- a/bttv/driver/i2c.c
+++ b/bttv/driver/i2c.c
@@ -1,7 +1,7 @@
/*
- * Generic i2c interface for linux
+ * Generic i2c interface for linux
*
- * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
+ * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
*
*/
@@ -23,6 +23,7 @@
static int scan = 0;
static int verbose = 1;
static int i2c_debug = 0;
+
#if LINUX_VERSION_CODE >= 0x020117
MODULE_PARM(scan,"i");
MODULE_PARM(verbose,"i");
@@ -37,221 +38,238 @@ static int bus_count = 0, driver_count = 0;
int i2c_init(void)
{
- printk(KERN_INFO "i2c: initialized%s\n",
- scan ? " (i2c bus scan enabled)" : "");
- /* anything to do here ? */
- return 0;
+ printk(KERN_INFO "i2c: initialized%s\n",
+ scan ? " (i2c bus scan enabled)" : "");
+ /* anything to do here ? */
+ return 0;
}
/* ----------------------------------------------------------------------- */
static void i2c_attach_device(struct i2c_bus *bus, struct i2c_driver *driver)
{
- unsigned long flags;
- struct i2c_device *device;
- int i,j,ack=1;
- unsigned char addr;
+ unsigned long flags;
+ struct i2c_device *device;
+ int i,j,ack=1;
+ unsigned char addr;
- /* probe for device */
- LOCK_I2C_BUS(bus);
- for (addr = driver->addr_l; addr <= driver->addr_h; addr += 2) {
- i2c_start(bus);
- ack = i2c_sendbyte(bus,addr,0);
- i2c_stop(bus);
- if (!ack)
- break;
- }
- UNLOCK_I2C_BUS(bus);
- if (ack)
- return;
-
- /* got answer */
- for (i = 0; i < I2C_DEVICE_MAX; i++)
- if (NULL == driver->devices[i])
- break;
- if (I2C_DEVICE_MAX == i)
- return;
-
- for (j = 0; j < I2C_DEVICE_MAX; j++)
- if (NULL == bus->devices[j])
- break;
- if (I2C_DEVICE_MAX == j)
- return;
-
- if (NULL == (device = kmalloc(sizeof(struct i2c_device),GFP_KERNEL)))
- return;
- device->bus = bus;
- device->driver = driver;
- device->addr = addr;
-
- /* attach */
- if (0 != driver->attach(device)) {
- kfree(device);
- return;
- }
- driver->devices[i] = device;
- driver->devcount++;
- bus->devices[j] = device;
- bus->devcount++;
-
- if (bus->attach_inform)
- bus->attach_inform(bus,driver->id);
- REGPRINT(printk("i2c: device attached: %s (addr=0x%02x, bus=%s, driver=%s)\n",device->name,addr,bus->name,driver->name));
+ /* probe for device */
+ LOCK_I2C_BUS(bus);
+ for (addr = driver->addr_l; addr <= driver->addr_h; addr += 2)
+ {
+ i2c_start(bus);
+ ack = i2c_sendbyte(bus,addr,0);
+ i2c_stop(bus);
+ if (!ack)
+ break;
+ }
+ UNLOCK_I2C_BUS(bus);
+ if (ack)
+ return;
+
+ /* got answer */
+ for (i = 0; i < I2C_DEVICE_MAX; i++)
+ if (NULL == driver->devices[i])
+ break;
+ if (I2C_DEVICE_MAX == i)
+ return;
+
+ for (j = 0; j < I2C_DEVICE_MAX; j++)
+ if (NULL == bus->devices[j])
+ break;
+ if (I2C_DEVICE_MAX == j)
+ return;
+
+ if (NULL == (device = kmalloc(sizeof(struct i2c_device),GFP_KERNEL)))
+ return;
+ device->bus = bus;
+ device->driver = driver;
+ device->addr = addr;
+
+ /* Attach */
+
+ if (driver->attach(device)!=0)
+ {
+ kfree(device);
+ return;
+ }
+ driver->devices[i] = device;
+ driver->devcount++;
+ bus->devices[j] = device;
+ bus->devcount++;
+
+ if (bus->attach_inform)
+ bus->attach_inform(bus,driver->id);
+ REGPRINT(printk("i2c: device attached: %s (addr=0x%02x, bus=%s, driver=%s)\n",device->name,addr,bus->name,driver->name));
}
static void i2c_detach_device(struct i2c_device *device)
{
- int i;
-
- if (device->bus->detach_inform)
- device->bus->detach_inform(device->bus,device->driver->id);
- device->driver->detach(device);
-
- for (i = 0; i < I2C_DEVICE_MAX; i++)
- if (device == device->driver->devices[i])
- break;
- if (I2C_DEVICE_MAX == i) {
- printk(KERN_WARNING "i2c: detach_device #1: device not found: %s\n",
- device->name);
- return;
- }
- device->driver->devices[i] = NULL;
- device->driver->devcount--;
-
- for (i = 0; i < I2C_DEVICE_MAX; i++)
- if (device == device->bus->devices[i])
- break;
- if (I2C_DEVICE_MAX == i) {
- printk(KERN_WARNING "i2c: detach_device #2: device not found: %s\n",
- device->name);
- return;
- }
- device->bus->devices[i] = NULL;
- device->bus->devcount--;
-
- REGPRINT(printk("i2c: device detached: %s (addr=0x%02x, bus=%s, driver=%s)\n",device->name,device->addr,device->bus->name,device->driver->name));
- kfree(device);
+ int i;
+
+ if (device->bus->detach_inform)
+ device->bus->detach_inform(device->bus,device->driver->id);
+ device->driver->detach(device);
+
+ for (i = 0; i < I2C_DEVICE_MAX; i++)
+ if (device == device->driver->devices[i])
+ break;
+ if (I2C_DEVICE_MAX == i)
+ {
+ printk(KERN_WARNING "i2c: detach_device #1: device not found: %s\n",
+ device->name);
+ return;
+ }
+ device->driver->devices[i] = NULL;
+ device->driver->devcount--;
+
+ for (i = 0; i < I2C_DEVICE_MAX; i++)
+ if (device == device->bus->devices[i])
+ break;
+ if (I2C_DEVICE_MAX == i)
+ {
+ printk(KERN_WARNING "i2c: detach_device #2: device not found: %s\n",
+ device->name);
+ return;
+ }
+ device->bus->devices[i] = NULL;
+ device->bus->devcount--;
+
+ REGPRINT(printk("i2c: device detached: %s (addr=0x%02x, bus=%s, driver=%s)\n",device->name,device->addr,device->bus->name,device->driver->name));
+ kfree(device);
}
/* ----------------------------------------------------------------------- */
int i2c_register_bus(struct i2c_bus *bus)
{
- unsigned long flags;
- int i,ack;
-
- memset(bus->devices,0,sizeof(bus->devices));
- bus->devcount = 0;
-
- for (i = 0; i < I2C_BUS_MAX; i++)
- if (NULL == busses[i])
- break;
- if (I2C_BUS_MAX == i)
- return -ENOMEM;
-
- busses[i] = bus;
- bus_count++;
- REGPRINT(printk("i2c: bus registered: %s\n",bus->name));
-
- LOCK_I2C_BUS(bus);
- i2c_reset(bus);
- if (scan) {
- /* scan whole i2c bus */
- for (i = 0; i < 256; i+=2) {
- i2c_start(bus);
- ack = i2c_sendbyte(bus,i,0);
- i2c_stop(bus);
- if (!ack) {
- printk("i2c: scanning bus %s: found device at addr=0x%02x\n",
- bus->name,i);
- }
+ unsigned long flags;
+ int i,ack;
+
+ memset(bus->devices,0,sizeof(bus->devices));
+ bus->devcount = 0;
+
+ for (i = 0; i < I2C_BUS_MAX; i++)
+ if (NULL == busses[i])
+ break;
+ if (I2C_BUS_MAX == i)
+ return -ENOMEM;
+
+ busses[i] = bus;
+ bus_count++;
+ REGPRINT(printk("i2c: bus registered: %s\n",bus->name));
+
+ MOD_INC_USE_COUNT;
+
+ if (scan)
+ {
+ /* scan whole i2c bus */
+ LOCK_I2C_BUS(bus);
+ for (i = 0; i < 256; i+=2)
+ {
+ i2c_start(bus);
+ ack = i2c_sendbyte(bus,i,0);
+ i2c_stop(bus);
+ if (!ack)
+ {
+ printk(KERN_INFO "i2c: scanning bus %s: found device at addr=0x%02x\n",
+ bus->name,i);
+ }
+ }
+ UNLOCK_I2C_BUS(bus);
}
- }
- UNLOCK_I2C_BUS(bus);
-
- /* probe available drivers */
- for (i = 0; i < I2C_DRIVER_MAX; i++)
- if (drivers[i])
- i2c_attach_device(bus,drivers[i]);
- return 0;
+ /* probe available drivers */
+ for (i = 0; i < I2C_DRIVER_MAX; i++)
+ if (drivers[i])
+ i2c_attach_device(bus,drivers[i]);
+ return 0;
}
int i2c_unregister_bus(struct i2c_bus *bus)
{
- int i;
-
- /* detach devices */
- for (i = 0; i < I2C_DEVICE_MAX; i++)
- if (bus->devices[i])
- i2c_detach_device(bus->devices[i]);
-
- for (i = 0; i < I2C_BUS_MAX; i++)
- if (bus == busses[i])
- break;
- if (I2C_BUS_MAX == i) {
- printk(KERN_WARNING "i2c: unregister_bus #1: bus not found: %s\n",
- bus->name);
- return -ENODEV;
- }
-
- busses[i] = NULL;
- bus_count--;
- REGPRINT(printk("i2c: bus unregistered: %s\n",bus->name));
-
- return 0;
+ int i;
+
+ /* detach devices */
+ for (i = 0; i < I2C_DEVICE_MAX; i++)
+ if (bus->devices[i])
+ i2c_detach_device(bus->devices[i]);
+
+ for (i = 0; i < I2C_BUS_MAX; i++)
+ if (bus == busses[i])
+ break;
+ if (I2C_BUS_MAX == i)
+ {
+ printk(KERN_WARNING "i2c: unregister_bus #1: bus not found: %s\n",
+ bus->name);
+ return -ENODEV;
+ }
+
+ MOD_DEC_USE_COUNT;
+
+ busses[i] = NULL;
+ bus_count--;
+ REGPRINT(printk("i2c: bus unregistered: %s\n",bus->name));
+
+ return 0;
}
/* ----------------------------------------------------------------------- */
int i2c_register_driver(struct i2c_driver *driver)
{
- int i;
-
- memset(driver->devices,0,sizeof(driver->devices));
- driver->devcount = 0;
-
- for (i = 0; i < I2C_DRIVER_MAX; i++)
- if (NULL == drivers[i])
- break;
- if (I2C_DRIVER_MAX == i)
- return -ENOMEM;
-
- drivers[i] = driver;
- driver_count++;
- REGPRINT(printk("i2c: driver registered: %s\n",driver->name));
-
- /* probe available busses */
- for (i = 0; i < I2C_BUS_MAX; i++)
- if (busses[i])
- i2c_attach_device(busses[i],driver);
-
- return 0;
+ int i;
+
+ memset(driver->devices,0,sizeof(driver->devices));
+ driver->devcount = 0;
+
+ for (i = 0; i < I2C_DRIVER_MAX; i++)
+ if (NULL == drivers[i])
+ break;
+ if (I2C_DRIVER_MAX == i)
+ return -ENOMEM;
+
+ drivers[i] = driver;
+ driver_count++;
+
+ MOD_INC_USE_COUNT;
+
+ REGPRINT(printk("i2c: driver registered: %s\n",driver->name));
+
+ /* Probe available busses */
+ for (i = 0; i < I2C_BUS_MAX; i++)
+ if (busses[i])
+ i2c_attach_device(busses[i],driver);
+
+ return 0;
}
int i2c_unregister_driver(struct i2c_driver *driver)
{
- int i;
-
- /* detach devices */
- for (i = 0; i < I2C_DEVICE_MAX; i++)
- if (driver->devices[i])
- i2c_detach_device(driver->devices[i]);
-
- for (i = 0; i < I2C_DRIVER_MAX; i++)
- if (driver == drivers[i])
- break;
- if (I2C_DRIVER_MAX == i) {
- printk(KERN_WARNING "i2c: unregister_driver: driver not found: %s\n",
- driver->name);
- return -ENODEV;
- }
-
- drivers[i] = NULL;
- driver_count--;
- REGPRINT(printk("i2c: driver unregistered: %s\n",driver->name));
-
- return 0;
+ int i;
+
+ /* detach devices */
+ for (i = 0; i < I2C_DEVICE_MAX; i++)
+ if (driver->devices[i])
+ i2c_detach_device(driver->devices[i]);
+
+ for (i = 0; i < I2C_DRIVER_MAX; i++)
+ if (driver == drivers[i])
+ break;
+ if (I2C_DRIVER_MAX == i)
+ {
+ printk(KERN_WARNING "i2c: unregister_driver: driver not found: %s\n",
+ driver->name);
+ return -ENODEV;
+ }
+
+ MOD_DEC_USE_COUNT;
+
+ drivers[i] = NULL;
+ driver_count--;
+ REGPRINT(printk("i2c: driver unregistered: %s\n",driver->name));
+
+ return 0;
}
/* ----------------------------------------------------------------------- */
@@ -259,16 +277,16 @@ int i2c_unregister_driver(struct i2c_driver *driver)
int i2c_control_device(struct i2c_bus *bus, int id,
unsigned int cmd, void *arg)
{
- int i;
-
- for (i = 0; i < I2C_DEVICE_MAX; i++)
- if (bus->devices[i] && bus->devices[i]->driver->id == id)
- break;
- if (i == I2C_DEVICE_MAX)
- return -ENODEV;
- if (NULL == bus->devices[i]->driver->command)
- return -ENODEV;
- return bus->devices[i]->driver->command(bus->devices[i],cmd,arg);
+ int i;
+
+ for (i = 0; i < I2C_DEVICE_MAX; i++)
+ if (bus->devices[i] && bus->devices[i]->driver->id == id)
+ break;
+ if (i == I2C_DEVICE_MAX)
+ return -ENODEV;
+ if (NULL == bus->devices[i]->driver->command)
+ return -ENODEV;
+ return bus->devices[i]->driver->command(bus->devices[i],cmd,arg);
}
/* ----------------------------------------------------------------------- */
@@ -276,116 +294,111 @@ int i2c_control_device(struct i2c_bus *bus, int id,
#define I2C_SET(bus,ctrl,data) (bus->i2c_setlines(bus,ctrl,data))
#define I2C_GET(bus) (bus->i2c_getdataline(bus))
-void i2c_reset(struct i2c_bus *bus)
-{
- I2C_SET(bus,1,1);
- I2C_DEBUG(printk("%s: bus reset",bus->name));
-}
-
void i2c_start(struct i2c_bus *bus)
{
- I2C_SET(bus,0,1);
- I2C_SET(bus,1,1);
- I2C_SET(bus,1,0);
- I2C_SET(bus,0,0);
- I2C_DEBUG(printk("%s: < ",bus->name));
+ I2C_SET(bus,0,1);
+ I2C_SET(bus,1,1);
+ I2C_SET(bus,1,0);
+ I2C_SET(bus,0,0);
+ I2C_DEBUG(printk("%s: < ",bus->name));
}
void i2c_stop(struct i2c_bus *bus)
{
- I2C_SET(bus,0,0);
- I2C_SET(bus,1,0);
- I2C_SET(bus,1,1);
- I2C_DEBUG(printk(">\n"));
+ I2C_SET(bus,0,0);
+ I2C_SET(bus,1,0);
+ I2C_SET(bus,1,1);
+ I2C_DEBUG(printk(">\n"));
}
void i2c_one(struct i2c_bus *bus)
{
- I2C_SET(bus,0,1);
- I2C_SET(bus,1,1);
- I2C_SET(bus,0,1);
+ I2C_SET(bus,0,1);
+ I2C_SET(bus,1,1);
+ I2C_SET(bus,0,1);
}
void i2c_zero(struct i2c_bus *bus)
{
- I2C_SET(bus,0,0);
- I2C_SET(bus,1,0);
- I2C_SET(bus,0,0);
+ I2C_SET(bus,0,0);
+ I2C_SET(bus,1,0);
+ I2C_SET(bus,0,0);
}
int i2c_ack(struct i2c_bus *bus)
{
- int ack;
+ int ack;
- I2C_SET(bus,0,1);
- I2C_SET(bus,1,1);
- ack = I2C_GET(bus);
- I2C_SET(bus,0,1);
- return ack;
+ I2C_SET(bus,0,1);
+ I2C_SET(bus,1,1);
+ ack = I2C_GET(bus);
+ I2C_SET(bus,0,1);
+ return ack;
}
int i2c_sendbyte(struct i2c_bus *bus,unsigned char data,int wait_for_ack)
{
- int i, ack;
+ int i, ack;
- I2C_SET(bus,0,0);
- for (i=7; i>=0; i--)
- (data&(1<<i)) ? i2c_one(bus) : i2c_zero(bus);
- if (wait_for_ack)
- udelay(wait_for_ack);
- ack=i2c_ack(bus);
- I2C_DEBUG(printk("%02x%c ",(int)data,ack?'-':'+'));
- return ack;
+ I2C_SET(bus,0,0);
+ for (i=7; i>=0; i--)
+ (data&(1<<i)) ? i2c_one(bus) : i2c_zero(bus);
+ if (wait_for_ack)
+ udelay(wait_for_ack);
+ ack=i2c_ack(bus);
+ I2C_DEBUG(printk("%02x%c ",(int)data,ack?'-':'+'));
+ return ack;
}
unsigned char i2c_readbyte(struct i2c_bus *bus,int last)
{
- int i;
- unsigned char data=0;
+ int i;
+ unsigned char data=0;
- I2C_SET(bus,0,1);
- for (i=7; i>=0; i--) {
- I2C_SET(bus,1,1);
- if (I2C_GET(bus))
- data |= (1<<i);
I2C_SET(bus,0,1);
- }
- last ? i2c_one(bus) : i2c_zero(bus);
- I2C_DEBUG(printk("=%02x%c ",(int)data,last?'-':'+'));
- return data;
+ for (i=7; i>=0; i--)
+ {
+ I2C_SET(bus,1,1);
+ if (I2C_GET(bus))
+ data |= (1<<i);
+ I2C_SET(bus,0,1);
+ }
+ last ? i2c_one(bus) : i2c_zero(bus);
+ I2C_DEBUG(printk("=%02x%c ",(int)data,last?'-':'+'));
+ return data;
}
/* ----------------------------------------------------------------------- */
int i2c_read(struct i2c_bus *bus, unsigned char addr)
{
- int ret;
+ int ret;
- if (bus->i2c_read)
- return bus->i2c_read(bus, addr);
-
- i2c_start(bus);
- i2c_sendbyte(bus,addr,0);
- ret = i2c_readbyte(bus,1);
- i2c_stop(bus);
- return ret;
+ if (bus->i2c_read)
+ return bus->i2c_read(bus, addr);
+
+ i2c_start(bus);
+ i2c_sendbyte(bus,addr,0);
+ ret = i2c_readbyte(bus,1);
+ i2c_stop(bus);
+ return ret;
}
int i2c_write(struct i2c_bus *bus, unsigned char addr,
unsigned char data1, unsigned char data2, int both)
{
- int ack;
-
- if (bus->i2c_write)
- return bus->i2c_write(bus, addr, data1, data2, both);
-
- i2c_start(bus);
- i2c_sendbyte(bus,addr,0);
- ack = i2c_sendbyte(bus,data1,0);
- if (both)
- ack = i2c_sendbyte(bus,data2,0);
- i2c_stop(bus);
- return ack ? -1 : 0 ;
+ int ack;
+
+ if (bus->i2c_write)
+ return bus->i2c_write(bus, addr, data1, data2, both);
+
+ i2c_start(bus);
+ i2c_sendbyte(bus,addr,0);
+ ack = i2c_sendbyte(bus,data1,0);
+ if (both)
+ ack = i2c_sendbyte(bus,data2,0);
+ i2c_stop(bus);
+ return ack ? -1 : 0 ;
}
/* ----------------------------------------------------------------------- */
@@ -398,7 +411,6 @@ EXPORT_SYMBOL(i2c_unregister_bus);
EXPORT_SYMBOL(i2c_register_driver);
EXPORT_SYMBOL(i2c_unregister_driver);
EXPORT_SYMBOL(i2c_control_device);
-EXPORT_SYMBOL(i2c_reset);
EXPORT_SYMBOL(i2c_start);
EXPORT_SYMBOL(i2c_stop);
EXPORT_SYMBOL(i2c_one);
@@ -412,11 +424,10 @@ EXPORT_SYMBOL(i2c_write);
int init_module(void)
{
- return i2c_init();
+ return i2c_init();
}
void cleanup_module(void)
{
}
-
#endif
diff --git a/bttv/driver/i2c.h b/bttv/driver/i2c.h
index 6bdba73..e2e6f21 100644
--- a/bttv/driver/i2c.h
+++ b/bttv/driver/i2c.h
@@ -10,7 +10,7 @@
* chip driver a driver for a chip connected
* to a i2c bus (cdrom/hd driver)
*
- * a devices will be attached to one bus and one chip driver. Every chip
+ * A device will be attached to one bus and one chip driver. Every chip
* driver gets a unique ID.
*
* A chip driver can provide a ioctl-like callback for the
@@ -32,10 +32,9 @@ struct i2c_device;
#define I2C_DRIVERID_MSP3400 1
#define I2C_DRIVERID_TUNER 2
-#define I2C_DRIVERID_VIDEOTEXT 3
-#define I2C_DRIVERID_CHARDEV 4
+#define I2C_DRIVERID_VIDEOTEXT 3
-#define I2C_BUSID_BT848 1
+#define I2C_BUSID_BT848 1 /* I2C bus on a BT848 */
/*
* struct for a driver for a i2c chip (tuner, soundprocessor,
@@ -54,15 +53,15 @@ struct i2c_device;
*
*/
-struct i2c_driver {
+struct i2c_driver
+{
char name[32]; /* some useful label */
int id; /* device type ID */
unsigned char addr_l, addr_h; /* address range of the chip */
int (*attach)(struct i2c_device *device);
int (*detach)(struct i2c_device *device);
- int (*command)(struct i2c_device *device,
- unsigned int cmd, void *arg);
+ int (*command)(struct i2c_device *device,unsigned int cmd, void *arg);
/* i2c internal */
struct i2c_device *devices[I2C_DEVICE_MAX];
@@ -77,7 +76,7 @@ struct i2c_driver {
* the i2c module. This struct provides functions to access the i2c bus.
*
* One must hold the spinlock to access the i2c bus (XXX: is the irqsave
- * required? Maybe better use a semaphore?).
+ * required? Maybe better use a semaphore?).
* [-AC-] having a spinlock_irqsave is only needed if we have drivers wishing
* to bang their i2c bus from an interrupt.
*
@@ -87,6 +86,7 @@ struct i2c_driver {
*/
/* needed: unsigned long flags */
+
#if LINUX_VERSION_CODE >= 0x020100
#define LOCK_I2C_BUS(bus) spin_lock_irqsave(&(bus->bus_lock),flags);
#define UNLOCK_I2C_BUS(bus) spin_unlock_irqrestore(&(bus->bus_lock),flags);
@@ -95,47 +95,48 @@ struct i2c_driver {
#define UNLOCK_I2C_BUS(bus) { restore_flags(flags); }
#endif
-struct i2c_bus {
- char name[32]; /* some useful label */
- int id;
- void *data; /* free for use by the bus driver */
+struct i2c_bus
+{
+ char name[32]; /* some useful label */
+ int id;
+ void *data; /* free for use by the bus driver */
#if LINUX_VERSION_CODE >= 0x020100
- spinlock_t bus_lock;
+ spinlock_t bus_lock;
#endif
- /* attach/detach inform callbacks */
- void (*attach_inform)(struct i2c_bus *bus, int id);
- void (*detach_inform)(struct i2c_bus *bus, int id);
+ /* attach/detach inform callbacks */
+ void (*attach_inform)(struct i2c_bus *bus, int id);
+ void (*detach_inform)(struct i2c_bus *bus, int id);
- /* Software I2C */
- void (*i2c_setlines)(struct i2c_bus *bus, int ctrl, int data);
- int (*i2c_getdataline)(struct i2c_bus *bus);
+ /* Software I2C */
+ void (*i2c_setlines)(struct i2c_bus *bus, int ctrl, int data);
+ int (*i2c_getdataline)(struct i2c_bus *bus);
- /* Hardware I2C */
- int (*i2c_read)(struct i2c_bus *bus, unsigned char addr);
- int (*i2c_write)(struct i2c_bus *bus, unsigned char addr,
+ /* Hardware I2C */
+ int (*i2c_read)(struct i2c_bus *bus, unsigned char addr);
+ int (*i2c_write)(struct i2c_bus *bus, unsigned char addr,
unsigned char b1, unsigned char b2, int both);
- /* internal data for i2c module */
- struct i2c_device *devices[I2C_DEVICE_MAX];
- int devcount;
+ /* internal data for i2c module */
+ struct i2c_device *devices[I2C_DEVICE_MAX];
+ int devcount;
};
/*
- * this holds per-device data for a i2c device
- *
+ * This holds per-device data for a i2c device
*/
-struct i2c_device {
- char name[32]; /* some useful label */
- void *data; /* free for use by the chip driver */
- unsigned char addr; /* chip addr */
+struct i2c_device
+{
+ char name[32]; /* some useful label */
+ void *data; /* free for use by the chip driver */
+ unsigned char addr; /* chip addr */
- /* i2c internal */
- struct i2c_bus *bus;
- struct i2c_driver *driver;
+ /* i2c internal */
+ struct i2c_bus *bus;
+ struct i2c_driver *driver;
};
@@ -155,7 +156,6 @@ int i2c_control_device(struct i2c_bus *bus, int id,
unsigned int cmd, void *arg);
/* i2c bus access functions */
-void i2c_reset(struct i2c_bus *bus);
void i2c_start(struct i2c_bus *bus);
void i2c_stop(struct i2c_bus *bus);
void i2c_one(struct i2c_bus *bus);
@@ -170,15 +170,4 @@ int i2c_read(struct i2c_bus *bus, unsigned char addr);
int i2c_write(struct i2c_bus *bus, unsigned char addr,
unsigned char b1, unsigned char b2, int both);
-/* ------------------------------------------------------------------------ */
-/* this allows i2c bus access from userspace */
-
-/* ioctls */
-#define I2C_SLAVE 0x0706
-#define I2C_WRITE_SIZE 0x0712
-#define I2C_WRITE_BUF 0x0713
-#define I2C_RESET 0x07fd
-
-#define I2C_BUFFER_SIZE 64 /* buffer size for write b4 read */
-
#endif /* I2C_H */
diff --git a/bttv/driver/linux-2.0.33.diff b/bttv/driver/linux-2.0.33.diff
deleted file mode 100644
index 39431cb..0000000
--- a/bttv/driver/linux-2.0.33.diff
+++ /dev/null
@@ -1,10 +0,0 @@
---- linux/kernel/ksyms.c-orig Mon Apr 6 23:46:19 1998
-+++ linux/kernel/ksyms.c Mon Apr 6 23:46:09 1998
-@@ -87,6 +87,7 @@
-
- /* stackable module support */
- X(register_symtab_from),
-+ X(request_module),
- #ifdef CONFIG_KERNELD
- X(kerneld_send),
- #endif
diff --git a/bttv/driver/msp3400.c b/bttv/driver/msp3400.c
index a5db7cf..d8e1e9d 100644
--- a/bttv/driver/msp3400.c
+++ b/bttv/driver/msp3400.c
@@ -3,10 +3,10 @@
*
* (c) 1997,1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
*
- * what works and what does'nt:
+ * what works and what doesn't:
*
* AM-Mono
- * probably does'nt (untested)
+ * probably doesn't (untested)
*
* FM-Mono
* should work. The stereo modes are backward compatible to FM-mono,
@@ -19,7 +19,7 @@
* should work, no autodetect (i.e. default is mono, but you can
* switch to stereo -- untested)
*
- * NICAM (B/G, used in Scandinavia and Spain)
+ * NICAM (B/G, used in UK, Scandinavia and Spain)
* should work, with autodetect. Support for NICAM was added by
* Pekka Pietikainen <pp@netppl.fi>
*
@@ -93,8 +93,8 @@ struct msp3400c {
/* 2.0.x */
#define signal_pending(current) (current->signal & ~current->blocked)
#define sigfillset(set)
+#define mdelay(x) udelay(1000*x)
#else
-/* 2.1.x */
MODULE_PARM(debug,"i");
#endif
@@ -107,29 +107,28 @@ MODULE_PARM(debug,"i");
/* ----------------------------------------------------------------------- */
/* functions for talking to the MSP3400C Sound processor */
-static int
-msp3400c_reset(struct i2c_bus *bus)
+static int msp3400c_reset(struct i2c_bus *bus)
{
int ret = 0;
- udelay(2000);
+ mdelay(2);
i2c_start(bus);
i2c_sendbyte(bus, I2C_MSP3400C,2000);
i2c_sendbyte(bus, 0x00,0);
i2c_sendbyte(bus, 0x80,0);
i2c_sendbyte(bus, 0x00,0);
i2c_stop(bus);
- udelay(2000);
+ mdelay(2);
i2c_start(bus);
if (0 != i2c_sendbyte(bus, I2C_MSP3400C,2000) ||
0 != i2c_sendbyte(bus, 0x00,0) ||
0 != i2c_sendbyte(bus, 0x00,0) ||
0 != i2c_sendbyte(bus, 0x00,0)) {
ret = -1;
- printk("msp3400: chip reset failed, penguin on i2c bus?\n");
+ printk(KERN_ERR "msp3400: chip reset failed, penguin on i2c bus?\n");
}
i2c_stop(bus);
- udelay(2000);
+ mdelay(2);
return ret;
}
@@ -155,7 +154,7 @@ msp3400c_read(struct i2c_bus *bus, int dev, int addr)
}
i2c_stop(bus);
if (-1 == ret) {
- printk("msp3400: I/O error, trying reset (read %s 0x%x)\n",
+ printk(KERN_WARNING "msp3400: I/O error, trying reset (read %s 0x%x)\n",
(dev == I2C_MSP3400C_DEM) ? "Demod" : "Audio", addr);
msp3400c_reset(bus);
}
@@ -177,7 +176,7 @@ msp3400c_write(struct i2c_bus *bus, int dev, int addr, int val)
ret = -1;
i2c_stop(bus);
if (-1 == ret) {
- printk("msp3400: I/O error, trying reset (write %s 0x%x)\n",
+ printk(KERN_WARNING "msp3400: I/O error, trying reset (write %s 0x%x)\n",
(dev == I2C_MSP3400C_DEM) ? "Demod" : "Audio", addr);
msp3400c_reset(bus);
}
@@ -273,8 +272,7 @@ static struct CARRIER_DETECT carrier_detect_65[] = {
/* ------------------------------------------------------------------------ */
-static void
-msp3400c_setcarrier(struct i2c_bus *bus, int cdo1, int cdo2)
+static void msp3400c_setcarrier(struct i2c_bus *bus, int cdo1, int cdo2)
{
msp3400c_write(bus,I2C_MSP3400C_DEM, 0x0093, cdo1 & 0xfff);
msp3400c_write(bus,I2C_MSP3400C_DEM, 0x009b, cdo1 >> 12);
@@ -282,8 +280,7 @@ msp3400c_setcarrier(struct i2c_bus *bus, int cdo1, int cdo2)
msp3400c_write(bus,I2C_MSP3400C_DEM, 0x00ab, cdo2 >> 12);
}
-static void
-msp3400c_setvolume(struct i2c_bus *bus, int left, int right)
+static void msp3400c_setvolume(struct i2c_bus *bus, int left, int right)
{
int vol,val,balance;
@@ -302,8 +299,7 @@ msp3400c_setvolume(struct i2c_bus *bus, int left, int right)
msp3400c_write(bus,I2C_MSP3400C_DFP, 0x0001, balance << 8);
}
-static void
-msp3400c_setbass(struct i2c_bus *bus, int bass)
+static void msp3400c_setbass(struct i2c_bus *bus, int bass)
{
int val = ((bass-32768) * 0x60 / 65535) << 8;
@@ -311,8 +307,7 @@ msp3400c_setbass(struct i2c_bus *bus, int bass)
msp3400c_write(bus,I2C_MSP3400C_DFP, 0x0002, val); /* loudspeaker */
}
-static void
-msp3400c_settreble(struct i2c_bus *bus, int treble)
+static void msp3400c_settreble(struct i2c_bus *bus, int treble)
{
int val = ((treble-32768) * 0x60 / 65535) << 8;
@@ -320,8 +315,7 @@ msp3400c_settreble(struct i2c_bus *bus, int treble)
msp3400c_write(bus,I2C_MSP3400C_DFP, 0x0003, val); /* loudspeaker */
}
-static void
-msp3400c_setmode(struct msp3400c *msp, int type)
+static void msp3400c_setmode(struct msp3400c *msp, int type)
{
int i;
@@ -364,8 +358,7 @@ msp3400c_setmode(struct msp3400c *msp, int type)
}
}
-static void
-msp3400c_setstereo(struct msp3400c *msp, int mode)
+static void msp3400c_setstereo(struct msp3400c *msp, int mode)
{
int nicam=0; /* channel source: FM/AM or nicam */
@@ -457,8 +450,7 @@ struct REGISTER_DUMP d1[] = {
* in the ioctl while doing the sound carrier & stereo detect
*/
-void
-msp3400c_stereo_wake(unsigned long data)
+static void msp3400c_stereo_wake(unsigned long data)
{
struct msp3400c *msp = (struct msp3400c*)data; /* XXX alpha ??? */
@@ -466,8 +458,7 @@ msp3400c_stereo_wake(unsigned long data)
up(msp->wait);
}
-int
-msp3400c_thread(void *data)
+static int msp3400c_thread(void *data)
{
unsigned long flags;
struct msp3400c *msp = data;
@@ -678,8 +669,7 @@ done:
#if 0 /* not finished yet */
-int
-msp3410d_thread(void *data)
+static int msp3410d_thread(void *data)
{
unsigned long flags;
struct msp3400c *msp = data;
@@ -776,8 +766,7 @@ done:
#include <../drivers/sound/sound_config.h>
#include <../drivers/sound/dev_table.h>
-static int
-mix_to_v4l(int i)
+static int mix_to_v4l(int i)
{
int r;
@@ -787,8 +776,7 @@ mix_to_v4l(int i)
return r;
}
-static int
-v4l_to_mix(int i)
+static int v4l_to_mix(int i)
{
int r;
@@ -798,8 +786,7 @@ v4l_to_mix(int i)
return r | (r << 8);
}
-static int
-v4l_to_mix2(int l, int r)
+static int v4l_to_mix2(int l, int r)
{
r = (r * 100 + 32768) / 65536;
if (r > 100) r = 100;
@@ -810,8 +797,7 @@ v4l_to_mix2(int l, int r)
return (r << 8) | l;
}
-static int
-msp3400c_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
+static int msp3400c_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
{
struct msp3400c *msp = mixer_devs[dev]->devc;
unsigned long flags;
@@ -881,8 +867,7 @@ struct mixer_operations msp3400c_mixer = {
msp3400c_mixer_ioctl
};
-static int
-msp3400c_mixer_init(struct msp3400c *msp)
+static int msp3400c_mixer_init(struct msp3400c *msp)
{
int m;
@@ -902,8 +887,7 @@ msp3400c_mixer_init(struct msp3400c *msp)
return 0;
}
-static int
-msp3400c_mixer_close(struct msp3400c *msp)
+static int msp3400c_mixer_close(struct msp3400c *msp)
{
int m = msp->mixer;
@@ -918,8 +902,7 @@ msp3400c_mixer_close(struct msp3400c *msp)
/* ----------------------------------------------------------------------- */
-static int
-msp3400c_attach(struct i2c_device *device)
+static int msp3400c_attach(struct i2c_device *device)
{
unsigned long flags;
struct semaphore sem = MUTEX_LOCKED;
@@ -940,17 +923,24 @@ msp3400c_attach(struct i2c_device *device)
if (-1 == msp3400c_reset(msp->bus)) {
UNLOCK_I2C_BUS(msp->bus);
kfree(msp);
+ dprintk("msp3400: no chip found\n");
return -1;
}
+ rev1 = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1e);
+ rev2 = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1f);
+ if (0 == rev1 && 0 == rev2) {
+ UNLOCK_I2C_BUS(msp->bus);
+ kfree(msp);
+ printk("msp3400: error while reading chip version\n");
+ return -1;
+ }
+
msp3400c_setmode(msp, MSP_MODE_FM_TERRA);
msp3400c_setvolume(msp->bus, msp->left, msp->right);
msp3400c_setbass(msp->bus, msp->bass);
msp3400c_settreble(msp->bus, msp->treble);
- rev1 = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1e);
- rev2 = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1f);
-
#if 0
/* this will turn on a 1kHz beep - might be useful for debugging... */
msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0014, 0x1040);
@@ -985,8 +975,7 @@ msp3400c_attach(struct i2c_device *device)
return 0;
}
-static int
-msp3400c_detach(struct i2c_device *device)
+static int msp3400c_detach(struct i2c_device *device)
{
unsigned long flags;
struct semaphore sem = MUTEX_LOCKED;
@@ -998,7 +987,8 @@ msp3400c_detach(struct i2c_device *device)
/* shutdown control thread */
del_timer(&msp->wake_stereo);
- if (msp->thread) {
+ if (msp->thread)
+ {
msp->notify = &sem;
msp->rmmod = 1;
if (!msp->active)
@@ -1016,8 +1006,7 @@ msp3400c_detach(struct i2c_device *device)
return 0;
}
-static int
-msp3400c_command(struct i2c_device *device,
+static int msp3400c_command(struct i2c_device *device,
unsigned int cmd, void *arg)
{
unsigned long flags;
diff --git a/bttv/driver/tuner.c b/bttv/driver/tuner.c
index db37406..6f8a6e3 100644
--- a/bttv/driver/tuner.c
+++ b/bttv/driver/tuner.c
@@ -22,30 +22,32 @@ MODULE_PARM(debug,"i");
MODULE_PARM(type,"i");
#endif
-struct tuner {
- struct i2c_bus *bus; /* where is our chip */
- int addr;
+struct tuner
+{
+ struct i2c_bus *bus; /* where is our chip */
+ int addr;
- int type; /* chip type */
- int freq; /* keep track of the current settings */
- int radio;
+ int type; /* chip type */
+ int freq; /* keep track of the current settings */
+ int radio;
};
/* ---------------------------------------------------------------------- */
-struct tunertype {
- char *name;
- unchar Vendor;
- unchar Type;
+struct tunertype
+{
+ char *name;
+ unsigned char Vendor;
+ unsigned char Type;
- ushort thresh1; /* frequency Range for UHF,VHF-L, VHF_H */
- ushort thresh2;
- unchar VHF_L;
- unchar VHF_H;
- unchar UHF;
- unchar config;
- unchar I2C;
- ushort IFPCoff;
+ unsigned short thresh1; /* frequency Range for UHF,VHF-L, VHF_H */
+ unsigned short thresh2;
+ unsigned char VHF_L;
+ unsigned char VHF_H;
+ unsigned char UHF;
+ unsigned char config;
+ unsigned char I2C;
+ unsigned short IFPCoff;
};
/*
@@ -108,7 +110,7 @@ static void set_tv_freq(struct tuner *t, int freq)
else
config = tun->UHF;
- div=freq + (int)(16*38.9);
+ div=freq + tun->IFPCoff;
div&=0x7fff;
LOCK_I2C_BUS(t->bus);
@@ -158,79 +160,89 @@ static void set_radio_freq(struct tuner *t, int freq)
/* ---------------------------------------------------------------------- */
-static int
-tuner_attach(struct i2c_device *device)
+static int tuner_attach(struct i2c_device *device)
{
- struct tuner *t;
-
- device->data = t = kmalloc(sizeof(struct tuner),GFP_KERNEL);
- if (NULL == t)
- return -ENOMEM;
- memset(t,0,sizeof(struct tuner));
- strcpy(device->name,"tuner");
- t->bus = device->bus;
- t->addr = device->addr;
- t->type = type;
- dprintk("tuner: type is %d (%s)\n",t->type,tuners[t->type].name);
- MOD_INC_USE_COUNT;
- return 0;
+ struct tuner *t;
+
+ /*
+ * For now we only try and attach these tuners to the BT848
+ * bus. This same module will however work different species
+ * of card using these chips. Just change the constraints
+ * (i2c doesn't have a totally clash free 'address' space)
+ */
+
+ if(device->bus->id!=I2C_BUSID_BT848)
+ return -EINVAL;
+
+ device->data = t = kmalloc(sizeof(struct tuner),GFP_KERNEL);
+ if (NULL == t)
+ return -ENOMEM;
+ memset(t,0,sizeof(struct tuner));
+ strcpy(device->name,"tuner");
+ t->bus = device->bus;
+ t->addr = device->addr;
+ t->type = type;
+ dprintk("tuner: type is %d (%s)\n",t->type,tuners[t->type].name);
+
+ MOD_INC_USE_COUNT;
+ return 0;
}
-static int
-tuner_detach(struct i2c_device *device)
+static int tuner_detach(struct i2c_device *device)
{
- struct tuner *t = (struct tuner*)device->data;
- kfree(t);
- MOD_DEC_USE_COUNT;
- return 0;
+ struct tuner *t = (struct tuner*)device->data;
+ kfree(t);
+ MOD_DEC_USE_COUNT;
+ return 0;
}
-static int
-tuner_command(struct i2c_device *device,
+static int tuner_command(struct i2c_device *device,
unsigned int cmd, void *arg)
{
- struct tuner *t = (struct tuner*)device->data;
- int *iarg = (int*)arg;
-
- switch (cmd) {
- case TUNER_SET_TYPE:
- t->type = *iarg;
- dprintk("tuner: type set to %d (%s)\n",
- t->type,tuners[t->type].name);
- break;
-
- case TUNER_SET_TVFREQ:
- dprintk("tuner: tv freq set to %d.%02d\n",
- (*iarg)/16,(*iarg)%16*100/16);
- set_tv_freq(t,*iarg);
- t->radio = 0;
- t->freq = *iarg;
- break;
+ struct tuner *t = (struct tuner*)device->data;
+ int *iarg = (int*)arg;
+
+ switch (cmd)
+ {
+ case TUNER_SET_TYPE:
+ t->type = *iarg;
+ dprintk("tuner: type set to %d (%s)\n",
+ t->type,tuners[t->type].name);
+ break;
+
+ case TUNER_SET_TVFREQ:
+ dprintk("tuner: tv freq set to %d.%02d\n",
+ (*iarg)/16,(*iarg)%16*100/16);
+ set_tv_freq(t,*iarg);
+ t->radio = 0;
+ t->freq = *iarg;
+ break;
- case TUNER_SET_RADIOFREQ:
- dprintk("tuner: radio freq set to %d.%02d\n",
- (*iarg)/16,(*iarg)%16*100/16);
- set_radio_freq(t,*iarg);
- t->radio = 1;
- t->freq = *iarg;
- break;
+ case TUNER_SET_RADIOFREQ:
+ dprintk("tuner: radio freq set to %d.%02d\n",
+ (*iarg)/16,(*iarg)%16*100/16);
+ set_radio_freq(t,*iarg);
+ t->radio = 1;
+ t->freq = *iarg;
+ break;
- default:
- return -EINVAL;
- }
- return 0;
+ default:
+ return -EINVAL;
+ }
+ return 0;
}
/* ----------------------------------------------------------------------- */
-struct i2c_driver i2c_driver_tuner = {
- "tuner", /* name */
- I2C_DRIVERID_TUNER, /* ID */
- 0xc0, 0xce, /* addr range */
+struct i2c_driver i2c_driver_tuner =
+{
+ "tuner", /* name */
+ I2C_DRIVERID_TUNER, /* ID */
+ 0xc0, 0xce, /* addr range */
- tuner_attach,
- tuner_detach,
- tuner_command
+ tuner_attach,
+ tuner_detach,
+ tuner_command
};
#ifdef MODULE
@@ -239,14 +251,14 @@ int init_module(void)
int msp3400c_init(void)
#endif
{
- i2c_register_driver(&i2c_driver_tuner);
- return 0;
+ i2c_register_driver(&i2c_driver_tuner);
+ return 0;
}
#ifdef MODULE
void cleanup_module(void)
{
- i2c_unregister_driver(&i2c_driver_tuner);
+ i2c_unregister_driver(&i2c_driver_tuner);
}
#endif
diff --git a/bttv/driver/update b/bttv/driver/update
index 7fac504..91db789 100644
--- a/bttv/driver/update
+++ b/bttv/driver/update
@@ -28,6 +28,8 @@ xrmmod bttv
xrmmod msp3400
xrmmod tuner
xrmmod i2c_chardev
+xrmmod i2c-dev
+xrmmod algo-bit
xrmmod i2c
xrmmod videodev
@@ -36,6 +38,6 @@ xinsmod videodev
xinsmod i2c verbose=1 scan=1 i2c_debug=0
test -f i2c_chardev.o && xinsmod i2c_chardev
xinsmod tuner debug=0 type=5
-xinsmod msp3400 debug=0
+xinsmod msp3400
xinsmod bttv radio=1 vidmem=0xff0
diff --git a/bttv/driver/videodev.c b/bttv/driver/videodev.c
index 4e5aa47..360058c 100644
--- a/bttv/driver/videodev.c
+++ b/bttv/driver/videodev.c
@@ -50,6 +50,15 @@ extern int init_colour_qcams(struct video_init *);
#ifdef CONFIG_VIDEO_BWQCAM
extern int init_bw_qcams(struct video_init *);
#endif
+#ifdef CONFIG_RADIO_AZTECH
+extern int aztech_init(struct video_init *);
+#endif
+#ifdef CONFIG_RADIO_RTRACK
+extern int rtrack_init(struct video_init *);
+#endif
+#ifdef CONFIG_RADIO_SF16FMI
+extern int fmi_init(struct video_init *);
+#endif
static struct video_init video_init_list[]={
#ifdef CONFIG_VIDEO_BT848
@@ -68,6 +77,15 @@ static struct video_init video_init_list[]={
{"PMS", init_pms_cards},
#endif
{"end", NULL}
+#ifdef CONFIG_RADIO_AZTECH
+ {"Aztech", aztech_init},
+#endif
+#ifdef CONFIG_RADIO_RTRACK
+ {"RTrack", rtrack_init},
+#endif
+#ifdef CONFIG_RADIO_SF16FMI
+ {"SF16FMI", fmi_init},
+#endif
};
#if LINUX_VERSION_CODE >= 0x020100
@@ -79,7 +97,10 @@ static ssize_t video_read(struct file *file,
char *buf, size_t count, loff_t *ppos)
{
struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)];
- return vfl->read(vfl, buf, count, file->f_flags&O_NONBLOCK);
+ if (vfl->read)
+ return vfl->read(vfl, buf, count, file->f_flags&O_NONBLOCK);
+ else
+ return -EINVAL;
}
@@ -93,15 +114,21 @@ static ssize_t video_write(struct file *file, const char *buf,
size_t count, loff_t *ppos)
{
struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)];
- return vfl->write(vfl, buf, count, file->f_flags&O_NONBLOCK);
+ if (vfl->write)
+ return vfl->write(vfl, buf, count, file->f_flags&O_NONBLOCK);
+ else
+ return 0;
}
#else
static int video_read(struct inode *ino,struct file *file,
char *buf, int count)
{
- int err;
- struct video_device *vfl=video_device[MINOR(ino->i_rdev)];
- return vfl->read(vfl, buf, count, file->f_flags&O_NONBLOCK);
+ int err;
+ struct video_device *vfl=video_device[MINOR(ino->i_rdev)];
+ if (vfl->read)
+ return vfl->read(vfl, buf, count, file->f_flags&O_NONBLOCK);
+ else
+ return -EINVAL;
}
static int video_write(struct inode *ino,struct file *file, const char *buf,
@@ -109,7 +136,10 @@ static int video_write(struct inode *ino,struct file *file, const char *buf,
{
int err;
struct video_device *vfl=video_device[MINOR(ino->i_rdev)];
- return vfl->write(vfl, buf, count, file->f_flags&O_NONBLOCK);
+ if (vfl->write)
+ return vfl->write(vfl, buf, count, file->f_flags&O_NONBLOCK);
+ else
+ return 0;
}
#endif
@@ -257,12 +287,15 @@ int video_register_device(struct video_device *vfd, int type)
/* The init call may sleep so we book the slot out
then call */
MOD_INC_USE_COUNT;
- err=vfd->initialize(vfd);
- if(err<0)
- {
- video_device[i]=NULL;
- MOD_DEC_USE_COUNT;
- return err;
+ if (vfd->initialize)
+ {
+ err=vfd->initialize(vfd);
+ if(err<0)
+ {
+ video_device[i]=NULL;
+ MOD_DEC_USE_COUNT;
+ return err;
+ }
}
return 0;
}
diff --git a/bttv/driver/videodev.h b/bttv/driver/videodev.h
index 1b7a6cf..6b13119 100644
--- a/bttv/driver/videodev.h
+++ b/bttv/driver/videodev.h
@@ -69,7 +69,6 @@ struct video_channel
__u16 type;
#define VIDEO_TYPE_TV 1
#define VIDEO_TYPE_CAMERA 2
- __u16 mode; /* PAL/NTSC/SECAM/OTHER */
};
struct video_tuner
@@ -81,11 +80,14 @@ struct video_tuner
#define VIDEO_TUNER_PAL 1
#define VIDEO_TUNER_NTSC 2
#define VIDEO_TUNER_SECAM 4
+#define VIDEO_TUNER_LOW 8 /* Uses KHz not MHz */
+#define VIDEO_TUNER_STEREO_ON 128 /* Tuner is seeing stereo */
__u16 mode; /* PAL/NTSC/SECAM/OTHER */
#define VIDEO_MODE_PAL 0
#define VIDEO_MODE_NTSC 1
#define VIDEO_MODE_SECAM 2
#define VIDEO_MODE_AUTO 3
+ __u16 signal; /* Signal strength 16bit scale */
};
struct video_picture
@@ -103,6 +105,7 @@ struct video_picture
#define VIDEO_PALETTE_RGB24 4 /* 24bit RGB */
#define VIDEO_PALETTE_RGB32 5 /* 32bit RGB */
#define VIDEO_PALETTE_RGB555 6 /* 555 15bit RGB */
+#define VIDEO_PALETTE_YUV422 7 /* YUV422 capture */
};
struct video_audio
@@ -194,6 +197,9 @@ struct video_key
#define VID_HARDWARE_QCAM_C 4
#define VID_HARDWARE_PSEUDO 5
#define VID_HARDWARE_SAA5249 6
+#define VID_HARDWARE_AZTECH 7
+#define VID_HARDWARE_SF16MI 8
+#define VID_HARDWARE_RTRACK 9
/*
* Initialiser list
diff --git a/bttv/experimental/Makefile b/bttv/experimental/Makefile
new file mode 100644
index 0000000..12ca401
--- /dev/null
+++ b/bttv/experimental/Makefile
@@ -0,0 +1,61 @@
+#################################################
+# config
+
+# 0: Temic PAL tuner
+# 1: Philips PAL_I tuner
+# 2: Philips NTSC tuner
+# 3: Philips SECAM tuner
+# 4: no tuner
+# 5: Philips PAL tuner
+# 6: Temic NTSC tuner
+# 7: Temic PAL tuner
+TUNER=0
+
+# 0: Auto-Detect
+# 1: Miro
+# 2: Hauppauge
+# 3: STB
+# 4: Intel
+# 5: Diamond
+# 6: AVerMedia
+# 7: MATRIX Vision MV-Delta
+# 8: FlyVideo
+CARD=0
+
+# Official major device number is 81
+# Older kernels might have problems with such high numbers.
+# But I rather recommend updating to kernel 2.0.31 or higher.
+BTTV_MAJOR=81
+
+# currently running kernel
+CURRENT=$(shell uname -r)
+
+# where the kernel sources are located
+#KERNEL_LOCATION=/usr/src/kernel/$(CURRENT)
+#KERNEL_LOCATION=/usr/src/kernel/vger
+KERNEL_LOCATION=/usr/src/linux
+
+
+#################################################
+# some magic for using linux kernel settings
+# when compiling module(s)
+
+M_OBJS = bttv.o tuner.o
+MX_OBJS = videodev.o i2c.o algo-bit.o
+#EXTRA_CFLAGS = -DTUNER_DEFAULT=$(TUNER) -DCARD_DEFAULT=$(CARD) \
+# -DBTTV_MAJOR=$(BTTV_MAJOR) $(INTERFACE) #-DUSE_PLL
+EXTRA_CFLAGS = -DTUNER_DEFAULT=$(TUNER) -DCARD_DEFAULT=$(CARD) \
+ -DBTTV_MAJOR=$(BTTV_MAJOR) $(INTERFACE) \
+ -DVERIFY_HEADERS -DSLOW_STARTER
+
+here:
+ DIR=`pwd`; (cd $(KERNEL_LOCATION); make SUBDIRS=$$DIR modules)
+
+install:
+ su -c "cp -v $(M_OBJS) $(MX_OBJS) /lib/modules/$(CURRENT)/misc"
+
+clean:
+ -rm -f $(M_OBJS) $(MX_OBJS) .*.o.flags *~
+
+include $(KERNEL_LOCATION)/Rules.make
+
diff --git a/bttv/experimental/README b/bttv/experimental/README
new file mode 100644
index 0000000..c3137c3
--- /dev/null
+++ b/bttv/experimental/README
@@ -0,0 +1,12 @@
+This is a very first version of bttv with the new i2c code. Work in
+progress, plenty of known bugs, pre-alpha quality. No msp3400 support
+yet, only the tuner works. You should know what you are doing if you
+want to play with it. Tested only with 2.1.x
+
+You should use the update script to load/unload the modules, it knows
+which order works without a kernel Oops.
+
+You have been warned,
+
+ Gerd
+
diff --git a/bttv/experimental/algo-bit.c b/bttv/experimental/algo-bit.c
new file mode 100644
index 0000000..cc63bed
--- /dev/null
+++ b/bttv/experimental/algo-bit.c
@@ -0,0 +1,893 @@
+/* ------------------------------------------------------------------------- */
+/* adap-bit.c i2c driver algorithms for bit-shift adapters */
+/* ------------------------------------------------------------------------- */
+/* Copyright (C) 1995-97 Simon G. Vogl
+
+ 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. */
+/* ------------------------------------------------------------------------- */
+static char alg_rcsid[] = "$Id: algo-bit.c,v 1.1 1998/05/25 12:08:00 i2c Exp i2c $";
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/malloc.h>
+#include <linux/version.h>
+
+
+#if LINUX_VERSION_CODE >= 0x020100
+# include <asm/uaccess.h>
+#else
+# include <asm/segment.h>
+#endif
+
+
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+
+#include "i2c.h"
+#include "algo-bit.h"
+
+/* ----- global defines ---------------------------------------------------- */
+#define DEB(x) x /* should be reasonable open, close &c. */
+#define DEB2(x) /* low level debugging - very slow */
+#define DEBE(x) /* error messages */
+#define DEBI(x) /* ioctl and its arguments */
+#define DEBACK(x) x /* ack failed message */
+#define DEBSTAT(x) /* print several statistical values */
+
+#define DEBPROTO(x) x /* debug the protocol by showing transferred bytes*/
+
+/* debugging - slow down transfer to have a look at the data .. */
+/* I use this with two leds&resistors, each one connected to sda,scl */
+/* respectively. This makes sure that the algorithm works. Some chips */
+/* might not like this, as they have an internal timeout of some mils */
+/*
+#define SLO_IO jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\
+ if (need_resched) schedule();
+*/
+
+/* ----- global variables --------------------------------------------- */
+
+#ifdef SLO_IO
+ int jif;
+#endif
+
+
+static int test=1; /* see if the line-setting functions work */
+static int scan=0; /* have a look at what's hanging 'round */
+/*
+ * This array contains the hw-specific functions for
+ * each port (hardware) type.
+ */
+static struct bit_adapter *bit_adaps[BIT_ADAP_MAX];
+static int adap_count;
+static struct i2c_adapter *i2c_adaps[BIT_ADAP_MAX];
+
+/* --- setting states on the bus with the right timing: --------------- */
+
+#define setsda(adap,val) adap->setsda(adap->data, val)
+#define setscl(adap,val) adap->setscl(adap->data, val)
+#define getsda(adap) adap->getsda(adap->data)
+#define getscl(adap) adap->getscl(adap->data)
+
+static inline void sdalo(struct bit_adapter *adap)
+{
+ setsda(adap,0);
+ udelay(adap->udelay);
+}
+
+static inline void sdahi(struct bit_adapter *adap)
+{
+ setsda(adap,1);
+ udelay(adap->udelay);
+}
+
+static inline void scllo(struct bit_adapter *adap)
+{
+ setscl(adap,0);
+ udelay(adap->udelay);
+#ifdef SLO_IO
+ SLO_IO
+#endif
+}
+
+/*
+ * Raise scl line, and do checking for delays. This is necessary for slower
+ * devices.
+ */
+static inline int sclhi(struct bit_adapter *adap)
+{
+ int start=jiffies;
+
+ setscl(adap,1);
+
+ udelay(adap->udelay);
+ while (! getscl(adap) ) { /* wait till high */
+ setscl(adap,1);
+ if (start+adap->timeout <= jiffies) {
+/* DEBE(printk("i2c(bit): (%s) sclhi timed out after %d jiffies\n",
+ adap->name, adap->timeout ) );
+*/ return -ETIMEDOUT;
+ }
+ if (need_resched)
+ schedule();
+ }
+ DEBSTAT(printk("needed %ld jiffies\n", jiffies-start));
+#ifdef SLO_IO
+ SLO_IO
+#endif
+ return 0;
+}
+
+
+/* --- other auxiliary functions -------------------------------------- */
+static void i2c_start(struct bit_adapter *adap)
+{
+ /* assert: scl, sda are high */
+ DEBPROTO(printk("S "));
+ sdalo(adap);
+ scllo(adap);
+}
+
+static void i2c_repstart(struct bit_adapter *adap)
+{
+ /* scl, sda may not be high */
+ DEBPROTO(printk(" Sr "));
+ setsda(adap,1);
+ setscl(adap,1);
+ udelay(adap->udelay);
+
+ sdalo(adap); /* includes delay! */
+ scllo(adap);
+}
+
+
+static void i2c_stop(struct bit_adapter *adap)
+{
+ DEBPROTO(printk("P\n"));
+ /* assert: scl is low */
+ sdalo(adap);
+ sclhi(adap);
+ sdahi(adap);
+}
+
+/* send a byte without start cond., look for arbitration,
+ check ackn. from slave */
+/* return 1 if ok */
+static int i2c_outb(struct bit_adapter *adap, char c)
+{
+ int i;
+ int sb;
+ int ack;
+
+ /* assert: scl is low */
+ DEB2(printk(" i2c_outb:%2.2X\n",c&0xff));
+ for ( i=7 ; i>=0 ; i-- ) {
+ sb = c & ( 1 << i );
+ setsda(adap,sb);
+ udelay(adap->udelay);
+ DEBPROTO(printk("%d",sb!=0));
+ if (sclhi(adap)<0) { /* timed out */
+ sdahi(adap); /* we don't want to block the net */
+ return -ETIMEDOUT;
+ };
+#if 0
+ /* arbitrate here: */
+ if ( sb && !getsda(adap) ){
+ /* we lost the arbitration process -> give up */
+ DEBE(printk("i2c(bit): %s i2c_outb: arbitration bailout! \n", adap->name ));
+ return -ETIMEDOUT;
+ }
+ /* scllo(adap); */
+#endif
+ setscl( adap, 0 );
+ udelay(adap->udelay);
+ }
+ sdahi(adap);
+ if (sclhi(adap)<0){ /* timeout */
+ return -ETIMEDOUT;
+ };
+ /* read ack: SDA should be pulled down by slave */
+ ack=getsda(adap); /* ack: sda is pulled low ->success. */
+ DEB2(printk(" i2c_outb: getsda() = 0x%2.2x\n", !ack ));
+
+ DEBPROTO( printk("[%2.2x]",c&0xff) );
+ DEBPROTO(if (0==ack) printk(" A "); else printk(" NA ") );
+ scllo(adap);
+ return 0==ack; /* return 1 if device acked */
+ /* assert: scl is low (sda undef) */
+}
+
+
+
+static int i2c_inb(struct bit_adapter *adap)
+{
+ /* read byte via i2c port, without start/stop sequence */
+ /* acknowledge is sent in i2c_read. */
+ int i;
+ char indata;
+
+ /* assert: scl is low */
+ DEB2(printk("i2c_inb.\n"));
+
+ sdahi(adap);
+ indata=0;
+ for (i=0;i<8;i++) {
+ if (sclhi(adap)<0) { /* timeout */
+ return -ETIMEDOUT;
+ };
+ indata *= 2;
+ if ( getsda(adap) )
+ indata |= 0x01;
+ scllo(adap);
+ }
+ /* assert: scl is low */
+ DEBPROTO(printk(" %2.2x", indata & 0xff));
+ return (int) (indata & 0xff);
+}
+
+
+/* ----- level 2: communication with the kernel ----- */
+#if 0
+
+static int i2c_write(struct inode * inode, struct file * file,
+ const char * buf, int count)
+{
+ unsigned struct bit_adapter *adap = ADAP(inode->i_rdev);
+ char c,adr;
+ const char *temp = buf;
+ int retval,i;
+ int wrcount=0;
+ struct i2c_data *data;
+
+ data=(struct i2c_data *)file->private_data;
+ if (data && (data->magic==I2C_MAGIC))
+ adr = (data->address);
+ else
+ return -EINVAL;
+ /* slave address is in the lower 7 bits -> shift left to make */
+ /* space for the data direction bit */
+ adr <<= 1;
+
+ DEB(printk("i2c%d: i2c_write: %d byte(s) to send\n", adap, count));
+
+#if LINUX_VERSION_CODE >= 0x020100
+ /* check data buffer once */
+ if ( !access_ok(VERIFY_READ,buf,count)) {
+ printk("i2c%d: Error accessing user memory!\n",adap);
+ return -ENOMEM;
+ }
+#endif
+
+ i2c_start(adap);
+ i=0;
+ while ( ! i2c_outb(adap,adr) ) {
+ i2c_stop(adap);
+ i++;
+ i2c_start(adap);
+ if (i>=i2c_table[adap].retries ) {
+ DEBACK(printk("i2c%d: i2c_write: address ack failed.\n",adap));
+ i2c_stop(adap);
+ return -EREMOTEIO;
+ };
+ }
+ while (count > 0) {
+#if LINUX_VERSION_CODE >= 0x020100
+ __get_user(c,temp); /* we use the non-checking version */
+#else
+ c = get_user(temp);
+#endif
+ DEB2(printk("i2c%d: i2c_write: writing %2.2X\n",adap, c&0xff));
+ retval = i2c_outb(adap,c);
+ if (retval>0) {
+ count--;
+ temp++;
+ wrcount++;
+ } else { /* arbitration or no acknowledge */
+ DEBE(printk("i2c%d: i2c_write: error - bailout.\n",adap));
+ i2c_stop(adap);
+ return -EREMOTEIO; /* got a better one ?? */
+ }
+ /* /usr/src/linux/include/asm/delay.h */
+ __delay(i2c_table[adap].mdelay * (loops_per_sec / 1000) );
+ }
+ i2c_stop(adap);
+ DEB2(printk(" i2c_write: wrote %d bytes.\n",wrcount));
+ return wrcount;
+}
+
+
+static int i2c_read(struct inode * inode, struct file * file,
+ char * buf, int count)
+{
+ unsigned struct bit_adapter *adap = ADAP(inode->i_rdev);
+ char *temp = buf;
+ char adr;
+ int i,inval;
+ int writetries=0; /* try to write some rounds before giving up */
+ int rdcount=0; /* counts bytes read */
+ struct i2c_data *data;
+
+ DEB(printk("i2c%d: ", adap ));
+ DEB2(printk("i2c%d: i2c_read: %d byte(s) to read\n", adap, count));
+ data=(struct i2c_data *)file->private_data;
+ if (data && (data->magic==I2C_MAGIC))
+ adr = (data->address);
+ else
+ return -EINVAL;
+ /* slave address is in the lower 7 bits -> shift left to make */
+ /* space for the data direction bit */
+ adr <<= 1;
+
+#if LINUX_VERSION_CODE >= 0x020100
+ /* check data buffer once */
+ if ( !access_ok(VERIFY_WRITE,buf,count)) {
+ printk("i2c%d: Error accessing user memory!\n",adap);
+ return -ENOMEM;
+ }
+#endif
+
+ i2c_start(adap);
+ i=0;
+
+newtry:
+
+ if ( i2c_table[adap].flags & P_COMBI ) {
+ /* This here is the repeated start condition stuff */
+ int retval;
+ /* for writing the subaddress, the R/W bit must be 0 */
+ while (!i2c_outb(adap,adr)) { /* send address first */
+ i2c_stop(adap);
+ i++;
+ if (i>=i2c_table[adap].retries ) {
+ DEBACK(printk("i2c%d: i2c_read: address ack failed\n",adap));
+ i2c_stop(adap);
+ return -EREMOTEIO;
+ };
+ i2c_start(adap); /* try again */
+ }
+ /* successful, reset fail counter */
+ i = 0;
+ /* send data */
+ for (i=0;i<data->writelength;i++) {
+ retval = i2c_outb(adap,data->buf[i]);
+ if ( !retval ) {
+ writetries++;
+ if (writetries>=i2c_table[adap].retries ) {
+ DEBE(printk("i2c%d: i2c_read: write data failed\n",adap));
+ i2c_stop(adap);
+ return -EREMOTEIO;
+ };
+ goto newtry;
+ }
+ }
+ i2c_repstart(adap);
+ }
+
+ /* send address and do a normal read */
+ if ( !i2c_outb(adap,adr | 0x01) ) {
+ i2c_stop(adap);
+ i++;
+ if ( i>=i2c_table[adap].retries ) {
+ DEBACK(printk("i2c%d: i2c_read: address ack failed.\n",adap));
+ i2c_stop(adap);
+ return -EREMOTEIO;
+ };
+ i2c_start(adap);
+ goto newtry;
+ }
+
+ while (count > 0) {
+ inval = i2c_inb(adap);
+ if (inval>=0) {
+ /* write result into user's buffer (macro) */
+#if LINUX_VERSION_CODE >= 0x020100
+ __put_user( (char)(inval) ,temp);
+#else
+ put_user((char)(inval),temp);
+#endif
+ rdcount++;
+ }
+ else { /* read timed out */
+ DEBE(printk("i2c%d: i2c_read: i2c_inb timed out.\n",adap));
+ break;
+ }
+
+ if ( count > 1 ) { /* send ack */
+ sdalo(adap);
+ DEBPROTO(printk(" Am "));
+ } else {
+ sdahi(adap); /* neg. ack on last byte */
+ DEBPROTO(printk(" NAm "));
+ }
+ if (sclhi(adap)<0) { /* timeout */
+ sdahi(adap);
+ DEBE(printk("i2c%d: i2c_read: Timeout at ack\n", adap));
+ return -ETIMEDOUT;
+ };
+ scllo(adap);
+ sdahi(adap);
+ temp++;
+ count--;
+ }
+
+ i2c_stop(adap);
+ DEB(printk("i2c%d: i2c_read: %d byte(s) read.\n", adap, rdcount ));
+ return rdcount;
+}
+
+
+static int i2c_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ unsigned struct bit_adapter *adap = ADAP(inode->i_rdev);
+ int retval = 0;
+
+ switch ( cmd ) {
+ case I2C_TIMEOUT:
+ i2c_table[adap].timeout = arg;
+ break;
+ case I2C_UDELAY:
+ i2c_table[adap].udelay = arg;
+ case I2C_MDELAY:
+ i2c_table[adap].mdelay = arg;
+ break;
+ case I2C_RETRIES:
+ i2c_table[adap].retries = arg;
+ break;
+#ifdef SLO_IO
+ case I2C_V_SLOW:
+ i2c_table[adap].veryslow = arg;
+ break;
+#endif
+ case I2C_RESET:
+ setsda(adap,1);
+ setscl(adap,1);
+ break;
+ default:
+ retval = -EINVAL;
+ }
+ return retval;
+}
+#endif
+
+static int test_bus(struct bit_adapter *adap) {
+ int scl,sda;
+ scl=getscl(adap);
+ sda=getsda(adap);
+ printk("i2c(bit): Adapter: %s scl: %d sda: %d -- testing...\n",
+ adap->name,getscl(adap),getsda(adap));
+ if (!scl || !sda ) {
+ printk("i2c(bit): %s seems to be busy.\n",adap->name);
+ goto bailout;
+ }
+ sdalo(adap);
+ printk("i2c(bit):1 scl: %d sda: %d \n",getscl(adap),getsda(adap));
+ if ( 0 != getsda(adap) ) {
+ printk("i2c(bit): %s SDA stuck high!\n",adap->name);
+ sdahi(adap);
+ goto bailout;
+ }
+ if ( 0 == getscl(adap) ) {
+ printk("i2c(bit): %s SCL unexpected low while pulling SDA low!\n",
+ adap->name);
+ goto bailout;
+ }
+ sdahi(adap);
+ printk("i2c(bit):2 scl: %d sda: %d \n",getscl(adap),getsda(adap));
+ if ( 0 == getsda(adap) ) {
+ printk("i2c(bit): %s SDA stuck low!\n",adap->name);
+ sdahi(adap);
+ goto bailout;
+ }
+ if ( 0 == getscl(adap) ) {
+ printk("i2c(bit): %s SCL unexpected low while SDA high!\n",adap->name);
+ goto bailout;
+ }
+ scllo(adap);
+ printk("i2c(bit):3 scl: %d sda: %d \n",getscl(adap),getsda(adap));
+ if ( 0 != getscl(adap) ) {
+ printk("i2c(bit): %s SCL stuck high!\n",adap->name);
+ sclhi(adap);
+ goto bailout;
+ }
+ if ( 0 == getsda(adap) ) {
+ printk("i2c(bit): %s SDA unexpected low while pulling SCL low!\n",
+ adap->name);
+ goto bailout;
+ }
+ sclhi(adap);
+ printk("i2c(bit):4 scl: %d sda: %d \n",getscl(adap),getsda(adap));
+ if ( 0 == getscl(adap) ) {
+ printk("i2c(bit): %s SCL stuck low!\n",adap->name);
+ sclhi(adap);
+ goto bailout;
+ }
+ if ( 0 == getsda(adap) ) {
+ printk("i2c(bit): %s SDA unexpected low while SCL high!\n",
+ adap->name);
+ goto bailout;
+ }
+ printk("i2c(bit): %s passed test.\n",adap->name);
+ return 0;
+bailout:
+ return -ENODEV;
+}
+
+/* ----- Utility functions
+ */
+
+inline int try_address(struct bit_adapter *adap,unsigned char addr, int retries)
+{
+ int i,ret = -1;
+ for (i=0;;) {
+ ret = i2c_outb(adap,addr);
+ if (ret==1)
+ break; /* success! */
+ i2c_stop(adap);
+ udelay(adap->udelay);
+ if (++i >= retries)
+ break;
+ i2c_start(adap);
+ udelay(adap->udelay);
+ }
+ DEB(if (i) printk("i2c(bit): needed %d retries for %d \n",i,addr));
+ return ret;
+}
+
+
+static int bit_send(struct i2c_client *client,const char *buf, int count)
+{
+ struct i2c_adapter *adapter=client->adapter;
+ struct bit_adapter *adap=(struct bit_adapter*)adapter->data;
+ char c;
+ const char *temp = buf;
+ int ret,retval,i;
+ int wrcount=0;
+ unsigned int flags=client->flags;
+ /* slave address is in the lower 7 bits -> shift left to make */
+ /* space for the data direction bit */
+
+ DEB(printk("i2c(bit): %s i2c_write: %d byte(s) to send\n", adap->name, count));
+
+ i2c_start(adap);
+ i=0;
+
+ /* first send address: */
+ if ( flags & CF_TEN ) { /* a ten bit address */
+ unsigned char addr = 0xf0 | ((flags>>15)&0x06);
+ printk("addr0: %d, sub %d\n",(unsigned char)addr,((flags>>15)&0x06));
+ /* try extended address code...*/
+ ret = try_address(adap, (unsigned char)addr, adapter->retries);
+ if (ret!=1) {
+ printk("died at extended address code.\n");
+ return -EREMOTEIO;
+ }
+ /* the remaining 8 bit address */
+ ret = i2c_outb(adap,client->addr);
+ if (ret != 1) {
+ printk("died at 2nd address code.\n");
+ return -EREMOTEIO;
+ }
+ /* okay, now we are set up to send data*/
+ } else { /* normal 7bit address */
+ char addr = ( client->addr << 1 );
+ ret = try_address(adap, addr, adapter->retries);
+ if (ret!=1)
+ return -EREMOTEIO;
+ }
+
+ /* send the data */
+ while (count > 0) {
+ c = *temp;
+ DEB2(printk("i2c(bit): %s i2c_write: writing %2.2X\n",adap->name, c&0xff));
+ retval = i2c_outb(adap,c);
+ if (retval>0) {
+ count--;
+ temp++;
+ wrcount++;
+ } else { /* arbitration or no acknowledge */
+ DEBE(printk("i2c(bit): %s i2c_write: error - bailout.\n",adap->name));
+ i2c_stop(adap);
+ return -EREMOTEIO; /* got a better one ?? */
+ }
+ /* from asm/delay.h */
+ __delay(adap->mdelay * (loops_per_sec / 1000) );
+ }
+ i2c_stop(adap);
+ DEB2(printk(" i2c_write: wrote %d bytes.\n",wrcount));
+ return wrcount;
+}
+
+
+static int bit_recv(struct i2c_client *client,char *buf,int count)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ struct bit_adapter *adap = (struct bit_adapter*)adapter->data;
+ char *temp = buf;
+ unsigned int flags = client->flags;
+ char addr;
+ int ret=0,i,inval;
+ int rdcount=0; /* counts bytes read */
+
+ DEB2(printk("i2c(bit): %s i2c_read: %d byte(s) to read\n", adap->name, count));
+
+ /* slave address is in the lower 7 bits -> shift left to make */
+ /* space for the data direction bit */
+
+#if LINUX_VERSION_CODE >= 0x020100
+ /* check data buffer once */
+ if ( !access_ok(VERIFY_WRITE,buf,count)) {
+ printk("i2c(bit): Error accessing user memory for bit_read!\n");
+ return -ENOMEM;
+ }
+#endif
+ i2c_start(adap);
+ i=0;
+ DEB2(printk("i2c(bit): flags %#x\n",flags));
+ /* first send address: */
+ if ( (flags & CF_TEN) != 0 ) { /* a ten bit address */
+ addr = 0xf0 | ((flags>>15)&0x06);
+ printk("addr0: %d, sub %d\n",addr,((flags>>15)&0x06));
+ /* try extended address code...*/
+ ret = try_address(adap, addr, adapter->retries);
+ if (ret!=1) {
+ printk("died at extended address code.\n");
+ return -EREMOTEIO;
+ }
+ /* the remaining 8 bit address */
+ ret = i2c_outb(adap,client->addr);
+ if (ret != 1) {
+ printk("died at 2nd address code.\n");
+ return -EREMOTEIO;
+ }
+ i2c_repstart(adap);
+ /* okay, now switch into reading mode */
+ addr |= 0x01;
+ ret = try_address(adap, addr, adapter->retries);
+ if (ret!=1) {
+ printk("died at extended address code.\n");
+ return -EREMOTEIO;
+ }
+ } else { /* normal 7bit address */
+ addr = ( client->addr << 1 ) | 0x01;
+ ret = try_address(adap, addr, adapter->retries);
+ if (ret!=1)
+ return -EREMOTEIO;
+ }
+
+ udelay(adap->udelay);
+ /* now read the data */
+ while (count > 0) {
+ inval = i2c_inb(adap);
+ if (inval>=0) {
+ /* write result into user's buffer (macro) */
+#if LINUX_VERSION_CODE >= 0x020100
+ __put_user( (char)(inval) ,temp);
+#else
+ put_user((char)(inval),temp);
+#endif
+ rdcount++;
+ }
+ else { /* read timed out */
+ DEBE(printk("i2c(bit): i2c_read: i2c_inb timed out.\n"));
+ break;
+ }
+
+ if ( count > 1 ) { /* send ack */
+ sdalo(adap);
+ DEBPROTO(printk(" Am "));
+ } else {
+ sdahi(adap); /* neg. ack on last byte */
+ DEBPROTO(printk(" NAm "));
+ }
+ if (sclhi(adap)<0) { /* timeout */
+ sdahi(adap);
+ DEBE(printk("i2c(bit): i2c_read: Timeout at ack\n"));
+ return -ETIMEDOUT;
+ };
+ scllo(adap);
+ sdahi(adap);
+ temp++;
+ count--;
+ }
+
+ i2c_stop(adap);
+ DEB(printk("i2c(bit): i2c_read: %d byte(s) read.\n", rdcount ));
+ return rdcount;
+}
+
+static int bit_comb(struct i2c_client *client,char*r,const char*w,int i,int j, int k)
+{
+ return 0;
+}
+
+
+static int algo_control(struct i2c_adapter *adapter,
+ unsigned int cmd, unsigned long arg)
+{
+ return 0;
+}
+
+static int client_register(struct i2c_client *client)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ struct bit_adapter *adap = (struct bit_adapter*)adapter->data;
+
+ if (adap->client_register != NULL)
+ return adap->client_register(client);
+ return 0;
+}
+
+int client_unregister(struct i2c_client *client)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ struct bit_adapter *adap = (struct bit_adapter*)adapter->data;
+
+ if (adap->client_unregister != NULL)
+ return adap->client_unregister(client);
+ return 0;
+}
+
+/* -----exported algorithm data: ------------------------------------- */
+
+struct i2c_algorithm bit_algo = {
+ "Bit-shift algorithm",
+ ALGO_BIT,
+ bit_send, /* master_xmit */
+ bit_recv, /* master_recv */
+ bit_comb, /* master_comb */
+ NULL, /* slave_xmit */
+ NULL, /* slave_recv */
+ algo_control, /* ioctl */
+ client_register,
+ client_unregister,
+};
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+int i2c_bit_register_bus(struct bit_adapter *adap)
+{
+ int i,ack;
+ struct i2c_adapter *i2c_adap;
+
+ for (i = 0; i < BIT_ADAP_MAX; i++)
+ if (NULL == bit_adaps[i])
+ break;
+ if (BIT_ADAP_MAX == i)
+ return -ENOMEM;
+
+ bit_adaps[i] = adap;
+ adap_count++;
+ DEB(printk("i2c(bit): algorithm %s registered.\n",adap->name));
+
+ MOD_INC_USE_COUNT;
+
+ if (test) {
+ int ret = test_bus(adap);
+ if (ret<0)
+ return -ENODEV;
+ }
+ /* register new adapter to i2c module... */
+
+ i2c_adap = kmalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
+ i2c_adap->name = adap->name;
+ i2c_adap->id = bit_algo.id | adap->id;
+ i2c_adap->algo = &bit_algo;
+ i2c_adap->data = adap;
+ i2c_adap->flags = 0;
+ i2c_adap->timeout = 100; /* default values, should */
+ i2c_adap->retries = 3; /* be replaced by defines */
+ i2c_adaps[i] = i2c_adap;
+ i2c_register_adapter(i2c_adap);
+
+ /* scan bus */
+ printk(KERN_INFO "i2c(bit): scanning bus %s.\n", adap->name);
+ if (scan)
+ for (i = 0x00; i < 0xff; i+=2) {
+ i2c_start(adap);
+ ack = i2c_outb(adap,i);
+ i2c_stop(adap);
+ if (ack>0) {
+ printk(KERN_INFO
+ "i2c(bit): found chip at addr=0x%2x\n",i);
+ }
+ }
+ return 0;
+}
+
+
+int i2c_bit_unregister_bus(struct bit_adapter *adap)
+{
+ int i;
+
+ for (i = 0; i < BIT_ADAP_MAX; i++)
+ if ( adap == bit_adaps[i])
+ break;
+ if ( BIT_ADAP_MAX == i) {
+ printk(KERN_WARNING "i2c(bit): could not unregister bus: %s\n",
+ adap->name);
+ return -ENODEV;
+ }
+
+ MOD_DEC_USE_COUNT;
+
+ bit_adaps[i] = NULL;
+ i2c_unregister_adapter(i2c_adaps[i]);
+ kfree(i2c_adaps[i]);
+ i2c_adaps[i] = NULL;
+ adap_count--;
+ DEB(printk("i2c(bit): adapter unregistered: %s\n",adap->name));
+
+ return 0;
+}
+
+int algo_bit_init (void)
+{
+ int i;
+
+ for (i=0;i<BIT_ADAP_MAX;i++) {
+ bit_adaps[i]=NULL;
+ }
+ adap_count=0;
+ i2c_register_algorithm(&bit_algo);
+ return 0;
+}
+
+#ifdef MODULE
+MODULE_PARM(test, "i");
+MODULE_PARM(scan, "i");
+
+/*
+EXPORT_SYMBOL(i2c_bit_register_bus);
+EXPORT_SYMBOL(i2c_bit_unregister_bus);
+*/
+
+int init_module(void)
+{
+ return algo_bit_init();
+}
+
+void cleanup_module(void)
+{
+ i2c_unregister_algorithm(&bit_algo);
+}
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bttv/experimental/algo-bit.h b/bttv/experimental/algo-bit.h
new file mode 100644
index 0000000..0cd97d8
--- /dev/null
+++ b/bttv/experimental/algo-bit.h
@@ -0,0 +1,38 @@
+#ifndef ALGO_BIT_H
+#define AGLO_BIT_H 1
+
+/* --- Defines for bit-adapters --------------------------------------- */
+#include "i2c.h"
+/*
+ * This struct contains the hw-dependent functions of bit-style adapters to
+ * manipulate the line states, and to init any hw-specific features. This is
+ * only used if you have more than one hw-type of adapter running.
+ */
+struct bit_adapter {
+ char *name; /* give it a nice name */
+ unsigned int id; /* not used yet, maybe later */
+ void *data; /* private data for lolevel routines */
+ void (*setsda) (void *data, int state);
+ void (*setscl) (void *data, int state);
+ int (*getsda) (void *data);
+ int (*getscl) (void *data);
+
+ /* administrative calls */
+ int (*client_register)(struct i2c_client *);
+ int (*client_unregister)(struct i2c_client *);
+
+ /* local settings */
+ int udelay;
+ int mdelay;
+ int timeout;
+
+};
+
+extern struct bit_adapter *bit_adaps[];
+
+#define BIT_ADAP_MAX 16
+
+int i2c_bit_register_bus(struct bit_adapter *);
+int i2c_bit_unregister_bus(struct bit_adapter *);
+
+#endif /* ALGO_BIT_H */
diff --git a/bttv/experimental/bt848.h b/bttv/experimental/bt848.h
new file mode 100644
index 0000000..0956360
--- /dev/null
+++ b/bttv/experimental/bt848.h
@@ -0,0 +1,348 @@
+/*
+ bt848.h - Bt848 register offsets
+
+ Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
+
+ 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 _BT848_H_
+#define _BT848_H_
+
+#ifndef PCI_VENDOR_ID_BROOKTREE
+#define PCI_VENDOR_ID_BROOKTREE 0x109e
+#endif
+#ifndef PCI_DEVICE_ID_BT848
+#define PCI_DEVICE_ID_BT848 0x350
+#endif
+#ifndef PCI_DEVICE_ID_BT849
+#define PCI_DEVICE_ID_BT849 0x351
+#endif
+#ifndef PCI_DEVICE_ID_BT878
+#define PCI_DEVICE_ID_BT878 0x36e
+#endif
+#ifndef PCI_DEVICE_ID_BT879
+#define PCI_DEVICE_ID_BT879 0x36f
+#endif
+
+
+/* Brooktree 848 registers */
+
+#define BT848_DSTATUS 0x000
+#define BT848_DSTATUS_PRES (1<<7)
+#define BT848_DSTATUS_HLOC (1<<6)
+#define BT848_DSTATUS_FIELD (1<<5)
+#define BT848_DSTATUS_NUML (1<<4)
+#define BT848_DSTATUS_CSEL (1<<3)
+#define BT848_DSTATUS_PLOCK (1<<2)
+#define BT848_DSTATUS_LOF (1<<1)
+#define BT848_DSTATUS_COF (1<<0)
+
+#define BT848_IFORM 0x004
+#define BT848_IFORM_HACTIVE (1<<7)
+#define BT848_IFORM_MUXSEL (3<<5)
+#define BT848_IFORM_MUX0 (2<<5)
+#define BT848_IFORM_MUX1 (3<<5)
+#define BT848_IFORM_MUX2 (1<<5)
+#define BT848_IFORM_XTSEL (3<<3)
+#define BT848_IFORM_XT0 (1<<3)
+#define BT848_IFORM_XT1 (2<<3)
+#define BT848_IFORM_XTAUTO (3<<3)
+#define BT848_IFORM_XTBOTH (3<<3)
+#define BT848_IFORM_NTSC 1
+#define BT848_IFORM_NTSC_J 2
+#define BT848_IFORM_PAL_BDGHI 3
+#define BT848_IFORM_PAL_M 4
+#define BT848_IFORM_PAL_N 5
+#define BT848_IFORM_SECAM 6
+#define BT848_IFORM_PAL_NC 7
+#define BT848_IFORM_AUTO 0
+#define BT848_IFORM_NORM 7
+
+#define BT848_TDEC 0x008
+#define BT848_TDEC_DEC_FIELD (1<<7)
+#define BT848_TDEC_FLDALIGN (1<<6)
+#define BT848_TDEC_DEC_RAT (0x1f)
+
+#define BT848_E_CROP 0x00C
+#define BT848_O_CROP 0x08C
+
+#define BT848_E_VDELAY_LO 0x010
+#define BT848_O_VDELAY_LO 0x090
+
+#define BT848_E_VACTIVE_LO 0x014
+#define BT848_O_VACTIVE_LO 0x094
+
+#define BT848_E_HDELAY_LO 0x018
+#define BT848_O_HDELAY_LO 0x098
+
+#define BT848_E_HACTIVE_LO 0x01C
+#define BT848_O_HACTIVE_LO 0x09C
+
+#define BT848_E_HSCALE_HI 0x020
+#define BT848_O_HSCALE_HI 0x0A0
+
+#define BT848_E_HSCALE_LO 0x024
+#define BT848_O_HSCALE_LO 0x0A4
+
+#define BT848_BRIGHT 0x028
+
+#define BT848_E_CONTROL 0x02C
+#define BT848_O_CONTROL 0x0AC
+#define BT848_CONTROL_LNOTCH (1<<7)
+#define BT848_CONTROL_COMP (1<<6)
+#define BT848_CONTROL_LDEC (1<<5)
+#define BT848_CONTROL_CBSENSE (1<<4)
+#define BT848_CONTROL_CON_MSB (1<<2)
+#define BT848_CONTROL_SAT_U_MSB (1<<1)
+#define BT848_CONTROL_SAT_V_MSB (1<<0)
+
+#define BT848_CONTRAST_LO 0x030
+#define BT848_SAT_U_LO 0x034
+#define BT848_SAT_V_LO 0x038
+#define BT848_HUE 0x03C
+
+#define BT848_E_SCLOOP 0x040
+#define BT848_O_SCLOOP 0x0C0
+#define BT848_SCLOOP_CAGC (1<<6)
+#define BT848_SCLOOP_CKILL (1<<5)
+#define BT848_SCLOOP_HFILT_AUTO (0<<3)
+#define BT848_SCLOOP_HFILT_CIF (1<<3)
+#define BT848_SCLOOP_HFILT_QCIF (2<<3)
+#define BT848_SCLOOP_HFILT_ICON (3<<3)
+
+#define BT848_SCLOOP_PEAK (1<<7)
+#define BT848_SCLOOP_HFILT_MINP (1<<3)
+#define BT848_SCLOOP_HFILT_MEDP (2<<3)
+#define BT848_SCLOOP_HFILT_MAXP (3<<3)
+
+
+#define BT848_OFORM 0x048
+#define BT848_OFORM_RANGE (1<<7)
+#define BT848_OFORM_CORE0 (0<<5)
+#define BT848_OFORM_CORE8 (1<<5)
+#define BT848_OFORM_CORE16 (2<<5)
+#define BT848_OFORM_CORE32 (3<<5)
+
+#define BT848_E_VSCALE_HI 0x04C
+#define BT848_O_VSCALE_HI 0x0CC
+#define BT848_VSCALE_YCOMB (1<<7)
+#define BT848_VSCALE_COMB (1<<6)
+#define BT848_VSCALE_INT (1<<5)
+#define BT848_VSCALE_HI 15
+
+#define BT848_E_VSCALE_LO 0x050
+#define BT848_O_VSCALE_LO 0x0D0
+#define BT848_TEST 0x054
+#define BT848_ADELAY 0x060
+#define BT848_BDELAY 0x064
+
+#define BT848_ADC 0x068
+#define BT848_ADC_RESERVED (2<<6)
+#define BT848_ADC_SYNC_T (1<<5)
+#define BT848_ADC_AGC_EN (1<<4)
+#define BT848_ADC_CLK_SLEEP (1<<3)
+#define BT848_ADC_Y_SLEEP (1<<2)
+#define BT848_ADC_C_SLEEP (1<<1)
+#define BT848_ADC_CRUSH (1<<0)
+
+#define BT848_E_VTC 0x06C
+#define BT848_O_VTC 0x0EC
+#define BT848_VTC_HSFMT (1<<7)
+#define BT848_VTC_VFILT_2TAP 0
+#define BT848_VTC_VFILT_3TAP 1
+#define BT848_VTC_VFILT_4TAP 2
+#define BT848_VTC_VFILT_5TAP 3
+
+#define BT848_SRESET 0x07C
+
+#define BT848_COLOR_FMT 0x0D4
+#define BT848_COLOR_FMT_O_RGB32 (0<<4)
+#define BT848_COLOR_FMT_O_RGB24 (1<<4)
+#define BT848_COLOR_FMT_O_RGB16 (2<<4)
+#define BT848_COLOR_FMT_O_RGB15 (3<<4)
+#define BT848_COLOR_FMT_O_YUY2 (4<<4)
+#define BT848_COLOR_FMT_O_BtYUV (5<<4)
+#define BT848_COLOR_FMT_O_Y8 (6<<4)
+#define BT848_COLOR_FMT_O_RGB8 (7<<4)
+#define BT848_COLOR_FMT_O_YCrCb422 (8<<4)
+#define BT848_COLOR_FMT_O_YCrCb411 (9<<4)
+#define BT848_COLOR_FMT_O_RAW (14<<4)
+#define BT848_COLOR_FMT_E_RGB32 0
+#define BT848_COLOR_FMT_E_RGB24 1
+#define BT848_COLOR_FMT_E_RGB16 2
+#define BT848_COLOR_FMT_E_RGB15 3
+#define BT848_COLOR_FMT_E_YUY2 4
+#define BT848_COLOR_FMT_E_BtYUV 5
+#define BT848_COLOR_FMT_E_Y8 6
+#define BT848_COLOR_FMT_E_RGB8 7
+#define BT848_COLOR_FMT_E_YCrCb422 8
+#define BT848_COLOR_FMT_E_YCrCb411 9
+#define BT848_COLOR_FMT_E_RAW 14
+
+#define BT848_COLOR_FMT_RGB32 0x00
+#define BT848_COLOR_FMT_RGB24 0x11
+#define BT848_COLOR_FMT_RGB16 0x22
+#define BT848_COLOR_FMT_RGB15 0x33
+#define BT848_COLOR_FMT_YUY2 0x44
+#define BT848_COLOR_FMT_BtYUV 0x55
+#define BT848_COLOR_FMT_Y8 0x66
+#define BT848_COLOR_FMT_RGB8 0x77
+#define BT848_COLOR_FMT_YCrCb422 0x88
+#define BT848_COLOR_FMT_YCrCb411 0x99
+#define BT848_COLOR_FMT_RAW 0xee
+
+#define BT848_COLOR_CTL 0x0D8
+#define BT848_COLOR_CTL_EXT_FRMRATE (1<<7)
+#define BT848_COLOR_CTL_COLOR_BARS (1<<6)
+#define BT848_COLOR_CTL_RGB_DED (1<<5)
+#define BT848_COLOR_CTL_GAMMA (1<<4)
+#define BT848_COLOR_CTL_WSWAP_ODD (1<<3)
+#define BT848_COLOR_CTL_WSWAP_EVEN (1<<2)
+#define BT848_COLOR_CTL_BSWAP_ODD (1<<1)
+#define BT848_COLOR_CTL_BSWAP_EVEN (1<<0)
+
+#define BT848_CAP_CTL 0x0DC
+#define BT848_CAP_CTL_DITH_FRAME (1<<4)
+#define BT848_CAP_CTL_CAPTURE_VBI_ODD (1<<3)
+#define BT848_CAP_CTL_CAPTURE_VBI_EVEN (1<<2)
+#define BT848_CAP_CTL_CAPTURE_ODD (1<<1)
+#define BT848_CAP_CTL_CAPTURE_EVEN (1<<0)
+
+#define BT848_VBI_PACK_SIZE 0x0E0
+
+#define BT848_VBI_PACK_DEL 0x0E4
+#define BT848_VBI_PACK_DEL_VBI_HDELAY 0xfc
+#define BT848_VBI_PACK_DEL_EXT_FRAME 2
+#define BT848_VBI_PACK_DEL_VBI_PKT_HI 1
+
+
+#define BT848_INT_STAT 0x100
+#define BT848_INT_MASK 0x104
+
+#define BT848_INT_ETBF (1<<23)
+
+#define BT848_INT_RISCS (0xf<<28)
+#define BT848_INT_RISC_EN (1<<27)
+#define BT848_INT_RACK (1<<25)
+#define BT848_INT_FIELD (1<<24)
+#define BT848_INT_SCERR (1<<19)
+#define BT848_INT_OCERR (1<<18)
+#define BT848_INT_PABORT (1<<17)
+#define BT848_INT_RIPERR (1<<16)
+#define BT848_INT_PPERR (1<<15)
+#define BT848_INT_FDSR (1<<14)
+#define BT848_INT_FTRGT (1<<13)
+#define BT848_INT_FBUS (1<<12)
+#define BT848_INT_RISCI (1<<11)
+#define BT848_INT_GPINT (1<<9)
+#define BT848_INT_I2CDONE (1<<8)
+#define BT848_INT_VPRES (1<<5)
+#define BT848_INT_HLOCK (1<<4)
+#define BT848_INT_OFLOW (1<<3)
+#define BT848_INT_HSYNC (1<<2)
+#define BT848_INT_VSYNC (1<<1)
+#define BT848_INT_FMTCHG (1<<0)
+
+
+#define BT848_GPIO_DMA_CTL 0x10C
+#define BT848_GPIO_DMA_CTL_GPINTC (1<<15)
+#define BT848_GPIO_DMA_CTL_GPINTI (1<<14)
+#define BT848_GPIO_DMA_CTL_GPWEC (1<<13)
+#define BT848_GPIO_DMA_CTL_GPIOMODE (3<<11)
+#define BT848_GPIO_DMA_CTL_GPCLKMODE (1<<10)
+#define BT848_GPIO_DMA_CTL_PLTP23_4 (0<<6)
+#define BT848_GPIO_DMA_CTL_PLTP23_8 (1<<6)
+#define BT848_GPIO_DMA_CTL_PLTP23_16 (2<<6)
+#define BT848_GPIO_DMA_CTL_PLTP23_32 (3<<6)
+#define BT848_GPIO_DMA_CTL_PLTP1_4 (0<<4)
+#define BT848_GPIO_DMA_CTL_PLTP1_8 (1<<4)
+#define BT848_GPIO_DMA_CTL_PLTP1_16 (2<<4)
+#define BT848_GPIO_DMA_CTL_PLTP1_32 (3<<4)
+#define BT848_GPIO_DMA_CTL_PKTP_4 (0<<2)
+#define BT848_GPIO_DMA_CTL_PKTP_8 (1<<2)
+#define BT848_GPIO_DMA_CTL_PKTP_16 (2<<2)
+#define BT848_GPIO_DMA_CTL_PKTP_32 (3<<2)
+#define BT848_GPIO_DMA_CTL_RISC_ENABLE (1<<1)
+#define BT848_GPIO_DMA_CTL_FIFO_ENABLE (1<<0)
+
+#define BT848_I2C 0x110
+#define BT848_I2C_DIV (0xf<<4)
+#define BT848_I2C_SYNC (1<<3)
+#define BT848_I2C_W3B (1<<2)
+#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
+#define BT848_RISC_COUNT 0x120
+#define BT848_GPIO_DATA 0x200
+
+
+/* Bt848 RISC commands */
+
+/* only for the SYNC RISC command */
+#define BT848_FIFO_STATUS_FM1 0x06
+#define BT848_FIFO_STATUS_FM3 0x0e
+#define BT848_FIFO_STATUS_SOL 0x02
+#define BT848_FIFO_STATUS_EOL4 0x01
+#define BT848_FIFO_STATUS_EOL3 0x0d
+#define BT848_FIFO_STATUS_EOL2 0x09
+#define BT848_FIFO_STATUS_EOL1 0x05
+#define BT848_FIFO_STATUS_VRE 0x04
+#define BT848_FIFO_STATUS_VRO 0x0c
+#define BT848_FIFO_STATUS_PXV 0x00
+
+#define BT848_RISC_RESYNC (1<<15)
+
+/* 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_BYTE_NONE 0
+/* cause RISCI */
+#define BT848_RISC_IRQ (1<<24)
+/* RISC command is last one in this line */
+#define BT848_RISC_EOL (1<<26)
+/* RISC command is first one in this line */
+#define BT848_RISC_SOL (1<<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_WRITE123 (0x09<<28)
+#define BT848_RISC_SKIP123 (0x0a<<28)
+#define BT848_RISC_WRITE1S23 (0x0b<<28)
+
+
+
+/* Bt848A and Bt849 only !! */
+#define BT848_TGLB 0x080
+#define BT848_TGCTRL 0x084
+#define BT848_FCAP 0x0E8
+#define BT848_PLL_F_LO 0x0F0
+#define BT848_PLL_F_HI 0x0F4
+#define BT848_PLL_XCI 0x0F8
+
+
+#endif
diff --git a/bttv/experimental/bttv.c b/bttv/experimental/bttv.c
new file mode 100644
index 0000000..14864a2
--- /dev/null
+++ b/bttv/experimental/bttv.c
@@ -0,0 +1,3261 @@
+/*
+ bttv - Bt848 frame grabber driver
+
+ Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
+ & Marcus Metzler (mocm@thp.uni-koeln.de)
+
+ 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.
+
+ Modified to put the RISC code writer in the kernel and to fit a
+ common (and I hope safe) kernel interface. When we have an X extension
+ all will now be really sweet.
+
+ TODO:
+
+ * move norm from tuner to channel struct!?
+ composite source from a satellite tuner can deliver different norms
+ depending on tuned channel
+ * mmap VBI data?
+ * use new PCI routines
+ * fix RAW Composite grabbing for NTSC
+ * allow for different VDELAYs
+ (larger to get Videodat in VBI and smaller to get the whole
+ picture in RAW grabbing)
+ * extra modules for tda9850, tda8425, any volunteers???
+ * right border clipping is still buggy
+ (decide which clipping code to use and throw the other out ...)
+*/
+
+#include <linux/module.h>
+#include <linux/bios32.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/sched.h>
+#include <asm/segment.h>
+#include <linux/types.h>
+#include <linux/wrapper.h>
+
+#include "videodev.h"
+#include <linux/version.h>
+#if LINUX_VERSION_CODE >= 0x020100
+#include <asm/uaccess.h>
+#else
+#define signal_pending(current) (current->signal & ~current->blocked)
+#define sigfillset(set)
+
+static inline unsigned long
+copy_to_user(void *to, const void *from, unsigned long n)
+{
+ memcpy_tofs(to,from,n);
+ return 0;
+}
+
+static inline unsigned long
+copy_from_user(void *to, const void *from, unsigned long n)
+{
+ memcpy_fromfs(to,from,n);
+ return 0;
+}
+#define ioremap vremap
+#define iounmap vfree
+#endif
+
+#include "i2c.h"
+#include "algo-bit.h"
+#include "bttv.h"
+#include "tuner.h"
+
+#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=CARD_DEFAULT;
+
+#if LINUX_VERSION_CODE >= 0x020117
+MODULE_PARM(remap,"i");
+MODULE_PARM(vidmem,"i");
+MODULE_PARM(triton1,"i");
+MODULE_PARM(radio,"i");
+MODULE_PARM(card,"i");
+#endif
+
+static int find_vga(void);
+static void bt848_set_risc_jmps(struct bttv *btv);
+
+/* Anybody who uses more than four? */
+#define BTTV_MAX 4
+
+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 AUDIO_MUTE_DELAY 10000
+#define FREQ_CHANGE_DELAY 20000
+#define EEPROM_WRITE_DELAY 20000
+
+/*******************************/
+/* Memory management functions */
+/*******************************/
+
+/* convert virtual user memory address to physical address */
+/* (virt_to_phys only works for kmalloced kernel memory) */
+
+static inline unsigned long uvirt_to_phys(unsigned long adr)
+{
+ pgd_t *pgd;
+ pmd_t *pmd;
+ pte_t *ptep, pte;
+
+ pgd = pgd_offset(current->mm, adr);
+ if (pgd_none(*pgd))
+ return 0;
+ pmd = pmd_offset(pgd, adr);
+ if (pmd_none(*pmd))
+ return 0;
+ ptep = pte_offset(pmd, adr/*&(~PGDIR_MASK)*/);
+ pte = *ptep;
+ if(pte_present(pte))
+ return
+ virt_to_phys((void *)(pte_page(pte)|(adr&(PAGE_SIZE-1))));
+ return 0;
+}
+
+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)));
+}
+
+/* convert virtual kernel memory address to physical address */
+/* (virt_to_phys only works for kmalloced kernel memory) */
+
+static inline unsigned long kvirt_to_phys(unsigned long adr)
+{
+ return uvirt_to_phys(VMALLOC_VMADDR(adr));
+}
+
+static inline unsigned long kvirt_to_bus(unsigned long adr)
+{
+ return uvirt_to_bus(VMALLOC_VMADDR(adr));
+}
+
+static void * rvmalloc(unsigned long size)
+{
+ void * mem;
+ unsigned long adr, page;
+
+ mem=vmalloc(size);
+ if (mem)
+ {
+ adr=(unsigned long) mem;
+ while (size > 0)
+ {
+ page = kvirt_to_phys(adr);
+ mem_map_reserve(MAP_NR(phys_to_virt(page)));
+ adr+=PAGE_SIZE;
+ size-=PAGE_SIZE;
+ }
+ }
+ return mem;
+}
+
+static void rvfree(void * mem, unsigned long size)
+{
+ unsigned long adr, page;
+
+ if (mem)
+ {
+ adr=(unsigned long) mem;
+ while (size > 0)
+ {
+ page = kvirt_to_phys(adr);
+ mem_map_unreserve(MAP_NR(phys_to_virt(page)));
+ adr+=PAGE_SIZE;
+ size-=PAGE_SIZE;
+ }
+ vfree(mem);
+ }
+}
+
+/*
+ * Create the giant waste of buffer space we need for now
+ * until we get DMA to user space sorted out (probably 2.3.x)
+ *
+ * We only create this as and when someone uses mmap
+ */
+
+static int fbuffer_alloc(struct bttv *btv)
+{
+ if(!btv->fbuffer)
+ btv->fbuffer=(unsigned char *) rvmalloc(2*BTTV_MAX_FBUF);
+ else
+ printk(KERN_ERR "bttv: Double alloc of fbuffer!\n");
+ if(!btv->fbuffer)
+ return -ENOBUFS;
+ return 0;
+}
+
+
+/* ----------------------------------------------------------------------- */
+/* I2C functions */
+
+/* hardware I2C functions */
+
+/* read I2C */
+static int I2CRead(struct bttv *btv, unsigned char addr)
+{
+ u32 i;
+ u32 stat;
+
+ /* clear status bit ; BT848_INT_RACK is ro */
+ btwrite(BT848_INT_I2CDONE, BT848_INT_STAT);
+
+ btwrite(((addr & 0xff) << 24) | I2C_COMMAND, BT848_I2C);
+
+ /*
+ * Timeout for I2CRead is 1 second (this should be enough, really!)
+ */
+ for (i=1000; i; i--)
+ {
+ stat=btread(BT848_INT_STAT);
+ if (stat & BT848_INT_I2CDONE)
+ break;
+#if LINUX_VERSION_CODE >= 0x020199
+ mdelay(1);
+#else
+ udelay(1000);
+#endif
+ }
+
+ if (!i)
+ {
+ printk(KERN_DEBUG "bttv: I2CRead timeout\n");
+ return -1;
+ }
+ if (!(stat & BT848_INT_RACK))
+ return -2;
+
+ i=(btread(BT848_I2C)>>8)&0xff;
+ return i;
+}
+
+/* set both to write both bytes, reset it to write only b1 */
+
+static int I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1,
+ unsigned char b2, int both)
+{
+ u32 i;
+ u32 data;
+ u32 stat;
+
+ /* clear status bit; BT848_INT_RACK is ro */
+ btwrite(BT848_INT_I2CDONE, BT848_INT_STAT);
+
+ data=((addr & 0xff) << 24) | ((b1 & 0xff) << 16) | I2C_COMMAND;
+ if (both)
+ {
+ data|=((b2 & 0xff) << 8);
+ data|=BT848_I2C_W3B;
+ }
+
+ btwrite(data, BT848_I2C);
+
+ for (i=0x1000; i; i--)
+ {
+ stat=btread(BT848_INT_STAT);
+ if (stat & BT848_INT_I2CDONE)
+ break;
+#if LINUX_VERSION_CODE >= 0x020199
+ mdelay(1);
+#else
+ udelay(1000);
+#endif
+ }
+
+ if (!i)
+ {
+ printk(KERN_DEBUG "bttv: I2CWrite timeout\n");
+ return -1;
+ }
+ if (!(stat & BT848_INT_RACK))
+ return -2;
+
+ return 0;
+}
+
+#define I2C_VERY_VERBOSE 0
+
+static void bit_bt848_setscl(void *data, int state)
+{
+ struct bttv *btv = (struct bttv*)data;
+
+ if (state)
+ btv->i2c_state |= 0x02;
+ else
+ btv->i2c_state &= ~0x02;
+#if I2C_VERY_VERBOSE
+ printk("bttv i2c: set ctrl %d - c%d d%d\n",
+ state,
+ btv->i2c_state & 0x02 ? 1 : 0, btv->i2c_state & 0x01 ? 1 : 0);
+#endif
+ btwrite(btv->i2c_state, BT848_I2C);
+}
+
+static void bit_bt848_setsda(void *data, int state)
+{
+ struct bttv *btv = (struct bttv*)data;
+
+ if (state)
+ btv->i2c_state |= 0x01;
+ else
+ btv->i2c_state &= ~0x01;
+#if I2C_VERY_VERBOSE
+ printk("bttv i2c: set data %d - c%d d%d\n",
+ state,
+ btv->i2c_state & 0x02 ? 1 : 0, btv->i2c_state & 0x01 ? 1 : 0);
+#endif
+ btwrite(btv->i2c_state, BT848_I2C);
+}
+
+static int bit_bt848_getscl(void *data)
+{
+ struct bttv *btv = (struct bttv*)data;
+ int state;
+
+ state = btread(BT848_I2C) & 0x02 ? 1 : 0;
+#if I2C_VERY_VERBOSE
+ printk("bttv i2c: get ctrl %d - c%d d%d\n",
+ state,
+ btv->i2c_state & 0x02 ? 1 : 0, btv->i2c_state & 0x01 ? 1 : 0);
+#endif
+ return state;
+}
+
+static int bit_bt848_getsda(void *data)
+{
+ struct bttv *btv = (struct bttv*)data;
+ int state;
+ state = btread(BT848_I2C) & 0x01;
+#if I2C_VERY_VERBOSE
+ printk("bttv i2c: get data %d - c%d d%d\n",
+ state,
+ btv->i2c_state & 0x02 ? 1 : 0, btv->i2c_state & 0x01 ? 1 : 0);
+#endif
+ return state;
+}
+
+static int bit_bt848_reg(struct i2c_client *client)
+{
+ struct bit_adapter *b = (struct bit_adapter*)client->adapter->data;
+ struct bttv *btv = (struct bttv*)b->data;
+
+ switch(client->id) {
+ case I2C_DRIVERID_TUNER:
+ btv->tuner = client;
+ break;
+ case I2C_DRIVERID_MSP3400:
+ btv->msp3400 = client;
+ break;
+ }
+ printk("bttv%d: i2c reg: %s (id 0x%x)\n",btv->nr,client->name,client->id);
+ return 0;
+}
+
+static int bit_bt848_unreg(struct i2c_client *client)
+{
+ struct bit_adapter *b = (struct bit_adapter*)client->adapter->data;
+ struct bttv *btv = (struct bttv*)b->data;
+
+ switch(client->id) {
+ case I2C_DRIVERID_TUNER:
+ btv->tuner = NULL;
+ break;
+ case I2C_DRIVERID_MSP3400:
+ btv->msp3400 = NULL;
+ break;
+ }
+ printk("bttv%d: i2c unreg: %s (id 0x%x)\n",btv->nr,client->name,client->id);
+ return 0;
+}
+
+struct bit_adapter bit_bt848_ops_template = {
+ "bt848 i2c adapter",
+ HW_B_BT848,
+ NULL,
+ bit_bt848_setsda,
+ bit_bt848_setscl,
+ bit_bt848_getsda,
+ bit_bt848_getscl,
+ bit_bt848_reg,
+ bit_bt848_unreg,
+ I2C_DELAY, I2C_DELAY, I2C_DELAY*100
+};
+
+/* ----------------------------------------------------------------------- */
+
+struct tvcard
+{
+ int inputs;
+ int tuner;
+ int svhs;
+ u32 gpiomask;
+ u32 muxsel[8];
+ u32 audiomux[6]; /* Tuner, Radio, internal, external, mute, stereo */
+ u32 gpiomask2; /* GPIO MUX mask */
+};
+
+static struct tvcard tvcards[] =
+{
+ /* default */
+ { 3, 0, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0}},
+ /* MIRO */
+ { 4, 0, 2,15, { 2, 3, 1, 1}, { 2, 0, 0, 0,10}},
+ /* Hauppauge */
+ { 3, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4}},
+ /* STB */
+ { 3, 0, 2, 7, { 2, 3, 1, 1}, { 4, 0, 2, 3, 1}},
+ /* Intel??? */
+ { 3, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4}},
+ /* 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}},
+ /* Matrix Vision MV-Delta */
+ { 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}},
+};
+#define TVCARDS (sizeof(tvcards)/sizeof(tvcard))
+
+static void audio(struct bttv *btv, int mode)
+{
+ btaor(tvcards[btv->type].gpiomask, ~tvcards[btv->type].gpiomask,
+ BT848_GPIO_OUT_EN);
+
+ switch (mode)
+ {
+ case AUDIO_MUTE:
+ btv->audio|=AUDIO_MUTE;
+ break;
+ case AUDIO_UNMUTE:
+ btv->audio&=~AUDIO_MUTE;
+ mode=btv->audio;
+ break;
+ case AUDIO_OFF:
+ mode=AUDIO_OFF;
+ break;
+ case AUDIO_ON:
+ mode=btv->audio;
+ break;
+ default:
+ btv->audio&=AUDIO_MUTE;
+ btv->audio|=mode;
+ break;
+ }
+ /* if audio mute or not in H-lock, turn audio off */
+ if ((btv->audio&AUDIO_MUTE)
+#if 0
+ ||
+ (!btv->radio && !(btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC))
+#endif
+ )
+ mode=AUDIO_OFF;
+ if ((mode == 0) && (btv->radio))
+ mode = 1;
+ btaor(tvcards[btv->type].audiomux[mode],
+ ~tvcards[btv->type].gpiomask, BT848_GPIO_DATA);
+}
+
+
+extern inline void bt848_dma(struct bttv *btv, uint state)
+{
+ if (state)
+ btor(3, BT848_GPIO_DMA_CTL);
+ else
+ btand(~3, BT848_GPIO_DMA_CTL);
+}
+
+
+static void bt848_cap(struct bttv *btv, uint state)
+{
+ if (state)
+ {
+ btv->cap|=3;
+ bt848_set_risc_jmps(btv);
+ }
+ else
+ {
+ btv->cap&=~3;
+ bt848_set_risc_jmps(btv);
+ }
+}
+
+
+/* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC*/
+
+static int set_pll(struct bttv *btv)
+{
+ int i;
+
+ if (!btv->pll)
+ return 0;
+ if ((btread(BT848_IFORM)&BT848_IFORM_XT0))
+ {
+ /* printk ("switching PLL off\n");*/
+ btwrite(0x00,BT848_TGCTRL);
+ btwrite(0x00,BT848_PLL_XCI);
+ btv->pll&=~2;
+ return 0;
+ }
+
+ /* do not set pll again if already active */
+ if (btv->pll&2)
+ return 1;
+
+ /* printk ("setting PLL for PAL/SECAM\n");*/
+
+ btwrite(0x00,BT848_TGCTRL);
+ btwrite(0xf9,BT848_PLL_F_LO);
+ btwrite(0xdc,BT848_PLL_F_HI);
+ btwrite(0x8e,BT848_PLL_XCI);
+
+ /* Ugh ugh ugh .. schedule ? */
+ udelay(100000);
+ for (i=0; i<100; i++)
+ {
+ if ((btread(BT848_DSTATUS)&BT848_DSTATUS_PLOCK))
+ btwrite(0,BT848_DSTATUS);
+ else
+ {
+ btwrite(0x08,BT848_TGCTRL);
+ btv->pll|=2;
+ return 1;
+ }
+#if LINUX_VERSION_CODE >= 0x020199
+ mdelay(10);
+#else
+ udelay(10000);
+#endif
+ }
+ return -1;
+}
+
+static void bt848_muxsel(struct bttv *btv, unsigned int input)
+{
+ 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);
+ udelay(10000);
+
+
+ input %= tvcards[btv->type].inputs;
+ if (input==tvcards[btv->type].svhs)
+ {
+ 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);
+ }
+ btaor((tvcards[btv->type].muxsel[input&7]&3)<<5, ~(3<<5), BT848_IFORM);
+ audio(btv, (input!=tvcards[btv->type].tuner) ?
+ AUDIO_EXTERN : AUDIO_TUNER);
+ btaor(tvcards[btv->type].muxsel[input]>>4,
+ ~tvcards[btv->type].gpiomask2, BT848_GPIO_DATA);
+}
+
+
+#define VBIBUF_SIZE 65536
+
+/* Maximum sample number per VBI line is 2044, can NTSC deliver this?
+ Note that we write 2048-aligned to keep alignment to memory pages
+*/
+#define VBI_SPL 2044
+
+/* 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)
+{
+ int i;
+ unsigned int *po=(unsigned int *) btv->vbi_odd;
+ unsigned int *pe=(unsigned int *) btv->vbi_even;
+
+ DEBUG(printk(KERN_DEBUG "vbiodd: 0x%08x\n",(int)btv->vbi_odd));
+ DEBUG(printk(KERN_DEBUG "vbievn: 0x%08x\n",(int)btv->vbi_even));
+ DEBUG(printk(KERN_DEBUG "po: 0x%08x\n",(int)po));
+ DEBUG(printk(KERN_DEBUG "pe: 0x%08x\n",(int)pe));
+
+ *(po++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(po++)=0;
+ for (i=0; i<16; i++)
+ {
+ *(po++)=VBI_RISC;
+ *(po++)=kvirt_to_bus((unsigned long)btv->vbibuf+i*2048);
+ }
+ *(po++)=BT848_RISC_JUMP;
+ *(po++)=virt_to_bus(btv->risc_jmp+4);
+
+ *(pe++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(pe++)=0;
+ for (i=16; i<32; i++)
+ {
+ *(pe++)=VBI_RISC;
+ *(pe++)=kvirt_to_bus((unsigned long)btv->vbibuf+i*2048);
+ }
+ *(pe++)=BT848_RISC_JUMP|BT848_RISC_IRQ|(0x01<<16);
+ *(pe++)=virt_to_bus(btv->risc_jmp+10);
+ DEBUG(printk(KERN_DEBUG "po: 0x%08x\n",(int)po));
+ DEBUG(printk(KERN_DEBUG "pe: 0x%08x\n",(int)pe));
+}
+
+int fmtbppx2[16] = {
+ 8, 6, 4, 4, 4, 3, 2, 2, 4, 3, 0, 0, 0, 0, 2, 0
+};
+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,
+};
+
+static int make_rawrisctab(struct bttv *btv, unsigned int *ro,
+ unsigned int *re, unsigned int *vbuf)
+{
+ unsigned long line;
+ 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 and without separate VBI grabbing.
+ We'll have to handle this inside the IRQ handler ... */
+
+ for (line=0; line < 640; line++)
+ {
+ *(ro++)=BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL;
+ *(ro++)=kvirt_to_bus(vadr);
+ *(re++)=BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL;
+ *(re++)=kvirt_to_bus(vadr+BTTV_MAX_FBUF/2);
+ vadr+=bpl;
+ }
+
+ *(ro++)=BT848_RISC_JUMP;
+ *(ro++)=btv->bus_vbi_even;
+ *(re++)=BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16);
+ *(re++)=btv->bus_vbi_odd;
+
+ 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 fmt)
+{
+ unsigned long line;
+ unsigned long bpl; /* bytes per line */
+ unsigned long bl;
+ unsigned long todo;
+ unsigned int **rp;
+ int inter;
+ unsigned long vadr=(unsigned long) vbuf;
+
+
+ if (btv->gfmt==BT848_COLOR_FMT_RAW)
+ return make_rawrisctab(btv, ro, re, vbuf);
+
+ inter = (height>btv->win.cropheight/2) ? 1 : 0;
+ bpl=width*fmtbppx2[fmt&0xf]/2;
+
+ *(ro++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(ro++)=0;
+ *(re++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(re++)=0;
+
+ for (line=0; line < (height<<(1^inter)); line++)
+ {
+ if (inter)
+ rp= (line&1) ? &re : &ro;
+ else
+ rp= (line>height) ? &re : &ro;
+
+ bl=PAGE_SIZE-((PAGE_SIZE-1)&vadr);
+ if (bpl<=bl)
+ {
+ *((*rp)++)=BT848_RISC_WRITE|BT848_RISC_SOL|
+ BT848_RISC_EOL|bpl;
+ *((*rp)++)=kvirt_to_bus(vadr);
+ vadr+=bpl;
+ }
+ else
+ {
+ todo=bpl;
+ *((*rp)++)=BT848_RISC_WRITE|BT848_RISC_SOL|bl;
+ *((*rp)++)=kvirt_to_bus(vadr);
+ vadr+=bl;
+ todo-=bl;
+ while (todo>PAGE_SIZE)
+ {
+ *((*rp)++)=BT848_RISC_WRITE|PAGE_SIZE;
+ *((*rp)++)=kvirt_to_bus(vadr);
+ vadr+=PAGE_SIZE;
+ todo-=PAGE_SIZE;
+ }
+ *((*rp)++)=BT848_RISC_WRITE|BT848_RISC_EOL|todo;
+ *((*rp)++)=kvirt_to_bus(vadr);
+ vadr+=todo;
+ }
+ }
+
+ *(ro++)=BT848_RISC_JUMP;
+ *(ro++)=btv->bus_vbi_even;
+ *(re++)=BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16);
+ *(re++)=btv->bus_vbi_odd;
+
+ return 0;
+}
+
+/* does this really make a difference ???? */
+#define BURST_MAX 4096
+
+static inline void write_risc_segment(unsigned int **rp, unsigned long line_adr, unsigned int command,
+ int *x, uint dx, uint bpp, uint width)
+{
+ unsigned int flags, len;
+
+ if (!dx)
+ return;
+ len=dx*bpp;
+
+#ifdef LIMIT_DMA
+ if (command==BT848_RISC_WRITEC)
+ {
+ unsigned int dx2=BURST_MAX/bpp;
+ while (len>BURST_MAX)
+ {
+ write_risc_segment(rp, line_adr, command,
+ &x,dx2, bpp, width);
+ dx-=dx2;
+ len=dx*bpp;
+ }
+ }
+#endif
+
+ /* mask upper 8 bits for 24+8 bit overlay modes */
+ flags = ((bpp==4) ? BT848_RISC_BYTE3 : 0);
+
+ if (*x==0)
+ {
+ if (command==BT848_RISC_SKIP)
+ {
+ if (dx<width)
+ {
+ flags|=BT848_RISC_BYTE_ALL;
+ command=BT848_RISC_WRITE;
+ }
+ }
+ else
+ if (command==BT848_RISC_WRITEC)
+ command=BT848_RISC_WRITE;
+ flags|=BT848_RISC_SOL;
+ }
+ if (*x+dx==width)
+ flags|=BT848_RISC_EOL;
+ *((*rp)++)=command|flags|len;
+ if (command==BT848_RISC_WRITE)
+ *((*rp)++)=line_adr+*x*bpp;
+ *x+=dx;
+}
+
+static void make_clip_tab(struct bttv *btv, struct cliprec *cr, int count)
+{
+ int i,ncr;
+ int yy, y, x, dx;
+ struct cliprec 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;
+ ncr=btv->ncr;
+ 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 (cr[i].y<cy)
+ {
+ if (cr[i].y2<cy)
+ continue;
+ cr[i].y=cy;
+ }
+ if (cr[i].y2>=cy2)
+ {
+ if (cr[i].y>=cy2)
+ continue;
+ cr[i].y2=cy2-1;
+ }
+ if (cr[i].x<cx)
+ {
+ if (cr[i].x2<cx)
+ continue;
+ cr[i].x=cx;
+ }
+ if (cr[i].x2>=cx2)
+ {
+ if (cr[i].x>=cx2)
+ continue;
+ cr[i].x2=cx2-1;
+ }
+ 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->y2 < 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->x2-x+1;
+ }
+ else if (x+dx < cur2->x2)
+ dx=cur2->x2-x+1;
+ }
+ 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
+ * 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.
+ */
+
+struct tvnorm
+{
+ u16 swidth, sheight; /* scaled standard width, height */
+ u16 totalwidth;
+ u8 adelay, bdelay, iform;
+ u32 scaledtwidth;
+ u16 hdelayx1, hactivex1;
+ u16 vdelay;
+};
+
+static struct tvnorm tvnorms[] = {
+ /* PAL-BDGHI */
+ //{ 1024, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
+ // 1135, 100, 1024, 0x20},
+
+ { 914, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
+ 1135, 186+16, 914, 0x20},
+/*
+ { 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},
+ /* SECAM */
+ { 768, 576, 1135, 0x7f, 0xb0, (BT848_IFORM_SECAM|BT848_IFORM_XT1),
+ 944, 186, 922, 0x20},
+ /* PAL-M */
+ { 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},
+ /* PAL-NC */
+ { 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},
+};
+#define TVNORMS (sizeof(tvnorms)/sizeof(tvnorm))
+
+
+/* set geometry for even/odd frames
+ just if you are wondering:
+ handling of even and odd frames will be separated, e.g. for grabbing
+ the even ones as RGB into videomem and the others as YUV in main memory for
+ compressing and sending to the video conferencing partner.
+
+*/
+static inline void bt848_set_eogeo(struct bttv *btv, int odd, u8 vtc,
+ u16 hscale, u16 vscale,
+ u16 hactive, u16 vactive,
+ u16 hdelay, u16 vdelay,
+ u8 crop)
+{
+ int off = odd ? 0x80 : 0x00;
+
+ 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(hactive&0xff, BT848_E_HACTIVE_LO+off);
+ btwrite(hdelay&0xff, BT848_E_HDELAY_LO+off);
+ btwrite(vactive&0xff, BT848_E_VACTIVE_LO+off);
+ btwrite(vdelay&0xff, BT848_E_VDELAY_LO+off);
+ btwrite(crop, BT848_E_CROP+off);
+}
+
+
+static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, u16 fmt)
+{
+ u16 vscale, hscale;
+ u32 xsf, sr;
+ u16 hdelay, vdelay;
+ u16 hactive, vactive;
+ u16 inter;
+ u8 crop, vtc;
+ struct tvnorm *tvn;
+
+ if (!width || !height)
+ return;
+
+ 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)
+ btv->win.cropheight=tvn->cropheight;
+
+ if (width>btv->win.cropwidth)
+ 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);
+
+ set_pll(btv);
+
+ btwrite(fmt, BT848_COLOR_FMT);
+ hactive=width;
+
+ vtc=0;
+ /* Some people say interpolation looks bad ... */
+ /* vtc = (hactive < 193) ? 2 : ((hactive < 385) ? 1 : 0); */
+
+ btv->win.interlace = (height>btv->win.cropheight/2) ? 1 : 0;
+ inter=(btv->win.interlace&1)^1;
+ 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&=0x3fe;
+
+ sr=((btv->win.cropheight>>inter)*512)/height-512;
+ vscale=(0x10000UL-sr)&0x1fff;
+ vactive=btv->win.cropheight;
+ crop=((hactive>>8)&0x03)|((hdelay>>6)&0x0c)|
+ ((vactive>>4)&0x30)|((vdelay>>2)&0xc0);
+ vscale|= btv->win.interlace ? (BT848_VSCALE_INT<<8) : 0;
+
+ bt848_set_eogeo(btv, 0, vtc, hscale, vscale, hactive, vactive,
+ hdelay, vdelay, crop);
+ bt848_set_eogeo(btv, 1, vtc, hscale, vscale, hactive, vactive,
+ hdelay, vdelay, crop);
+
+}
+
+
+int bpp2fmt[4] = {
+ BT848_COLOR_FMT_RGB8, BT848_COLOR_FMT_RGB16,
+ BT848_COLOR_FMT_RGB24, BT848_COLOR_FMT_RGB32
+};
+
+static void bt848_set_winsize(struct bttv *btv)
+{
+ unsigned short format;
+
+ 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
+ * datasheet??? [AC - because its a standard format so I guess
+ * it never occured them]
+ * Enable dithering in this mode
+ */
+ 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);
+
+ bt848_set_geo(btv, btv->win.width, btv->win.height, format);
+}
+
+/*
+ * Set TSA5522 synthesizer frequency in 1/16 Mhz steps
+ */
+
+static void set_freq(struct bttv *btv, unsigned short freq)
+{
+ int fixme = freq; /* XXX */
+ int oldAudio = btv->audio;
+
+ audio(btv, AUDIO_MUTE);
+ udelay(AUDIO_MUTE_DELAY);
+
+ if (btv->radio)
+ {
+ if (btv->tuner)
+ btv->tuner->driver->command(btv->tuner,TUNER_SET_RADIOFREQ,&fixme);
+
+#if 0
+ if (btv->have_msp3400) {
+ i2c_control_device(&(btv->i2c),I2C_DRIVERID_MSP3400,
+ MSP_SET_RADIO,0);
+ i2c_control_device(&(btv->i2c),I2C_DRIVERID_MSP3400,
+ MSP_NEWCHANNEL,0);
+ }
+#endif
+ }
+ else
+ {
+ if (btv->tuner)
+ btv->tuner->driver->command(btv->tuner,TUNER_SET_TVFREQ,&fixme);
+#if 0
+ if (btv->have_msp3400) {
+ i2c_control_device(&(btv->i2c),I2C_DRIVERID_MSP3400,
+ MSP_SET_TVNORM,&(btv->win.norm));
+ i2c_control_device(&(btv->i2c),I2C_DRIVERID_MSP3400,
+ MSP_NEWCHANNEL,0);
+ }
+#endif
+ }
+
+ if (!(oldAudio & AUDIO_MUTE)) {
+ udelay(FREQ_CHANGE_DELAY);
+ audio(btv, AUDIO_UNMUTE);
+ }
+}
+
+
+/*
+ * Grab into virtual memory.
+ * Currently only does double buffering. Do we need more?
+ */
+
+static int vgrab(struct bttv *btv, struct video_mmap *mp)
+{
+ unsigned int *ro, *re;
+ unsigned int *vbuf;
+
+ if(btv->fbuffer==NULL)
+ {
+ if(fbuffer_alloc(btv))
+ return -ENOBUFS;
+ }
+ if (btv->grabbing >= MAX_GBUFFERS)
+ return -ENOBUFS;
+
+ /*
+ * No grabbing past the end of the buffer!
+ */
+
+ if(mp->frame>1 || mp->frame <0)
+ return -EINVAL;
+
+ if(mp->height <0 || mp->width <0)
+ return -EINVAL;
+
+ if(mp->height>576 || mp->width>768)
+ return -EINVAL;
+
+ /*
+ * FIXME: Check the format of the grab here. This is probably
+ * also less restrictive than the normal overlay grabs. Stuff
+ * like QCIF has meaning as a capture.
+ */
+
+ /*
+ * Ok load up the BT848
+ */
+
+ vbuf=(unsigned int *)(btv->fbuffer+BTTV_MAX_FBUF*mp->frame);
+ if (!(btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC))
+ return -EAGAIN;
+ ro=btv->grisc+(((btv->grabcount++)&1) ? 4096 :0);
+ re=ro+2048;
+ btv->gwidth=mp->width;
+ btv->gheight=mp->height;
+ btv->gfmt=mp->format;
+ 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;
+ /* interruptible_sleep_on(&btv->capq); */
+ return 0;
+}
+
+static long bttv_write(struct video_device *v, const char *buf, unsigned long count, int nonblock)
+{
+ return -EINVAL;
+}
+
+static long bttv_read(struct video_device *v, char *buf, unsigned long count, int nonblock)
+{
+ struct bttv *btv= (struct bttv *)v;
+ int q,todo;
+
+ todo=count;
+ while (todo && todo>(q=VBIBUF_SIZE-btv->vbip))
+ {
+ if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, q))
+ return -EFAULT;
+ todo-=q;
+ buf+=q;
+
+ cli();
+ if (todo && q==VBIBUF_SIZE-btv->vbip)
+ {
+ if(nonblock)
+ {
+ sti();
+ if(count==todo)
+ return -EWOULDBLOCK;
+ return count-todo;
+ }
+ interruptible_sleep_on(&btv->vbiq);
+ sti();
+ if(signal_pending(current))
+ {
+ if(todo==count)
+ return -EINTR;
+ else
+ return count-todo;
+ }
+ }
+ }
+ if (todo)
+ {
+ if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, todo))
+ return -EFAULT;
+ btv->vbip+=todo;
+ }
+ return count;
+}
+
+/*
+ * Open a bttv card. Right now the flags stuff is just playing
+ */
+
+static int bttv_open(struct video_device *dev, int flags)
+{
+ struct bttv *btv = (struct bttv *)dev;
+ int users, i;
+
+ switch (flags)
+ {
+ case 0:
+ if (btv->user)
+ return -EBUSY;
+ btv->user++;
+ audio(btv, AUDIO_UNMUTE);
+ for (i=users=0; i<bttv_num; i++)
+ users+=bttvs[i].user;
+ if (users==1)
+ find_vga();
+ btv->fbuffer=NULL;
+ if (!btv->fbuffer)
+ btv->fbuffer=(unsigned char *) rvmalloc(2*BTTV_MAX_FBUF);
+ if (!btv->fbuffer)
+ {
+ btv->user--;
+ return -EINVAL;
+ }
+ btv->grabbing = 0;
+ btv->grab = 0;
+ btv->lastgrab = 0;
+ break;
+ case 1:
+ break;
+ }
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static void bttv_close(struct video_device *dev)
+{
+ struct bttv *btv=(struct bttv *)dev;
+
+ btv->user--;
+ audio(btv, AUDIO_MUTE);
+ btv->cap&=~3;
+ bt848_set_risc_jmps(btv);
+
+ if(btv->fbuffer)
+ rvfree((void *) btv->fbuffer, 2*BTTV_MAX_FBUF);
+ btv->fbuffer=0;
+ MOD_DEC_USE_COUNT;
+}
+
+
+/***********************************/
+/* ioctls and supporting functions */
+/***********************************/
+
+extern inline void bt848_bright(struct bttv *btv, uint bright)
+{
+ btwrite(bright&0xff, BT848_BRIGHT);
+}
+
+extern inline void bt848_hue(struct bttv *btv, uint hue)
+{
+ btwrite(hue&0xff, BT848_HUE);
+}
+
+extern inline void bt848_contrast(struct bttv *btv, uint cont)
+{
+ unsigned int conthi;
+
+ conthi=(cont>>6)&4;
+ btwrite(cont&0xff, BT848_CONTRAST_LO);
+ btaor(conthi, ~4, BT848_E_CONTROL);
+ btaor(conthi, ~4, BT848_O_CONTROL);
+}
+
+extern inline void bt848_sat_u(struct bttv *btv, unsigned long data)
+{
+ u32 datahi;
+
+ datahi=(data>>7)&2;
+ btwrite(data&0xff, BT848_SAT_U_LO);
+ btaor(datahi, ~2, BT848_E_CONTROL);
+ btaor(datahi, ~2, BT848_O_CONTROL);
+}
+
+static inline void bt848_sat_v(struct bttv *btv, unsigned long data)
+{
+ u32 datahi;
+
+ datahi=(data>>8)&1;
+ btwrite(data&0xff, BT848_SAT_V_LO);
+ btaor(datahi, ~1, BT848_E_CONTROL);
+ 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
+ */
+
+
+static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+ struct bttv *btv=(struct bttv *)dev;
+ static int lastchan=0,i;
+
+ switch (cmd)
+ {
+ case VIDIOCGCAP:
+ {
+ struct video_capability b;
+ strcpy(b.name,btv->video_dev.name);
+ b.type = VID_TYPE_CAPTURE|
+ VID_TYPE_TUNER|
+ VID_TYPE_TELETEXT|
+ VID_TYPE_OVERLAY|
+ VID_TYPE_CLIPPING|
+ VID_TYPE_FRAMERAM|
+ VID_TYPE_SCALES;
+ b.channels = 4; /* tv , input, svhs */
+ b.audios = 4; /* tv, input, svhs */
+ b.maxwidth = 768;
+ b.maxheight = 576;
+ b.minwidth = 32;
+ b.minheight = 32;
+ if(copy_to_user(arg,&b,sizeof(b)))
+ return -EFAULT;
+ return 0;
+ }
+ case VIDIOCGCHAN:
+ {
+ 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;
+#if 0
+ v.mode = btv->win.norm;
+#endif
+ 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;
+ }
+ if(copy_to_user(arg,&v,sizeof(v)))
+ return -EFAULT;
+ return 0;
+ }
+ /*
+ * Each channel has 1 tuner
+ */
+ case VIDIOCSCHAN:
+ {
+ int v;
+ if(copy_from_user(&v, arg, sizeof(v)))
+ return -EFAULT;
+ bt848_muxsel(btv, v);
+ lastchan=v;
+ return 0;
+ }
+ case VIDIOCGTUNER:
+ {
+ struct video_tuner v;
+ if(copy_from_user(&v,arg,sizeof(v))!=0)
+ return -EFAULT;
+ if(v.tuner||lastchan) /* Only tuner 0 */
+ return -EINVAL;
+ strcpy(v.name, "Television");
+ v.rangelow=0;
+ v.rangehigh=0xFFFFFFFF;
+ v.flags=VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC;
+ v.mode = btv->win.norm;
+ if(copy_to_user(arg,&v,sizeof(v)))
+ return -EFAULT;
+ return 0;
+ }
+ /* We have but tuner 0 */
+ case VIDIOCSTUNER:
+ {
+ /* FIXME: norm should be in video_channel struct
+ composite source can have different norms too
+ */
+
+ struct video_tuner v;
+ if(copy_from_user(&v, arg, sizeof(v)))
+ return -EFAULT;
+ /* Only 1 channel has a tuner */
+ /*if(v.tuner!=tvcards[btv->type].tuner || lastchan)
+ return -EINVAL;*/
+ if(v.mode!=VIDEO_MODE_PAL&&v.mode!=VIDEO_MODE_NTSC
+ &&v.mode!=VIDEO_MODE_SECAM)
+ return -EOPNOTSUPP;
+ btv->win.norm = v.mode;
+ bt848_set_winsize(btv);
+ return 0;
+ }
+ case VIDIOCGPICT:
+ {
+ struct video_picture p=btv->picture;
+ if(btv->win.depth==8)
+ p.palette=VIDEO_PALETTE_HI240;
+ if(btv->win.depth==15)
+ p.palette=VIDEO_PALETTE_RGB555;
+ if(btv->win.depth==16)
+ p.palette=VIDEO_PALETTE_RGB565;
+ if(btv->win.depth==24)
+ p.palette=VIDEO_PALETTE_RGB24;
+ if(btv->win.depth==32)
+ p.palette=VIDEO_PALETTE_RGB32;
+
+ if(copy_to_user(arg, &p, sizeof(p)))
+ return -EFAULT;
+ return 0;
+ }
+ case VIDIOCSPICT:
+ {
+ struct video_picture p;
+ int format;
+ if(copy_from_user(&p, arg,sizeof(p)))
+ return -EFAULT;
+ /* 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;
+
+ /* set palette if bpp matches */
+ if (p.palette < sizeof(palette2fmt)/sizeof(int)) {
+ format = palette2fmt[p.palette];
+ if (fmtbppx2[format&0x0f]/2 == btv->win.bpp)
+ btv->win.color_fmt = format;
+ }
+ return 0;
+ }
+ case VIDIOCSWIN:
+ {
+ struct video_window vw;
+ struct video_clip *vcp;
+ int on;
+
+ if(copy_from_user(&vw,arg,sizeof(vw)))
+ return -EFAULT;
+
+ if(vw.flags)
+ return -EINVAL;
+
+ btv->win.x=vw.x;
+ btv->win.y=vw.y;
+ btv->win.width=vw.width;
+ btv->win.height=vw.height;
+
+ if(btv->win.height>btv->win.cropheight/2)
+ btv->win.interlace=1;
+ else
+ btv->win.interlace=0;
+
+ on=(btv->cap&3)?1:0;
+
+ bt848_cap(btv,0);
+ bt848_set_winsize(btv);
+
+ if(vw.clipcount>256)
+ return -EDOM; /* Too many! */
+
+ /*
+ * Do any clips.
+ */
+
+ vcp=vmalloc(sizeof(struct video_clip)*(vw.clipcount+4));
+ if(vcp==NULL)
+ 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);
+ vfree(vcp);
+ if(on && btv->win.vidadr!=0)
+ bt848_cap(btv,1);
+ return 0;
+ }
+ case VIDIOCGWIN:
+ {
+ struct video_window vw;
+ /* Oh for a COBOL move corresponding .. */
+ vw.x=btv->win.x;
+ vw.y=btv->win.y;
+ vw.width=btv->win.width;
+ vw.height=btv->win.height;
+ vw.chromakey=0;
+ vw.flags=0;
+ if(btv->win.interlace)
+ vw.flags|=VIDEO_WINDOW_INTERLACE;
+ if(copy_to_user(arg,&vw,sizeof(vw)))
+ return -EFAULT;
+ return 0;
+ }
+ case VIDIOCCAPTURE:
+ {
+ int v;
+ if(copy_from_user(&v, arg,sizeof(v)))
+ return -EFAULT;
+ if(v==0)
+ {
+ bt848_cap(btv,0);
+ }
+ else
+ {
+ if(btv->win.vidadr==0 || btv->win.width==0
+ || btv->win.height==0)
+ return -EINVAL;
+ bt848_cap(btv,1);
+ }
+ return 0;
+ }
+ case VIDIOCGFBUF:
+ {
+ 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;
+ return 0;
+
+ }
+ case VIDIOCSFBUF:
+ {
+ struct video_buffer v;
+#if LINUX_VERSION_CODE >= 0x020100
+ if(!capable(CAP_SYS_ADMIN))
+#else
+ if(!suser())
+#endif
+ return -EPERM;
+ if(copy_from_user(&v, arg,sizeof(v)))
+ return -EFAULT;
+ if(v.depth!=8 && v.depth!=16 && v.depth!=15
+ && v.depth!=24 && v.depth!=32)
+ return -EINVAL;
+ if (v.base)
+ {
+ /* also handle virtual base addresses */
+ if ((unsigned int)v.base>=0xe0000000UL)
+ btv->win.vidadr=(uint)v.base;
+ else
+ btv->win.vidadr=
+#if LINUX_VERSION_CODE >= 0x020199
+ __va(uvirt_to_bus((uint)v.base));
+#else
+ PAGE_OFFSET|uvirt_to_bus((uint)v.base);
+#endif
+ }
+ 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;
+
+ DEBUG(printk("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;
+ }
+ case VIDIOCKEY:
+ {
+ /* Will be handled higher up .. */
+ return 0;
+ }
+ case VIDIOCGFREQ:
+ {
+ unsigned long v=btv->win.freq;
+ if(copy_to_user(arg,&v,sizeof(v)))
+ return -EFAULT;
+ return 0;
+ }
+ case VIDIOCSFREQ:
+ {
+ unsigned long v;
+ if(copy_from_user(&v, arg, sizeof(v)))
+ return -EFAULT;
+ btv->win.freq=v;
+ set_freq(btv, btv->win.freq);
+ return 0;
+ }
+
+ case VIDIOCGAUDIO:
+ {
+ struct video_audio v;
+ v=btv->audio_dev;
+ v.flags&=~(VIDEO_AUDIO_MUTE|VIDEO_AUDIO_MUTABLE);
+ v.flags|=VIDEO_AUDIO_MUTABLE;
+ strcpy(v.name,"TV");
+#if 0
+ if (btv->have_msp3400)
+ {
+ v.flags|=VIDEO_AUDIO_VOLUME |
+ VIDEO_AUDIO_BASS |
+ VIDEO_AUDIO_TREBLE;
+ i2c_control_device(&(btv->i2c),
+ I2C_DRIVERID_MSP3400,
+ MSP_GET_VOLUME,&(v.volume));
+ i2c_control_device(&(btv->i2c),
+ I2C_DRIVERID_MSP3400,
+ MSP_GET_BASS,&(v.bass));
+ i2c_control_device(&(btv->i2c),
+ I2C_DRIVERID_MSP3400,
+ MSP_GET_TREBLE,&(v.treble));
+ i2c_control_device(&(btv->i2c),
+ I2C_DRIVERID_MSP3400,
+ MSP_GET_STEREO,&(v.mode));
+ }
+ else
+#endif
+ v.mode = VIDEO_SOUND_MONO;
+ if(copy_to_user(arg,&v,sizeof(v)))
+ return -EFAULT;
+ return 0;
+ }
+ case VIDIOCSAUDIO:
+ {
+ struct video_audio v;
+ if(copy_from_user(&v,arg, sizeof(v)))
+ return -EFAULT;
+ if(v.flags&VIDEO_AUDIO_MUTE)
+ audio(btv, AUDIO_MUTE);
+ /* One audio source per tuner */
+ if(v.audio!=0)
+ return -EINVAL;
+ bt848_muxsel(btv,v.audio);
+ if(!(v.flags&VIDEO_AUDIO_MUTE))
+ audio(btv, AUDIO_UNMUTE);
+#if 0
+ if (btv->have_msp3400)
+ {
+ i2c_control_device(&(btv->i2c),
+ I2C_DRIVERID_MSP3400,
+ MSP_SET_VOLUME,&(v.volume));
+ i2c_control_device(&(btv->i2c),
+ I2C_DRIVERID_MSP3400,
+ MSP_SET_BASS,&(v.bass));
+ i2c_control_device(&(btv->i2c),
+ I2C_DRIVERID_MSP3400,
+ MSP_SET_TREBLE,&(v.treble));
+ i2c_control_device(&(btv->i2c),
+ I2C_DRIVERID_MSP3400,
+ MSP_SET_STEREO,&(v.mode));
+ }
+#endif
+ btv->audio_dev=v;
+ return 0;
+ }
+ case VIDIOCSYNC_OLD:
+#if 0
+ if (!btv->grabbing)
+ return -EAGAIN;
+#endif
+ if (btv->grab==btv->lastgrab)
+ interruptible_sleep_on(&btv->capq);
+ btv->lastgrab++;
+ return 0;
+ case VIDIOCSYNC:
+ 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_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);
+ }
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static int bttv_init_done(struct video_device *dev)
+{
+ return 0;
+}
+
+/*
+ * This maps the vmalloced and reserved fbuffer to user space.
+ *
+ * FIXME:
+ * - PAGE_READONLY should suffice!?
+ * - remap_page_range is kind of inefficient for page by page remapping.
+ * But e.g. pte_alloc() does not work in modules ... :-(
+ */
+
+static int bttv_mmap(struct video_device *dev, const char *adr, unsigned long size)
+{
+ struct bttv *btv=(struct bttv *)dev;
+ unsigned long start=(unsigned long) adr;
+ unsigned long page,pos;
+
+ if (size>2*BTTV_MAX_FBUF)
+ return -EINVAL;
+ if (!btv->fbuffer)
+ {
+ if(fbuffer_alloc(btv))
+ return -EINVAL;
+ }
+ pos=(unsigned long) btv->fbuffer;
+ while (size > 0)
+ {
+ page = kvirt_to_phys(pos);
+ if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
+ return -EAGAIN;
+ start+=PAGE_SIZE;
+ pos+=PAGE_SIZE;
+ size-=PAGE_SIZE;
+ }
+ return 0;
+}
+
+static struct video_device bttv_template=
+{
+ "UNSET",
+ VID_TYPE_TUNER|VID_TYPE_CAPTURE|VID_TYPE_OVERLAY|VID_TYPE_TELETEXT,
+ VID_HARDWARE_BT848,
+ bttv_open,
+ bttv_close,
+ bttv_read,
+ bttv_write,
+ bttv_ioctl,
+ bttv_mmap,
+ bttv_init_done,
+ NULL,
+ 0,
+ 0
+};
+
+
+static long vbi_read(struct video_device *v, char *buf, unsigned long count,
+ int nonblock)
+{
+ struct bttv *btv=(struct bttv *)(v-2);
+ int q,todo;
+
+ todo=count;
+ while (todo && todo>(q=VBIBUF_SIZE-btv->vbip))
+ {
+ if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, q))
+ return -EFAULT;
+ todo-=q;
+ buf+=q;
+
+ cli();
+ if (todo && q==VBIBUF_SIZE-btv->vbip)
+ {
+ if(nonblock)
+ {
+ sti();
+ if(count==todo)
+ return -EWOULDBLOCK;
+ return count-todo;
+ }
+ interruptible_sleep_on(&btv->vbiq);
+ sti();
+ if(signal_pending(current))
+ {
+ if(todo==count)
+ return -EINTR;
+ else
+ return count-todo;
+ }
+ }
+ }
+ if (todo)
+ {
+ if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, todo))
+ return -EFAULT;
+ btv->vbip+=todo;
+ }
+ return count;
+}
+
+static int vbi_open(struct video_device *dev, int flags)
+{
+ struct bttv *btv=(struct bttv *)(dev-2);
+
+ btv->vbip=VBIBUF_SIZE;
+ btv->cap|=0x0c;
+ bt848_set_risc_jmps(btv);
+
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static void vbi_close(struct video_device *dev)
+{
+ struct bttv *btv=(struct bttv *)(dev-2);
+
+ btv->cap&=~0x0c;
+ bt848_set_risc_jmps(btv);
+
+ MOD_DEC_USE_COUNT;
+}
+
+
+static int vbi_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+ return -EINVAL;
+}
+
+static struct video_device vbi_template=
+{
+ "bttv vbi",
+ VID_TYPE_CAPTURE|VID_TYPE_TELETEXT,
+ VID_HARDWARE_BT848,
+ vbi_open,
+ vbi_close,
+ vbi_read,
+ bttv_write,
+ vbi_ioctl,
+ NULL, /* no mmap yet */
+ bttv_init_done,
+ NULL,
+ 0,
+ 0
+};
+
+
+static int radio_open(struct video_device *dev, int flags)
+{
+ struct bttv *btv = (struct bttv *)(dev-1);
+
+ if (btv->user)
+ return -EBUSY;
+ btv->user++;
+ set_freq(btv,400*16);
+ btv->radio = 1;
+ bt848_muxsel(btv,0);
+ audio(btv, AUDIO_UNMUTE);
+
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static void radio_close(struct video_device *dev)
+{
+ struct bttv *btv=(struct bttv *)(dev-1);
+
+ btv->user--;
+ btv->radio = 0;
+ audio(btv, AUDIO_MUTE);
+ MOD_DEC_USE_COUNT;
+}
+
+static long radio_read(struct video_device *v, char *buf, unsigned long count, int nonblock)
+{
+ return -EINVAL;
+}
+
+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 */
+ 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 */
+ return -EINVAL;
+ strcpy(v.name, "Radio");
+ v.rangelow=(int)(87.5*16);
+ v.rangehigh=(int)(108.0*16);
+ v.flags= 0; /* XXX */
+ v.mode = 0; /* XXX */
+ if(copy_to_user(arg,&v,sizeof(v)))
+ return -EFAULT;
+ return 0;
+ }
+ 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;
+ /* XXX anything to do ??? */
+ return 0;
+ }
+ case VIDIOCGFREQ:
+ case VIDIOCSFREQ:
+ case VIDIOCGAUDIO:
+ case VIDIOCSAUDIO:
+ bttv_ioctl((struct video_device *)btv,cmd,arg);
+ break;
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static struct video_device radio_template=
+{
+ "bttv radio",
+ VID_TYPE_TUNER,
+ VID_HARDWARE_BT848,
+ radio_open,
+ radio_close,
+ radio_read, /* just returns -EINVAL */
+ bttv_write, /* just returns -EINVAL */
+ radio_ioctl,
+ NULL, /* no mmap */
+ bttv_init_done, /* just returns 0 */
+ NULL,
+ 0,
+ 0
+};
+
+
+struct vidbases
+{
+ unsigned short vendor, device;
+ char *name;
+ uint badr;
+};
+
+static struct vidbases vbs[] = {
+/* This id is not defined in pci.h but this entry was mailed to me?!?
+ { PCI_VENDOR_ID_ALLIANCE, PCI_DEVICE_ID_ALLIANCE_AT25,
+ "Alliance AT25", 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,
+ "ATI MACH64 GT", PCI_BASE_ADDRESS_0},
+ { PCI_VENDOR_ID_CIRRUS, 0, "Cirrus Logic", PCI_BASE_ADDRESS_0},
+ { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA,
+ "DEC DC21030", PCI_BASE_ADDRESS_0},
+ { PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL,
+ "Matrox Millennium", PCI_BASE_ADDRESS_1},
+ { 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},
+};
+
+
+/* DEC TGA offsets stolen from XFree-3.2 */
+
+static uint dec_offsets[4] = {
+ 0x200000,
+ 0x804000,
+ 0,
+ 0x1004000
+};
+
+#define NR_CARDS (sizeof(vbs)/sizeof(struct vidbases))
+
+/* Scan for PCI display adapter
+ if more than one card is present the last one is used for now */
+
+static int find_vga(void)
+{
+ unsigned int devfn, class, vendev;
+ unsigned short vendor, device, badr;
+ int found=0, bus=0, i, tga_type;
+ unsigned int vidadr=0;
+
+
+ for (devfn = 0; devfn < 0xff; devfn++)
+ {
+ if (PCI_FUNC(devfn) != 0)
+ continue;
+ pcibios_read_config_dword(bus, devfn, PCI_VENDOR_ID, &vendev);
+ if (vendev == 0xffffffff || vendev == 0x00000000)
+ continue;
+ pcibios_read_config_word(bus, devfn, PCI_VENDOR_ID, &vendor);
+ pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &device);
+ pcibios_read_config_dword(bus, devfn, PCI_CLASS_REVISION, &class);
+ class = class >> 16;
+/* if (class == PCI_CLASS_DISPLAY_VGA) {*/
+ if ((class>>8) == PCI_BASE_CLASS_DISPLAY ||
+ /* Number 9 GXE64Pro needs this */
+ class == PCI_CLASS_NOT_DEFINED_VGA)
+ {
+ badr=0;
+ printk(KERN_INFO "bttv: PCI display adapter: ");
+ for (i=0; i<NR_CARDS; i++)
+ {
+ if (vendor==vbs[i].vendor)
+ {
+ if (vbs[i].device)
+ if (vbs[i].device!=device)
+ continue;
+ printk("%s.\n", vbs[i].name);
+ badr=vbs[i].badr;
+ break;
+ }
+ }
+ if (!badr)
+ {
+ printk(KERN_ERR "bttv: Unknown video memory base address.\n");
+ continue;
+ }
+ pcibios_read_config_dword(bus, devfn, badr, &vidadr);
+ if (vidadr & PCI_BASE_ADDRESS_SPACE_IO)
+ {
+ printk(KERN_ERR "bttv: Memory seems to be I/O memory.\n");
+ printk(KERN_ERR "bttv: Check entry for your card type in bttv.c vidbases struct.\n");
+ continue;
+ }
+ vidadr &= PCI_BASE_ADDRESS_MEM_MASK;
+ if (!vidadr)
+ {
+ printk(KERN_ERR "bttv: Memory @ 0, must be something wrong!");
+ continue;
+ }
+
+ if (vendor==PCI_VENDOR_ID_DEC)
+ if (device==PCI_DEVICE_ID_DEC_TGA)
+ {
+ tga_type = (readl((unsigned long)vidadr) >> 12) & 0x0f;
+ if (tga_type != 0 && tga_type != 1 && tga_type != 3)
+ {
+ printk(KERN_ERR "bttv: TGA type (0x%x) unrecognized!\n", tga_type);
+ found--;
+ }
+ vidadr+=dec_offsets[tga_type];
+ }
+
+ DEBUG(printk(KERN_DEBUG "bttv: memory @ 0x%08x, ", vidadr));
+ DEBUG(printk(KERN_DEBUG "devfn: 0x%04x.\n", devfn));
+ found++;
+ }
+ }
+
+ if (vidmem)
+ {
+ vidadr=vidmem<<20;
+ printk(KERN_INFO "bttv: Video memory override: 0x%08x\n", vidadr);
+ found=1;
+ }
+ for (i=0; i<BTTV_MAX; i++)
+ bttvs[i].win.vidadr=vidadr;
+
+ return found;
+}
+
+
+
+#define TRITON_PCON 0x50
+#define TRITON_BUS_CONCURRENCY (1<<0)
+#define TRITON_STREAMING (1<<1)
+#define TRITON_WRITE_BURST (1<<2)
+#define TRITON_PEER_CONCURRENCY (1<<3)
+
+static void handle_chipset(void)
+{
+ int index;
+
+ /* Just in case some nut set this to something dangerous */
+ if (triton1)
+ triton1=BT848_INT_ETBF;
+
+ for (index = 0; index < 8; index++)
+ {
+ unsigned char bus, devfn;
+ unsigned char b;
+
+ /* Beware the SiS 85C496 my friend - rev 49 don't work with a bttv */
+
+ if (!pcibios_find_device(PCI_VENDOR_ID_SI,
+ PCI_DEVICE_ID_SI_496,
+ index, &bus, &devfn))
+ {
+ printk(KERN_WARNING "BT848 and SIS 85C496 chipset don't always work together.\n");
+ }
+
+ if (!pcibios_find_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_82441,
+ index, &bus, &devfn))
+ {
+ pcibios_read_config_byte(bus, devfn, 0x53, &b);
+ DEBUG(printk(KERN_INFO "bttv: Host bridge: 82441FX Natoma, "));
+ DEBUG(printk("bufcon=0x%02x\n",b));
+ }
+
+ if (!pcibios_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437,
+ index, &bus, &devfn))
+ {
+ printk(KERN_INFO "bttv: Host bridge 82437FX Triton PIIX\n");
+ triton1=BT848_INT_ETBF;
+
+#if 0
+ /* The ETBF bit SHOULD make all this unnecessary */
+ /* 430FX (Triton I) freezes with bus concurrency on -> switch it off */
+ {
+ unsigned char bo;
+
+ pcibios_read_config_byte(bus, devfn, TRITON_PCON, &b);
+ bo=b;
+ DEBUG(printk(KERN_DEBUG "bttv: 82437FX: PCON: 0x%x\n",b));
+
+ if(!(b & TRITON_BUS_CONCURRENCY))
+ {
+ printk(KERN_WARNING "bttv: 82437FX: disabling bus concurrency\n");
+ b |= TRITON_BUS_CONCURRENCY;
+ }
+
+ if(b & TRITON_PEER_CONCURRENCY)
+ {
+ printk(KERN_WARNING "bttv: 82437FX: disabling peer concurrency\n");
+ b &= ~TRITON_PEER_CONCURRENCY;
+ }
+ if(!(b & TRITON_STREAMING))
+ {
+ printk(KERN_WARNING "bttv: 82437FX: disabling streaming\n");
+ b |= TRITON_STREAMING;
+ }
+
+ if (b!=bo)
+ {
+ pcibios_write_config_byte(bus, devfn, TRITON_PCON, b);
+ printk(KERN_DEBUG "bttv: 82437FX: PCON changed to: 0x%x\n",b);
+ }
+ }
+#endif
+ }
+ }
+}
+
+static void init_tda8425(struct bttv *btv)
+{
+ I2CWrite(btv, I2C_TDA8425, TDA8425_VL, 0xFC, 1); /* volume left 0dB */
+ I2CWrite(btv, I2C_TDA8425, TDA8425_VR, 0xFC, 1); /* volume right 0dB */
+ I2CWrite(btv, I2C_TDA8425, TDA8425_BA, 0xF6, 1); /* bass 0dB */
+ I2CWrite(btv, I2C_TDA8425, TDA8425_TR, 0xF6, 1); /* treble 0dB */
+ I2CWrite(btv, I2C_TDA8425, TDA8425_S1, 0xCE, 1); /* mute off */
+}
+
+static void init_tda9850(struct bttv *btv)
+{
+ I2CWrite(btv, I2C_TDA9850, TDA9850_CON1, 0x08, 1); /* noise threshold st */
+ I2CWrite(btv, I2C_TDA9850, TDA9850_CON2, 0x08, 1); /* noise threshold sap */
+ I2CWrite(btv, I2C_TDA9850, TDA9850_CON3, 0x40, 1); /* stereo mode */
+ I2CWrite(btv, I2C_TDA9850, TDA9850_CON4, 0x07, 1); /* 0 dB input gain?*/
+ I2CWrite(btv, I2C_TDA9850, TDA9850_ALI1, 0x10, 1); /* wideband alignment? */
+ I2CWrite(btv, I2C_TDA9850, TDA9850_ALI2, 0x10, 1); /* spectral alignment? */
+ I2CWrite(btv, I2C_TDA9850, TDA9850_ALI3, 0x03, 1);
+}
+
+/* Figure out card and tuner type */
+
+static void idcard(struct bttv *btv)
+{
+ int tunertype;
+ btwrite(0, BT848_GPIO_OUT_EN);
+ DEBUG(printk(KERN_DEBUG "bttv: GPIO: 0x%08x\n", btread(BT848_GPIO_DATA)));
+
+ /* Default the card to the user-selected one. */
+ btv->type=card;
+
+ /* If we were asked to auto-detect, then do so!
+ Right now this will only recognize Miro, Hauppauge or STB
+ */
+ if (btv->type == BTTV_UNKNOWN)
+ {
+ btv->type=BTTV_MIRO;
+
+ if (I2CRead(btv, I2C_HAUPEE)>=0)
+ btv->type=BTTV_HAUPPAUGE;
+ else
+ if (I2CRead(btv, I2C_STBEE)>=0)
+ btv->type=BTTV_STB;
+ }
+
+ if (I2CRead(btv, I2C_TDA9850) >=0)
+ {
+ btv->audio_chip = TDA9850;
+ printk(KERN_INFO "bttv%d: audio chip: TDA9850\n",btv->nr);
+ }
+
+ if (I2CRead(btv, I2C_TDA8425) >=0)
+ {
+ btv->audio_chip = TDA8425;
+ printk(KERN_INFO "bttv%d: audio chip: TDA8425\n",btv->nr);
+ }
+
+ switch(btv->audio_chip)
+ {
+ case TDA9850:
+ init_tda9850(btv);
+ break;
+ case TDA8425:
+ init_tda8425(btv);
+ break;
+ }
+
+ /* How do I detect the tuner type for other cards but Miro ??? */
+ printk(KERN_INFO "bttv: model: ");
+ switch (btv->type)
+ {
+ case BTTV_MIRO:
+ printk("MIRO\n");
+#if 0
+ if (btv->have_tuner)
+ {
+ tunertype=((btread(BT848_GPIO_DATA)>>10)-1)&7;
+ i2c_control_device(&(btv->i2c),
+ I2C_DRIVERID_TUNER,
+ TUNER_SET_TYPE,&tunertype);
+ }
+#endif
+ strcpy(btv->video_dev.name,"BT848(Miro)");
+ break;
+ case BTTV_HAUPPAUGE:
+ printk("HAUPPAUGE\n");
+ strcpy(btv->video_dev.name,"BT848(Hauppauge)");
+ break;
+ case BTTV_STB:
+ printk("STB\n");
+ strcpy(btv->video_dev.name,"BT848(STB)");
+ break;
+ case BTTV_INTEL:
+ printk("Intel\n");
+ strcpy(btv->video_dev.name,"BT848(Intel)");
+ break;
+ case BTTV_DIAMOND:
+ printk("Diamond\n");
+ strcpy(btv->video_dev.name,"BT848(Diamond)");
+ break;
+ case BTTV_AVERMEDIA:
+ printk("AVerMedia\n");
+ strcpy(btv->video_dev.name,"BT848(AVerMedia)");
+ break;
+ case BTTV_MATRIX_VISION:
+ printk("MATRIX-Vision\n");
+ strcpy(btv->video_dev.name,"BT848(MATRIX-Vision)");
+ break;
+ }
+ audio(btv, AUDIO_MUTE);
+}
+
+static void bt848_set_risc_jmps(struct bttv *btv)
+{
+ int flags=btv->cap;
+
+ /* Sync to start of odd field */
+ btv->risc_jmp[0]=BT848_RISC_SYNC|BT848_RISC_RESYNC|BT848_FIFO_STATUS_VRE;
+ btv->risc_jmp[1]=0;
+
+ /* Jump to odd vbi sub */
+ btv->risc_jmp[2]=BT848_RISC_JUMP|(0x5<<20);
+ if (flags&8)
+ btv->risc_jmp[3]=virt_to_bus(btv->vbi_odd);
+ else
+ btv->risc_jmp[3]=virt_to_bus(btv->risc_jmp+4);
+
+ /* Jump to odd sub */
+ btv->risc_jmp[4]=BT848_RISC_JUMP|(0x6<<20);
+ if (flags&2)
+ btv->risc_jmp[5]=virt_to_bus(btv->risc_odd);
+ else
+ btv->risc_jmp[5]=virt_to_bus(btv->risc_jmp+6);
+
+
+ /* Sync to start of even field */
+ btv->risc_jmp[6]=BT848_RISC_SYNC|BT848_RISC_RESYNC|BT848_FIFO_STATUS_VRO;
+ btv->risc_jmp[7]=0;
+
+ /* Jump to even vbi sub */
+ btv->risc_jmp[8]=BT848_RISC_JUMP;
+ if (flags&4)
+ btv->risc_jmp[9]=virt_to_bus(btv->vbi_even);
+ else
+ btv->risc_jmp[9]=virt_to_bus(btv->risc_jmp+10);
+
+ /* Jump to even sub */
+ btv->risc_jmp[10]=BT848_RISC_JUMP|(8<<20);
+ if (flags&1)
+ btv->risc_jmp[11]=virt_to_bus(btv->risc_even);
+ else
+ btv->risc_jmp[11]=virt_to_bus(btv->risc_jmp+12);
+
+ btv->risc_jmp[12]=BT848_RISC_JUMP;
+ btv->risc_jmp[13]=virt_to_bus(btv->risc_jmp);
+
+ /* enable cpaturing and DMA */
+ btaor(flags, ~0x0f, BT848_CAP_CTL);
+ if (flags&0x0f)
+ bt848_dma(btv, 3);
+ else
+ bt848_dma(btv, 0);
+}
+
+static int init_bt848(int i)
+{
+ struct bttv *btv = &bttvs[i];
+
+ btv->user=0;
+
+ /* reset the bt848 */
+ btwrite(0, BT848_SRESET);
+ DEBUG(printk(KERN_DEBUG "bttv%d: bt848_mem: 0x%08x\n",i,(unsigned int) btv->bt848_mem));
+
+ /* 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=768; /* 640 */
+ btv->win.height=576; /* 480 */
+ btv->win.cropwidth=768; /* 640 */
+ btv->win.cropheight=576; /* 480 */
+ btv->win.cropx=0;
+ btv->win.cropy=0;
+ 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->cap=0;
+
+ btv->gmode=0;
+ btv->risc_odd=0;
+ btv->risc_even=0;
+ btv->risc_jmp=0;
+ btv->vbibuf=0;
+ btv->grisc=0;
+ btv->grabbing=0;
+ btv->grabcount=0;
+ btv->grab=0;
+ btv->lastgrab=0;
+ btv->field=btv->last_field=0;
+
+ /* i2c */
+ memcpy(&(btv->i2c),&bit_bt848_ops_template,sizeof(struct bit_adapter));
+ sprintf(btv->i2c.name+strlen(btv->i2c.name)," #%d",i);
+ btv->i2c.data = btv;
+ bit_bt848_setscl(btv, 1);
+ bit_bt848_setsda(btv, 1);
+
+ if (!(btv->risc_odd=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL)))
+ return -1;
+ if (!(btv->risc_even=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL)))
+ return -1;
+ if (!(btv->risc_jmp =(unsigned int *) kmalloc(2048, GFP_KERNEL)))
+ return -1;
+ DEBUG(printk(KERN_DEBUG "risc_jmp: %p\n",btv->risc_jmp));
+ btv->vbi_odd=btv->risc_jmp+16;
+ btv->vbi_even=btv->vbi_odd+256;
+ btv->bus_vbi_odd=virt_to_bus(btv->risc_jmp+12);
+ btv->bus_vbi_even=virt_to_bus(btv->risc_jmp+6);
+
+ btwrite(virt_to_bus(btv->risc_jmp+2), BT848_RISC_STRT_ADD);
+ btv->vbibuf=(unsigned char *) vmalloc(VBIBUF_SIZE);
+ if (!btv->vbibuf)
+ return -1;
+ if (!(btv->grisc=(unsigned int *) kmalloc(32768, GFP_KERNEL)))
+ return -1;
+
+ btv->fbuffer=NULL;
+
+ bt848_muxsel(btv, 1);
+ bt848_set_winsize(btv);
+
+/* btwrite(0, BT848_TDEC); */
+ btwrite(0x10, BT848_COLOR_CTL);
+ btwrite(0x00, BT848_CAP_CTL);
+ btwrite(0xfc, BT848_GPIO_DMA_CTL);
+
+ /* select direct input */
+ btwrite(0x00, BT848_GPIO_REG_INP);
+
+
+ btwrite(0xff, BT848_VBI_PACK_SIZE);
+ btwrite(1, BT848_VBI_PACK_DEL);
+
+
+ btwrite(BT848_IFORM_MUX1 | BT848_IFORM_XTAUTO | BT848_IFORM_PAL_BDGHI,
+ BT848_IFORM);
+
+ btwrite(0xd8, BT848_CONTRAST_LO);
+ bt848_bright(btv, 0x10);
+
+ 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);
+
+ btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL);
+ btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL);
+
+ btv->picture.colour=254<<7;
+ btv->picture.brightness=128<<8;
+ btv->picture.hue=128<<8;
+ btv->picture.contrast=0xd8<<7;
+
+ btwrite(0x00, BT848_E_SCLOOP);
+ btwrite(0x00, BT848_O_SCLOOP);
+
+ /* clear interrupt status */
+ 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|eBT848_INT_FBUS|*/
+ BT848_INT_VSYNC|
+ BT848_INT_SCERR|
+ BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES|
+ BT848_INT_FMTCHG|BT848_INT_HLOCK,
+ BT848_INT_MASK);
+
+ make_vbitab(btv);
+ bt848_set_risc_jmps(btv);
+
+ /*
+ * Now add the template and register the device unit.
+ */
+
+ 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);
+
+ if(video_register_device(&btv->video_dev,VFL_TYPE_GRABBER)<0)
+ return -1;
+ if(video_register_device(&btv->vbi_dev,VFL_TYPE_VBI)<0)
+ {
+ video_unregister_device(&btv->video_dev);
+ return -1;
+ }
+ if (radio)
+ {
+ if(video_register_device(&btv->radio_dev, VFL_TYPE_RADIO)<0)
+ {
+ video_unregister_device(&btv->vbi_dev);
+ video_unregister_device(&btv->video_dev);
+ return -1;
+ }
+ }
+ i2c_bit_register_bus(&btv->i2c);
+
+ return 0;
+}
+
+static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
+{
+ u32 stat,astat;
+ u32 dstat;
+ int count;
+ struct bttv *btv;
+
+ btv=(struct bttv *)dev_id;
+ count=0;
+ while (1)
+ {
+ /* get/clear interrupt status bits */
+ stat=btread(BT848_INT_STAT);
+ astat=stat&btread(BT848_INT_MASK);
+ if (!astat)
+ return;
+ btwrite(astat,BT848_INT_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%d: IRQ_FMTCHG\n", btv->nr));
+ /*btv->win.norm&=
+ (dstat&BT848_DSTATUS_NUML) ? (~1) : (~0); */
+ }
+ if (astat&BT848_INT_VPRES)
+ {
+ IDEBUG(printk ("bttv%d: IRQ_VPRES\n", btv->nr));
+ }
+ if (astat&BT848_INT_VSYNC)
+ {
+ IDEBUG(printk ("bttv%d: IRQ_VSYNC\n",btv->nr));
+ btv->field++;
+ }
+ if (astat&BT848_INT_SCERR) {
+ IDEBUG(printk ("bttv%d: IRQ_SCERR\n", btv->nr));
+ bt848_dma(btv, 0);
+ bt848_dma(btv, 1);
+ wake_up_interruptible(&btv->vbiq);
+ wake_up_interruptible(&btv->capq);
+
+ }
+ if (astat&BT848_INT_RISCI)
+ {
+ IDEBUG(printk ("bttv%d: IRQ_RISCI\n", btv->nr));
+
+ /* captured VBI frame */
+ if (stat&(1<<28))
+ {
+ btv->vbip=0;
+ wake_up_interruptible(&btv->vbiq);
+ }
+
+ /* captured full frame */
+ if (stat&(2<<28))
+ {
+ 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,
+ btv->gheight,
+ btv->gfmt);
+ } else {
+ bt848_set_risc_jmps(btv);
+ bt848_set_geo(btv, btv->win.width,
+ btv->win.height,
+ btv->win.color_fmt);
+ }
+ wake_up_interruptible(&btv->capq);
+ break;
+ }
+ if (stat&(8<<28))
+ {
+ btv->risc_jmp[5]=btv->gro;
+ btv->risc_jmp[11]=btv->gre;
+ btv->risc_jmp[12]=BT848_RISC_JUMP;
+ bt848_set_geo(btv, btv->gwidth, btv->gheight,
+ btv->gfmt);
+ }
+ }
+ if (astat&BT848_INT_OCERR)
+ {
+ IDEBUG(printk ("bttv%d: IRQ_OCERR\n", btv->nr));
+ }
+ if (astat&BT848_INT_PABORT)
+ {
+ IDEBUG(printk ("bttv%d: IRQ_PABORT\n", btv->nr));
+ }
+ if (astat&BT848_INT_RIPERR)
+ {
+ IDEBUG(printk ("bttv%d: IRQ_RIPERR\n", btv->nr));
+ }
+ if (astat&BT848_INT_PPERR)
+ {
+ IDEBUG(printk ("bttv%d: IRQ_PPERR\n", btv->nr));
+ }
+ if (astat&BT848_INT_FDSR)
+ {
+ IDEBUG(printk ("bttv%d: IRQ_FDSR\n", btv->nr));
+ }
+ if (astat&BT848_INT_FTRGT)
+ {
+ IDEBUG(printk ("bttv%d: IRQ_FTRGT\n", btv->nr));
+ }
+ if (astat&BT848_INT_FBUS)
+ {
+ IDEBUG(printk ("bttv%d: IRQ_FBUS\n", btv->nr));
+ }
+ if (astat&BT848_INT_HLOCK)
+ {
+ if ((dstat&BT848_DSTATUS_HLOC) || (btv->radio))
+ audio(btv, AUDIO_ON);
+ else
+ audio(btv, AUDIO_OFF);
+ }
+
+ if (astat&BT848_INT_I2CDONE)
+ {
+ }
+
+ count++;
+ if (count > 10)
+ printk (KERN_WARNING "bttv: irq loop %d\n", count);
+ if (count > 20)
+ {
+ btwrite(0, BT848_INT_MASK);
+ printk(KERN_ERR
+ "bttv: IRQ lockup, cleared int mask\n");
+ }
+ }
+}
+
+
+
+/*
+ * Scan for a Bt848 card, request the irq and map the io memory
+ */
+
+static int find_bt848(void)
+{
+ short pci_index;
+ unsigned char command, latency;
+ int result;
+ unsigned char bus, devfn;
+ struct bttv *btv;
+
+ bttv_num=0;
+
+ if (!pcibios_present())
+ {
+ DEBUG(printk(KERN_DEBUG "bttv: PCI-BIOS not present or not accessable!\n"));
+ return 0;
+ }
+
+ for (pci_index = 0;
+ !pcibios_find_device(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849,
+ pci_index, &bus, &devfn)
+ ||!pcibios_find_device(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
+ pci_index, &bus, &devfn)
+ ||!pcibios_find_device(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878,
+ pci_index, &bus, &devfn)
+ ||!pcibios_find_device(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879,
+ pci_index, &bus, &devfn);
+ ++pci_index)
+ {
+ btv=&bttvs[bttv_num];
+ btv->nr = bttv_num;
+ btv->bus=bus;
+ btv->devfn=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;
+
+ pcibios_read_config_word(btv->bus, btv->devfn, PCI_DEVICE_ID,
+ &btv->id);
+ pcibios_read_config_byte(btv->bus, btv->devfn,
+ PCI_INTERRUPT_LINE, &btv->irq);
+ pcibios_read_config_dword(btv->bus, btv->devfn, PCI_BASE_ADDRESS_0,
+ &btv->bt848_adr);
+
+ 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);
+ pcibios_write_config_dword(btv->bus, btv->devfn, PCI_BASE_ADDRESS_0,
+ remap);
+ pcibios_read_config_dword(btv->bus, btv->devfn, PCI_BASE_ADDRESS_0,
+ &btv->bt848_adr);
+ }
+
+ btv->bt848_adr&=PCI_BASE_ADDRESS_MEM_MASK;
+ pcibios_read_config_byte(btv->bus, btv->devfn, PCI_CLASS_REVISION,
+ &btv->revision);
+ printk(KERN_INFO "bttv: Brooktree Bt%d (rev %d) ",
+ 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;
+#ifdef USE_PLL
+ if (!(btv->id==848 && btv->revision==0x11))
+ {
+<<<<<<< old/bttv.c
+ printk("bttv: internal PLL, single crystal operation enabled\n");
+||||||| /home/kraxel/2/src/xawtv-2.14/bttv/old-driver/bttv.c
+ printk("bttv%d: internal PLL, single crystal operation enabled\n",bttv_num);
+=======
+ printk(KERN_INFO "bttv%d: internal PLL, single crystal operation enabled\n",bttv_num);
+>>>>>>> /home/kraxel/2/src/xawtv-2.14/bttv/driver/bttv.c
+ btv->pll=1;
+ }
+#endif
+
+ btv->bt848_mem=ioremap(btv->bt848_adr, 0x1000);
+
+ result = request_irq(btv->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->irq);
+ return result;
+ }
+ if (result < 0)
+ return result;
+
+ /* Enable bus-mastering */
+ pcibios_read_config_byte(btv->bus, btv->devfn, PCI_COMMAND, &command);
+ command|=PCI_COMMAND_MASTER;
+ pcibios_write_config_byte(btv->bus, btv->devfn, PCI_COMMAND, command);
+ pcibios_read_config_byte(btv->bus, btv->devfn, PCI_COMMAND, &command);
+ if (!(command&PCI_COMMAND_MASTER))
+ {
+ printk(KERN_ERR "bttv: PCI bus-mastering could not be enabled\n");
+ return -1;
+ }
+ pcibios_read_config_byte(btv->bus, btv->devfn, PCI_LATENCY_TIMER,
+ &latency);
+ if (!latency)
+ {
+ latency=32;
+ pcibios_write_config_byte(btv->bus, btv->devfn,
+ PCI_LATENCY_TIMER, latency);
+ }
+ DEBUG(printk(KERN_DEBUG "bttv: latency: %02x\n", latency));
+ bttv_num++;
+ }
+ if(bttv_num)
+ printk(KERN_INFO "bttv: %d Bt848 card(s) found.\n", bttv_num);
+ return bttv_num;
+}
+
+
+static void release_bttv(void)
+{
+ u8 command;
+ int i;
+ struct bttv *btv;
+
+ for (i=0;i<bttv_num; i++)
+ {
+ btv=&bttvs[i];
+
+ /* turn off all capturing, DMA and IRQs */
+
+ btand(~15, BT848_GPIO_DMA_CTL);
+
+ /* first disable interrupts before unmapping the memory! */
+ btwrite(0, BT848_INT_MASK);
+ btwrite(0xffffffffUL,BT848_INT_STAT);
+ btwrite(0x0, BT848_GPIO_OUT_EN);
+
+ /* unregister i2c_bus */
+ i2c_bit_unregister_bus((&btv->i2c));
+
+ /* disable PCI bus-mastering */
+ pcibios_read_config_byte(btv->bus, btv->devfn, PCI_COMMAND, &command);
+ command|=PCI_COMMAND_MASTER;
+ pcibios_write_config_byte(btv->bus, btv->devfn, PCI_COMMAND, command);
+
+ /* unmap and free memory */
+ if (btv->grisc)
+ kfree((void *) btv->grisc);
+
+ if (btv->risc_odd)
+ kfree((void *) btv->risc_odd);
+
+ if (btv->risc_even)
+ kfree((void *) btv->risc_even);
+
+ DEBUG(printk(KERN_DEBUG "free: risc_jmp: 0x%08x.\n", btv->risc_jmp));
+ if (btv->risc_jmp)
+ kfree((void *) btv->risc_jmp);
+
+ DEBUG(printk(KERN_DEBUG "bt848_vbibuf: 0x%08x.\n", btv->vbibuf));
+ if (btv->vbibuf)
+ vfree((void *) btv->vbibuf);
+
+
+ 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);
+
+ video_unregister_device(&btv->video_dev);
+ video_unregister_device(&btv->vbi_dev);
+ if (radio)
+ video_unregister_device(&btv->radio_dev);
+ }
+}
+
+#ifdef MODULE
+
+int init_module(void)
+{
+#else
+int init_bttv_cards(struct video_init *unused)
+{
+#endif
+ int i;
+
+ handle_chipset();
+ if (find_bt848()<0)
+ return -EIO;
+
+ /* initialize Bt848s */
+ for (i=0; i<bttv_num; i++)
+ {
+ if (init_bt848(i)<0)
+ {
+ release_bttv();
+ return -EIO;
+ }
+ }
+
+#if 0
+ /* load i2c chip drivers (requires a tiny patch for 2.0.x) */
+ request_module("msp3400");
+ request_module("tuner");
+#endif
+
+ return 0;
+}
+
+
+
+#ifdef MODULE
+
+void cleanup_module(void)
+{
+ release_bttv();
+}
+
+#endif
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff --git a/bttv/experimental/bttv.h b/bttv/experimental/bttv.h
new file mode 100644
index 0000000..886edde
--- /dev/null
+++ b/bttv/experimental/bttv.h
@@ -0,0 +1,212 @@
+/*
+ bttv - Bt848 frame grabber driver
+
+ Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de)
+
+ 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 _BTTV_H_
+#define _BTTV_H_
+
+#define TEST_VBI
+
+#include <linux/types.h>
+#include <linux/wait.h>
+
+#include "i2c.h"
+/* #include "msp3400.h" */
+#include "bt848.h"
+#include "videodev.h"
+
+#define MAX_CLIPRECS 100
+#define MAX_GBUFFERS 2
+#define RISCMEM_LEN (32744*2)
+
+/* maximum needed buffer size for extended VBI frame mode capturing */
+#define BTTV_MAX_FBUF 0x151000
+
+/* clipping rectangle */
+struct cliprec
+{
+ int x, y, x2, y2;
+ struct cliprec *next;
+};
+
+
+#ifdef __KERNEL__
+
+struct bttv_window
+{
+ int x, y;
+ ushort width, height;
+ ushort bpp, bpl;
+ ushort swidth, sheight;
+ short cropx, cropy;
+ ushort cropwidth, cropheight;
+ unsigned int vidadr;
+ ushort freq;
+ int norm;
+ int interlace;
+ int color_fmt;
+ ushort depth;
+};
+
+
+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 */
+
+ struct bit_adapter i2c;
+ int i2c_state;
+ struct i2c_client *msp3400;
+ struct i2c_client *tuner;
+
+ unsigned int nr;
+ unsigned short id;
+ unsigned char bus; /* PCI bus the Bt848 is on */
+ unsigned char devfn;
+ unsigned char revision;
+ unsigned char irq; /* IRQ used by Bt848 card */
+ unsigned int bt848_adr; /* bus address of IO mem returned by PCI BIOS */
+ unsigned char *bt848_mem; /* pointer to mapped IO memory */
+ unsigned long busriscmem;
+ u32 *riscmem;
+
+ unsigned char *vbibuf;
+ struct bttv_window win;
+ int type; /* card type */
+ int audio; /* audio mode */
+ int user;
+ int audio_chip;
+ int radio;
+
+ u32 *risc_jmp;
+ u32 *vbi_odd;
+ u32 *vbi_even;
+ u32 bus_vbi_even;
+ u32 bus_vbi_odd;
+ struct wait_queue *vbiq;
+ struct wait_queue *capq;
+ struct wait_queue *capqo;
+ struct wait_queue *capqe;
+ int vbip;
+
+ u32 *risc_odd;
+ u32 *risc_even;
+ int cap;
+ struct cliprec *cliprecs;
+ int ncr; /* number of clipping rectangles */
+
+ struct gbuffer *ogbuffers;
+ struct gbuffer *egbuffers;
+ u16 gwidth, gheight, gfmt;
+ u32 *grisc;
+
+ unsigned long gro;
+ unsigned long gre;
+ unsigned long gro_next;
+ unsigned long gre_next;
+
+ int grf,grf_next; /* frame numbers in grab queue */
+ int frame_stat[MAX_GBUFFERS];
+#define GBUFFER_UNUSED 0
+#define GBUFFER_GRABBING 1
+#define GBUFFER_DONE 2
+
+ char *fbuffer;
+ int gmode;
+ int grabbing;
+ int lastgrab;
+ int grab;
+ int grabcount;
+
+ int pll;
+ unsigned int field;
+ unsigned int last_field; /* number of last grabbed field */
+};
+
+#endif
+
+/*The following should be done in more portable way. It depends on define
+ of _ALPHA_BTTV in the Makefile.*/
+
+#ifdef _ALPHA_BTTV
+#define btwrite(dat,adr) writel((dat),(char *) (btv->bt848_adr+(adr)))
+#define btread(adr) readl(btv->bt848_adr+(adr))
+#else
+#define btwrite(dat,adr) writel((dat), (char *) (btv->bt848_mem+(adr)))
+#define btread(adr) readl(btv->bt848_mem+(adr))
+#endif
+
+#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)
+
+/* bttv ioctls */
+
+#define BTTV_READEE _IOW('v', BASE_VIDIOCPRIVATE+0, char [256])
+#define BTTV_WRITEE _IOR('v', BASE_VIDIOCPRIVATE+1, char [256])
+#define BTTV_GRAB _IOR('v' , BASE_VIDIOCPRIVATE+2, struct gbuf)
+#define BTTV_FIELDNR _IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int)
+
+
+#define BTTV_UNKNOWN 0x00
+#define BTTV_MIRO 0x01
+#define BTTV_HAUPPAUGE 0x02
+#define BTTV_STB 0x03
+#define BTTV_INTEL 0x04
+#define BTTV_DIAMOND 0x05
+#define BTTV_AVERMEDIA 0x06
+#define BTTV_MATRIX_VISION 0x07
+#define BTTV_FLYVIDEO 0x08
+
+#define AUDIO_TUNER 0x00
+#define AUDIO_RADIO 0x01
+#define AUDIO_EXTERN 0x02
+#define AUDIO_INTERN 0x03
+#define AUDIO_OFF 0x04
+#define AUDIO_ON 0x05
+#define AUDIO_MUTE 0x80
+#define AUDIO_UNMUTE 0x81
+
+#define TDA9850 0x01
+#define TDA8425 0x02
+
+#define I2C_TSA5522 0xc2
+#define I2C_TDA9850 0xb6
+#define I2C_TDA8425 0x82
+#define I2C_HAUPEE 0xa0
+#define I2C_STBEE 0xae
+
+#define TDA9850_CON1 0x04
+#define TDA9850_CON2 0x05
+#define TDA9850_CON3 0x06
+#define TDA9850_CON4 0x07
+#define TDA9850_ALI1 0x08
+#define TDA9850_ALI2 0x09
+#define TDA9850_ALI3 0x0a
+
+#define TDA8425_VL 0x00
+#define TDA8425_VR 0x01
+#define TDA8425_BA 0x02
+#define TDA8425_TR 0x03
+#define TDA8425_S1 0x08
+
+#endif
diff --git a/bttv/experimental/i2c.c b/bttv/experimental/i2c.c
new file mode 100644
index 0000000..2bd52a7
--- /dev/null
+++ b/bttv/experimental/i2c.c
@@ -0,0 +1,385 @@
+/* ------------------------------------------------------------------------- */
+/* i2c.c - a device driver for the iic-bus interface */
+/* ------------------------------------------------------------------------- */
+/* Copyright (C) 1995-97 Simon G. Vogl
+
+ 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. */
+/* ------------------------------------------------------------------------- */
+#define RCSID "$Id: i2c.c,v 1.1 1998/05/25 12:08:09 i2c Exp i2c $"
+/* ------------------------------------------------------------------------- */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+
+#include "i2c.h"
+
+/* ----- global defines ---------------------------------------------------- */
+#define DEB(x) /* should be reasonable open, close &c. */
+#define DEB2(x) /* low level debugging - very slow */
+#define DEBE(x) x /* error messages */
+#define DEBI(x) /* ioctl and its arguments */
+
+/* exclusive access to the bus */
+#define I2C_LOCK(adap) spin_lock_irqsave(&adap->lock,adap->lockflags)
+#define I2C_UNLOCK(adap) spin_unlock_irqrestore(&adap->lock,adap->lockflags)
+
+/* ----- global variables -------------------------------------------------- */
+
+/**** algorithm list */
+struct i2c_algorithm *algorithms[I2C_ALGO_MAX];
+static int algo_count;
+
+/**** algorithm list */
+struct i2c_adapter *adapters[I2C_ADAP_MAX];
+static int adap_count;
+
+/**** drivers list */
+struct i2c_driver *drivers[I2C_DRIVER_MAX];
+static int driver_count;
+
+/**** clients list */
+struct i2c_client *clients[I2C_CLIENT_MAX];
+static int client_count;
+
+/* ---------------------------------------------------
+ * registering functions
+ * ---------------------------------------------------
+ */
+
+/* -----
+ * Algorithms - used to access groups of similar hw adapters or
+ * specific interfaces like the PCF8584 et al.
+ */
+int i2c_register_algorithm(struct i2c_algorithm *algo)
+{
+ int i;
+
+ for (i = 0; i < I2C_ALGO_MAX; i++)
+ if (NULL == algorithms[i])
+ break;
+ if (I2C_ALGO_MAX == i)
+ return -ENOMEM;
+
+ algorithms[i] = algo;
+ algo_count++;
+ MOD_INC_USE_COUNT;
+ DEB(printk("i2c: algorithm %s registered.\n",algo->name));
+ return 0;
+}
+
+
+int i2c_unregister_algorithm(struct i2c_algorithm *algo)
+{
+ int i;
+
+ for (i = 0; i < I2C_ALGO_MAX; i++)
+ if (algo == algorithms[i])
+ break;
+ if (I2C_ALGO_MAX == i)
+ {
+ printk(KERN_WARNING "i2c: unregister_algorithm algo not found: %s\n",
+ algo->name);
+ return -ENODEV;
+ }
+
+ algorithms[i] = NULL;
+ algo_count--;
+ MOD_DEC_USE_COUNT;
+ DEB(printk("i2c: algorithm unregistered: %s\n",algo->name));
+ return 0;
+}
+
+
+/* -----
+ * i2c_register_adapter is called from within the algorithm layer,
+ * when a new hw adapter registers. A new device is register to be
+ * available for clients.
+ */
+int i2c_register_adapter(struct i2c_adapter *adap)
+{
+ int i;
+
+ for (i = 0; i < I2C_ADAP_MAX; i++)
+ if (NULL == adapters[i])
+ break;
+ if (I2C_ADAP_MAX == i)
+ return -ENOMEM;
+
+ adapters[i] = adap;
+ adap_count++;
+/* MOD_INC_USE_COUNT;*/
+
+ /* init data types */
+
+ adap->lock = (spinlock_t)SPIN_LOCK_UNLOCKED;
+
+
+ /* inform drivers of new adapters */
+ for (i=0;i<I2C_DRIVER_MAX;i++)
+ if (drivers[i]!=NULL && drivers[i]->flags&DF_NOTIFY)
+ drivers[i]->attach_adapter(adap);
+
+ DEB(printk("i2c: adapter %s registered.\n",adap->name));
+ return 0;
+}
+
+int i2c_unregister_adapter(struct i2c_adapter *adap)
+{
+ int i;
+
+ for (i = 0; i < I2C_ADAP_MAX; i++)
+ if (adap == adapters[i])
+ break;
+ if (I2C_ADAP_MAX == i)
+ {
+ printk(KERN_WARNING "i2c: unregister_adapter adap not found: %s\n",
+ adap->name);
+ return -ENODEV;
+ }
+
+ adapters[i] = NULL;
+ adap_count--;
+
+/* MOD_DEC_USE_COUNT;*/
+
+ /* inform drivers */
+ for (i=0;i<I2C_DRIVER_MAX;i++)
+ if (drivers[i]!=NULL && drivers[i]->flags&DF_NOTIFY)
+ drivers[i]->detach_adapter(adap);
+
+ DEB(printk("i2c: adapter unregistered: %s\n",adap->name));
+ return 0;
+}
+
+/* -----
+ * What follows is the "upwards" interface: commands for talking to clients,
+ * which implement the functions to access the physical information of the
+ * chips.
+ */
+
+int i2c_register_driver(struct i2c_driver *driver)
+{
+ int i;
+
+ for (i = 0; i < I2C_DRIVER_MAX; i++)
+ if (NULL == drivers[i])
+ break;
+ if (I2C_DRIVER_MAX == i)
+ return -ENOMEM;
+
+ drivers[i] = driver;
+ driver_count++;
+ MOD_INC_USE_COUNT;
+
+ if ( driver->flags&DF_NOTIFY )
+ for (i=0;i<I2C_ADAP_MAX;i++)
+ if (adapters[i]!=NULL)
+ driver->attach_adapter(adapters[i]);
+
+ DEB(printk("i2c: driver %s registered.\n",driver->name));
+ return 0;
+}
+
+int i2c_unregister_driver(struct i2c_driver *driver)
+{
+ int i;
+
+ for (i = 0; i < I2C_DRIVER_MAX; i++)
+ if (driver == drivers[i])
+ break;
+ if (I2C_DRIVER_MAX == i)
+ {
+ printk(KERN_WARNING "i2c: unregister_driver %s not found\n",
+ driver->name);
+ return -ENODEV;
+ }
+
+ drivers[i] = NULL;
+ driver_count--;
+ MOD_DEC_USE_COUNT;
+ DEB(printk("i2c: driver unregistered: %s\n",driver->name));
+ return 0;
+}
+
+
+int i2c_attach_client(struct i2c_client *client)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ struct i2c_algorithm *algo = adapter->algo;
+ int i;
+
+ for (i = 0; i < I2C_CLIENT_MAX; i++)
+ if (NULL == clients[i])
+ break;
+ if (I2C_CLIENT_MAX == i)
+ return -ENOMEM;
+
+ clients[i] = client;
+ client_count++;
+ if (algo->client_register != NULL)
+ algo->client_register(client);
+ DEB(printk("i2c: client %s registered.\n",client->name));
+ return 0;
+}
+
+
+int i2c_detach_client(struct i2c_client *client)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ struct i2c_algorithm *algo = adapter->algo;
+ int i;
+
+ for (i = 0; i < I2C_CLIENT_MAX; i++)
+ if (client == clients[i])
+ break;
+ if (I2C_CLIENT_MAX == i)
+ {
+ printk(KERN_WARNING "i2c: unregister_client %s not found\n",
+ client->name);
+ return -ENODEV;
+ }
+
+ clients[i] = NULL;
+ client_count--;
+ if (algo->client_unregister != NULL)
+ algo->client_unregister(client);
+ DEB(printk("i2c: client unregistered: %s\n",client->name));
+ return 0;
+}
+
+int i2c_init(void)
+{
+ /* clear algorithms */
+ memset(algorithms,0,sizeof(algorithms));
+ memset(adapters,0,sizeof(adapters));
+ memset(clients,0,sizeof(clients));
+ memset(drivers,0,sizeof(drivers));
+ algo_count=0;
+ adap_count=0;
+ client_count=0;
+ driver_count=0;
+
+ printk("i2c module initialized.\n");
+ return 0;
+}
+
+
+/* ----------------------------------------------------
+ * the functional interface to the i2c busses.
+ * ----------------------------------------------------
+ */
+
+int i2c_probe(struct i2c_adapter *adap, int low_addr, int hi_addr)
+{
+ struct i2c_client client;
+ int i;
+
+ memset(&client,0,sizeof(client));
+ client.adapter=adap;
+ I2C_LOCK(adap);
+ for (i = low_addr; i <= hi_addr; i++) {
+ client.addr=i;
+ if (0 == adap->algo->master_send(&client,NULL,0))
+ break;
+ }
+ I2C_UNLOCK(adap);
+ return (i <= hi_addr) ? i : -1;
+}
+
+int i2c_master_send(struct i2c_client *client,const char *buf ,int count)
+{
+ int ret;
+ struct i2c_adapter *adap=client->adapter;
+ DEB(printk("master_send: writing %d bytes on %s.\n",
+ count,client->adapter->name));
+
+ I2C_LOCK(adap);
+ ret = adap->algo->master_send(client,buf,count);
+ I2C_UNLOCK(adap);
+
+ return ret;
+}
+
+int i2c_master_recv(struct i2c_client *client, char *buf ,int count)
+{
+ int ret;
+ struct i2c_adapter *adap=client->adapter;
+ DEB(printk("master_recv: reading %d bytes on %s.\n",
+ count,client->adapter->name));
+
+ I2C_LOCK(adap);
+ ret = adap->algo->master_recv(client,buf,count);
+ I2C_UNLOCK(adap);
+ DEB2(printk("master_recv: read %d bytes\n",ret));
+ return ret;
+}
+
+int i2c_master_comb(struct i2c_client *client, char *readbuf,const char *writebuf,
+ int nread, int nwrite, int flags)
+{
+ int ret;
+ struct i2c_adapter *adap=client->adapter;
+ DEB(printk("master_comb: %s - %d in %d out on %s.\n",
+ flags?"rd,wr":"wr,rd",nread,nwrite,
+ client->adapter->name));
+
+ I2C_LOCK(adap);
+ ret = adap->algo->master_comb(client,readbuf,writebuf,
+ nread,nwrite,flags);
+ I2C_UNLOCK(adap);
+
+ return ret;
+}
+
+
+int i2c_control(struct i2c_client *client,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret = 0;
+ struct i2c_adapter *adap = client->adapter;
+
+ DEBI(printk("i2c ioctl, cmd: 0x%x, arg: %#lx\n", cmd, arg));
+ switch ( cmd ) {
+ case I2C_RETRIES:
+ adap->retries = arg;
+ break;
+ case I2C_TIMEOUT:
+ adap->timeout = arg;
+ break;
+ default:
+ if (adap->algo->algo_control!=NULL)
+ ret = adap->algo->algo_control(adap,cmd,arg);
+ }
+ return ret;
+}
+
+
+#ifdef MODULE
+/*
+EXPORT_SYMBOL(i2c_register_algorithm);
+EXPORT_SYMBOL(i2c_unregister_algorithm);
+*/
+
+int init_module(void)
+{
+ return i2c_init();
+}
+
+void cleanup_module(void)
+{
+}
+#endif
diff --git a/bttv/experimental/i2c.h b/bttv/experimental/i2c.h
new file mode 100644
index 0000000..f2f321a
--- /dev/null
+++ b/bttv/experimental/i2c.h
@@ -0,0 +1,246 @@
+/* ------------------------------------------------------------------------- */
+/* */
+/* i2c.h - definitions for the \iic-bus interface */
+/* */
+/* ------------------------------------------------------------------------- */
+/* Copyright (C) 1995 Simon G. Vogl
+
+ 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 _I2C_H
+#define _I2C_H
+#include <asm/spinlock.h> /* for spinlock_t */
+
+/* --- General options ------------------------------------------------ */
+#define I2C_MAJOR 89 /* Device major number */
+
+#define I2C_ALGO_MAX 4
+#define I2C_ADAP_MAX 16
+#define I2C_DRIVER_MAX 16
+#define I2C_CLIENT_MAX 32
+
+struct i2c_algorithm;
+struct i2c_adapter;
+struct i2c_client;
+struct i2c_driver;
+
+/* ----- registration structures */
+struct i2c_algorithm {
+ char *name; /* textual description */
+ unsigned int id;
+ int (*master_send)(struct i2c_client *,const char*,int);
+ int (*master_recv)(struct i2c_client *,char*,int);
+ int (*master_comb)(struct i2c_client *,char*,const char*,int,int,int);
+
+ /* --- these optional/future use for some adapter types.*/
+ int (*slave_send)(struct i2c_adapter *,char*,int);
+ int (*slave_recv)(struct i2c_adapter *,char*,int);
+
+ /* --- ioctl like call to set div. parameters. */
+ int (*algo_control)(struct i2c_adapter *, unsigned int, unsigned long);
+
+ /* --- administration stuff. */
+ int (*client_register)(struct i2c_client *);
+ int (*client_unregister)(struct i2c_client *);
+};
+
+
+/* i2c_adapter is the structure used to identify a physical i2c bus along
+ * with the access algorithms necessary to access it.
+ */
+struct i2c_adapter {
+ char *name; /* some useful name to identify the adapter */
+ unsigned int id;/* == is algo->id | hwdep.struct->id, */
+ /* for registered values see below */
+ struct i2c_algorithm *algo;/* the algorithm to access the bus */
+
+ void *data; /* private data for the adapter */
+ /* some data fields that are used by all types */
+ /* these data fields are readonly to the public */
+ /* and can be set via the i2c_ioctl call */
+
+ /* data fields that are valid for all devices */
+ spinlock_t lock;/* used to access the adapter exclusively */
+ unsigned long lockflags;
+ unsigned int flags;/* flags specifying div. data */
+ int timeout;
+ int retries;
+};
+
+/* i2c_client identifies a single device that is connected to an
+ * i2c bus.
+ */
+struct i2c_client {
+ char *name;
+ int id;
+ unsigned int flags; /* div., see below */
+ unsigned char addr; /* chip address - NOTE: 7bit */
+ /* addresses are stored in the */
+ /* _LOWER_ 7 bits of this char */
+ /* 10 bit addresses use the full*/
+ /* 8 bits & set the correct */
+ /* flags in the flags field... */
+ struct i2c_adapter *adapter; /* the adapter we sit on */
+ struct i2c_driver *driver; /* and our access routines */
+ void *data; /* for the clients */
+};
+
+/* a driver is capable of handling one or more physical devices present on
+ * I2C adapters. This information is used to inform the driver of adapter
+ * events.
+ */
+
+struct i2c_driver {
+ char *name;
+ int id;
+ unsigned char addr_l, addr_h; /* address range of the chip */
+ unsigned int flags; /* div., see below */
+
+ int (*attach_adapter)(struct i2c_adapter *);
+ int (*detach_adapter)(struct i2c_client *);
+ int (*command)(struct i2c_client *client,unsigned int cmd, void *arg);
+
+};
+
+/*flags for the driver struct:
+ */
+#define DF_NOTIFY 0x01 /* notify on bus (de/a)ttaches */
+/* #define DF_SCAN 0x02 scan the addr_l-_h for chips */
+
+/*flags for the client struct:
+ */
+#define CF_TEN 0x100000 /* we have a ten bit chip address */
+#define CF_TEN0 0x100000 /* herein lie the first 2 bits */
+#define CF_TEN1 0x110000
+#define CF_TEN2 0x120000
+#define CF_TEN3 0x130000
+#define TENMASK 0x130000
+
+
+/* ----- functions exported by i2c.o */
+
+/* administration...
+ */
+extern int i2c_register_algorithm(struct i2c_algorithm *);
+extern int i2c_unregister_algorithm(struct i2c_algorithm *);
+
+extern int i2c_register_adapter(struct i2c_adapter *);
+extern int i2c_unregister_adapter(struct i2c_adapter *);
+
+extern int i2c_register_driver(struct i2c_driver *);
+extern int i2c_unregister_driver(struct i2c_driver *);
+
+extern int i2c_attach_client(struct i2c_client *);
+extern int i2c_detach_client(struct i2c_client *);
+extern int i2c_client_command(struct i2c_client *);
+
+/* ----- ioctl like call to set div. parameters
+ */
+extern int i2c_control(struct i2c_client *,unsigned int, unsigned long);
+
+/* ----- data transfer
+ */
+extern int i2c_probe(struct i2c_adapter *adap, int low_addr, int hi_addr);
+
+extern int i2c_master_send(struct i2c_client *,const char* ,int);
+extern int i2c_master_recv(struct i2c_client *,char* ,int);
+extern int i2c_master_comb(struct i2c_client *,char* ,const char* ,int, int, int);
+
+/* --- flags for master_comb - combined read/write sequences w/ rep.start */
+#define RD_AFTER_RW 0
+#define WR_AFTER_RD 1
+
+ /*--- these optional/future use for some adapter types.*/
+extern int i2c_slave_send(struct i2c_client *,char*,int);
+extern int i2c_slave_recv(struct i2c_client *,char*,int);
+
+
+/* ----- commands for the ioctl like i2c_command call:
+ * note that additional calls are defined in the algorithm and hw
+ * dependent layers - these can be listed here, or see the
+ * corresponding header files.
+ */
+ /* -> bit-adapter specific ioctls */
+#define I2C_RETRIES 0x0701 /* number times a device adress should */
+ /* be polled when not acknowledging */
+#define I2C_TIMEOUT 0x0702 /* set timeout - call with int */
+
+
+/* this is for i2c-dev.c */
+#define I2C_SLAVE 0x0703 /* Change slave address */
+ /* Attn.: Slave address is 7 bits long, */
+ /* these are to be passed as the */
+ /* lowest 7 bits in the arg. */
+ /* for 10-bit addresses pass lower 8bits*/
+#define I2C_TENBIT 0x0704 /* with 0-3 as arg to this call */
+ /* a value <0 resets to 7 bits */
+/* ... algo-bit.c recognizes */
+#define I2C_UDELAY 0x0705 /* set delay in microsecs between each */
+ /* written byte (except address) */
+#define I2C_MDELAY 0x0706 /* millisec delay between written bytes */
+
+#if 0
+#define I2C_ADDR 0x0707 /* Change adapter's \iic address */
+ /* ...not supported by all adap's */
+
+#define I2C_RESET 0x07fd /* reset adapter */
+#define I2C_CLEAR 0x07fe /* when lost, use to clear stale info */
+#define I2C_V_SLOW 0x07ff /* set jiffies delay call with int */
+
+#define I2C_INTR 0x0708 /* Pass interrupt number - 2be impl. */
+
+#endif
+
+/*
+ * ---- Adapter types: Add a define statement & the struct ---------------
+ *
+ * First, we distinguish between several algorithms to access the hardware
+ * interface types, as a PCF 8584 needs other care than a bit adapter.
+ */
+
+#define ALGO_NONE 0x000
+#define ALGO_BIT 0x100 /* bit style adapters */
+#define ALGO_PCF 0x200 /* PCF 8584 style adapters */
+
+#define ALGO_MASK 0xf00 /* Mask for algorithms */
+#define ALGO_SHIFT 0x08 /* right shift to get index values */
+
+#define I2C_HW_ADAPS 0x100 /* number of different hw implements per*/
+ /* algorithm layer module */
+#define I2C_HW_MASK 0xff /* space for indiv. hw implmentations */
+
+
+/* hw specific modules that are defined per algorithm layer
+ */
+
+/* --- Bit algorithm adapters */
+#define HW_B_LP 0x00 /* Parallel port Philips style adapter */
+#define HW_B_LPC 0x01 /* Parallel port, over control reg. */
+#define HW_B_SER 0x02 /* Serial line interface */
+#define HW_B_ELV 0x03 /* ELV Card */
+#define HW_B_VELLE 0x04 /* Vellemann K8000 */
+#define HW_B_BT848 0x05 /* BT848 video boards */
+
+/* --- PCF 8584 based algorithms */
+#define HW_P_LP 0x00 /* Parallel port interface */
+#define HW_P_ISA 0x01 /* generic ISA Bus inteface card */
+#define HW_P_ELEK 0x02 /* Elektor ISA Bus inteface card */
+
+#define I2C_DRIVERID_MSP3400 1
+#define I2C_DRIVERID_TUNER 2
+#define I2C_DRIVERID_VIDEOTEXT 3
+
+
+#endif
diff --git a/bttv/experimental/tuner.c b/bttv/experimental/tuner.c
new file mode 100644
index 0000000..6de2b9a
--- /dev/null
+++ b/bttv/experimental/tuner.c
@@ -0,0 +1,270 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+
+#include "i2c.h"
+#include "videodev.h"
+
+#include "tuner.h"
+
+int debug = 0; /* insmod parameter */
+int type = 0; /* tuner type */
+
+#define dprintk if (debug) printk
+
+#if LINUX_VERSION_CODE > 0x020100
+MODULE_PARM(debug,"i");
+MODULE_PARM(type,"i");
+#endif
+
+struct tuner {
+ int type; /* chip type */
+ int freq; /* keep track of the current settings */
+ int radio;
+};
+
+static struct i2c_driver driver;
+static struct i2c_client client_template;
+
+/* ---------------------------------------------------------------------- */
+
+struct tunertype {
+ char *name;
+ unchar Vendor;
+ unchar Type;
+
+ ushort thresh1; /* frequency Range for UHF,VHF-L, VHF_H */
+ ushort thresh2;
+ unchar VHF_L;
+ unchar VHF_H;
+ unchar UHF;
+ unchar config;
+ unchar I2C;
+ ushort IFPCoff;
+};
+
+/*
+ * The floats in the tuner struct are computed at compile time
+ * by gcc and cast back to integers. Thus we don't violate the
+ * "no float in kernel" rule.
+ */
+static struct tunertype tuners[] = {
+ {"Temic PAL", TEMIC, PAL,
+ 16*140.25,16*463.25,0x02,0x04,0x01,0x8e,0xc2,623},
+ {"Philips PAL_I", Philips, PAL_I,
+ 16*140.25,16*463.25,0xa0,0x90,0x30,0x8e,0xc0,623},
+ {"Philips NTSC", Philips, NTSC,
+ 16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,0xc0,732},
+ {"Philips SECAM", Philips, SECAM,
+ 16*168.25,16*447.25,0xA7,0x97,0x37,0x8e,0xc0,623},
+ {"NoTuner", NoTuner, NOTUNER,
+ 0 ,0 ,0x00,0x00,0x00,0x00,0x00,000},
+ {"Philips PAL", Philips, PAL,
+ 16*168.25,16*447.25,0xA0,0x90,0x30,0x8e,0xc0,623},
+ {"Temic NTSC", TEMIC, NTSC,
+ 16*157.25,16*463.25,0x02,0x04,0x01,0x8e,0xc2,732},
+ {"TEMIC PAL_I", TEMIC, PAL_I,
+ 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,0xc2,623},
+};
+
+/* ---------------------------------------------------------------------- */
+
+static int tuner_getstatus (struct tuner *t)
+{
+#if 0
+ return i2c_read(t->bus,t->addr+1);
+#endif
+}
+
+#define TUNER_POR 0x80
+#define TUNER_FL 0x40
+#define TUNER_AFC 0x07
+
+static int tuner_islocked (struct tuner *t)
+{
+ return (tuner_getstatus (t) & TUNER_FL);
+}
+
+static int tuner_afcstatus (struct tuner *t)
+{
+ return (tuner_getstatus (t) & TUNER_AFC) - 2;
+}
+
+static void set_tv_freq(struct i2c_client *client, int freq)
+{
+ struct tuner *t = (struct tuner*)client->data;
+ struct tunertype *tun = &tuners[t->type];
+ unsigned char buffer[4];
+ int rc;
+ u8 config;
+ u16 div;
+
+ if (freq < tun->thresh1)
+ config = tun->VHF_L;
+ else if (freq < tun->thresh2)
+ config = tun->VHF_H;
+ else
+ config = tun->UHF;
+
+ div=freq + (int)(16*38.9);
+ div&=0x7fff;
+
+ buffer[0] = (div>>8) & 0x7f;
+ buffer[1] = div & 0xff;
+ buffer[2] = tun->config;
+ buffer[3] = config;
+ if (4 != (rc = i2c_master_send(client,buffer,4)))
+ printk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc);
+}
+
+static void set_radio_freq(struct i2c_client *client, int freq)
+{
+ struct tuner *t = (struct tuner*)client->data;
+ struct tunertype *tun = &tuners[t->type];
+ unsigned char buffer[4];
+ int rc;
+ u8 config;
+ u16 div;
+
+ config = 0xa5;
+ div=freq + (int)(16*10.7);
+ div&=0x7fff;
+
+ buffer[0] = (div>>8) & 0x7f;
+ buffer[1] = div & 0xff;
+ buffer[2] = tun->config;
+ buffer[3] = config;
+ if (4 != (rc = i2c_master_send(client,buffer,4)))
+ printk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc);
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int
+tuner_attach(struct i2c_adapter *adap)
+{
+ struct tuner *t;
+ struct i2c_client *client;
+ int addr;
+
+ /* check bus */
+ addr = i2c_probe(adap, 0xc0>>1, 0xde>>1);
+ if (addr == -1)
+ return -ENODEV;
+ printk("tuner: chip found @ 0x%x\n",addr);
+
+ client = (struct i2c_client *)kmalloc(sizeof(struct i2c_client),
+ GFP_KERNEL);
+ if (client==NULL)
+ return -ENOMEM;
+ memcpy(client,&client_template,sizeof(struct i2c_client));
+ client->addr = addr;
+ client->adapter = adap;
+ client->data = t = kmalloc(sizeof(struct tuner),GFP_KERNEL);
+ if (NULL == t) {
+ kfree(client);
+ return -ENOMEM;
+ }
+ memset(t,0,sizeof(struct tuner));
+ t->type = type;
+ i2c_attach_client(client);
+ return 0;
+}
+
+static int
+tuner_detach(struct i2c_client *client)
+{
+ struct tuner *t = (struct tuner*)client->data;
+
+ i2c_detach_client(client);
+ kfree(t);
+ kfree(client);
+ return 0;
+}
+
+static int
+tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+ struct tuner *t = (struct tuner*)client->data;
+ int *iarg = (int*)arg;
+
+ switch (cmd) {
+ case TUNER_SET_TYPE:
+ t->type = *iarg;
+ dprintk("tuner: type set to %d (%s)\n",
+ t->type,tuners[t->type].name);
+ break;
+
+ case TUNER_SET_TVFREQ:
+ dprintk("tuner: tv freq set to %d.%02d\n",
+ (*iarg)/16,(*iarg)%16*100/16);
+ set_tv_freq(client,*iarg);
+ t->radio = 0;
+ t->freq = *iarg;
+ break;
+
+ case TUNER_SET_RADIOFREQ:
+ dprintk("tuner: radio freq set to %d.%02d\n",
+ (*iarg)/16,(*iarg)%16*100/16);
+ set_radio_freq(client,*iarg);
+ t->radio = 1;
+ t->freq = *iarg;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_driver driver = {
+ "i2c tv tuner driver",
+ -1,
+ 0xc0,0xde,
+ DF_NOTIFY,
+ tuner_attach,
+ tuner_detach,
+ tuner_command,
+};
+
+static struct i2c_client client_template =
+{
+ "i2c tv tuner chip", /* name */
+ I2C_DRIVERID_TUNER, /* ID */
+ 0,
+ 0,
+ NULL,
+ &driver
+};
+
+#ifdef MODULE
+int init_module(void)
+#else
+int tuner_init(void)
+#endif
+{
+ i2c_register_driver(&driver);
+ return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+ i2c_unregister_driver(&driver);
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/bttv/experimental/tuner.h b/bttv/experimental/tuner.h
new file mode 100644
index 0000000..3fb77de
--- /dev/null
+++ b/bttv/experimental/tuner.h
@@ -0,0 +1,49 @@
+/*
+ tuner.h - definition for different tuners
+
+ Copyright (C) 1997 Markus Schroeder (schroedm@uni-duesseldorf.de)
+ minor modifications by Ralph Metzler (rjkm@thp.uni-koeln.de)
+
+ 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 _TUNER_H
+#define _TUNER_H
+
+#define TUNER_TEMIC_PAL 0 /* Miro Gpio Coding -1 */
+#define TUNER_PHILIPS_PAL_I 1
+#define TUNER_PHILIPS_NTSC 2
+#define TUNER_PHILIPS_SECAM 3
+#define TUNER_ABSENT 4
+#define TUNER_PHILIPS_PAL 5
+#define TUNER_TEMIC_NTSC 6
+#define TUNER_TEMIC_PAL_I 7
+
+#define NOTUNER 0
+#define PAL 1
+#define PAL_I 2
+#define NTSC 3
+#define SECAM 4
+
+#define NoTuner 0
+#define Philips 1
+#define TEMIC 2
+#define Sony 3
+
+#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 */
+
+#endif
diff --git a/bttv/experimental/update b/bttv/experimental/update
new file mode 100644
index 0000000..b23592c
--- /dev/null
+++ b/bttv/experimental/update
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+if test "$UID" = "0"; then
+ # running as root anyway, don't need sudo
+ INSMOD="/sbin/insmod"
+ RMMOD="/sbin/rmmod"
+else
+ INSMOD="sudo /sbin/insmod"
+ RMMOD="sudo /sbin/rmmod"
+fi
+
+# handy functions for rmmod/insmod
+function xrmmod () {
+ grep -qe "^$1" /proc/modules || return
+ echo rmmod $1
+ $RMMOD $1 || exit 1
+}
+function xinsmod () {
+ echo insmod $*
+ $INSMOD -f $* || exit 1
+}
+
+# prepare for crashing the box -- flush dirty buffers
+sync; sleep 1; sync
+
+# kill old modules ...
+xrmmod tuner
+xrmmod i2c-dev
+xrmmod bttv
+xrmmod algo-bit
+xrmmod i2c
+xrmmod videodev
+
+# ... and load the new ones
+xinsmod videodev
+xinsmod i2c.o
+xinsmod algo-bit.o test=1 scan=0
+xinsmod tuner debug=1 type=5
+xinsmod bttv radio=1 vidmem=0xff0
+
diff --git a/bttv/experimental/videodev.c b/bttv/experimental/videodev.c
new file mode 100644
index 0000000..360058c
--- /dev/null
+++ b/bttv/experimental/videodev.c
@@ -0,0 +1,375 @@
+/*
+ * Video capture interface for Linux
+ *
+ * A generic video device interface for the LINUX operating system
+ * using a set of device structures/vectors for low level operations.
+ *
+ * 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.
+ *
+ * Author: Alan Cox, <alan@cymru.net>
+ *
+ * Fixes:
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include "videodev.h"
+
+#if LINUX_VERSION_CODE >= 0x020100
+#include <asm/uaccess.h>
+#endif
+#include <asm/system.h>
+
+
+#define VIDEO_NUM_DEVICES 256
+
+/*
+ * Active devices
+ */
+
+static struct video_device *video_device[VIDEO_NUM_DEVICES];
+
+#ifdef CONFIG_VIDEO_BT848
+extern int init_bttv_cards(struct video_init *);
+#endif
+#ifdef CONFIG_VIDEO_SAA5249
+extern int init_saa_5249(struct video_init *);
+#endif
+#ifdef CONFIG_VIDEO_CQCAM
+extern int init_colour_qcams(struct video_init *);
+#endif
+#ifdef CONFIG_VIDEO_BWQCAM
+extern int init_bw_qcams(struct video_init *);
+#endif
+#ifdef CONFIG_RADIO_AZTECH
+extern int aztech_init(struct video_init *);
+#endif
+#ifdef CONFIG_RADIO_RTRACK
+extern int rtrack_init(struct video_init *);
+#endif
+#ifdef CONFIG_RADIO_SF16FMI
+extern int fmi_init(struct video_init *);
+#endif
+
+static struct video_init video_init_list[]={
+#ifdef CONFIG_VIDEO_BT848
+ {"bttv", init_bttv_cards},
+#endif
+#ifdef CONFIG_VIDEO_SAA5249
+ {"saa5249", init_saa_5249},
+#endif
+#ifdef CONFIG_VIDEO_CQCAM
+ {"c-qcam", init_colour_qcams},
+#endif
+#ifdef CONFIG_VIDEO_BWQCAM
+ {"bw-qcam", init_bw_qcams},
+#endif
+#ifdef CONFIG_VIDEO_PMS
+ {"PMS", init_pms_cards},
+#endif
+ {"end", NULL}
+#ifdef CONFIG_RADIO_AZTECH
+ {"Aztech", aztech_init},
+#endif
+#ifdef CONFIG_RADIO_RTRACK
+ {"RTrack", rtrack_init},
+#endif
+#ifdef CONFIG_RADIO_SF16FMI
+ {"SF16FMI", fmi_init},
+#endif
+};
+
+#if LINUX_VERSION_CODE >= 0x020100
+/*
+ * Read will do some smarts later on. Buffer pin etc.
+ */
+
+static ssize_t video_read(struct file *file,
+ char *buf, size_t count, loff_t *ppos)
+{
+ struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)];
+ if (vfl->read)
+ return vfl->read(vfl, buf, count, file->f_flags&O_NONBLOCK);
+ else
+ return -EINVAL;
+}
+
+
+
+/*
+ * Write for now does nothing. No reason it shouldnt do overlay setting
+ * for some boards I guess..
+ */
+
+static ssize_t video_write(struct file *file, const char *buf,
+ size_t count, loff_t *ppos)
+{
+ struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)];
+ if (vfl->write)
+ return vfl->write(vfl, buf, count, file->f_flags&O_NONBLOCK);
+ else
+ return 0;
+}
+#else
+static int video_read(struct inode *ino,struct file *file,
+ char *buf, int count)
+{
+ int err;
+ struct video_device *vfl=video_device[MINOR(ino->i_rdev)];
+ if (vfl->read)
+ return vfl->read(vfl, buf, count, file->f_flags&O_NONBLOCK);
+ else
+ return -EINVAL;
+}
+
+static int video_write(struct inode *ino,struct file *file, const char *buf,
+ int count)
+{
+ int err;
+ struct video_device *vfl=video_device[MINOR(ino->i_rdev)];
+ if (vfl->write)
+ return vfl->write(vfl, buf, count, file->f_flags&O_NONBLOCK);
+ else
+ return 0;
+}
+#endif
+
+/*
+ * Open a video device.
+ */
+
+static int video_open(struct inode *inode, struct file *file)
+{
+ unsigned int minor = MINOR(inode->i_rdev);
+ int err;
+ struct video_device *vfl;
+
+ if(minor>=VIDEO_NUM_DEVICES)
+ return -ENODEV;
+
+ vfl=video_device[minor];
+ if(vfl==NULL)
+ return -ENODEV;
+ if(vfl->busy)
+ return -EBUSY;
+ vfl->busy=1; /* In case vfl->open sleeps */
+
+ if(vfl->open)
+ {
+ err=vfl->open(vfl,0); /* Tell the device it is open */
+ if(err)
+ {
+ vfl->busy=0;
+ return err;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Last close of a video for Linux device
+ */
+
+static int video_release(struct inode *inode, struct file *file)
+{
+ struct video_device *vfl=video_device[MINOR(inode->i_rdev)];
+ if(vfl->close)
+ vfl->close(vfl);
+ vfl->busy=0;
+ return 0;
+}
+
+/*
+ * Question: Should we be able to capture and then seek around the
+ * image ?
+ */
+
+#if LINUX_VERSION_CODE >= 0x020100
+static long long video_lseek(struct file * file,
+ long long offset, int origin)
+{
+ return -ESPIPE;
+}
+#else
+static long long video_lseek(struct inode *inode, struct file * file,
+ long long offset, int origin)
+{
+ return -ESPIPE;
+}
+#endif
+
+
+static int video_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct video_device *vfl=video_device[MINOR(inode->i_rdev)];
+ int err=vfl->ioctl(vfl, cmd, (void *)arg);
+
+ if(err!=-ENOIOCTLCMD)
+ return err;
+
+ switch(cmd)
+ {
+ default:
+ return -EINVAL;
+ }
+}
+
+/*
+ * We need to do MMAP support
+ */
+
+
+#if LINUX_VERSION_CODE >= 0x020100
+int video_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)];
+#else
+static int video_mmap(struct inode * ino, struct file * file,
+ struct vm_area_struct * vma)
+{
+ struct video_device *vfl=video_device[MINOR(ino->i_rdev)];
+#endif
+ if(vfl->mmap)
+ return vfl->mmap(vfl, (char *)vma->vm_start,
+ (unsigned long)(vma->vm_end-vma->vm_start));
+ return -EINVAL;
+}
+
+/*
+ * Video For Linux device drivers request registration here.
+ */
+
+int video_register_device(struct video_device *vfd, int type)
+{
+ int i=0;
+ int base;
+ int err;
+ int end;
+
+ switch(type)
+ {
+ case VFL_TYPE_GRABBER:
+ base=0;
+ end=64;
+ break;
+ case VFL_TYPE_VTX:
+ base=192;
+ end=224;
+ break;
+ case VFL_TYPE_VBI:
+ base=224;
+ end=240;
+ break;
+ case VFL_TYPE_RADIO:
+ base=64;
+ end=128;
+ break;
+ default:
+ return -1;
+ }
+
+ for(i=base;i<end;i++)
+ {
+ if(video_device[i]==NULL)
+ {
+ video_device[i]=vfd;
+ vfd->minor=i;
+ /* The init call may sleep so we book the slot out
+ then call */
+ MOD_INC_USE_COUNT;
+ if (vfd->initialize)
+ {
+ err=vfd->initialize(vfd);
+ if(err<0)
+ {
+ video_device[i]=NULL;
+ MOD_DEC_USE_COUNT;
+ return err;
+ }
+ }
+ return 0;
+ }
+ }
+ return -ENFILE;
+}
+
+/*
+ * Unregister an unused video for linux device
+ */
+
+void video_unregister_device(struct video_device *vfd)
+{
+ if(video_device[vfd->minor]!=vfd)
+ panic("vfd: bad unregister");
+ video_device[vfd->minor]=NULL;
+ MOD_DEC_USE_COUNT;
+}
+
+
+static struct file_operations video_fops=
+{
+ video_lseek,
+ video_read,
+ video_write,
+ NULL, /* readdir */
+ NULL, /* poll */
+ video_ioctl,
+ video_mmap,
+ video_open,
+ video_release
+};
+
+/*
+ * Initialise video for linux
+ */
+
+int videodev_init(void)
+{
+ struct video_init *vfli = video_init_list;
+
+ printk(KERN_INFO "Linux video capture interface: v0.01 ALPHA\n");
+ if(register_chrdev(VIDEO_MAJOR,"video_capture", &video_fops))
+ {
+ printk("video_dev: unable to get major %d\n", VIDEO_MAJOR);
+ return -EIO;
+ }
+
+ /*
+ * Init kernel installed video drivers
+ */
+
+ while(vfli->init!=NULL)
+ {
+ vfli->init(vfli);
+ vfli++;
+ }
+ return 0;
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return videodev_init();
+}
+
+void cleanup_module(void)
+{
+ unregister_chrdev(VIDEO_MAJOR, "video_capture");
+}
+
+#endif
+
+#if LINUX_VERSION_CODE >= 0x020100
+EXPORT_SYMBOL(video_register_device);
+EXPORT_SYMBOL(video_unregister_device);
+#endif
diff --git a/bttv/experimental/videodev.h b/bttv/experimental/videodev.h
new file mode 100644
index 0000000..6b13119
--- /dev/null
+++ b/bttv/experimental/videodev.h
@@ -0,0 +1,214 @@
+#ifndef __LINUX_VIDEODEV_H
+#define __LINUX_VIDEODEV_H
+
+#ifdef __KERNEL__
+
+struct video_device
+{
+ char name[32];
+ int type;
+ int hardware;
+
+ int (*open)(struct video_device *, int mode);
+ void (*close)(struct video_device *);
+ long (*read)(struct video_device *, char *, unsigned long, int noblock);
+ /* Do we need a write method ? */
+ long (*write)(struct video_device *, const char *, unsigned long, int noblock);
+ int (*ioctl)(struct video_device *, unsigned int , void *);
+ int (*mmap)(struct video_device *, const char *, unsigned long);
+ int (*initialize)(struct video_device *);
+ void *priv; /* Used to be 'private' but that upsets C++ */
+ int busy;
+ int minor;
+};
+
+extern int videodev_init(void);
+#define VIDEO_MAJOR 81
+extern int video_register_device(struct video_device *, int type);
+
+#define VFL_TYPE_GRABBER 0
+#define VFL_TYPE_VBI 1
+#define VFL_TYPE_RADIO 2
+#define VFL_TYPE_VTX 3
+
+extern void video_unregister_device(struct video_device *);
+#endif
+
+
+#define VID_TYPE_CAPTURE 1 /* Can capture */
+#define VID_TYPE_TUNER 2 /* Can tune */
+#define VID_TYPE_TELETEXT 4 /* Does teletext */
+#define VID_TYPE_OVERLAY 8 /* Overlay onto frame buffer */
+#define VID_TYPE_CHROMAKEY 16 /* Overlay by chromakey */
+#define VID_TYPE_CLIPPING 32 /* Can clip */
+#define VID_TYPE_FRAMERAM 64 /* Uses the frame buffer memory */
+#define VID_TYPE_SCALES 128 /* Scalable */
+#define VID_TYPE_MONOCHROME 256 /* Monochrome only */
+
+struct video_capability
+{
+ char name[32];
+ int type;
+ int channels; /* Num channels */
+ int audios; /* Num audio devices */
+ int maxwidth; /* Supported width */
+ int maxheight; /* And height */
+ int minwidth; /* Supported width */
+ int minheight; /* And height */
+};
+
+
+struct video_channel
+{
+ int channel;
+ char name[32];
+ int tuners;
+ __u32 flags;
+#define VIDEO_VC_TUNER 1 /* Channel has a tuner */
+#define VIDEO_VC_AUDIO 2 /* Channel has audio */
+ __u16 type;
+#define VIDEO_TYPE_TV 1
+#define VIDEO_TYPE_CAMERA 2
+};
+
+struct video_tuner
+{
+ int tuner;
+ char name[32];
+ ulong rangelow, rangehigh; /* Tuner range */
+ __u32 flags;
+#define VIDEO_TUNER_PAL 1
+#define VIDEO_TUNER_NTSC 2
+#define VIDEO_TUNER_SECAM 4
+#define VIDEO_TUNER_LOW 8 /* Uses KHz not MHz */
+#define VIDEO_TUNER_STEREO_ON 128 /* Tuner is seeing stereo */
+ __u16 mode; /* PAL/NTSC/SECAM/OTHER */
+#define VIDEO_MODE_PAL 0
+#define VIDEO_MODE_NTSC 1
+#define VIDEO_MODE_SECAM 2
+#define VIDEO_MODE_AUTO 3
+ __u16 signal; /* Signal strength 16bit scale */
+};
+
+struct video_picture
+{
+ __u16 brightness;
+ __u16 hue;
+ __u16 colour;
+ __u16 contrast;
+ __u16 whiteness; /* Black and white only */
+ __u16 depth; /* Capture depth */
+ __u16 palette; /* Palette in use */
+#define VIDEO_PALETTE_GREY 1 /* Linear greyscale */
+#define VIDEO_PALETTE_HI240 2 /* High 240 cube (BT848) */
+#define VIDEO_PALETTE_RGB565 3 /* 565 16 bit RGB */
+#define VIDEO_PALETTE_RGB24 4 /* 24bit RGB */
+#define VIDEO_PALETTE_RGB32 5 /* 32bit RGB */
+#define VIDEO_PALETTE_RGB555 6 /* 555 15bit RGB */
+#define VIDEO_PALETTE_YUV422 7 /* YUV422 capture */
+};
+
+struct video_audio
+{
+ int audio; /* Audio channel */
+ __u16 volume; /* If settable */
+ __u16 bass, treble;
+ __u32 flags;
+#define VIDEO_AUDIO_MUTE 1
+#define VIDEO_AUDIO_MUTABLE 2
+#define VIDEO_AUDIO_VOLUME 4
+#define VIDEO_AUDIO_BASS 8
+#define VIDEO_AUDIO_TREBLE 16
+ char name[16];
+#define VIDEO_SOUND_MONO 1
+#define VIDEO_SOUND_STEREO 2
+#define VIDEO_SOUND_LANG1 3
+#define VIDEO_SOUND_LANG2 4
+ __u16 mode;
+};
+
+struct video_clip
+{
+ __s32 x,y;
+ __s32 width, height;
+ struct video_clip *next; /* For user use/driver use only */
+};
+
+struct video_window
+{
+ __u32 x,y;
+ __u32 width,height;
+ __u32 chromakey;
+ __u32 flags;
+ struct video_clip *clips; /* Set only */
+ int clipcount;
+#define VIDEO_WINDOW_INTERLACE 1
+};
+
+struct video_buffer
+{
+ void *base;
+ int height,width;
+ int depth;
+ int bytesperline;
+};
+
+struct video_mmap
+{
+ unsigned int frame; /* Frame (0 or 1) for double buffer */
+ int height,width;
+ unsigned int format;
+};
+
+struct video_key
+{
+ __u8 key[8];
+ __u32 flags;
+};
+
+#define VIDIOCGCAP _IOR('v',1,struct video_capability) /* Get capabilities */
+#define VIDIOCGCHAN _IOWR('v',2,struct video_channel) /* Get channel info (sources) */
+#define VIDIOCSCHAN _IOW('v',3,int) /* Set channel */
+#define VIDIOCGTUNER _IOWR('v',4,struct video_tuner) /* Get tuner abilities */
+#define VIDIOCSTUNER _IOW('v',5,struct video_tuner) /* Tune the tuner for the current channel */
+#define VIDIOCGPICT _IOR('v',6,struct video_picture) /* Get picture properties */
+#define VIDIOCSPICT _IOW('v',7,struct video_picture) /* Set picture properties */
+#define VIDIOCCAPTURE _IOW('v',8,int) /* Start, end capture */
+#define VIDIOCGWIN _IOR('v',9, struct video_window) /* Set the video overlay window */
+#define VIDIOCSWIN _IOW('v',10, struct video_window) /* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */
+#define VIDIOCGFBUF _IOR('v',11, struct video_buffer) /* Get frame buffer */
+#define VIDIOCSFBUF _IOW('v',12, struct video_buffer) /* Set frame buffer - root only */
+#define VIDIOCKEY _IOR('v',13, struct video_key) /* Video key event - to dev 255 is to all - cuts capture on all DMA windows with this key (0xFFFFFFFF == all) */
+#define VIDIOCGFREQ _IOR('v',14, unsigned long) /* Set tuner */
+#define VIDIOCSFREQ _IOW('v',15, unsigned long) /* Set tuner */
+#define VIDIOCGAUDIO _IOR('v',16, struct video_audio) /* Get audio info */
+#define VIDIOCSAUDIO _IOW('v',17, struct video_audio) /* Audio source, mute etc */
+#define VIDIOCSYNC_OLD _IO('v',18) /* Sync with mmap grabbing */
+#define VIDIOCSYNC _IOW('v',18, int) /* Sync with mmap grabbing */
+#define VIDIOCMCAPTURE _IOW('v',19, struct video_mmap) /* Grab frames */
+
+
+#define BASE_VIDIOCPRIVATE 192 /* 192-255 are private */
+
+
+#define VID_HARDWARE_BT848 1
+#define VID_HARDWARE_QCAM_BW 2
+#define VID_HARDWARE_PMS 3
+#define VID_HARDWARE_QCAM_C 4
+#define VID_HARDWARE_PSEUDO 5
+#define VID_HARDWARE_SAA5249 6
+#define VID_HARDWARE_AZTECH 7
+#define VID_HARDWARE_SF16MI 8
+#define VID_HARDWARE_RTRACK 9
+
+/*
+ * Initialiser list
+ */
+
+struct video_init
+{
+ char *name;
+ int (*init)(struct video_init *);
+};
+
+#endif

Privacy Policy