Commit 8354eb8a authored by Gerd Knorr's avatar Gerd Knorr Committed by Linus Torvalds

[PATCH] bttv update

This updates the bttv driver.  Major changes are (a) adaptions to the
final v4l2 API and (b) lots of updates in the card-specific code.  There
are also various other small changes.
parent 3344276f
......@@ -347,6 +347,8 @@
#define BT848_PLL_X (1<<7)
#define BT848_PLL_C (1<<6)
#define BT848_DVSIF 0x0FC
/* Bt878 register */
#define BT878_DEVCTRL 0x40
......
......@@ -37,15 +37,16 @@
#include "bttvp.h"
#include "tuner.h"
#if 0
# include "bt832.h"
#endif
/* fwd decl */
static void boot_msp34xx(struct bttv *btv, int pin);
static void hauppauge_eeprom(struct bttv *btv);
static void avermedia_eeprom(struct bttv *btv);
static void osprey_eeprom(struct bttv *btv);
static void init_PXC200(struct bttv *btv);
#if 0
static void init_tea5757(struct bttv *btv);
#endif
static void winview_audio(struct bttv *btv, struct video_audio *v, int set);
static void lt9415_audio(struct bttv *btv, struct video_audio *v, int set);
......@@ -58,6 +59,12 @@ static void pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set);
static void fv2000s_audio(struct bttv *btv, struct video_audio *v, int set);
static void windvr_audio(struct bttv *btv, struct video_audio *v, int set);
static void rv605_muxsel(struct bttv *btv, unsigned int input);
static void eagle_muxsel(struct bttv *btv, unsigned int input);
static int terratec_active_radio_upgrade(struct bttv *btv);
static int tea5757_read(struct bttv *btv);
static int tea5757_write(struct bttv *btv, int value);
/* config variables */
static int triton1=0;
......@@ -83,11 +90,11 @@ MODULE_PARM(vsfx,"i");
MODULE_PARM_DESC(vsfx,"set VSFX pci config bit "
"[yet another chipset flaw workaround]");
MODULE_PARM(no_overlay,"i");
MODULE_PARM(card,"1-" __MODULE_STRING(BTTV_MAX) "i");
MODULE_PARM(card,"1-" __stringify(BTTV_MAX) "i");
MODULE_PARM_DESC(card,"specify TV/grabber card model, see CARDLIST file for a list");
MODULE_PARM(pll,"1-" __MODULE_STRING(BTTV_MAX) "i");
MODULE_PARM(pll,"1-" __stringify(BTTV_MAX) "i");
MODULE_PARM_DESC(pll,"specify installed crystal (0=none, 28=28 MHz, 35=35 MHz)");
MODULE_PARM(tuner,"1-" __MODULE_STRING(BTTV_MAX) "i");
MODULE_PARM(tuner,"1-" __stringify(BTTV_MAX) "i");
MODULE_PARM_DESC(tuner,"specify installed tuner type");
MODULE_PARM(autoload,"i");
MODULE_PARM_DESC(autoload,"automatically load i2c modules like tuner.o, default is 1 (yes)");
......@@ -127,24 +134,29 @@ static struct CARD {
} cards[] __devinitdata = {
{ 0x13eb0070, BTTV_HAUPPAUGE878, "Hauppauge WinTV" },
{ 0x39000070, BTTV_HAUPPAUGE878, "Hauppauge WinTV-D" },
{ 0x45000070, BTTV_HAUPPAUGE878, "Hauppauge WinTV/PVR" },
{ 0xff000070, BTTV_HAUPPAUGE878, "Osprey-100" },
{ 0xff010070, BTTV_HAUPPAUGE878, "Osprey-200" },
{ 0x45000070, BTTV_HAUPPAUGEPVR, "Hauppauge WinTV/PVR" },
{ 0xff000070, BTTV_OSPREY1x0, "Osprey-100" },
{ 0xff010070, BTTV_OSPREY2x0_SVID,"Osprey-200" },
{ 0xff020070, BTTV_OSPREY500, "Osprey-500" },
{ 0xff030070, BTTV_OSPREY2000, "Osprey-2000" },
{ 0xff040070, BTTV_OSPREY540, "Osprey-540" },
{ 0x00011002, BTTV_ATI_TVWONDER, "ATI TV Wonder" },
{ 0x00031002, BTTV_ATI_TVWONDERVE,"ATI TV Wonder/VE" },
{ 0x6606107d, BTTV_WINFAST2000, "Leadtek WinFast TV 2000" },
{ 0x6607107d, BTTV_WINFAST2000, "Leadtek WinFast VC 100" },
{ 0x263610b4, BTTV_STB2, "STB TV PCI FM, P/N 6000704" },
{ 0x263610b4, BTTV_STB2, "STB TV PCI FM, Gateway P/N 6000704" },
{ 0x402010fc, BTTV_GVBCTV3PCI, "I-O Data Co. GV-BCTV3/PCI" },
{ 0x405010fc, BTTV_GVBCTV4PCI, "I-O Data Co. GV-BCTV4/PCI" },
{ 0x407010fc, BTTV_GVBCTV5PCI, "I-O Data Co. GV-BCTV5/PCI" },
{ 0x1200bd11, BTTV_PINNACLE, "Pinnacle PCTV" },
{ 0x001211bd, BTTV_PINNACLE, "Pinnacle PCTV" },
{ 0x001c11bd, BTTV_PINNACLE, "Pinnacle PCTV Sat" },
{ 0x3000121a, BTTV_VOODOOTV_FM, "3Dfx VoodooTV FM/ VoodooTV 200" },
{ 0x3060121a, BTTV_STB2, "3Dfx VoodooTV 100/ STB OEM" },
{ 0x3000144f, BTTV_MAGICTVIEW063, "(Askey Magic/others) TView99 CPH06x" },
{ 0x3002144f, BTTV_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH05x" },
......@@ -170,6 +182,7 @@ static struct CARD {
{ 0x1135153b, BTTV_TERRATVALUER, "Terratec TValue Radio" },
{ 0x5018153b, BTTV_TERRATVALUE, "Terratec TValue" },
{ 0x400015b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
{ 0x400a15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
{ 0x400d15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
{ 0x401015b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
......@@ -225,7 +238,7 @@ struct tvcard bttv_tvcards[] = {
needs_tvaudio: 1,
tuner_type: -1,
},{
name: "STB",
name: "STB, Gateway P/N 6000699 (bt848)",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
......@@ -235,7 +248,9 @@ struct tvcard bttv_tvcards[] = {
audiomux: { 4, 0, 2, 3, 1},
no_msp34xx: 1,
needs_tvaudio: 1,
tuner_type: -1,
tuner_type: TUNER_PHILIPS_NTSC,
pll: PLL_28,
has_radio: 1,
},{
/* ---- card 0x04 ---------------------------------- */
......@@ -357,7 +372,7 @@ struct tvcard bttv_tvcards[] = {
audiomux: { 13, 14, 11, 7, 0, 0},
needs_tvaudio: 1,
pll: PLL_28,
tuner_type: -1,
tuner_type: TUNER_PHILIPS_PAL,
},{
name: "Aimslab Video Highway Xtreme (VHX)",
video_inputs: 3,
......@@ -490,16 +505,17 @@ struct tvcard bttv_tvcards[] = {
pll: PLL_28,
tuner_type: -1,
},{
name: "Terratec Terra TV+ Version 1.0 (Bt848)/Vobis TV-Boostar",
name: "Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 16777215,
gpiomask: 0x1f0fff,
muxsel: { 2, 3, 1, 1},
audiomux: { 131072, 1, 1638400, 3,4},
needs_tvaudio: 1,
tuner_type: -1,
audiomux: { 0x20000, 0x30000, 0x10000, 0, 0x40000},
needs_tvaudio: 0,
tuner_type: TUNER_PHILIPS_PAL,
audio_hook: terratv_audio,
},{
name: "Hauppauge WinCam newer (bt878)",
video_inputs: 4,
......@@ -525,17 +541,48 @@ struct tvcard bttv_tvcards[] = {
},{
/* ---- card 0x1c ---------------------------------- */
name: "Terratec TerraTV+",
name: "Terratec TerraTV+ Version 1.1 (bt878)",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 0x70000,
gpiomask: 0x1f0fff,
muxsel: { 2, 3, 1, 1},
audiomux: { 0x20000, 0x30000, 0x10000, 0x00000, 0x40000},
needs_tvaudio: 1,
needs_tvaudio: 0,
tuner_type: TUNER_PHILIPS_PAL,
audio_hook: terratv_audio,
/* GPIO wiring:
External 20 pin connector (for Active Radio Upgrade board)
gpio00: i2c-sda
gpio01: i2c-scl
gpio02: om5610-data
gpio03: om5610-clk
gpio04: om5610-wre
gpio05: om5610-stereo
gpio06: rds6588-davn
gpio07: Pin 7 n.c.
gpio08: nIOW
gpio09+10: nIOR, nSEL ?? (bt878)
gpio09: nIOR (bt848)
gpio10: nSEL (bt848)
Sound Routing:
gpio16: u2-A0 (1st 4052bt)
gpio17: u2-A1
gpio18: u2-nEN
gpio19: u4-A0 (2nd 4052)
gpio20: u4-A1
u4-nEN - GND
Btspy:
00000 : Cdrom (internal audio input)
10000 : ext. Video audio input
20000 : TV Mono
a0000 : TV Mono/2
1a0000 : TV Stereo
30000 : Radio
40000 : Mute
*/
},{
/* Jannik Fritsch <jannik@techfak.uni-bielefeld.de> */
name: "Imagenation PXC200",
......@@ -583,7 +630,7 @@ struct tvcard bttv_tvcards[] = {
needs_tvaudio: 0,
tuner_type: 4,
},{
name: "Terratec TerraTValue",
name: "Terratec TerraTValue Version Bt878",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
......@@ -595,17 +642,29 @@ struct tvcard bttv_tvcards[] = {
pll: PLL_28,
tuner_type: TUNER_PHILIPS_PAL,
},{
name: "Leadtek WinFast 2000",
video_inputs: 3,
name: "Leadtek WinFast 2000/ WinFast 2000 XP",
video_inputs: 4,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 0xc33000,
muxsel: { 2, 3, 1, 1,0},
audiomux: { 0x422000,0x001000,0x621100,0x620000,0x800000,0x620000},
muxsel: { 2, 3, 1, 1, 0}, // TV, CVid, SVid, CVid over SVid connector
audiomux: { 0x422000,0x1000,0x0000,0x620000,0x800000},
/* Audio Routing for "WinFast 2000 XP" (no tv stereo !)
gpio23 -- hef4052:nEnable (0x800000)
gpio12 -- hef4052:A1
gpio13 -- hef4052:A0
0x0000: external audio
0x1000: FM
0x2000: TV
0x3000: n.c.
Note: There exists another variant "Winfast 2000" with tv stereo !?
Note: eeprom only contains FF and pci subsystem id 107d:6606
*/
needs_tvaudio: 0,
pll: PLL_28,
tuner_type: -1,
has_radio: 1,
tuner_type: 5, // default for now, gpio reads BFFF06 for Pal bg+dk
audio_hook: winfast2000_audio,
},{
name: "Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II",
......@@ -671,7 +730,7 @@ struct tvcard bttv_tvcards[] = {
},{
/* ---- card 0x28 ---------------------------------- */
name: "STB2",
name: "STB TV PCI FM, Gateway P/N 6000704 (bt878), 3Dfx VoodooTV 100",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
......@@ -681,7 +740,9 @@ struct tvcard bttv_tvcards[] = {
audiomux: { 4, 0, 2, 3, 1},
no_msp34xx: 1,
needs_tvaudio: 1,
tuner_type: -1,
tuner_type: TUNER_PHILIPS_NTSC,
pll: PLL_28,
has_radio: 1,
},{
name: "AVerMedia TVPhone 98",
video_inputs: 3,
......@@ -810,6 +871,15 @@ struct tvcard bttv_tvcards[] = {
no_msp34xx: 1,
pll: PLL_28,
tuner_type: TUNER_PHILIPS_PAL_I,
/* GPIO wiring: (different from Rev.4C !)
GPIO17: U4.A0 (first hef4052bt)
GPIO19: U4.A1
GPIO20: U5.A1 (second hef4052bt)
GPIO21: U4.nEN
GPIO22: BT832 Reset Line
GPIO23: A5,A0, U5,nEN
Note: At i2c=0x8a is a Bt832 chip, which changes to 0x88 after being reset via GPIO22
*/
},{
name: "Eagle Wireless Capricorn2 (bt878A)",
video_inputs: 4,
......@@ -1105,10 +1175,17 @@ struct tvcard bttv_tvcards[] = {
svhs: 2,
gpiomask: 15,
muxsel: { 2, 3, 1, 1},
audiomux: { 0, 0, 11, 7, 13, 0},
audiomux: { 0, 0, 11, 7, 13, 0}, // TV and Radio with same GPIO !
needs_tvaudio: 1,
pll: PLL_28,
tuner_type: 25,
/* GPIO wiring:
GPIO0: U4.A0 (hef4052bt)
GPIO1: U4.A1
GPIO2: U4.A1 (second hef4052bt)
GPIO3: U4.nEN, U5.A0, A5.nEN
GPIO8-15: vrd866b ?
*/
},{
name: "Lifeview FlyVideo 98EZ (capture only) LR51",
video_inputs: 4,
......@@ -1123,20 +1200,27 @@ struct tvcard bttv_tvcards[] = {
/* ---- card 0x48 ---------------------------------- */
/* Dariusz Kowalewski <darekk@automex.pl> */
name: "Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)",
video_inputs: 3,
video_inputs: 4,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 0x3f,
muxsel: { 2, 3, 0, 1 },
muxsel: { 2, 3, 1, 1 },
audiomux: { 0x01, 0x00, 0x03, 0x03, 0x09, 0x02 },
needs_tvaudio: 1,
no_msp34xx: 1,
no_tda9875: 1,
pll: PLL_28,
tuner_type: -1,
audio_hook: pvbt878p9b_audio,
has_radio: 1,
tuner_type: 5,
audio_hook: pvbt878p9b_audio, // Note: not all cards have stereo
has_radio: 1, // Note: not all cards have radio
/* GPIO wiring:
GPIO0: A0 hef4052
GPIO1: A1 hef4052
GPIO3: nEN hef4052
GPIO8-15: vrd866b
GPIO20,22,23: R30,R29,R28
*/
},{
/* Clay Kunz <ckunz@mail.arc.nasa.gov> */
/* you must jumper JP5 for the card to work */
......@@ -1242,6 +1326,193 @@ struct tvcard bttv_tvcards[] = {
muxsel: { 2, 3, 1, 0},
pll: PLL_28,
tuner_type: -1,
},{
/* ---- card 0x50 ---------------------------------- */
name: "Hauppauge WinTV PVR",
video_inputs: 4,
audio_inputs: 1,
tuner: 0,
svhs: 2,
muxsel: { 2, 0, 1, 1},
needs_tvaudio: 1,
pll: PLL_28,
tuner_type: -1,
gpiomask: 7,
audiomux: {7},
},{
name: "GV-BCTV5/PCI",
video_inputs: 3,
audio_inputs: 1,
tuner: 0,
svhs: 2,
gpiomask: 0x010f00,
muxsel: {2, 3, 1, 0},
audiomux: {0x10000, 0, 0x10000, 0, 0, 0},
no_msp34xx: 1,
pll: PLL_28,
tuner_type: TUNER_PHILIPS_NTSC_M,
audio_hook: gvbctv3pci_audio,
},{
name: "Osprey 100/150 (878)", /* 0x1(2|3)-45C6-C1 */
video_inputs: 4, /* id-inputs-clock */
audio_inputs: 0,
tuner: -1,
svhs: 3,
muxsel: { 3, 2, 0, 1 },
pll: PLL_28,
tuner_type: -1,
no_msp34xx: 1,
no_tda9875: 1,
no_tda7432: 1,
},{
name: "Osprey 100/150 (848)", /* 0x04-54C0-C1 & older boards */
video_inputs: 3,
audio_inputs: 0,
tuner: -1,
svhs: 2,
muxsel: { 2, 3, 1 },
pll: PLL_28,
tuner_type: -1,
no_msp34xx: 1,
no_tda9875: 1,
no_tda7432: 1,
},{
/* ---- card 0x54 ---------------------------------- */
name: "Osprey 101 (848)", /* 0x05-40C0-C1 */
video_inputs: 2,
audio_inputs: 0,
tuner: -1,
svhs: 1,
muxsel: { 3, 1 },
pll: PLL_28,
tuner_type: -1,
no_msp34xx: 1,
no_tda9875: 1,
no_tda7432: 1,
},{
name: "Osprey 101/151", /* 0x1(4|5)-0004-C4 */
video_inputs: 1,
audio_inputs: 0,
tuner: -1,
svhs: -1,
muxsel: { 0 },
pll: PLL_28,
tuner_type: -1,
no_msp34xx: 1,
no_tda9875: 1,
no_tda7432: 1,
},{
name: "Osprey 101/151 w/ svid", /* 0x(16|17|20)-00C4-C1 */
video_inputs: 2,
audio_inputs: 0,
tuner: -1,
svhs: 1,
muxsel: { 0, 1 },
pll: PLL_28,
tuner_type: -1,
no_msp34xx: 1,
no_tda9875: 1,
no_tda7432: 1,
},{
name: "Osprey 200/201/250/251", /* 0x1(8|9|E|F)-0004-C4 */
video_inputs: 1,
audio_inputs: 1,
tuner: -1,
svhs: -1,
muxsel: { 0 },
pll: PLL_28,
tuner_type: -1,
no_msp34xx: 1,
no_tda9875: 1,
no_tda7432: 1,
},{
/* ---- card 0x58 ---------------------------------- */
name: "Osprey 200/250", /* 0x1(A|B)-00C4-C1 */
video_inputs: 2,
audio_inputs: 1,
tuner: -1,
svhs: 1,
muxsel: { 0, 1 },
pll: PLL_28,
tuner_type: -1,
no_msp34xx: 1,
no_tda9875: 1,
no_tda7432: 1,
},{
name: "Osprey 210/220", /* 0x1(A|B)-04C0-C1 */
video_inputs: 2,
audio_inputs: 1,
tuner: -1,
svhs: 1,
muxsel: { 2, 3 },
pll: PLL_28,
tuner_type: -1,
no_msp34xx: 1,
no_tda9875: 1,
no_tda7432: 1,
},{
name: "Osprey 500", /* 500 */
video_inputs: 2,
audio_inputs: 1,
tuner: -1,
svhs: 1,
muxsel: { 2, 3 },
pll: PLL_28,
tuner_type: -1,
no_msp34xx: 1,
no_tda9875: 1,
no_tda7432: 1,
},{
name: "Osprey 540", /* 540 */
video_inputs: 4,
audio_inputs: 1,
tuner: -1,
#if 0 /* TODO ... */
svhs: OSPREY540_SVID_ANALOG,
muxsel: { [OSPREY540_COMP_ANALOG] = 2,
[OSPREY540_SVID_ANALOG] = 3, },
#endif
pll: PLL_28,
tuner_type: -1,
no_msp34xx: 1,
no_tda9875: 1,
no_tda7432: 1,
#if 0 /* TODO ... */
muxsel_hook: osprey_540_muxsel,
picture_hook: osprey_540_set_picture,
#endif
},{
/* ---- card 0x5C ---------------------------------- */
name: "Osprey 2000", /* 2000 */
video_inputs: 2,
audio_inputs: 1,
tuner: -1,
svhs: 1,
muxsel: { 2, 3 },
pll: PLL_28,
tuner_type: -1,
no_msp34xx: 1,
no_tda9875: 1,
no_tda7432: 1, /* must avoid, conflicts with the bt860 */
},{
/* M G Berberich <berberic@forwiss.uni-passau.de> */
name: "IDS Eagle",
video_inputs: 4,
audio_inputs: 0,
tuner: -1,
tuner_type: -1,
svhs: -1,
gpiomask: 0,
muxsel: { 0, 1, 2, 3 },
muxsel_hook: eagle_muxsel,
no_msp34xx: 1,
no_tda9875: 1,
pll: PLL_28,
}};
const int bttv_num_tvcards = (sizeof(bttv_tvcards)/sizeof(struct tvcard));
......@@ -1355,11 +1626,13 @@ static void flyvideo_gpio(struct bttv *btv)
switch(ttype) {
case 0x0: tuner=4; // None
break;
case 0x4: tuner=5; // Philips PAL
case 0x2: tuner=39;// LG NTSC (newer TAPC series) TAPC-H701P
break;
case 0x6: tuner=37; // LG PAL (newer TAPC series)
case 0x4: tuner=5; // Philips PAL TPI8PSB02P, TPI8PSB12P, TPI8PSB12D or FI1216, FM1216
break;
case 0xC: tuner=3; // Philips SECAM(+PAL)
case 0x6: tuner=37; // LG PAL (newer TAPC series) TAPC-G702P
break;
case 0xC: tuner=3; // Philips SECAM(+PAL) FQ1216ME or FI1216MF
break;
default:
printk(KERN_INFO "bttv%d: FlyVideo_gpio: unknown tuner type.\n", btv->nr);
......@@ -1394,48 +1667,148 @@ static void flyvideo_gpio(struct bttv *btv)
int miro_tunermap[] = { 0,6,2,3, 4,5,6,0, 3,0,4,5, 5,2,16,1,
14,2,17,1, 4,1,4,3, 1,2,16,1, 4,4,4,4 };
int miro_fmtuner[] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1,
1,1,1,1, 1,1,1,0, 0,0,0,0, 0,0,0,0 };
1,1,1,1, 1,1,1,0, 0,0,0,0, 0,1,0,0 };
static void miro_pinnacle_gpio(struct bttv *btv)
{
int id,msp;
id = ((btread(BT848_GPIO_DATA)>>10) & 31) -1;
msp = bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx");
btv->tuner_type = miro_tunermap[id];
if (0 == (btread(BT848_GPIO_DATA) & 0x20)) {
btv->has_radio = 1;
if (!miro_fmtuner[id]) {
btv->has_matchbox = 1;
btv->mbox_we = (1<<6);
btv->mbox_most = (1<<7);
btv->mbox_clk = (1<<8);
btv->mbox_data = (1<<9);
btv->mbox_mask = (1<<6)|(1<<7)|(1<<8)|(1<<9);
int id,msp,gpio;
char *info;
btwrite(0,BT848_GPIO_OUT_EN);
gpio = btread(BT848_GPIO_DATA);
id = ((gpio>>10) & 63) -1;
msp = bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx");
if (id < 32) {
btv->tuner_type = miro_tunermap[id];
if (0 == (gpio & 0x20)) {
btv->has_radio = 1;
if (!miro_fmtuner[id]) {
btv->has_matchbox = 1;
btv->mbox_we = (1<<6);
btv->mbox_most = (1<<7);
btv->mbox_clk = (1<<8);
btv->mbox_data = (1<<9);
btv->mbox_mask = (1<<6)|(1<<7)|(1<<8)|(1<<9);
}
} else {
btv->has_radio = 0;
}
if (-1 != msp) {
if (btv->type == BTTV_MIRO)
btv->type = BTTV_MIROPRO;
if (btv->type == BTTV_PINNACLE)
btv->type = BTTV_PINNACLEPRO;
}
printk(KERN_INFO "bttv%d: miro: id=%d tuner=%d radio=%s stereo=%s\n",
btv->nr, id+1, btv->tuner_type,
!btv->has_radio ? "no" :
(btv->has_matchbox ? "matchbox" : "fmtuner"),
(-1 == msp) ? "no" : "yes");
} else {
/* new cards with microtune tuner */
id = 63 - id;
btv->has_radio = 0;
switch (id) {
case 1:
info = "PAL / mono";
break;
case 2:
info = "PAL+SECAM / stereo";
btv->has_radio = 1;
break;
case 3:
info = "NTSC / stereo";
btv->has_radio = 1;
break;
case 4:
info = "PAL+SECAM / mono";
break;
case 5:
info = "NTSC / mono";
break;
case 6:
info = "NTSC / stereo";
break;
default:
info = "oops: unknown card";
break;
}
printk(KERN_INFO
"bttv%d: pinnacle/mt: id=%d info=\"%s\" radio=%s\n",
btv->nr, id, info, btv->has_radio ? "yes" : "no");
btv->tuner_type = 33;
if (autoload)
request_module("tda9887");
bttv_call_i2c_clients(btv,AUDC_CONFIG_PINNACLE,&id);
}
if (-1 != msp) {
if (btv->type == BTTV_MIRO)
btv->type = BTTV_MIROPRO;
if (btv->type == BTTV_PINNACLE)
btv->type = BTTV_PINNACLEPRO;
}
printk(KERN_INFO "bttv%d: miro: id=%d tuner=%d radio=%s stereo=%s\n",
btv->nr, id+1, btv->tuner_type,
!btv->has_radio ? "no" :
(btv->has_matchbox ? "matchbox" : "fmtuner"),
(-1 == msp) ? "no" : "yes");
}
/* GPIO21 L: Buffer aktiv, H: Buffer inaktiv */
#define LM1882_SYNC_DRIVE 0x200000L
static void init_ids_eagle(struct bttv *btv)
{
btwrite(0xFFFF37, BT848_GPIO_OUT_EN);
btwrite(0x000000, BT848_GPIO_REG_INP);
btwrite(0x200020, BT848_GPIO_DATA);
/* flash strobe inverter ?! */
btwrite(0x200024, BT848_GPIO_DATA);
/* switch sync drive off */
btor(LM1882_SYNC_DRIVE, BT848_GPIO_DATA);
/* set BT848 muxel to 2 */
btaor((2)<<5, ~(2<<5), BT848_IFORM);
}
/* Muxsel helper for the IDS Eagle.
* the eagles does not use the standard muxsel-bits but
* has its own multiplexer */
static void eagle_muxsel(struct bttv *btv, unsigned int input)
{
btaor((2)<<5, ~(3<<5), BT848_IFORM);
btaor((bttv_tvcards[btv->type].muxsel[input&7]&3),
~3, BT848_GPIO_DATA);
#if 0
/* svhs */
/* wake chroma ADC */
btand(~BT848_ADC_C_SLEEP, BT848_ADC);
/* set to YC video */
btor(BT848_CONTROL_COMP, BT848_E_CONTROL);
btor(BT848_CONTROL_COMP, BT848_O_CONTROL);
#else
/* composite */
/* set chroma ADC to sleep */
btor(BT848_ADC_C_SLEEP, BT848_ADC);
/* set to composite video */
btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
#endif
/* switch sync drive off */
btor(LM1882_SYNC_DRIVE, BT848_GPIO_DATA);
}
/* ----------------------------------------------------------------------- */
/* initialization part one -- before registering i2c bus */
void __devinit bttv_init_card1(struct bttv *btv)
{
if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878)
switch (btv->type) {
case BTTV_HAUPPAUGE:
case BTTV_HAUPPAUGE878:
boot_msp34xx(btv,5);
if (btv->type == BTTV_VOODOOTV_FM)
break;
case BTTV_VOODOOTV_FM:
boot_msp34xx(btv,20);
break;
case BTTV_HAUPPAUGEPVR:
pvr_boot(btv);
break;
}
}
/* initialization part two -- after registering i2c bus */
......@@ -1443,40 +1816,43 @@ void __devinit bttv_init_card2(struct bttv *btv)
{
btv->tuner_type = -1;
/* miro/pinnacle */
if (btv->type == BTTV_MIRO ||
btv->type == BTTV_MIROPRO ||
btv->type == BTTV_PINNACLE ||
btv->type == BTTV_PINNACLEPRO)
switch (btv->type) {
case BTTV_MIRO:
case BTTV_MIROPRO:
case BTTV_PINNACLE:
case BTTV_PINNACLEPRO:
/* miro/pinnacle */
miro_pinnacle_gpio(btv);
if (btv->type == BTTV_FLYVIDEO_98 ||
btv->type == BTTV_LIFE_FLYKIT ||
btv->type == BTTV_FLYVIDEO ||
btv->type == BTTV_TYPHOON_TVIEW ||
btv->type == BTTV_CHRONOS_VS2 ||
btv->type == BTTV_FLYVIDEO_98FM ||
btv->type == BTTV_FLYVIDEO2000 ||
btv->type == BTTV_FLYVIDEO98EZ ||
btv->type == BTTV_CONFERENCETV ||
btv->type == BTTV_LIFETEC_9415)
break;
case BTTV_FLYVIDEO_98:
case BTTV_MAXI:
case BTTV_LIFE_FLYKIT:
case BTTV_FLYVIDEO:
case BTTV_TYPHOON_TVIEW:
case BTTV_CHRONOS_VS2:
case BTTV_FLYVIDEO_98FM:
case BTTV_FLYVIDEO2000:
case BTTV_FLYVIDEO98EZ:
case BTTV_CONFERENCETV:
case BTTV_LIFETEC_9415:
flyvideo_gpio(btv);
if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878) {
break;
case BTTV_HAUPPAUGE:
case BTTV_HAUPPAUGE878:
case BTTV_HAUPPAUGEPVR:
/* pick up some config infos from the eeprom */
bttv_readee(btv,eeprom_data,0xa0);
hauppauge_eeprom(btv);
}
if (btv->type == BTTV_AVERMEDIA98 || btv->type == BTTV_AVPHONE98) {
break;
case BTTV_AVERMEDIA98:
case BTTV_AVPHONE98:
bttv_readee(btv,eeprom_data,0xa0);
avermedia_eeprom(btv);
}
if (btv->type == BTTV_PXC200)
break;
case BTTV_PXC200:
init_PXC200(btv);
if (btv->type == BTTV_VHX) {
break;
case BTTV_VHX:
btv->has_radio = 1;
btv->has_matchbox = 1;
btv->mbox_we = 0x20;
......@@ -1484,13 +1860,42 @@ void __devinit bttv_init_card2(struct bttv *btv)
btv->mbox_clk = 0x08;
btv->mbox_data = 0x10;
btv->mbox_mask = 0x38;
}
if (btv->type == BTTV_MAGICTVIEW061) {
if(btv->cardid == 0x4002144f) {
break;
case BTTV_VOBIS_BOOSTAR:
case BTTV_TERRATV:
terratec_active_radio_upgrade(btv);
break;
case BTTV_MAGICTVIEW061:
if (btv->cardid == 0x3002144f) {
btv->has_radio=1;
printk("bttv%d: radio detected by subsystem id (CPH05x)\n",btv->nr);
}
break;
case BTTV_STB2:
if (btv->cardid == 0x3060121a) {
/* Fix up entry for 3DFX VoodooTV 100,
which is an OEM STB card variant. */
btv->has_radio=0;
btv->tuner_type=TUNER_TEMIC_NTSC;
}
break;
case BTTV_OSPREY1x0:
case BTTV_OSPREY1x0_848:
case BTTV_OSPREY101_848:
case BTTV_OSPREY1x1:
case BTTV_OSPREY1x1_SVID:
case BTTV_OSPREY2xx:
case BTTV_OSPREY2x0_SVID:
case BTTV_OSPREY2x0:
case BTTV_OSPREY500:
case BTTV_OSPREY540:
case BTTV_OSPREY2000:
bttv_readee(btv,eeprom_data,0xa0);
osprey_eeprom(btv);
break;
case BTTV_IDS_EAGLE:
init_ids_eagle(btv);
break;
}
/* pll configuration */
......@@ -1542,6 +1947,34 @@ void __devinit bttv_init_card2(struct bttv *btv)
if (bttv_tvcards[btv->type].audio_hook)
btv->audio_hook=bttv_tvcards[btv->type].audio_hook;
#if 0
/* detect Bt832 chip for quartzsight digital camera */
if((bttv_I2CRead(btv, I2C_BT832_ALT1, "Bt832") >=0) ||
(bttv_I2CRead(btv, I2C_BT832_ALT2, "Bt832") >=0)) {
int outbits,databits;
request_module("bt832");
bttv_call_i2c_clients(btv, BT832_HEXDUMP, NULL);
printk("Reset Bt832 (0x400000 for Pixelview 4E)\n");
btwrite(0, BT848_GPIO_DATA);
outbits = btread(BT848_GPIO_OUT_EN);
databits= btread(BT848_GPIO_DATA);
btwrite(0x400000, BT848_GPIO_OUT_EN);
udelay(5);
btwrite(0x400000, BT848_GPIO_DATA);
udelay(5);
btwrite(0, BT848_GPIO_DATA);
udelay(5);
btwrite(outbits, BT848_GPIO_OUT_EN);
btwrite(databits, BT848_GPIO_DATA);
// bt832 on pixelview changes from i2c 0x8a to 0x88 after
// being reset as above. So we must follow by this:
bttv_call_i2c_clients(btv, BT832_REATTACH, NULL);
}
#endif
/* try to detect audio/fader chips */
if (!bttv_tvcards[btv->type].no_msp34xx &&
bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx") >=0) {
......@@ -1555,7 +1988,8 @@ void __devinit bttv_init_card2(struct bttv *btv)
request_module("tda9875");
}
if (bttv_I2CRead(btv, I2C_TDA7432, "TDA7432") >=0) {
if (!bttv_tvcards[btv->type].no_tda7432 &&
bttv_I2CRead(btv, I2C_TDA7432, "TDA7432") >=0) {
if (autoload)
request_module("tda7432");
}
......@@ -1663,6 +2097,220 @@ static void __devinit hauppauge_eeprom(struct bttv *btv)
btv->tuner_type, radio ? "yes" : "no");
}
static int terratec_active_radio_upgrade(struct bttv *btv)
{
int freq;
btv->has_radio = 1;
btv->has_matchbox = 1;
btv->mbox_we = 0x10;
btv->mbox_most = 0x20;
btv->mbox_clk = 0x08;
btv->mbox_data = 0x04;
btv->mbox_mask = 0x3c;
btv->mbox_iow = 1 << 8;
btv->mbox_ior = 1 << 9;
btv->mbox_csel = 1 << 10;
freq=88000/62.5;
tea5757_write(btv, 5 * freq + 0x358); // write 0x1ed8
if (0x1ed8 == tea5757_read(btv)) {
printk("bttv%d: Terratec Active Radio Upgrade found.\n",
btv->nr);
btv->has_radio = 1;
btv->has_matchbox = 1;
} else {
btv->has_radio = 0;
btv->has_matchbox = 0;
}
return 0;
}
/* ----------------------------------------------------------------------- */
/*
* minimal bootstrap for the WinTV/PVR -- upload altera firmware.
*
* The hcwamc.rbf firmware file is on the Hauppauge driver CD. Have
* a look at Pvr/pvr45xxx.EXE (self-extracting zip archive, can be
* unpacked with unzip).
*/
static char *firm_altera = "/usr/lib/video4linux/hcwamc.rbf";
MODULE_PARM(firm_altera,"s");
MODULE_PARM_DESC(firm_altera,"WinTV/PVR firmware "
"(driver CD => unzip pvr45xxx.exe => hcwamc.rbf)");
/* drivers/sound/sound_firmware.c => soundcore.o */
extern int mod_firmware_load(const char *fn, char **fp);
#define PVR_GPIO_DELAY 10
#define BTTV_ALT_DATA 0x000001
#define BTTV_ALT_DCLK 0x100000
#define BTTV_ALT_NCONFIG 0x800000
static int __devinit pvr_altera_load(struct bttv *btv, u8 *micro, u32 microlen)
{
u32 n;
u8 bits;
int i;
btwrite(BTTV_ALT_DATA|BTTV_ALT_DCLK|BTTV_ALT_NCONFIG,
BT848_GPIO_OUT_EN);
btwrite(0,BT848_GPIO_DATA);
udelay(PVR_GPIO_DELAY);
btwrite(BTTV_ALT_NCONFIG,BT848_GPIO_DATA);
udelay(PVR_GPIO_DELAY);
for (n = 0; n < microlen; n++) {
bits = micro[n];
for ( i = 0 ; i < 8 ; i++ ) {
btand(~BTTV_ALT_DCLK,BT848_GPIO_DATA);
if (bits & 0x01)
btor(BTTV_ALT_DATA,BT848_GPIO_DATA);
else
btand(~BTTV_ALT_DATA,BT848_GPIO_DATA);
btor(BTTV_ALT_DCLK,BT848_GPIO_DATA);
bits >>= 1;
}
}
btand(~BTTV_ALT_DCLK,BT848_GPIO_DATA);
udelay(PVR_GPIO_DELAY);
/* begin Altera init loop (Not necessary,but doesn't hurt) */
for (i = 0 ; i < 30 ; i++) {
btand(~BTTV_ALT_DCLK,BT848_GPIO_DATA);
btor(BTTV_ALT_DCLK,BT848_GPIO_DATA);
}
btand(~BTTV_ALT_DCLK,BT848_GPIO_DATA);
return 0;
}
int __devinit pvr_boot(struct bttv *btv)
{
u32 microlen;
u8 *micro;
int result;
microlen = mod_firmware_load(firm_altera, (char**) &micro);
if (!microlen)
return -1;
printk(KERN_INFO "bttv%d: uploading altera firmware [%s] ...\n",
btv->nr, firm_altera);
result = pvr_altera_load(btv, micro, microlen);
printk(KERN_INFO "bttv%d: ... upload %s\n",
btv->nr, (result < 0) ? "failed" : "ok");
vfree(micro);
return result;
}
/* ----------------------------------------------------------------------- */
/* some osprey specific stuff */
static void __devinit osprey_eeprom(struct bttv *btv)
{
int i = 0;
unsigned char *ee = eeprom_data;
unsigned long serial = 0;
if (btv->type == 0) {
/* this might be an antique... check for MMAC label in eeprom */
if ((ee[0]=='M') && (ee[1]=='M') && (ee[2]=='A') && (ee[3]=='C')) {
unsigned char checksum = 0;
for (i =0; i<21; i++)
checksum += ee[i];
if (checksum != ee[21])
return;
btv->type = BTTV_OSPREY1x0_848;
for (i = 12; i < 21; i++)
serial *= 10, serial += ee[i] - '0';
}
} else {
unsigned short type;
int offset = 4*16;
for(; offset < 8*16; offset += 16) {
unsigned short checksum = 0;
/* verify the checksum */
for(i = 0; i<14; i++) checksum += ee[i+offset];
checksum = ~checksum; /* no idea why */
if ((((checksum>>8)&0x0FF) == ee[offset+14]) &&
((checksum & 0x0FF) == ee[offset+15])) {
break;
}
}
if (offset >= 8*16)
return;
/* found a valid descriptor */
type = (ee[offset+4]<<8) | (ee[offset+5]);
switch(type) {
/* 848 based */
case 0x0004:
btv->type = BTTV_OSPREY1x0_848;
break;
case 0x0005:
btv->type = BTTV_OSPREY101_848;
break;
/* 878 based */
case 0x0012:
case 0x0013:
btv->type = BTTV_OSPREY1x0;
break;
case 0x0014:
case 0x0015:
btv->type = BTTV_OSPREY1x1;
break;
case 0x0016:
case 0x0017:
case 0x0020:
btv->type = BTTV_OSPREY1x1_SVID;
break;
case 0x0018:
case 0x0019:
case 0x001E:
case 0x001F:
btv->type = BTTV_OSPREY2xx;
break;
case 0x001A:
case 0x001B:
btv->type = BTTV_OSPREY2x0_SVID;
break;
case 0x0040:
btv->type = BTTV_OSPREY500;
break;
case 0x0050:
case 0x0056:
btv->type = BTTV_OSPREY540;
/* bttv_osprey_540_init(btv); */
break;
case 0x0060:
case 0x0070:
btv->type = BTTV_OSPREY2x0;
//enable output on select control lines
btwrite(0x000303, BT848_GPIO_OUT_EN);
break;
default:
/* unknown...leave generic, but get serial # */
break;
}
serial = (ee[offset+6] << 24)
| (ee[offset+7] << 16)
| (ee[offset+8] << 8)
| (ee[offset+9]);
}
printk(KERN_INFO "bttv%d: osprey eeprom: card=%d name=%s serial=%ld\n",
btv->nr, btv->type, bttv_tvcards[btv->type].name,serial);
}
/* ----------------------------------------------------------------------- */
/* AVermedia specific stuff, from bktr_card.c */
......@@ -1822,17 +2470,55 @@ static void __devinit init_PXC200(struct bttv *btv)
* Brutally hacked by Dan Sheridan <dan.sheridan@contact.org.uk> djs52 8/3/00
*/
#if 0
/* bus bits on the GPIO port */
#define TEA_WE 6
#define TEA_DATA 9
#define TEA_CLK 8
#define TEA_MOST 7
#endif
void bus_low(struct bttv *btv, int bit)
{
if (btv->mbox_ior) {
btor(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
BT848_GPIO_DATA);
udelay(5);
}
btand(~(bit), BT848_GPIO_DATA);
udelay(5);
if (btv->mbox_ior) {
btand(~(btv->mbox_iow | btv->mbox_csel),
BT848_GPIO_DATA);
udelay(5);
}
}
void bus_high(struct bttv *btv, int bit)
{
if (btv->mbox_ior) {
btor(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
BT848_GPIO_DATA);
udelay(5);
}
btor((bit), BT848_GPIO_DATA);
udelay(5);
#define BUS_LOW(bit) btand(~(bit), BT848_GPIO_DATA)
#define BUS_HIGH(bit) btor((bit), BT848_GPIO_DATA)
#define BUS_IN(bit) (btread(BT848_GPIO_DATA) & (bit))
if (btv->mbox_ior) {
btand(~(btv->mbox_iow | btv->mbox_csel),
BT848_GPIO_DATA);
udelay(5);
}
}
int bus_in(struct bttv *btv, int bit)
{
if (btv->mbox_ior) {
btor(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
BT848_GPIO_DATA);
udelay(5);
btand(~(btv->mbox_ior | btv->mbox_csel),
BT848_GPIO_DATA);
udelay(5);
}
return btread(BT848_GPIO_DATA) & (bit);
}
/* TEA5757 register bits */
#define TEA_FREQ 0:14
......@@ -1871,34 +2557,41 @@ static int tea5757_read(struct bttv *btv)
/* better safe than sorry */
btaor((btv->mbox_clk | btv->mbox_we),
~btv->mbox_mask, BT848_GPIO_OUT_EN);
if (btv->mbox_ior) {
btor(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
BT848_GPIO_DATA);
udelay(5);
}
if (bttv_gpio)
bttv_gpio_tracking(btv,"tea5757 read");
BUS_LOW(btv->mbox_we);
BUS_LOW(btv->mbox_clk);
bus_low(btv,btv->mbox_we);
bus_low(btv,btv->mbox_clk);
udelay(10);
for(timeout = jiffies + 10 * HZ;
BUS_IN(btv->mbox_data) && time_before(jiffies, timeout);
schedule()); /* 10 s */
if (BUS_IN(btv->mbox_data)) {
timeout= jiffies + HZ;
// wait for DATA line to go low; error if it doesn't
while (bus_in(btv,btv->mbox_data) && time_before(jiffies, timeout))
schedule();
if (bus_in(btv,btv->mbox_data)) {
printk(KERN_WARNING "bttv%d: tea5757: read timeout\n",btv->nr);
return -1;
}
for(timeout = jiffies + HZ/5;
BUS_IN(btv->mbox_data) == 1 && time_before(jiffies, timeout);
schedule()); /* 0.2 s */
dprintk("bttv%d: tea5757:",btv->nr);
for(i = 0; i < 24; i++)
{
udelay(5);
BUS_HIGH(btv->mbox_clk);
bus_high(btv,btv->mbox_clk);
udelay(5);
dprintk("%c",(BUS_IN(btv->mbox_most) == 0)?'T':'-');
BUS_LOW(btv->mbox_clk);
dprintk("%c",(bus_in(btv,btv->mbox_most) == 0)?'T':'-');
bus_low(btv,btv->mbox_clk);
value <<= 1;
value |= (BUS_IN(btv->mbox_data) == 0)?0:1; /* MSB first */
dprintk("%c", (BUS_IN(btv->mbox_most) == 0)?'S':'M');
value |= (bus_in(btv,btv->mbox_data) == 0)?0:1; /* MSB first */
dprintk("%c", (bus_in(btv,btv->mbox_most) == 0)?'S':'M');
}
dprintk("\nbttv%d: tea5757: read 0x%X\n", btv->nr, value);
return value;
......@@ -1911,32 +2604,42 @@ static int tea5757_write(struct bttv *btv, int value)
btaor(btv->mbox_clk | btv->mbox_we | btv->mbox_data,
~btv->mbox_mask, BT848_GPIO_OUT_EN);
if (btv->mbox_ior) {
btor(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
BT848_GPIO_DATA);
udelay(5);
}
if (bttv_gpio)
bttv_gpio_tracking(btv,"tea5757 write");
dprintk("bttv%d: tea5757: write 0x%X\n", btv->nr, value);
BUS_LOW(btv->mbox_clk);
BUS_HIGH(btv->mbox_we);
bus_low(btv,btv->mbox_clk);
bus_high(btv,btv->mbox_we);
for(i = 0; i < 25; i++)
{
if (reg & 0x1000000)
BUS_HIGH(btv->mbox_data);
bus_high(btv,btv->mbox_data);
else
BUS_LOW(btv->mbox_data);
bus_low(btv,btv->mbox_data);
reg <<= 1;
BUS_HIGH(btv->mbox_clk);
bus_high(btv,btv->mbox_clk);
udelay(10);
BUS_LOW(btv->mbox_clk);
bus_low(btv,btv->mbox_clk);
udelay(10);
}
BUS_LOW(btv->mbox_we); /* unmute !!! */
bus_low(btv,btv->mbox_we); /* unmute !!! */
return 0;
}
void tea5757_set_freq(struct bttv *btv, unsigned short freq)
{
int value;
dprintk("tea5757_set_freq %d\n",freq);
tea5757_write(btv, 5 * freq + 0x358); /* add 10.7MHz (see docs) */
if (bttv_debug)
tea5757_read(btv);
value = tea5757_read(btv);
dprintk("bttv%d: tea5757 readback =0x%x\n",btv->nr,value);
}
......@@ -2076,7 +2779,7 @@ lt9415_audio(struct bttv *btv, struct video_audio *v, int set)
}
}
// TDA9821 on TerraTV+ Bt848, Bt878
static void
terratv_audio(struct bttv *btv, struct video_audio *v, int set)
{
......@@ -2127,6 +2830,9 @@ winfast2000_audio(struct bttv *btv, struct video_audio *v, int set)
* Dariusz Kowalewski <darekk@automex.pl>
* sound control for Prolink PV-BT878P+9B (PixelView PlayTV Pro FM+NICAM
* revision 9B has on-board TDA9874A sound decoder).
*
* Note: There are card variants without tda9874a. Forcing the "stereo sound route"
* will mute this cards.
*/
static void
pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set)
......
......@@ -23,6 +23,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/init.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/delay.h>
......@@ -31,7 +32,6 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/kdev_t.h>
#include <asm/io.h>
......@@ -74,14 +74,11 @@ static unsigned int adc_crush = 1;
/* API features (turn on/off stuff for testing) */
static unsigned int sloppy = 0;
static unsigned int mmap = 1;
#ifdef HAVE_V4L2
static unsigned int v4l2 = 1;
#endif
/* insmod args */
MODULE_PARM(radio,"1-" __MODULE_STRING(BTTV_MAX) "i");
MODULE_PARM(radio,"1-" __stringify(BTTV_MAX) "i");
MODULE_PARM_DESC(radio,"The TV card supports radio, default is 0 (no)");
MODULE_PARM(bigendian,"i");
MODULE_PARM_DESC(bigendian,"byte order of the framebuffer, default is native endian");
......@@ -115,10 +112,7 @@ MODULE_PARM(adc_crush,"i");
MODULE_PARM_DESC(adc_crush,"enables the luminance ADC crush, default is 1 (yes)");
MODULE_PARM(sloppy,"i");
MODULE_PARM(mmap,"i");
#ifdef HAVE_V4L2
MODULE_PARM(v4l2,"i");
#endif
MODULE_DESCRIPTION("bttv - v4l/v4l2 driver module for bt848/878 based cards");
MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr");
......@@ -130,74 +124,148 @@ static int __init p_radio(char *str) { return bttv_parse(str,BTTV_MAX,radio); }
__setup("bttv.radio=", p_radio);
#endif
#ifndef HAVE_V4L2
/* some dummy defines to avoid cluttering up the source code with
a huge number of ifdef's for V4L2 */
# define V4L2_STD_PAL -1
# define V4L2_STD_NTSC -1
# define V4L2_STD_SECAM -1
# define V4L2_STD_PAL_60 -1
# define V4L2_STD_PAL_M -1
# define V4L2_STD_PAL_N -1
# define V4L2_STD_NTSC_N -1
# define V4L2_PIX_FMT_GREY -1
# define V4L2_PIX_FMT_HI240 -1
# define V4L2_PIX_FMT_RGB555 -1
# define V4L2_PIX_FMT_RGB555X -1
# define V4L2_PIX_FMT_RGB565 -1
# define V4L2_PIX_FMT_RGB565X -1
# define V4L2_PIX_FMT_BGR24 -1
# define V4L2_PIX_FMT_BGR32 -1
# define V4L2_PIX_FMT_RGB32 -1
# define V4L2_PIX_FMT_YUYV -1
# define V4L2_PIX_FMT_UYVY -1
# define V4L2_PIX_FMT_YUV422P -1
# define V4L2_PIX_FMT_YUV420 -1
# define V4L2_PIX_FMT_YVU420 -1
# define V4L2_PIX_FMT_YUV411P -1
# define V4L2_PIX_FMT_YUV410 -1
# define V4L2_PIX_FMT_YVU410 -1
# define V4L2_BUF_TYPE_CAPTURE -1
# define V4L2_BUF_TYPE_VBI -1
# define BTTV_APIS "[v4l]"
#else
# define BTTV_APIS "[v4l/v4l2]"
#endif
/* ----------------------------------------------------------------------- */
/* static data */
/* special timing tables from conexant... */
static u8 SRAM_Table[][60] =
{
/* PAL digital input over GPIO[7:0] */
{
0x36,0x11,0x01,0x00,0x90,0x02,0x05,0x10,0x04,0x16,
0x12,0x05,0x11,0x00,0x04,0x12,0xC0,0x00,0x31,0x00,
0x06,0x51,0x08,0x03,0x89,0x08,0x07,0xC0,0x44,0x00,
0x81,0x01,0x01,0xA9,0x0D,0x02,0x02,0x50,0x03,0x37,
0x37,0x00,0xAF,0x21,0x00
},
/* NTSC digital input over GPIO[7:0] */
{
0x0C,0xC0,0x00,0x00,0x90,0x02,0x03,0x10,0x03,0x06,
0x10,0x04,0x12,0x12,0x05,0x02,0x13,0x04,0x19,0x00,
0x04,0x39,0x00,0x06,0x59,0x08,0x03,0x83,0x08,0x07,
0x03,0x50,0x00,0xC0,0x40,0x00,0x86,0x01,0x01,0xA6,
0x0D,0x02,0x03,0x11,0x01,0x05,0x37,0x00,0xAC,0x21,
0x00,
},
};
const struct bttv_tvnorm bttv_tvnorms[] = {
/* PAL-BDGHI */
{ V4L2_STD_PAL, 35468950,
922, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
1135, 186, 922, 0x20, 255},
/* NTSC */
{ V4L2_STD_NTSC, 28636363,
754, 480, 910, 0x70, 0x5d, (BT848_IFORM_NTSC|BT848_IFORM_XT0),
910, 135, 754, 0x1a, 144},
/* SECAM */
{ V4L2_STD_SECAM, 35468950,
922, 576, 1135, 0x7f, 0xa0, (BT848_IFORM_SECAM|BT848_IFORM_XT1),
1135, 186, 922, 0x20, 255},
/* these ones are bttv specific (for v4l1) */
/* PAL-NC */
{ V4L2_STD_PAL_60, 28636363,
640, 576, 910, 0x7f, 0x72, (BT848_IFORM_PAL_NC|BT848_IFORM_XT0),
780, 130, 734, 0x1a, 144},
/* PAL-M */
{ V4L2_STD_PAL_M, 28636363,
640, 480, 910, 0x70, 0x5d, (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
780, 135, 754, 0x1a, 144},
/* PAL-N */
{ V4L2_STD_PAL_N, 35468950,
768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_N|BT848_IFORM_XT0),
944, 186, 922, 0x20, 144},
/* NTSC-Japan */
{ V4L2_STD_NTSC_N, 28636363,
640, 480, 910, 0x70, 0x5d, (BT848_IFORM_NTSC_J|BT848_IFORM_XT0),
780, 135, 754, 0x16, 144},
/* max. active video is actually 922, but 924 is divisible by 4 and 3! */
/* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */
{
.v4l2_id = V4L2_STD_PAL,
.name = "PAL",
.Fsc = 35468950,
.swidth = 924,
.sheight = 576,
.totalwidth = 1135,
.adelay = 0x7f,
.bdelay = 0x72,
.iform = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
.scaledtwidth = 1135,
.hdelayx1 = 186,
.hactivex1 = 924,
.vdelay = 0x20,
.vbipack = 255,
.sram = 0,
},{
.v4l2_id = V4L2_STD_NTSC,
.name = "NTSC",
.Fsc = 28636363,
.swidth = 768,
.sheight = 480,
.totalwidth = 910,
.adelay = 0x68,
.bdelay = 0x5d,
.iform = (BT848_IFORM_NTSC|BT848_IFORM_XT0),
.scaledtwidth = 910,
.hdelayx1 = 128,
.hactivex1 = 910,
.vdelay = 0x1a,
.vbipack = 144,
.sram = 1,
},{
.v4l2_id = V4L2_STD_SECAM,
.name = "SECAM",
.Fsc = 35468950,
.swidth = 924,
.sheight = 576,
.totalwidth = 1135,
.adelay = 0x7f,
.bdelay = 0xb0,
.iform = (BT848_IFORM_SECAM|BT848_IFORM_XT1),
.scaledtwidth = 1135,
.hdelayx1 = 186,
.hactivex1 = 922,
.vdelay = 0x20,
.vbipack = 255,
.sram = 0, /* like PAL, correct? */
},{
.v4l2_id = V4L2_STD_PAL_Nc,
.name = "PAL-Nc",
.Fsc = 28636363,
.swidth = 640,
.sheight = 576,
.totalwidth = 910,
.adelay = 0x68,
.bdelay = 0x5d,
.iform = (BT848_IFORM_PAL_NC|BT848_IFORM_XT0),
.scaledtwidth = 780,
.hdelayx1 = 130,
.hactivex1 = 734,
.vdelay = 0x1a,
.vbipack = 144,
.sram = -1,
},{
.v4l2_id = V4L2_STD_PAL_M,
.name = "PAL-M",
.Fsc = 28636363,
.swidth = 640,
.sheight = 480,
.totalwidth = 910,
.adelay = 0x68,
.bdelay = 0x5d,
.iform = (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
.scaledtwidth = 780,
.hdelayx1 = 135,
.hactivex1 = 754,
.vdelay = 0x1a,
.vbipack = 144,
.sram = -1,
},{
.v4l2_id = V4L2_STD_PAL_N,
.name = "PAL-N",
.Fsc 35468950,
.swidth = 768,
.sheight = 576,
.totalwidth = 1135,
.adelay = 0x7f,
.bdelay = 0x72,
.iform = (BT848_IFORM_PAL_N|BT848_IFORM_XT1),
.scaledtwidth = 944,
.hdelayx1 = 186,
.hactivex1 = 922,
.vdelay = 0x20,
.vbipack = 144,
.sram = -1,
},{
.v4l2_id = V4L2_STD_NTSC_M_JP,
.name = "NTSC-JP",
.Fsc = 28636363,
.swidth = 640,
.sheight = 480,
.totalwidth = 910,
.adelay = 0x68,
.bdelay = 0x5d,
.iform = (BT848_IFORM_NTSC_J|BT848_IFORM_XT0),
.scaledtwidth = 780,
.hdelayx1 = 135,
.hactivex1 = 754,
.vdelay = 0x16,
.vbipack = 144,
.sram = -1,
}
};
const int BTTV_TVNORMS = (sizeof(bttv_tvnorms)/sizeof(struct bttv_tvnorm));
......@@ -360,7 +428,6 @@ const int BTTV_FORMATS = (sizeof(bttv_formats)/sizeof(struct bttv_format));
/* ----------------------------------------------------------------------- */
#ifdef HAVE_V4L2
#define V4L2_CID_PRIVATE_CHROMA_AGC (V4L2_CID_PRIVATE_BASE + 0)
#define V4L2_CID_PRIVATE_COMBFILTER (V4L2_CID_PRIVATE_BASE + 1)
#define V4L2_CID_PRIVATE_AUTOMUTE (V4L2_CID_PRIVATE_BASE + 2)
......@@ -382,8 +449,6 @@ static const struct v4l2_queryctrl bttv_ctls[] = {
step: 256,
default_value: 32768,
type: V4L2_CTRL_TYPE_INTEGER,
category: V4L2_CTRL_CAT_VIDEO,
group: "Video",
},{
id: V4L2_CID_CONTRAST,
name: "Contrast",
......@@ -392,8 +457,6 @@ static const struct v4l2_queryctrl bttv_ctls[] = {
step: 128,
default_value: 32768,
type: V4L2_CTRL_TYPE_INTEGER,
category: V4L2_CTRL_CAT_VIDEO,
group: "Video",
},{
id: V4L2_CID_SATURATION,
name: "Saturation",
......@@ -402,8 +465,6 @@ static const struct v4l2_queryctrl bttv_ctls[] = {
step: 128,
default_value: 32768,
type: V4L2_CTRL_TYPE_INTEGER,
category: V4L2_CTRL_CAT_VIDEO,
group: "Video",
},{
id: V4L2_CID_HUE,
name: "Hue",
......@@ -412,8 +473,6 @@ static const struct v4l2_queryctrl bttv_ctls[] = {
step: 256,
default_value: 32768,
type: V4L2_CTRL_TYPE_INTEGER,
category: V4L2_CTRL_CAT_VIDEO,
group: "Video",
},
/* --- audio --- */
{
......@@ -422,8 +481,6 @@ static const struct v4l2_queryctrl bttv_ctls[] = {
minimum: 0,
maximum: 1,
type: V4L2_CTRL_TYPE_BOOLEAN,
category: V4L2_CTRL_CAT_AUDIO,
group: "Audio",
},{
id: V4L2_CID_AUDIO_VOLUME,
name: "Volume",
......@@ -432,8 +489,6 @@ static const struct v4l2_queryctrl bttv_ctls[] = {
step: 65535/100,
default_value: 65535,
type: V4L2_CTRL_TYPE_INTEGER,
category: V4L2_CTRL_CAT_AUDIO,
group: "Audio",
},{
id: V4L2_CID_AUDIO_BALANCE,
name: "Balance",
......@@ -442,8 +497,6 @@ static const struct v4l2_queryctrl bttv_ctls[] = {
step: 65535/100,
default_value: 32768,
type: V4L2_CTRL_TYPE_INTEGER,
category: V4L2_CTRL_CAT_AUDIO,
group: "Audio",
},{
id: V4L2_CID_AUDIO_BASS,
name: "Bass",
......@@ -452,8 +505,6 @@ static const struct v4l2_queryctrl bttv_ctls[] = {
step: 65535/100,
default_value: 32768,
type: V4L2_CTRL_TYPE_INTEGER,
category: V4L2_CTRL_CAT_AUDIO,
group: "Audio",
},{
id: V4L2_CID_AUDIO_TREBLE,
name: "Treble",
......@@ -462,8 +513,6 @@ static const struct v4l2_queryctrl bttv_ctls[] = {
step: 65535/100,
default_value: 32768,
type: V4L2_CTRL_TYPE_INTEGER,
category: V4L2_CTRL_CAT_AUDIO,
group: "Audio",
},
/* --- private --- */
{
......@@ -472,39 +521,33 @@ static const struct v4l2_queryctrl bttv_ctls[] = {
minimum: 0,
maximum: 1,
type: V4L2_CTRL_TYPE_BOOLEAN,
group: "Private",
},{
id: V4L2_CID_PRIVATE_COMBFILTER,
name: "combfilter",
minimum: 0,
maximum: 1,
type: V4L2_CTRL_TYPE_BOOLEAN,
group: "Private",
},{
id: V4L2_CID_PRIVATE_AUTOMUTE,
name: "automute",
minimum: 0,
maximum: 1,
type: V4L2_CTRL_TYPE_BOOLEAN,
group: "Private",
},{
id: V4L2_CID_PRIVATE_LUMAFILTER,
name: "luma decimation filter",
minimum: 0,
maximum: 1,
type: V4L2_CTRL_TYPE_BOOLEAN,
group: "Private",
},{
id: V4L2_CID_PRIVATE_AGC_CRUSH,
name: "agc crush",
minimum: 0,
maximum: 1,
type: V4L2_CTRL_TYPE_BOOLEAN,
group: "Private",
}
};
const int BTTV_CTLS = (sizeof(bttv_ctls)/sizeof(struct v4l2_queryctrl));
#endif /* HAVE_V4L2 */
/* ----------------------------------------------------------------------- */
/* resource management */
......@@ -557,57 +600,6 @@ void free_btres(struct bttv *btv, struct bttv_fh *fh, int bits)
up(&btv->reslock);
}
/* ----------------------------------------------------------------------- */
/*
* sanity check for video framebuffer address ranges (overlay).
* let's see if that address range actually belongs to some
* pci display adapter.
*
* FIXME: stuff isn't portable. It's also a v4l API bug, pass a
* physical address in VIDIOCSFBUF isn't portable too ...
*/
static int
find_videomem(unsigned long from, unsigned long to)
{
#if PCI_DMA_BUS_IS_PHYS
struct pci_dev *dev = NULL;
int i,match,found;
found = 0;
dprintk(KERN_DEBUG "bttv: checking video framebuffer address"
" (%lx-%lx)\n",from,to);
pci_for_each_dev(dev) {
if (dev->class != PCI_CLASS_NOT_DEFINED_VGA &&
dev->class >> 16 != PCI_BASE_CLASS_DISPLAY)
continue;
dprintk(KERN_DEBUG
" pci display adapter %04x:%04x at %02x:%02x.%x\n",
dev->vendor,dev->device,dev->bus->number,
PCI_SLOT(dev->devfn),PCI_FUNC(dev->devfn));
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
if (!(dev->resource[i].flags & IORESOURCE_MEM))
continue;
if (dev->resource[i].flags & IORESOURCE_READONLY)
continue;
match = (from >= dev->resource[i].start) &&
(to-1 <= dev->resource[i].end);
if (match)
found = 1;
dprintk(KERN_DEBUG " memory at %08lx-%08lx%s\n",
dev->resource[i].start,
dev->resource[i].end,
match ? " (check passed)" : "");
}
}
return found;
#else
/* Hmm, the physical address passed to us is probably bogous */
dprintk(KERN_DEBUG "bttv: no overlay for this arch, sorry\n");
return 0;
#endif
}
/* ----------------------------------------------------------------------- */
/* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC */
......@@ -688,6 +680,34 @@ static int set_pll(struct bttv *btv)
return -1;
}
/* used to switch between the bt848's analog/digital video capture modes */
void bt848A_set_timing(struct bttv *btv)
{
u8 dvsif_val = 0;
int table_idx = bttv_tvnorms[btv->tvnorm].sram;
int i;
/* timing change...reset timing generator address */
btwrite(0x00, BT848_TGCTRL);
btwrite(0x02, BT848_TGCTRL);
btwrite(0x00, BT848_TGCTRL);
if (btv->digital_video && -1 != table_idx) {
dprintk("bttv%d: load digital timing table (table_idx=%d)\n",
btv->nr,table_idx);
dvsif_val = 0x41;
for(i = 0; i < 51; i++)
btwrite(SRAM_Table[table_idx][i],BT848_TGLB);
btwrite(0x75,BT848_PLL_F_LO);
btwrite(0x50,BT848_PLL_F_HI);
btwrite(0x8B,BT848_PLL_XCI);
btwrite(0x11,BT848_TGCTRL);
btv->pll.pll_current = 0;
}
btwrite(dvsif_val,BT848_DVSIF);
}
/* ----------------------------------------------------------------------- */
static void bt848_bright(struct bttv *btv, int bright)
......@@ -813,9 +833,11 @@ audio_mux(struct bttv *btv, int mode)
i2c_mux = mux = (btv->audio & AUDIO_MUTE) ? AUDIO_OFF : btv->audio;
if (btv->opt_automute && !signal && !btv->radio_user)
mux = AUDIO_OFF;
#if 0
printk("bttv%d: amux: mode=%d audio=%d signal=%s mux=%d/%d irq=%s\n",
btv->nr, mode, btv->audio, signal ? "yes" : "no",
mux, i2c_mux, in_interrupt() ? "yes" : "no");
#endif
val = bttv_tvcards[btv->type].audiomux[mux];
btaor(val,~bttv_tvcards[btv->type].gpiomask, BT848_GPIO_DATA);
......@@ -856,9 +878,24 @@ set_tvnorm(struct bttv *btv, unsigned int norm)
BT848_IFORM);
btwrite(tvnorm->vbipack, BT848_VBI_PACK_SIZE);
btwrite(1, BT848_VBI_PACK_DEL);
btv->pll.pll_ofreq = tvnorm->Fsc;
set_pll(btv);
if (btv->digital_video) {
bt848A_set_timing(btv);
} else {
btv->pll.pll_ofreq = tvnorm->Fsc;
set_pll(btv);
}
switch (btv->type) {
case BTTV_VOODOOTV_FM:
bttv_tda9880_setnorm(btv,norm);
break;
#if 0
case BTTV_OSPREY540:
osprey_540_set_norm(btv,norm);
break;
#endif
}
return 0;
}
......@@ -924,7 +961,6 @@ extern void bttv_reinit_bt848(struct bttv *btv)
set_input(btv,btv->input);
}
#ifdef HAVE_V4L2
static int get_control(struct bttv *btv, struct v4l2_control *c)
{
struct video_audio va;
......@@ -935,7 +971,7 @@ static int get_control(struct bttv *btv, struct v4l2_control *c)
break;
if (i == BTTV_CTLS)
return -EINVAL;
if (bttv_ctls[i].category == V4L2_CTRL_CAT_AUDIO) {
if (i >= 4 && i <= 8) {
memset(&va,0,sizeof(va));
bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
if (btv->audio_hook)
......@@ -1002,7 +1038,7 @@ static int set_control(struct bttv *btv, struct v4l2_control *c)
break;
if (i == BTTV_CTLS)
return -EINVAL;
if (bttv_ctls[i].category == V4L2_CTRL_CAT_AUDIO) {
if (i >= 4 && i <= 8) {
memset(&va,0,sizeof(va));
bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
if (btv->audio_hook)
......@@ -1074,14 +1110,13 @@ static int set_control(struct bttv *btv, struct v4l2_control *c)
default:
return -EINVAL;
}
if (bttv_ctls[i].category == V4L2_CTRL_CAT_AUDIO) {
if (i >= 4 && i <= 8) {
bttv_call_i2c_clients(btv, VIDIOCSAUDIO, &va);
if (btv->audio_hook)
btv->audio_hook(btv,&va,1);
}
return 0;
}
#endif /* HAVE_V4L2 */
/* ----------------------------------------------------------------------- */
......@@ -1098,9 +1133,9 @@ void bttv_field_count(struct bttv *btv)
{
int need_count = 0;
if (locked_btres(btv,RESOURCE_STREAMING))
if (locked_btres(btv,RESOURCE_VIDEO))
need_count++;
if (btv->vbi.users)
if (locked_btres(btv,RESOURCE_VBI))
need_count++;
if (need_count) {
......@@ -1127,7 +1162,6 @@ format_by_palette(int palette)
return NULL;
}
#ifdef HAVE_V4L2
static const struct bttv_format*
format_by_fourcc(int fourcc)
{
......@@ -1141,7 +1175,6 @@ format_by_fourcc(int fourcc)
}
return NULL;
}
#endif
/* ----------------------------------------------------------------------- */
/* misc helpers */
......@@ -1173,7 +1206,8 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
static int bttv_prepare_buffer(struct bttv *btv, struct bttv_buffer *buf,
const struct bttv_format *fmt,
int width, int height, int field)
int width, int height,
enum v4l2_field field)
{
int redo_dma_risc = 0;
int rc;
......@@ -1196,8 +1230,6 @@ static int bttv_prepare_buffer(struct bttv *btv, struct bttv_buffer *buf,
buf->vb.size = (width * height * fmt->depth) >> 3;
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
return -EINVAL;
field = bttv_buffer_field(btv, field, VBUF_FIELD_EVEN,
btv->tvnorm, height);
}
/* alloc + fill struct bttv_buffer (if changed) */
......@@ -1252,13 +1284,14 @@ buffer_setup(struct file *file, int *count, int *size)
}
static int
buffer_prepare(struct file *file, struct videobuf_buffer *vb, int field)
buffer_prepare(struct file *file, struct videobuf_buffer *vb)
{
struct bttv_buffer *buf = (struct bttv_buffer*)vb;
struct bttv_fh *fh = file->private_data;
return bttv_prepare_buffer(fh->btv,buf,fh->buf.fmt,
fh->buf.vb.width,fh->buf.vb.height,field);
fh->buf.vb.width,fh->buf.vb.height,
fh->buf.vb.field);
}
static void
......@@ -1280,7 +1313,7 @@ static void buffer_release(struct file *file, struct videobuf_buffer *vb)
bttv_dma_free(fh->btv,buf);
}
static struct videobuf_queue_ops bttv_qops = {
static struct videobuf_queue_ops bttv_video_qops = {
buf_setup: buffer_setup,
buf_prepare: buffer_prepare,
buf_queue: buffer_queue,
......@@ -1295,20 +1328,6 @@ static const char *v4l1_ioctls[] = {
"SMICROCODE", "GVBIFMT", "SVBIFMT" };
#define V4L1_IOCTLS (sizeof(v4l1_ioctls)/sizeof(char*))
static const char *v4l2_ioctls[] = {
"QUERYCAP", "1", "ENUM_PIXFMT", "ENUM_FBUFFMT", "G_FMT", "S_FMT",
"G_COMP", "S_COMP", "REQBUFS", "QUERYBUF", "G_FBUF", "S_FBUF",
"G_WIN", "S_WIN", "PREVIEW", "QBUF", "16", "DQBUF", "STREAMON",
"STREAMOFF", "G_PERF", "G_PARM", "S_PARM", "G_STD", "S_STD",
"ENUMSTD", "ENUMINPUT", "G_CTRL", "S_CTRL", "G_TUNER", "S_TUNER",
"G_FREQ", "S_FREQ", "G_AUDIO", "S_AUDIO", "35", "QUERYCTRL",
"QUERYMENU", "G_INPUT", "S_INPUT", "ENUMCVT", "41", "42", "43",
"44", "45", "G_OUTPUT", "S_OUTPUT", "ENUMOUTPUT", "G_AUDOUT",
"S_AUDOUT", "ENUMFX", "G_EFFECT", "S_EFFECT", "G_MODULATOR",
"S_MODULATOR"
};
#define V4L2_IOCTLS (sizeof(v4l2_ioctls)/sizeof(char*))
int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
{
switch (cmd) {
......@@ -1317,18 +1336,12 @@ int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
/* *** v4l1 *** ************************************************ */
case VIDIOCGFREQ:
#ifdef HAVE_V4L2
case VIDIOC_G_FREQ:
#endif
{
unsigned long *freq = arg;
*freq = btv->freq;
return 0;
}
case VIDIOCSFREQ:
#ifdef HAVE_V4L2
case VIDIOC_S_FREQ:
#endif
{
unsigned long *freq = arg;
down(&btv->lock);
......@@ -1456,32 +1469,30 @@ int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
return 0;
}
#ifdef HAVE_V4L2
/* *** v4l2 *** ************************************************ */
case VIDIOC_ENUMSTD:
{
struct v4l2_enumstd *e = arg;
struct v4l2_standard *e = arg;
if (e->index < 0 || e->index >= BTTV_TVNORMS)
return -EINVAL;
v4l2_video_std_construct(&e->std, bttv_tvnorms[e->index].v4l2_id, 0);
e->inputs = 0x0f;
e->outputs = 0x00;
v4l2_video_std_construct(e, bttv_tvnorms[e->index].v4l2_id,
bttv_tvnorms[e->index].name);
return 0;
}
case VIDIOC_G_STD:
{
struct v4l2_standard *s = arg;
v4l2_video_std_construct(s,bttv_tvnorms[btv->tvnorm].v4l2_id,0);
v4l2_std_id *id = arg;
*id = bttv_tvnorms[btv->tvnorm].v4l2_id;
return 0;
}
case VIDIOC_S_STD:
{
struct v4l2_standard *s = arg;
int i, id = v4l2_video_std_confirm(s);
v4l2_std_id *id = arg;
int i;
for(i = 0; i < BTTV_TVNORMS; i++)
if (id == bttv_tvnorms[i].v4l2_id)
for (i = 0; i < BTTV_TVNORMS; i++)
if (*id & bttv_tvnorms[i].v4l2_id)
break;
if (i == BTTV_TVNORMS)
return -EINVAL;
......@@ -1492,6 +1503,16 @@ int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
up(&btv->lock);
return 0;
}
case VIDIOC_QUERYSTD:
{
v4l2_std_id *id = arg;
if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML)
*id = V4L2_STD_625_50;
else
*id = V4L2_STD_525_60;
return 0;
}
case VIDIOC_ENUMINPUT:
{
......@@ -1500,12 +1521,10 @@ int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
if (i->index >= bttv_tvcards[btv->type].video_inputs)
return -EINVAL;
i->type = V4L2_INPUT_TYPE_CAMERA;
i->capability = 0;
i->assoc_audio = 0;
if (i->index == bttv_tvcards[btv->type].tuner) {
sprintf(i->name, "Television");
i->type = V4L2_INPUT_TYPE_TUNER;
i->capability = V4L2_INPUT_CAP_AUDIO;
i->type = V4L2_INPUT_TYPE_TUNER;
i->tuner = 0;
} else if (i->index==bttv_tvcards[btv->type].svhs) {
sprintf(i->name, "S-Video");
} else {
......@@ -1532,14 +1551,17 @@ int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
return 0;
}
case VIDIOC_G_TUNER: {
case VIDIOC_G_TUNER:
{
struct v4l2_tuner *t = arg;
if (-1 == bttv_tvcards[btv->type].tuner)
return -EINVAL;
if (0 != t->index)
return -EINVAL;
down(&btv->lock);
memset(t,0,sizeof(*t));
t->input = bttv_tvcards[btv->type].tuner;
strcpy(t->name, "Television");
v4l2_video_std_construct(&t->std, bttv_tvnorms[btv->tvnorm].v4l2_id, 0);
t->capability = V4L2_TUNER_CAP_NORM;
t->rangehigh = 0xffffffffUL;
t->rxsubchans = V4L2_TUNER_SUB_MONO;
......@@ -1563,10 +1585,13 @@ int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
up(&btv->lock);
return 0;
}
case VIDIOC_S_TUNER: {
case VIDIOC_S_TUNER:
{
struct v4l2_tuner *t = arg;
if(t->input!=bttv_tvcards[btv->type].tuner)
if (-1 == bttv_tvcards[btv->type].tuner)
return -EINVAL;
if (0 != t->index)
return -EINVAL;
down(&btv->lock);
{
......@@ -1587,7 +1612,32 @@ int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
up(&btv->lock);
return 0;
}
#endif /* HAVE_V4L2 */
case VIDIOC_G_FREQUENCY:
{
struct v4l2_frequency *f = arg;
memset(f,0,sizeof(*f));
f->type = V4L2_TUNER_ANALOG_TV;
f->frequency = btv->freq;
return 0;
}
case VIDIOC_S_FREQUENCY:
{
struct v4l2_frequency *f = arg;
if (unlikely(f->tuner != 0))
return -EINVAL;
if (unlikely(f->type != V4L2_TUNER_ANALOG_TV))
return -EINVAL;
down(&btv->lock);
btv->freq = f->frequency;
bttv_call_i2c_clients(btv,VIDIOCSFREQ,&btv->freq);
if (btv->has_matchbox && btv->radio_user)
tea5757_set_freq(btv,btv->freq);
up(&btv->lock);
return 0;
}
default:
return -ENOIOCTLCMD;
......@@ -1596,55 +1646,88 @@ int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
return 0;
}
static int setup_window(struct bttv_fh *fh, struct bttv *btv,
int x, int y, int width, int height,
struct video_clip *user_clips, int nclips)
static int verify_window(const struct bttv_tvnorm *tvn,
struct v4l2_window *win, int fixup)
{
struct video_clip *clips = NULL;
int n,size,retval = 0;
enum v4l2_field field;
int maxw, maxh;
if (width < 48 ||
height < 32 ||
width > bttv_tvnorms[btv->tvnorm].swidth ||
height > bttv_tvnorms[btv->tvnorm].sheight ||
NULL == fh->ovfmt)
if (win->w.width < 48 || win->w.height < 32)
return -EINVAL;
if (win->clipcount > 2048)
return -EINVAL;
if (nclips > 2048)
field = win->field;
maxw = tvn->swidth;
maxh = tvn->sheight;
if (V4L2_FIELD_ANY == field) {
field = (win->w.height > maxh/2)
? V4L2_FIELD_INTERLACED
: V4L2_FIELD_TOP;
}
switch (field) {
case V4L2_FIELD_TOP:
case V4L2_FIELD_BOTTOM:
maxh = maxh / 2;
break;
case V4L2_FIELD_INTERLACED:
break;
default:
return -EINVAL;
}
if (!fixup && (win->w.width > maxw || win->w.height > maxh))
return -EINVAL;
if (win->w.width > maxw)
win->w.width = maxw;
if (win->w.height > maxh)
win->w.height = maxh;
win->field = field;
return 0;
}
static int setup_window(struct bttv_fh *fh, struct bttv *btv,
struct v4l2_window *win, int fixup)
{
struct v4l2_clip *clips = NULL;
int n,size,retval = 0;
retval = verify_window(&bttv_tvnorms[btv->tvnorm],win,fixup);
if (0 != retval)
return retval;
/* copy clips -- luckily v4l1 + v4l2 are binary
compatible here ...*/
n = nclips;
n = win->clipcount;
size = sizeof(struct video_clip)*(n+4);
clips = kmalloc(size,GFP_KERNEL);
if (NULL == clips)
return -ENOMEM;
if (n > 0) {
if (copy_from_user(clips,user_clips,
sizeof(struct video_clip)*nclips)) {
if (copy_from_user(clips,win->clips,
sizeof(struct v4l2_clip)*win->clipcount)) {
kfree(clips);
return -EFAULT;
}
}
/* clip against screen */
if (NULL != btv->fbuf.base)
n = bttv_screen_clips(&btv->fbuf, x, y,
width, height,
clips, n);
bttv_sort_clips(clips,nclips);
n = bttv_screen_clips(btv->fbuf.width, btv->fbuf.width,
&win->w, clips, n);
bttv_sort_clips(clips,n);
down(&fh->q.lock);
down(&fh->cap.lock);
if (fh->ov.clips)
kfree(fh->ov.clips);
fh->ov.clips = clips;
fh->ov.nclips = nclips;
fh->ov.nclips = n;
fh->ov.x = x;
fh->ov.y = y;
fh->ov.width = width;
fh->ov.height = height;
btv->init.ov.width = width;
btv->init.ov.height = height;
fh->ov.w = win->w;
fh->ov.field = win->field;
btv->init.ov.w.width = win->w.width;
btv->init.ov.w.height = win->w.height;
/* update overlay if needed */
retval = 0;
......@@ -1655,10 +1738,205 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
retval = bttv_switch_overlay(btv,fh,new);
}
up(&fh->q.lock);
up(&fh->cap.lock);
return retval;
}
/* ----------------------------------------------------------------------- */
static struct videobuf_queue* bttv_queue(struct bttv_fh *fh)
{
struct videobuf_queue* q = NULL;
switch (fh->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
q = &fh->cap;
break;
case V4L2_BUF_TYPE_VBI_CAPTURE:
q = &fh->vbi;
break;
default:
BUG();
}
return q;
}
static int bttv_resource(struct bttv_fh *fh)
{
int res = 0;
switch (fh->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
res = RESOURCE_VIDEO;
break;
case V4L2_BUF_TYPE_VBI_CAPTURE:
res = RESOURCE_VBI;
break;
default:
BUG();
}
return res;
}
static int bttv_switch_type(struct bttv_fh *fh, enum v4l2_buf_type type)
{
struct videobuf_queue *q = bttv_queue(fh);
int res = bttv_resource(fh);
if (check_btres(fh,res))
return -EBUSY;
if (videobuf_queue_is_busy(q))
return -EBUSY;
fh->type = type;
return 0;
}
static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f)
{
switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
memset(&f->fmt.pix,0,sizeof(struct v4l2_pix_format));
f->fmt.pix.width = fh->buf.vb.width;
f->fmt.pix.height = fh->buf.vb.height;
f->fmt.pix.pixelformat = fh->buf.fmt->fourcc;
f->fmt.pix.sizeimage =
(fh->buf.vb.width*fh->buf.vb.height*fh->buf.fmt->depth)/8;
return 0;
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
memset(&f->fmt.win,0,sizeof(struct v4l2_window));
f->fmt.win.w = fh->ov.w;
return 0;
case V4L2_BUF_TYPE_VBI_CAPTURE:
bttv_vbi_fmt(fh,f);
return 0;
default:
return -EINVAL;
}
}
static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv,
struct v4l2_format *f)
{
switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
{
const struct bttv_format *fmt;
enum v4l2_field field;
int maxw,maxh;
fmt = format_by_fourcc(f->fmt.pix.pixelformat);
if (NULL == fmt)
return -EINVAL;
if (0 != f->fmt.pix.bytesperline)
/* FIXME -- not implemented yet */
return -EINVAL;
/* fixup format */
maxw = bttv_tvnorms[btv->tvnorm].swidth;
maxh = bttv_tvnorms[btv->tvnorm].sheight;
field = f->fmt.pix.field;
if (V4L2_FIELD_ANY == field)
field = (f->fmt.pix.height > maxh/2)
? V4L2_FIELD_INTERLACED
: V4L2_FIELD_BOTTOM;
if (V4L2_FIELD_SEQ_BT == field)
field = V4L2_FIELD_SEQ_TB;
switch (field) {
case V4L2_FIELD_TOP:
case V4L2_FIELD_BOTTOM:
maxh = maxh/2;
break;
case V4L2_FIELD_INTERLACED:
break;
case V4L2_FIELD_SEQ_TB:
if (fmt->flags & FORMAT_FLAGS_PLANAR)
return -EINVAL;
default:
return -EINVAL;
}
/* update data for the application */
f->fmt.pix.field = field;
if (f->fmt.pix.width < 48)
f->fmt.pix.width = 48;
if (f->fmt.pix.height < 32)
f->fmt.pix.height = 32;
if (f->fmt.pix.width > maxw)
f->fmt.pix.width = maxw;
if (f->fmt.pix.height > maxh)
f->fmt.pix.height = maxh;
f->fmt.pix.sizeimage =
(fh->buf.vb.width * fh->buf.vb.height * fmt->depth)/8;
return 0;
}
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
return verify_window(&bttv_tvnorms[btv->tvnorm],
&f->fmt.win, 1);
#if 0
case V4L2_BUF_TYPE_VBI_CAPTURE:
retval = bttv_switch_type(fh,f->type);
if (0 != retval)
return retval;
if (fh->vbi.reading || fh->vbi.streaming)
return -EBUSY;
bttv_vbi_setlines(fh,btv,f->fmt.vbi.count[0]);
bttv_vbi_fmt(fh,f);
return 0;
#endif
default:
return -EINVAL;
}
}
static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
struct v4l2_format *f)
{
int retval;
switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
{
const struct bttv_format *fmt;
retval = bttv_switch_type(fh,f->type);
if (0 != retval)
return retval;
retval = bttv_try_fmt(fh,btv,f);
if (0 != retval)
return retval;
fmt = format_by_fourcc(f->fmt.pix.pixelformat);
/* update our state informations */
down(&fh->cap.lock);
fh->buf.fmt = fmt;
fh->buf.vb.field = f->fmt.pix.field;
fh->buf.vb.width = f->fmt.pix.width;
fh->buf.vb.height = f->fmt.pix.height;
btv->init.buf.fmt = fmt;
btv->init.buf.vb.field = f->fmt.pix.field;
btv->init.buf.vb.width = f->fmt.pix.width;
btv->init.buf.vb.height = f->fmt.pix.height;
up(&fh->cap.lock);
return 0;
}
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
return setup_window(fh, btv, &f->fmt.win, 1);
case V4L2_BUF_TYPE_VBI_CAPTURE:
retval = bttv_switch_type(fh,f->type);
if (0 != retval)
return retval;
if (fh->vbi.reading || fh->vbi.streaming)
return -EBUSY;
bttv_vbi_setlines(fh,btv,f->fmt.vbi.count[0]);
bttv_vbi_fmt(fh,f);
return 0;
default:
return -EINVAL;
}
}
static int bttv_do_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *arg)
{
......@@ -1676,8 +1954,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
break;
case 'V':
printk("bttv%d: ioctl 0x%x (v4l2, VIDIOC_%s)\n",
btv->nr, cmd, (_IOC_NR(cmd) < V4L2_IOCTLS) ?
v4l2_ioctls[_IOC_NR(cmd)] : "???");
btv->nr, cmd, v4l2_ioctl_names[_IOC_NR(cmd)]);
break;
default:
printk("bttv%d: ioctl 0x%x (???)\n",
......@@ -1696,17 +1973,23 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
memset(cap,0,sizeof(*cap));
strcpy(cap->name,btv->video_dev.name);
cap->type = VID_TYPE_CAPTURE|
VID_TYPE_TUNER|
VID_TYPE_OVERLAY|
VID_TYPE_CLIPPING|
VID_TYPE_SCALES;
cap->channels = bttv_tvcards[btv->type].video_inputs;
cap->audios = bttv_tvcards[btv->type].audio_inputs;
cap->maxwidth = bttv_tvnorms[btv->tvnorm].swidth;
cap->maxheight = bttv_tvnorms[btv->tvnorm].sheight;
cap->minwidth = 48;
cap->minheight = 32;
if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
/* vbi */
cap->type = VID_TYPE_TUNER|VID_TYPE_TELETEXT;
} else {
/* others */
cap->type = VID_TYPE_CAPTURE|
VID_TYPE_TUNER|
VID_TYPE_OVERLAY|
VID_TYPE_CLIPPING|
VID_TYPE_SCALES;
cap->channels = bttv_tvcards[btv->type].video_inputs;
cap->audios = bttv_tvcards[btv->type].audio_inputs;
cap->maxwidth = bttv_tvnorms[btv->tvnorm].swidth;
cap->maxheight = bttv_tvnorms[btv->tvnorm].sheight;
cap->minwidth = 48;
cap->minheight = 32;
}
return 0;
}
......@@ -1733,7 +2016,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
fmt = format_by_palette(pic->palette);
if (NULL == fmt)
return -EINVAL;
down(&fh->q.lock);
down(&fh->cap.lock);
retval = -EINVAL;
if (fmt->depth != pic->depth && !sloppy)
goto fh_unlock_and_return;
......@@ -1754,7 +2037,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
bt848_contrast(btv,pic->contrast);
bt848_hue(btv,pic->hue);
bt848_sat(btv,pic->colour);
up(&fh->q.lock);
up(&fh->cap.lock);
return 0;
}
......@@ -1763,26 +2046,31 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
struct video_window *win = arg;
memset(win,0,sizeof(*win));
win->x = fh->ov.x;
win->y = fh->ov.y;
win->width = fh->ov.width;
win->height = fh->ov.height;
win->x = fh->ov.w.left;
win->y = fh->ov.w.top;
win->width = fh->ov.w.width;
win->height = fh->ov.w.height;
return 0;
}
case VIDIOCSWIN:
{
struct video_window *win = arg;
retval = setup_window(fh,btv,win->x,win->y,
win->width,win->height,
win->clips,
win->clipcount);
struct v4l2_window w2;
w2.field = V4L2_FIELD_ANY;
w2.w.left = win->x;
w2.w.top = win->y;
w2.w.width = win->width;
w2.w.height = win->height;
w2.clipcount = win->clipcount;
w2.clips = (struct v4l2_clip*)win->clips;
retval = setup_window(fh, btv, &w2, 0);
if (0 == retval) {
/* on v4l1 this ioctl affects the read() size too */
fh->buf.vb.width = fh->ov.width;
fh->buf.vb.height = fh->ov.height;
btv->init.buf.vb.width = fh->ov.width;
btv->init.buf.vb.height = fh->ov.height;
fh->buf.vb.width = fh->ov.w.width;
fh->buf.vb.height = fh->ov.w.height;
btv->init.buf.vb.width = fh->ov.w.width;
btv->init.buf.vb.height = fh->ov.w.height;
}
return retval;
}
......@@ -1804,9 +2092,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
return -EPERM;
end = (unsigned long)fbuf->base +
fbuf->height * fbuf->bytesperline;
if (0 == find_videomem((unsigned long)fbuf->base,end))
return -EINVAL;
down(&fh->q.lock);
down(&fh->cap.lock);
retval = -EINVAL;
if (sloppy) {
/* also set the default palette -- for backward
......@@ -1846,14 +2132,12 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
goto fh_unlock_and_return;
}
btv->fbuf = *fbuf;
up(&fh->q.lock);
up(&fh->cap.lock);
return 0;
}
case VIDIOCCAPTURE:
#ifdef HAVE_V4L2
case VIDIOC_PREVIEW:
#endif
case VIDIOC_OVERLAY:
{
struct bttv_buffer *new;
int *on = arg;
......@@ -1862,10 +2146,10 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
/* verify args */
if (NULL == btv->fbuf.base)
return -EINVAL;
if (fh->ov.width <48 ||
fh->ov.height<32 ||
fh->ov.width >bttv_tvnorms[btv->tvnorm].swidth ||
fh->ov.height>bttv_tvnorms[btv->tvnorm].sheight ||
if (fh->ov.w.width <48 ||
fh->ov.w.height<32 ||
fh->ov.w.width >bttv_tvnorms[btv->tvnorm].swidth ||
fh->ov.w.height>bttv_tvnorms[btv->tvnorm].sheight||
NULL == fh->ovfmt)
return -EINVAL;
}
......@@ -1873,7 +2157,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY))
return -EBUSY;
down(&fh->q.lock);
down(&fh->cap.lock);
if (*on) {
fh->ov.tvnorm = btv->tvnorm;
new = videobuf_alloc(sizeof(*new));
......@@ -1884,7 +2168,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
/* switch over */
retval = bttv_switch_overlay(btv,fh,new);
up(&fh->q.lock);
up(&fh->cap.lock);
return retval;
}
......@@ -1893,10 +2177,8 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
struct video_mbuf *mbuf = arg;
int i;
if (!mmap)
return -EINVAL;
down(&fh->q.lock);
retval = videobuf_mmap_setup(file,&fh->q,gbuffers,gbufsize);
down(&fh->cap.lock);
retval = videobuf_mmap_setup(file,&fh->cap,gbuffers,gbufsize);
if (retval < 0)
goto fh_unlock_and_return;
memset(mbuf,0,sizeof(*mbuf));
......@@ -1904,20 +2186,21 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
mbuf->size = gbuffers * gbufsize;
for (i = 0; i < gbuffers; i++)
mbuf->offsets[i] = i * gbufsize;
up(&fh->q.lock);
up(&fh->cap.lock);
return 0;
}
case VIDIOCMCAPTURE:
{
struct video_mmap *vm = arg;
struct bttv_buffer *buf;
enum v4l2_field field;
if (vm->frame >= VIDEO_MAX_FRAME)
return -EINVAL;
down(&fh->q.lock);
down(&fh->cap.lock);
retval = -EINVAL;
buf = (struct bttv_buffer *)fh->q.bufs[vm->frame];
buf = (struct bttv_buffer *)fh->cap.bufs[vm->frame];
if (NULL == buf)
goto fh_unlock_and_return;
if (0 == buf->vb.baddr)
......@@ -1926,15 +2209,18 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
buf->vb.state == STATE_ACTIVE)
goto fh_unlock_and_return;
field = (vm->height > bttv_tvnorms[btv->tvnorm].sheight/2)
? V4L2_FIELD_INTERLACED
: V4L2_FIELD_BOTTOM;
retval = bttv_prepare_buffer(btv,buf,
format_by_palette(vm->format),
vm->width,vm->height,0);
vm->width,vm->height,field);
if (0 != retval)
goto fh_unlock_and_return;
spin_lock_irqsave(&btv->s_lock,flags);
buffer_queue(file,&buf->vb);
spin_unlock_irqrestore(&btv->s_lock,flags);
up(&fh->q.lock);
up(&fh->cap.lock);
return 0;
}
case VIDIOCSYNC:
......@@ -1945,9 +2231,9 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
if (*frame >= VIDEO_MAX_FRAME)
return -EINVAL;
down(&fh->q.lock);
down(&fh->cap.lock);
retval = -EINVAL;
buf = (struct bttv_buffer *)fh->q.bufs[*frame];
buf = (struct bttv_buffer *)fh->cap.bufs[*frame];
if (NULL == buf)
goto fh_unlock_and_return;
retval = videobuf_waiton(&buf->vb,0,1);
......@@ -1965,7 +2251,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
retval = -EINVAL;
break;
}
up(&fh->q.lock);
up(&fh->cap.lock);
return retval;
}
......@@ -1980,8 +2266,11 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
case VIDIOCSAUDIO:
return bttv_common_ioctls(btv,cmd,arg);
/* vbi/teletext ioctls */
case BTTV_VBISIZE:
bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
return fh->lines * 2 * 2048;
#ifdef HAVE_V4L2
/* *** v4l2 *** ************************************************ */
case VIDIOC_QUERYCAP:
{
......@@ -1989,25 +2278,21 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
if (0 == v4l2)
return -EINVAL;
strcpy(cap->name,btv->video_dev.name);
cap->type = V4L2_TYPE_CAPTURE;
cap->flags = V4L2_FLAG_TUNER | V4L2_FLAG_PREVIEW
| V4L2_FLAG_READ | V4L2_FLAG_SELECT;
if (mmap)
cap->flags |= V4L2_FLAG_STREAMING;
cap->inputs = bttv_tvcards[btv->type].video_inputs;
cap->outputs = 0;
cap->audios = bttv_tvcards[btv->type].audio_inputs;
cap->maxwidth = bttv_tvnorms[btv->tvnorm].swidth;
cap->maxheight = bttv_tvnorms[btv->tvnorm].sheight;
cap->minwidth = 48;
cap->minheight = 32;
cap->maxframerate = 30;
strcpy(cap->driver,"bttv");
strncpy(cap->card,btv->video_dev.name,sizeof(cap->card));
sprintf(cap->bus_info,"PCI:%s",btv->dev->slot_name);
cap->version = BTTV_VERSION_CODE;
cap->capabilities =
V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_VIDEO_OVERLAY |
V4L2_CAP_VBI_CAPTURE |
V4L2_CAP_TUNER |
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING;
return 0;
}
case VIDIOC_ENUM_PIXFMT:
case VIDIOC_ENUM_FBUFFMT:
case VIDIOC_ENUM_FMT:
{
struct v4l2_fmtdesc *f = arg;
int i, index;
......@@ -2021,81 +2306,38 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
}
if (BTTV_FORMATS == i)
return -EINVAL;
if (cmd == VIDIOC_ENUM_FBUFFMT &&
0 == (bttv_formats[i].flags & FORMAT_FLAGS_PACKED))
switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
break;
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
if (!(bttv_formats[i].flags & FORMAT_FLAGS_PACKED))
return -EINVAL;
break;
default:
return -EINVAL;
}
memset(f,0,sizeof(*f));
f->index = index;
strncpy(f->description,bttv_formats[i].name,31);
f->pixelformat = bttv_formats[i].fourcc;
f->depth = bttv_formats[i].depth;
return 0;
}
case VIDIOC_TRY_FMT:
{
struct v4l2_format *f = arg;
return bttv_try_fmt(fh,btv,f);
}
case VIDIOC_G_FMT:
{
struct v4l2_format *f = arg;
memset(f,0,sizeof(*f));
f->type = V4L2_BUF_TYPE_CAPTURE;
f->fmt.pix.width = fh->buf.vb.width;
f->fmt.pix.height = fh->buf.vb.height;
f->fmt.pix.depth = fh->buf.fmt->depth;
f->fmt.pix.pixelformat = fh->buf.fmt->fourcc;
f->fmt.pix.sizeimage =
(fh->buf.vb.width*fh->buf.vb.height*fh->buf.fmt->depth)/8;
return 0;
return bttv_g_fmt(fh,f);
}
case VIDIOC_S_FMT:
{
struct v4l2_format *f = arg;
const struct bttv_format *fmt;
if ((f->type & V4L2_BUF_TYPE_field) != V4L2_BUF_TYPE_CAPTURE)
return -EINVAL;
fmt = format_by_fourcc(f->fmt.pix.pixelformat);
if (NULL == fmt)
return -EINVAL;
if (f->fmt.pix.width < 48 ||
f->fmt.pix.height < 32)
return -EINVAL;
if (f->fmt.pix.flags & V4L2_FMT_FLAG_BYTESPERLINE)
/* FIXME -- not implemented yet */
return -EINVAL;
down(&fh->q.lock);
/* fixup format */
if (f->fmt.pix.width > bttv_tvnorms[btv->tvnorm].swidth)
f->fmt.pix.width = bttv_tvnorms[btv->tvnorm].swidth;
if (f->fmt.pix.height > bttv_tvnorms[btv->tvnorm].sheight)
f->fmt.pix.height = bttv_tvnorms[btv->tvnorm].sheight;
if (!(f->fmt.pix.flags & V4L2_FMT_FLAG_INTERLACED) &&
f->fmt.pix.height>bttv_tvnorms[btv->tvnorm].sheight/2)
f->fmt.pix.height=bttv_tvnorms[btv->tvnorm].sheight/2;
if (f->fmt.pix.height > bttv_tvnorms[btv->tvnorm].sheight/2) {
/* must interlace -- no field splitting available */
f->fmt.pix.flags &= ~(V4L2_FMT_FLAG_TOPFIELD|
V4L2_FMT_FLAG_BOTFIELD);
} else {
/* one field is enouth -- no interlace needed */
f->fmt.pix.flags &= ~V4L2_FMT_FLAG_INTERLACED;
}
/* update our state informations */
fh->buf.fmt = fmt;
fh->buf.vb.width = f->fmt.pix.width;
fh->buf.vb.height = f->fmt.pix.height;
btv->init.buf.fmt = fmt;
btv->init.buf.vb.width = f->fmt.pix.width;
btv->init.buf.vb.height = f->fmt.pix.height;
/* update data for the application */
f->fmt.pix.depth = fmt->depth;
f->fmt.pix.sizeimage =
(fh->buf.vb.width * fh->buf.vb.height * fmt->depth)/8;
up(&fh->q.lock);
return 0;
return bttv_s_fmt(fh,btv,f);
}
case VIDIOC_G_FBUF:
......@@ -2103,16 +2345,13 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
struct v4l2_framebuffer *fb = arg;
memset(fb,0,sizeof(*fb));
fb->base[0] = btv->fbuf.base;
fb->base = btv->fbuf.base;
fb->fmt.width = btv->fbuf.width;
fb->fmt.height = btv->fbuf.height;
fb->fmt.bytesperline = btv->fbuf.bytesperline;
fb->fmt.flags = V4L2_FMT_FLAG_BYTESPERLINE;
fb->capability = V4L2_FBUF_CAP_CLIPPING;
if (fh->ovfmt) {
fb->fmt.depth = fh->ovfmt->depth;
fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
if (fh->ovfmt)
fb->fmt.pixelformat = fh->ovfmt->fourcc;
}
return 0;
}
case VIDIOC_S_FBUF:
......@@ -2126,18 +2365,16 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
return -EPERM;
/* check args */
end = (unsigned long)fb->base[0] +
end = (unsigned long)fb->base +
fb->fmt.height * fb->fmt.bytesperline;
if (0 == find_videomem((unsigned long)fb->base[0],end))
return -EINVAL;
fmt = format_by_fourcc(fb->fmt.pixelformat);
if (NULL == fmt)
return -EINVAL;
if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))
return -EINVAL;
down(&fh->q.lock);
down(&fh->cap.lock);
retval = -EINVAL;
if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
if (fb->fmt.width > bttv_tvnorms[btv->tvnorm].swidth)
......@@ -2147,11 +2384,11 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
}
/* ok, accept it */
btv->fbuf.base = fb->base[0];
btv->fbuf.base = fb->base;
btv->fbuf.width = fb->fmt.width;
btv->fbuf.height = fb->fmt.height;
btv->fbuf.depth = fmt->depth;
if (fb->fmt.flags & V4L2_FMT_FLAG_BYTESPERLINE)
if (0 != fb->fmt.bytesperline)
btv->fbuf.bytesperline = fb->fmt.bytesperline;
else
btv->fbuf.bytesperline = btv->fbuf.width*fmt->depth/8;
......@@ -2160,12 +2397,12 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
fh->ovfmt = fmt;
btv->init.ovfmt = fmt;
if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
fh->ov.x = 0;
fh->ov.y = 0;
fh->ov.width = fb->fmt.width;
fh->ov.height = fb->fmt.height;
btv->init.ov.width = fb->fmt.width;
btv->init.ov.height = fb->fmt.height;
fh->ov.w.left = 0;
fh->ov.w.top = 0;
fh->ov.w.width = fb->fmt.width;
fh->ov.w.height = fb->fmt.height;
btv->init.ov.w.width = fb->fmt.width;
btv->init.ov.w.height = fb->fmt.height;
if (fh->ov.clips)
kfree(fh->ov.clips);
fh->ov.clips = NULL;
......@@ -2179,64 +2416,48 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
retval = bttv_switch_overlay(btv,fh,new);
}
}
up(&fh->q.lock);
up(&fh->cap.lock);
return retval;
}
case VIDIOC_G_WIN:
{
struct v4l2_window *win = arg;
memset(win,0,sizeof(*win));
win->x = fh->ov.x;
win->y = fh->ov.y;
win->width = fh->ov.width;
win->height = fh->ov.height;
return 0;
}
case VIDIOC_S_WIN:
{
struct v4l2_window *win = arg;
return setup_window(fh,btv,win->x,win->y,
win->width,win->height,
(struct video_clip*)win->clips,
win->clipcount);
}
case VIDIOC_REQBUFS:
if (!mmap)
return -EINVAL;
return videobuf_reqbufs(file,&fh->q,arg);
return videobuf_reqbufs(file,bttv_queue(fh),arg);
case VIDIOC_QUERYBUF:
return videobuf_querybuf(&fh->q,arg);
return videobuf_querybuf(bttv_queue(fh),arg);
case VIDIOC_QBUF:
return videobuf_qbuf(file,&fh->q,arg);
return videobuf_qbuf(file,bttv_queue(fh),arg);
case VIDIOC_DQBUF:
return videobuf_dqbuf(file,&fh->q,arg);
return videobuf_dqbuf(file,bttv_queue(fh),arg);
case VIDIOC_STREAMON:
if (!check_alloc_btres(btv,fh,RESOURCE_STREAMING))
{
int res = bttv_resource(fh);
if (!check_alloc_btres(btv,fh,res))
return -EBUSY;
bttv_field_count(btv);
return videobuf_streamon(file,&fh->q);
return videobuf_streamon(file,bttv_queue(fh));
}
case VIDIOC_STREAMOFF:
retval = videobuf_streamoff(file,&fh->q);
{
int res = bttv_resource(fh);
retval = videobuf_streamoff(file,bttv_queue(fh));
if (retval < 0)
return retval;
free_btres(btv,fh,RESOURCE_STREAMING);
free_btres(btv,fh,res);
bttv_field_count(btv);
return 0;
}
case VIDIOC_QUERYCTRL:
{
struct v4l2_queryctrl *c = arg;
int i;
v4l2_fill_ctrl_category(c);
if ((c->id < V4L2_CID_BASE ||
c->id >= V4L2_CID_LASTP1) &&
(c->id < V4L2_CID_PRIVATE_BASE ||
......@@ -2250,7 +2471,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
return 0;
}
*c = bttv_ctls[i];
if (bttv_ctls[i].category == V4L2_CTRL_CAT_AUDIO) {
if (i >= 4 && i <= 8) {
struct video_audio va;
memset(&va,0,sizeof(va));
bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
......@@ -2285,11 +2506,12 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
{
struct v4l2_streamparm *parm = arg;
struct v4l2_standard s;
if (parm->type != V4L2_BUF_TYPE_CAPTURE)
if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
memset(parm,0,sizeof(*parm));
v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id, 0);
parm->parm.capture.timeperframe = v4l2_video_std_tpf(&s);
v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id,
bttv_tvnorms[btv->tvnorm].name);
parm->parm.capture.timeperframe = s.frameperiod;
return 0;
}
......@@ -2301,10 +2523,9 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_S_INPUT:
case VIDIOC_G_TUNER:
case VIDIOC_S_TUNER:
case VIDIOC_G_FREQ:
case VIDIOC_S_FREQ:
case VIDIOC_G_FREQUENCY:
case VIDIOC_S_FREQUENCY:
return bttv_common_ioctls(btv,cmd,arg);
#endif /* HAVE_V4L2 */
default:
return -ENOIOCTLCMD;
......@@ -2312,7 +2533,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
return 0;
fh_unlock_and_return:
up(&fh->q.lock);
up(&fh->cap.lock);
return retval;
}
......@@ -2322,55 +2543,30 @@ static int bttv_ioctl(struct inode *inode, struct file *file,
return video_usercopy(inode, file, cmd, arg, bttv_do_ioctl);
}
#if 0
/*
* blocking read for a complete video frame
* => no kernel bounce buffer needed.
*/
static ssize_t
bttv_read_zerocopy(struct bttv_fh *fh, struct bttv *btv,
char *data,size_t count, loff_t *ppos)
{
int rc;
/* setup stuff */
dprintk("bttv%d: read zerocopy\n",btv->nr);
fh->q.read_buf->baddr = (unsigned long)data;
fh->q.read_buf->bsize = count;
rc = bttv_prepare_buffer(btv,fh->q.read_buf,fh->buf.fmt,
fh->buf.vb.width,fh->buf.vb.height,0);
if (0 != rc)
goto done;
/* start capture & wait */
bttv_queue_buffer(btv,fh->q.read_buf);
rc = videobuf_waiton(fh->q.read_buf,0,1);
if (0 == rc) {
videobuf_dma_pci_sync(btv->dev,&fh->q.read_buf->dma);
rc = fh->q.read_buf->size;
}
done:
/* cleanup */
bttv_dma_free(btv,fh->q.read_buf);
fh->q.read_buf->baddr = 0;
fh->q.read_buf->size = 0;
return rc;
}
#endif
static ssize_t bttv_read(struct file *file, char *data,
size_t count, loff_t *ppos)
{
struct bttv_fh *fh = file->private_data;
int retval = 0;
if (fh->btv->errors)
bttv_reinit_bt848(fh->btv);
if (locked_btres(fh->btv,RESOURCE_STREAMING))
return -EBUSY;
dprintk("read count=%d type=%s\n",
(int)count,v4l2_type_names[fh->type]);
return videobuf_read_one(file, &fh->q, data, count, ppos);
switch (fh->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
if (locked_btres(fh->btv,RESOURCE_VIDEO))
return -EBUSY;
retval = videobuf_read_one(file, &fh->cap, data, count, ppos);
break;
case V4L2_BUF_TYPE_VBI_CAPTURE:
retval = videobuf_read_stream(file, &fh->vbi, data, count, ppos, 1);
break;
default:
BUG();
}
return retval;
}
static unsigned int bttv_poll(struct file *file, poll_table *wait)
......@@ -2378,34 +2574,37 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
struct bttv_fh *fh = file->private_data;
struct bttv_buffer *buf;
if (check_btres(fh,RESOURCE_STREAMING)) {
if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type)
return videobuf_poll_stream(file, &fh->vbi, wait);
if (check_btres(fh,RESOURCE_VIDEO)) {
/* streaming capture */
if (list_empty(&fh->q.stream))
if (list_empty(&fh->cap.stream))
return POLLERR;
buf = list_entry(fh->q.stream.next,struct bttv_buffer,vb.stream);
buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream);
} else {
/* read() capture */
down(&fh->q.lock);
if (NULL == fh->q.read_buf) {
down(&fh->cap.lock);
if (NULL == fh->cap.read_buf) {
/* need to capture a new frame */
if (locked_btres(fh->btv,RESOURCE_STREAMING)) {
up(&fh->q.lock);
if (locked_btres(fh->btv,RESOURCE_VIDEO)) {
up(&fh->cap.lock);
return POLLERR;
}
fh->q.read_buf = videobuf_alloc(fh->q.msize);
if (NULL == fh->q.read_buf) {
up(&fh->q.lock);
fh->cap.read_buf = videobuf_alloc(fh->cap.msize);
if (NULL == fh->cap.read_buf) {
up(&fh->cap.lock);
return POLLERR;
}
if (0 != fh->q.ops->buf_prepare(file,fh->q.read_buf,0)) {
up(&fh->q.lock);
if (0 != fh->cap.ops->buf_prepare(file,fh->cap.read_buf)) {
up(&fh->cap.lock);
return POLLERR;
}
fh->q.ops->buf_queue(file,fh->q.read_buf);
fh->q.read_off = 0;
fh->cap.ops->buf_queue(file,fh->cap.read_buf);
fh->cap.read_off = 0;
}
up(&fh->q.lock);
buf = (struct bttv_buffer*)fh->q.read_buf;
up(&fh->cap.lock);
buf = (struct bttv_buffer*)fh->cap.read_buf;
}
poll_wait(file, &buf->vb.done, wait);
......@@ -2420,6 +2619,7 @@ static int bttv_open(struct inode *inode, struct file *file)
unsigned int minor = minor(inode->i_rdev);
struct bttv *btv = NULL;
struct bttv_fh *fh;
enum v4l2_buf_type type = 0;
int i;
dprintk(KERN_DEBUG "bttv: open minor=%d\n",minor);
......@@ -2427,13 +2627,20 @@ static int bttv_open(struct inode *inode, struct file *file)
for (i = 0; i < bttv_num; i++) {
if (bttvs[i].video_dev.minor == minor) {
btv = &bttvs[i];
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
break;
}
if (bttvs[i].vbi_dev.minor == minor) {
btv = &bttvs[i];
type = V4L2_BUF_TYPE_VBI_CAPTURE;
break;
}
}
if (NULL == btv)
return -ENODEV;
dprintk(KERN_DEBUG "bttv%d: open called (video)\n",btv->nr);
dprintk(KERN_DEBUG "bttv%d: open called (type=%s)\n",
btv->nr,v4l2_type_names[type]);
/* allocate per filehandle data */
fh = kmalloc(sizeof(*fh),GFP_KERNEL);
......@@ -2441,8 +2648,15 @@ static int bttv_open(struct inode *inode, struct file *file)
return -ENOMEM;
file->private_data = fh;
*fh = btv->init;
videobuf_queue_init(&fh->q, &bttv_qops, btv->dev, &btv->s_lock,
V4L2_BUF_TYPE_CAPTURE,sizeof(struct bttv_buffer));
fh->type = type;
videobuf_queue_init(&fh->cap, &bttv_video_qops,
btv->dev, &btv->s_lock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
sizeof(struct bttv_buffer));
videobuf_queue_init(&fh->vbi, &bttv_vbi_qops,
btv->dev, &btv->s_lock,
V4L2_BUF_TYPE_VBI_CAPTURE,
sizeof(struct bttv_buffer));
i2c_vidiocschan(btv);
return 0;
......@@ -2456,16 +2670,24 @@ static int bttv_release(struct inode *inode, struct file *file)
/* turn off overlay, stop outstanding captures */
if (check_btres(fh, RESOURCE_OVERLAY))
bttv_switch_overlay(btv,fh,NULL);
if (check_btres(fh, RESOURCE_STREAMING)) {
videobuf_streamoff(file,&fh->q);
free_btres(btv,fh,RESOURCE_STREAMING);
/* stop video capture */
if (check_btres(fh, RESOURCE_VIDEO)) {
videobuf_streamoff(file,&fh->cap);
free_btres(btv,fh,RESOURCE_VIDEO);
bttv_field_count(btv);
}
if (fh->q.read_buf) {
buffer_release(file,fh->q.read_buf);
kfree(fh->q.read_buf);
if (fh->cap.read_buf) {
buffer_release(file,fh->cap.read_buf);
kfree(fh->cap.read_buf);
}
/* stop vbi capture */
if (fh->vbi.streaming)
videobuf_streamoff(file,&fh->vbi);
if (fh->vbi.reading)
videobuf_read_stop(file,&fh->vbi);
file->private_data = NULL;
kfree(fh);
return 0;
......@@ -2476,11 +2698,10 @@ bttv_mmap(struct file *file, struct vm_area_struct *vma)
{
struct bttv_fh *fh = file->private_data;
if (!mmap)
return -EINVAL;
dprintk("mmap 0x%lx+%ld\n",vma->vm_start,
vma->vm_end - vma->vm_start);
return videobuf_mmap_mapper(vma,&fh->q);
dprintk("bttv%d: mmap type=%s 0x%lx+%ld\n",
fh->btv->nr, v4l2_type_names[fh->type],
vma->vm_start, vma->vm_end - vma->vm_start);
return videobuf_mmap_mapper(vma,bttv_queue(fh));
}
static struct file_operations bttv_fops =
......@@ -2495,7 +2716,7 @@ static struct file_operations bttv_fops =
poll: bttv_poll,
};
static struct video_device bttv_template =
static struct video_device bttv_video_template =
{
name: "UNSET",
type: VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_OVERLAY|
......@@ -2505,6 +2726,15 @@ static struct video_device bttv_template =
minor: -1,
};
struct video_device bttv_vbi_template =
{
name: "bt848/878 vbi",
type: VID_TYPE_TUNER|VID_TYPE_TELETEXT,
hardware: VID_HARDWARE_BT848,
fops: &bttv_fops,
minor: -1,
};
/* ----------------------------------------------------------------------- */
/* radio interface */
......@@ -2653,20 +2883,20 @@ static void bttv_print_riscaddr(struct bttv *btv)
printk(" main: %08Lx\n",
(u64)btv->main.dma);
printk(" vbi : o=%08Lx e=%08Lx\n",
btv->vcurr ? (u64)btv->vcurr->odd.dma : 0,
btv->vcurr ? (u64)btv->vcurr->even.dma : 0);
btv->vcurr ? (u64)btv->vcurr->top.dma : 0,
btv->vcurr ? (u64)btv->vcurr->bottom.dma : 0);
printk(" cap : o=%08Lx e=%08Lx\n",
btv->odd ? (u64)btv->odd->odd.dma : 0,
btv->even ? (u64)btv->even->even.dma : 0);
btv->top ? (u64)btv->top->top.dma : 0,
btv->bottom ? (u64)btv->bottom->bottom.dma : 0);
printk(" scr : o=%08Lx e=%08Lx\n",
btv->screen ? (u64)btv->screen->odd.dma : 0,
btv->screen ? (u64)btv->screen->even.dma : 0);
btv->screen ? (u64)btv->screen->top.dma : 0,
btv->screen ? (u64)btv->screen->bottom.dma : 0);
}
static void bttv_irq_timeout(unsigned long data)
{
struct bttv *btv = (struct bttv *)data;
struct bttv_buffer *o_even,*o_odd,*o_vcurr;
struct bttv_buffer *o_bottom,*o_top,*o_vcurr;
struct bttv_buffer *capture;
if (bttv_verbose) {
......@@ -2677,12 +2907,12 @@ static void bttv_irq_timeout(unsigned long data)
}
spin_lock(&btv->s_lock);
o_odd = btv->odd;
o_even = btv->even;
o_vcurr = btv->vcurr;
btv->odd = NULL;
btv->even = NULL;
btv->vcurr = NULL;
o_top = btv->top;
o_bottom = btv->bottom;
o_vcurr = btv->vcurr;
btv->top = NULL;
btv->bottom = NULL;
btv->vcurr = NULL;
/* deactivate stuff */
bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
......@@ -2692,19 +2922,19 @@ static void bttv_irq_timeout(unsigned long data)
bttv_set_dma(btv, 0, 0);
/* wake up + free */
if (o_odd == o_even) {
if (NULL != o_odd) {
o_odd->vb.state = STATE_ERROR;
wake_up(&o_odd->vb.done);
if (o_top == o_bottom) {
if (NULL != o_top) {
o_top->vb.state = STATE_ERROR;
wake_up(&o_top->vb.done);
}
} else {
if (NULL != o_odd) {
o_odd->vb.state = STATE_ERROR;
wake_up(&o_odd->vb.done);
if (NULL != o_top) {
o_top->vb.state = STATE_ERROR;
wake_up(&o_top->vb.done);
}
if (NULL != o_even) {
o_even->vb.state = STATE_ERROR;
wake_up(&o_even->vb.done);
if (NULL != o_bottom) {
o_bottom->vb.state = STATE_ERROR;
wake_up(&o_bottom->vb.done);
}
}
if (NULL != o_vcurr) {
......@@ -2733,20 +2963,18 @@ static void bttv_irq_timeout(unsigned long data)
static void
bttv_irq_switch_fields(struct bttv *btv)
{
struct bttv_buffer *o_even,*o_odd,*o_vcurr;
struct bttv_buffer *o_bottom,*o_top,*o_vcurr;
struct bttv_buffer *capture;
int irqflags = 0;
#ifdef HAVE_V4L2
stamp_t ts;
#endif
struct timeval ts;
spin_lock(&btv->s_lock);
o_odd = btv->odd;
o_even = btv->even;
o_vcurr = btv->vcurr;
btv->odd = NULL;
btv->even = NULL;
btv->vcurr = NULL;
o_top = btv->top;
o_bottom = btv->bottom;
o_vcurr = btv->vcurr;
btv->top = NULL;
btv->bottom = NULL;
btv->vcurr = NULL;
/* vbi request ? */
if (!list_empty(&btv->vcapture)) {
......@@ -2760,24 +2988,24 @@ bttv_irq_switch_fields(struct bttv *btv)
irqflags = 1;
capture = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
list_del(&capture->vb.queue);
if (capture->vb.field & VBUF_FIELD_ODD)
btv->odd = capture;
if (capture->vb.field & VBUF_FIELD_EVEN)
btv->even = capture;
if (V4L2_FIELD_HAS_TOP(capture->vb.field))
btv->top = capture;
if (V4L2_FIELD_HAS_BOTTOM(capture->vb.field))
btv->bottom = capture;
/* capture request for other field ? */
if (!(capture->vb.field & VBUF_FIELD_INTER) &&
if (!V4L2_FIELD_HAS_BOTH(capture->vb.field) &&
!list_empty(&btv->capture)) {
capture = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
if (!(capture->vb.field & VBUF_FIELD_INTER)) {
if (NULL == btv->odd &&
capture->vb.field & VBUF_FIELD_ODD) {
btv->odd = capture;
if (!V4L2_FIELD_HAS_BOTH(capture->vb.field)) {
if (NULL == btv->top &&
V4L2_FIELD_TOP == capture->vb.field) {
btv->top = capture;
list_del(&capture->vb.queue);
}
if (NULL == btv->even &&
capture->vb.field & VBUF_FIELD_EVEN) {
btv->even = capture;
if (NULL == btv->bottom &&
V4L2_FIELD_BOTTOM == capture->vb.field) {
btv->bottom = capture;
list_del(&capture->vb.queue);
}
}
......@@ -2786,34 +3014,34 @@ bttv_irq_switch_fields(struct bttv *btv)
/* screen overlay ? */
if (NULL != btv->screen) {
if (btv->screen->vb.field & VBUF_FIELD_INTER) {
if (NULL == btv->odd && NULL == btv->even) {
btv->odd = btv->screen;
btv->even = btv->screen;
if (V4L2_FIELD_HAS_BOTH(btv->screen->vb.field)) {
if (NULL == btv->top && NULL == btv->bottom) {
btv->top = btv->screen;
btv->bottom = btv->screen;
}
} else {
if ((btv->screen->vb.field & VBUF_FIELD_ODD) &&
NULL == btv->odd) {
btv->odd = btv->screen;
if (V4L2_FIELD_TOP == btv->screen->vb.field &&
NULL == btv->top) {
btv->top = btv->screen;
}
if ((btv->screen->vb.field & VBUF_FIELD_EVEN) &&
NULL == btv->even) {
btv->even = btv->screen;
if (V4L2_FIELD_BOTTOM == btv->screen->vb.field &&
NULL == btv->bottom) {
btv->bottom = btv->screen;
}
}
}
if (irq_debug)
printk(KERN_DEBUG
"bttv: irq odd=%p even=%p screen=%p vbi=%p\n",
btv->odd,btv->even,btv->screen,btv->vcurr);
"bttv: irq top=%p bottom=%p screen=%p vbi=%p\n",
btv->top,btv->bottom,btv->screen,btv->vcurr);
/* activate new fields */
bttv_buffer_activate(btv,btv->odd,btv->even);
bttv_buffer_activate(btv,btv->top,btv->bottom);
if (btv->vcurr) {
btv->vcurr->vb.state = STATE_ACTIVE;
bttv_risc_hook(btv, RISC_SLOT_O_VBI, &btv->vcurr->odd, 0);
bttv_risc_hook(btv, RISC_SLOT_E_VBI, &btv->vcurr->even, 0);
bttv_risc_hook(btv, RISC_SLOT_O_VBI, &btv->vcurr->top, 0);
bttv_risc_hook(btv, RISC_SLOT_E_VBI, &btv->vcurr->bottom, 0);
} else {
bttv_risc_hook(btv, RISC_SLOT_O_VBI, NULL, 0);
bttv_risc_hook(btv, RISC_SLOT_E_VBI, NULL, 0);
......@@ -2821,40 +3049,30 @@ bttv_irq_switch_fields(struct bttv *btv)
bttv_set_dma(btv, 0, irqflags);
/* wake up + free */
#ifdef HAVE_V4L2
v4l2_masterclock_gettime(&ts);
#endif
if (o_odd == o_even) {
if (NULL != o_odd && btv->odd != o_odd) {
#ifdef HAVE_V4L2
o_odd->vb.ts = ts;
#endif
o_odd->vb.field_count = btv->field_count;
o_odd->vb.state = STATE_DONE;
wake_up(&o_odd->vb.done);
do_gettimeofday(&ts);
if (o_top == o_bottom) {
if (NULL != o_top && btv->top != o_top) {
o_top->vb.ts = ts;
o_top->vb.field_count = btv->field_count;
o_top->vb.state = STATE_DONE;
wake_up(&o_top->vb.done);
}
} else {
if (NULL != o_odd && btv->odd != o_odd) {
#ifdef HAVE_V4L2
o_odd->vb.ts = ts;
#endif
o_odd->vb.field_count = btv->field_count;
o_odd->vb.state = STATE_DONE;
wake_up(&o_odd->vb.done);
if (NULL != o_top && btv->top != o_top) {
o_top->vb.ts = ts;
o_top->vb.field_count = btv->field_count;
o_top->vb.state = STATE_DONE;
wake_up(&o_top->vb.done);
}
if (NULL != o_even && btv->even != o_even) {
#ifdef HAVE_V4L2
o_even->vb.ts = ts;
#endif
o_even->vb.field_count = btv->field_count;
o_even->vb.state = STATE_DONE;
wake_up(&o_even->vb.done);
if (NULL != o_bottom && btv->bottom != o_bottom) {
o_bottom->vb.ts = ts;
o_bottom->vb.field_count = btv->field_count;
o_bottom->vb.state = STATE_DONE;
wake_up(&o_bottom->vb.done);
}
}
if (NULL != o_vcurr) {
#ifdef HAVE_V4L2
o_vcurr->vb.ts = ts;
#endif
o_vcurr->vb.field_count = btv->field_count;
o_vcurr->vb.state = STATE_DONE;
wake_up(&o_vcurr->vb.done);
......@@ -2896,7 +3114,7 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
printk(" PRES => %s", (dstat & BT848_DSTATUS_PRES)
? "yes" : "no");
if (stat & BT848_INT_FMTCHG)
printk(" NUML => %s", (dstat & BT848_DSTATUS_PRES)
printk(" NUML => %s", (dstat & BT848_DSTATUS_NUML)
? "625" : "525");
printk("\n");
}
......@@ -3006,8 +3224,6 @@ static int __devinit bttv_probe(struct pci_dev *dev,
init_waitqueue_head(&btv->gpioq);
INIT_LIST_HEAD(&btv->capture);
INIT_LIST_HEAD(&btv->vcapture);
videobuf_queue_init(&btv->vbi.q, &vbi_qops, btv->dev, &btv->s_lock,
V4L2_BUF_TYPE_VBI,sizeof(struct bttv_buffer));
btv->timeout.function = bttv_irq_timeout;
btv->timeout.data = (unsigned long)btv;
......@@ -3015,9 +3231,9 @@ static int __devinit bttv_probe(struct pci_dev *dev,
btv->i2c_rc = -1;
btv->tuner_type = -1;
memcpy(&btv->video_dev, &bttv_template, sizeof(bttv_template));
memcpy(&btv->radio_dev, &radio_template, sizeof(radio_template));
memcpy(&btv->vbi_dev, &bttv_vbi_template, sizeof(bttv_vbi_template));
memcpy(&btv->video_dev, &bttv_video_template, sizeof(bttv_video_template));
memcpy(&btv->radio_dev, &radio_template, sizeof(radio_template));
memcpy(&btv->vbi_dev, &bttv_vbi_template, sizeof(bttv_vbi_template));
btv->video_dev.minor = -1;
btv->video_dev.priv = btv;
btv->radio_dev.minor = -1;
......@@ -3060,9 +3276,8 @@ static int __devinit bttv_probe(struct pci_dev *dev,
}
pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %02x:%02x.%x, ",
bttv_num,btv->id, btv->revision, dev->bus->number,
PCI_SLOT(dev->devfn),PCI_FUNC(dev->devfn));
printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ",
bttv_num,btv->id, btv->revision, dev->slot_name);
printk("irq: %d, latency: %d, mmio: 0x%lx\n",
btv->dev->irq, lat, pci_resource_start(dev,0));
......@@ -3100,11 +3315,13 @@ static int __devinit bttv_probe(struct pci_dev *dev,
/* fill struct bttv with some useful defaults */
btv->init.btv = btv;
btv->init.ov.width = 320;
btv->init.ov.height = 240;
btv->init.ov.w.width = 320;
btv->init.ov.w.height = 240;
btv->init.buf.fmt = format_by_palette(VIDEO_PALETTE_RGB24);
btv->init.buf.vb.width = 320;
btv->init.buf.vb.height = 240;
btv->init.buf.vb.field = V4L2_FIELD_BOTTOM;
btv->init.lines = 16;
btv->input = 0;
/* initialize hardware */
......@@ -3173,7 +3390,7 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev)
/* shutdown everything (DMA+IRQs) */
btand(~15, BT848_GPIO_DMA_CTL);
btwrite(0, BT848_INT_MASK);
btwrite(~0x0UL,BT848_INT_STAT);
btwrite(~0x0, BT848_INT_STAT);
btwrite(0x0, BT848_GPIO_OUT_EN);
if (bttv_gpio)
bttv_gpio_tracking(btv,"cleanup");
......@@ -3231,8 +3448,7 @@ static int bttv_init_module(void)
{
bttv_num = 0;
printk(KERN_INFO "bttv: driver version %d.%d.%d loaded "
BTTV_APIS "\n",
printk(KERN_INFO "bttv: driver version %d.%d.%d loaded\n",
(BTTV_VERSION_CODE >> 16) & 0xff,
(BTTV_VERSION_CODE >> 8) & 0xff,
BTTV_VERSION_CODE & 0xff);
......
......@@ -41,11 +41,13 @@ static struct i2c_adapter bttv_i2c_adap_template;
static struct i2c_client bttv_i2c_client_template;
EXPORT_SYMBOL(bttv_get_cardinfo);
EXPORT_SYMBOL(bttv_get_pcidev);
EXPORT_SYMBOL(bttv_get_id);
EXPORT_SYMBOL(bttv_gpio_enable);
EXPORT_SYMBOL(bttv_read_gpio);
EXPORT_SYMBOL(bttv_write_gpio);
EXPORT_SYMBOL(bttv_get_gpio_queue);
EXPORT_SYMBOL(bttv_i2c_call);
/* ----------------------------------------------------------------------- */
/* Exported functions - for other modules which want to access the */
......@@ -62,6 +64,13 @@ int bttv_get_cardinfo(unsigned int card, int *type, int *cardid)
return 0;
}
struct pci_dev* bttv_get_pcidev(unsigned int card)
{
if (card >= bttv_num)
return NULL;
return bttvs[card].dev;
}
int bttv_get_id(unsigned int card)
{
printk("bttv_get_id is obsolete, use bttv_get_cardinfo instead\n");
......@@ -245,6 +254,13 @@ void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg)
}
}
void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg)
{
if (card >= bttv_num)
return;
bttv_call_i2c_clients(&bttvs[card], cmd, arg);
}
static struct i2c_algo_bit_data bttv_i2c_algo_template = {
setsda: bttv_bit_setsda,
setscl: bttv_bit_setscl,
......
......@@ -5,7 +5,7 @@
- memory management
- generation
(c) 2000 Gerd Knorr <kraxel@goldbach.in-berlin.de>
(c) 2000 Gerd Knorr <kraxel@bytesex.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -43,8 +43,8 @@ int bttv_riscmem_alloc(struct pci_dev *pci,
struct bttv_riscmem *risc,
unsigned int size)
{
unsigned long *cpu;
dma_addr_t dma;
u32 *cpu;
dma_addr_t dma;
cpu = pci_alloc_consistent(pci, size, &dma);
if (NULL == cpu)
......@@ -82,7 +82,7 @@ bttv_risc_packed(struct bttv *btv, struct bttv_riscmem *risc,
{
int instructions,rc,line,todo;
struct scatterlist *sg;
unsigned long *rp;
u32 *rp;
/* estimate risc mem: worst case is one write per page border +
one write per scan line + sync + jump (all 2 dwords) */
......@@ -146,7 +146,7 @@ bttv_risc_planar(struct bttv *btv, struct bttv_riscmem *risc,
int cpadding)
{
int instructions,rc,line,todo,ylen,chroma;
unsigned long *rp,ri;
u32 *rp,ri;
struct scatterlist *ysg;
struct scatterlist *usg;
struct scatterlist *vsg;
......@@ -241,54 +241,53 @@ struct SKIPLIST {
};
int
bttv_screen_clips(struct video_buffer *fbuf,
int x, int y, int width, int height,
struct video_clip *clips, int n)
bttv_screen_clips(int swidth, int sheight, struct v4l2_rect *win,
struct v4l2_clip *clips, int n)
{
if (x < 0) {
if (win->left < 0) {
/* left */
clips[n].x = 0;
clips[n].y = 0;
clips[n].width = -x;
clips[n].height = height;
clips[n].c.left = 0;
clips[n].c.top = 0;
clips[n].c.width = -win->left;
clips[n].c.height = win->height;
n++;
}
if (x+width > fbuf->width) {
if (win->left + win->width > swidth) {
/* right */
clips[n].x = fbuf->width - x;
clips[n].y = 0;
clips[n].width = width - clips[n].x;
clips[n].height = height;
clips[n].c.left = swidth - win->left;
clips[n].c.top = 0;
clips[n].c.width = win->width - clips[n].c.left;
clips[n].c.height = win->height;
n++;
}
if (y < 0) {
if (win->top < 0) {
/* top */
clips[n].x = 0;
clips[n].y = 0;
clips[n].width = width;
clips[n].height = -y;
clips[n].c.left = 0;
clips[n].c.top = 0;
clips[n].c.width = win->width;
clips[n].c.height = -win->top;
n++;
}
if (y+height > fbuf->height) {
if (win->top + win->height > sheight) {
/* bottom */
clips[n].x = 0;
clips[n].y = fbuf->height - y;
clips[n].width = width;
clips[n].height = height - clips[n].y;
clips[n].c.left = 0;
clips[n].c.top = sheight - win->top;
clips[n].c.width = win->width;
clips[n].c.height = win->height - clips[n].c.top;
n++;
}
return n;
}
void
bttv_sort_clips(struct video_clip *clips, int nclips)
bttv_sort_clips(struct v4l2_clip *clips, int nclips)
{
struct video_clip swap;
struct v4l2_clip swap;
int i,j,n;
for (i = nclips-2; i >= 0; i--) {
for (n = 0, j = 0; j <= i; j++) {
if (clips[j].x > clips[j+1].x) {
if (clips[j].c.left > clips[j+1].c.left) {
swap = clips[j];
clips[j] = clips[j+1];
clips[j+1] = swap;
......@@ -303,7 +302,7 @@ bttv_sort_clips(struct video_clip *clips, int nclips)
static void
calc_skips(int line, int width, int *maxy,
struct SKIPLIST *skips, int *nskips,
const struct video_clip *clips, int nclips)
const struct v4l2_clip *clips, int nclips)
{
int clip,skip,maxline,end;
......@@ -312,35 +311,35 @@ calc_skips(int line, int width, int *maxy,
for (clip = 0; clip < nclips; clip++) {
/* sanity checks */
if (clips[clip].x + clips[clip].width <= 0)
if (clips[clip].c.left + clips[clip].c.width <= 0)
continue;
if (clips[clip].x > width)
if (clips[clip].c.left > width)
break;
/* vertical range */
if (line > clips[clip].y+clips[clip].height-1)
if (line > clips[clip].c.top+clips[clip].c.height-1)
continue;
if (line < clips[clip].y) {
if (maxline > clips[clip].y-1)
maxline = clips[clip].y-1;
if (line < clips[clip].c.top) {
if (maxline > clips[clip].c.top-1)
maxline = clips[clip].c.top-1;
continue;
}
if (maxline > clips[clip].y+clips[clip].height-1)
maxline = clips[clip].y+clips[clip].height-1;
if (maxline > clips[clip].c.top+clips[clip].c.height-1)
maxline = clips[clip].c.top+clips[clip].c.height-1;
/* horizontal range */
if (0 == skip || clips[clip].x > skips[skip-1].end) {
if (0 == skip || clips[clip].c.left > skips[skip-1].end) {
/* new one */
skips[skip].start = clips[clip].x;
skips[skip].start = clips[clip].c.left;
if (skips[skip].start < 0)
skips[skip].start = 0;
skips[skip].end = clips[clip].x + clips[clip].width;
skips[skip].end = clips[clip].c.left + clips[clip].c.width;
if (skips[skip].end > width)
skips[skip].end = width;
skip++;
} else {
/* overlaps -- expand last one */
end = clips[clip].x + clips[clip].width;
end = clips[clip].c.left + clips[clip].c.width;
if (skips[skip-1].end < end)
skips[skip-1].end = end;
if (skips[skip-1].end > width)
......@@ -362,12 +361,12 @@ calc_skips(int line, int width, int *maxy,
int
bttv_risc_overlay(struct bttv *btv, struct bttv_riscmem *risc,
const struct bttv_format *fmt, struct bttv_overlay *ov,
int fields)
int skip_even, int skip_odd)
{
int instructions,rc,line,maxy,start,end,skip,nskips;
struct SKIPLIST *skips;
unsigned long *rp,ri,ra;
unsigned long addr;
u32 *rp,ri,ra;
u32 addr;
/* skip list for window clipping */
if (NULL == (skips = kmalloc(sizeof(*skips) * ov->nclips,GFP_KERNEL)))
......@@ -376,7 +375,7 @@ bttv_risc_overlay(struct bttv *btv, struct bttv_riscmem *risc,
/* estimate risc mem: worst case is (clip+1) * lines instructions
+ sync + jump (all 2 dwords) */
instructions = (ov->nclips + 1) *
((fields & VBUF_FIELD_INTER) ? ov->height>>1 : ov->height);
((skip_even || skip_odd) ? ov->w.height>>1 : ov->w.height);
instructions += 2;
if ((rc = bttv_riscmem_alloc(btv->dev,risc,instructions*8)) < 0)
return rc;
......@@ -387,29 +386,27 @@ bttv_risc_overlay(struct bttv *btv, struct bttv_riscmem *risc,
*(rp++) = cpu_to_le32(0);
addr = (unsigned long)btv->fbuf.base;
addr += btv->fbuf.bytesperline * ov->y;
addr += ((btv->fbuf.depth+7) >> 3) * ov->x;
addr += btv->fbuf.bytesperline * ov->w.top;
addr += ((btv->fbuf.depth+7) >> 3) * ov->w.left;
/* scan lines */
for (maxy = -1, line = 0; line < ov->height;
for (maxy = -1, line = 0; line < ov->w.height;
line++, addr += btv->fbuf.bytesperline) {
if (fields & VBUF_FIELD_INTER) {
if ((line%2) != 0 && (fields & VBUF_FIELD_ODD))
continue;
if ((line%2) != 1 && (fields & VBUF_FIELD_EVEN))
continue;
}
if ((line%2) == 0 && skip_even)
continue;
if ((line%2) == 1 && skip_odd)
continue;
/* calculate clipping */
if (line > maxy)
calc_skips(line, ov->width, &maxy,
calc_skips(line, ov->w.width, &maxy,
skips, &nskips, ov->clips, ov->nclips);
/* write out risc code */
for (start = 0, skip = 0; start < ov->width; start = end) {
for (start = 0, skip = 0; start < ov->w.width; start = end) {
if (skip >= nskips) {
ri = BT848_RISC_WRITE;
end = ov->width;
end = ov->w.width;
} else if (start < skips[skip].start) {
ri = BT848_RISC_WRITE;
end = skips[skip].start;
......@@ -425,7 +422,7 @@ bttv_risc_overlay(struct bttv *btv, struct bttv_riscmem *risc,
if (0 == start)
ri |= BT848_RISC_SOL;
if (ov->width == end)
if (ov->w.width == end)
ri |= BT848_RISC_EOL;
ri |= (fmt->depth>>3) * (end-start);
......@@ -448,19 +445,30 @@ void
bttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo,
int width, int height, int interleaved, int norm)
{
const struct bttv_tvnorm *tvnorm;
const struct bttv_tvnorm *tvnorm = &bttv_tvnorms[norm];
u32 xsf, sr;
int vdelay;
tvnorm = &bttv_tvnorms[norm];
int swidth = tvnorm->swidth;
int totalwidth = tvnorm->totalwidth;
int scaledtwidth = tvnorm->scaledtwidth;
if (btv->digital_video) {
swidth = 720;
totalwidth = 858;
scaledtwidth = 858;
}
vdelay = tvnorm->vdelay;
#if 0 /* FIXME */
if (vdelay < btv->vbi.lines*2)
vdelay = btv->vbi.lines*2;
#endif
xsf = (width*tvnorm->scaledtwidth)/tvnorm->swidth;
geo->hscale = ((tvnorm->totalwidth*4096UL)/xsf-4096);
xsf = (width*scaledtwidth)/swidth;
geo->hscale = ((totalwidth*4096UL)/xsf-4096);
geo->hdelay = tvnorm->hdelayx1;
geo->hdelay = (geo->hdelay*width)/tvnorm->swidth;
geo->hdelay = (geo->hdelay*width)/swidth;
geo->hdelay &= 0x3fe;
sr = ((tvnorm->sheight >> (interleaved?0:1))*512)/height - 512;
geo->vscale = (0x10000UL-sr) & 0x1fff;
......@@ -512,8 +520,8 @@ bttv_set_dma(struct bttv *btv, int override, int irqflags)
int capctl;
btv->cap_ctl = 0;
if (NULL != btv->odd) btv->cap_ctl |= 0x02;
if (NULL != btv->even) btv->cap_ctl |= 0x01;
if (NULL != btv->top) btv->cap_ctl |= 0x02;
if (NULL != btv->bottom) btv->cap_ctl |= 0x01;
if (NULL != btv->vcurr) btv->cap_ctl |= 0x0c;
capctl = 0;
......@@ -522,12 +530,12 @@ bttv_set_dma(struct bttv *btv, int override, int irqflags)
capctl |= override;
d2printk(KERN_DEBUG
"bttv%d: capctl=%x irq=%d odd=%08Lx/%08Lx even=%08Lx/%08Lx\n",
"bttv%d: capctl=%x irq=%d top=%08Lx/%08Lx even=%08Lx/%08Lx\n",
btv->nr,capctl,irqflags,
btv->vcurr ? (u64)btv->vcurr->odd.dma : 0,
btv->odd ? (u64)btv->odd->odd.dma : 0,
btv->vcurr ? (u64)btv->vcurr->even.dma : 0,
btv->even ? (u64)btv->even->even.dma : 0);
btv->vcurr ? (u64)btv->vcurr->top.dma : 0,
btv->top ? (u64)btv->top->top.dma : 0,
btv->vcurr ? (u64)btv->vcurr->bottom.dma : 0,
btv->bottom ? (u64)btv->bottom->bottom.dma : 0);
cmd = BT848_RISC_JUMP;
if (irqflags) {
......@@ -570,7 +578,7 @@ bttv_risc_init_main(struct bttv *btv)
btv->main.cpu[2] = cpu_to_le32(BT848_RISC_JUMP);
btv->main.cpu[3] = cpu_to_le32(btv->main.dma + (4<<2));
/* odd field */
/* top field */
btv->main.cpu[4] = cpu_to_le32(BT848_RISC_JUMP);
btv->main.cpu[5] = cpu_to_le32(btv->main.dma + (6<<2));
btv->main.cpu[6] = cpu_to_le32(BT848_RISC_JUMP);
......@@ -580,13 +588,13 @@ bttv_risc_init_main(struct bttv *btv)
BT848_FIFO_STATUS_VRO);
btv->main.cpu[9] = cpu_to_le32(0);
/* even field */
/* bottom field */
btv->main.cpu[10] = cpu_to_le32(BT848_RISC_JUMP);
btv->main.cpu[11] = cpu_to_le32(btv->main.dma + (12<<2));
btv->main.cpu[12] = cpu_to_le32(BT848_RISC_JUMP);
btv->main.cpu[13] = cpu_to_le32(btv->main.dma + (14<<2));
/* jump back to odd field */
/* jump back to top field */
btv->main.cpu[14] = cpu_to_le32(BT848_RISC_JUMP);
btv->main.cpu[15] = cpu_to_le32(btv->main.dma + (0<<2));
......@@ -625,43 +633,43 @@ bttv_dma_free(struct bttv *btv, struct bttv_buffer *buf)
videobuf_waiton(&buf->vb,0,0);
videobuf_dma_pci_unmap(btv->dev, &buf->vb.dma);
videobuf_dma_free(&buf->vb.dma);
bttv_riscmem_free(btv->dev,&buf->even);
bttv_riscmem_free(btv->dev,&buf->odd);
bttv_riscmem_free(btv->dev,&buf->bottom);
bttv_riscmem_free(btv->dev,&buf->top);
buf->vb.state = STATE_NEEDS_INIT;
}
int
bttv_buffer_activate(struct bttv *btv,
struct bttv_buffer *odd,
struct bttv_buffer *even)
struct bttv_buffer *top,
struct bttv_buffer *bottom)
{
if (NULL != odd && NULL != even) {
odd->vb.state = STATE_ACTIVE;
even->vb.state = STATE_ACTIVE;
bttv_apply_geo(btv, &odd->geo, 1);
bttv_apply_geo(btv, &even->geo,0);
bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &odd->odd, 0);
bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &even->even, 0);
btaor((odd->btformat & 0xf0) | (even->btformat & 0x0f),
if (NULL != top && NULL != bottom) {
top->vb.state = STATE_ACTIVE;
bottom->vb.state = STATE_ACTIVE;
bttv_apply_geo(btv, &top->geo, 1);
bttv_apply_geo(btv, &bottom->geo,0);
bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &top->top, 0);
bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &bottom->bottom, 0);
btaor((top->btformat & 0xf0) | (bottom->btformat & 0x0f),
~0xff, BT848_COLOR_FMT);
btaor((odd->btswap & 0x0a) | (even->btswap & 0x05),
btaor((top->btswap & 0x0a) | (bottom->btswap & 0x05),
~0x0f, BT848_COLOR_CTL);
} else if (NULL != odd) {
odd->vb.state = STATE_ACTIVE;
bttv_apply_geo(btv, &odd->geo,1);
bttv_apply_geo(btv, &odd->geo,0);
bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &odd->odd, 0);
} else if (NULL != top) {
top->vb.state = STATE_ACTIVE;
bttv_apply_geo(btv, &top->geo,1);
bttv_apply_geo(btv, &top->geo,0);
bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &top->top, 0);
bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0);
btaor(odd->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
btaor(odd->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL);
} else if (NULL != even) {
even->vb.state = STATE_ACTIVE;
bttv_apply_geo(btv, &even->geo,1);
bttv_apply_geo(btv, &even->geo,0);
bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &even->even, 0);
btaor(even->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
btaor(even->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL);
btaor(top->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
btaor(top->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL);
} else if (NULL != bottom) {
bottom->vb.state = STATE_ACTIVE;
bttv_apply_geo(btv, &bottom->geo,1);
bttv_apply_geo(btv, &bottom->geo,0);
bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &bottom->bottom, 0);
btaor(bottom->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
btaor(bottom->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL);
} else {
bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0);
......@@ -671,72 +679,53 @@ bttv_buffer_activate(struct bttv *btv,
/* ---------------------------------------------------------- */
int
bttv_buffer_field(struct bttv *btv, int field, int def_field,
int norm, int height)
{
const struct bttv_tvnorm *tvnorm = bttv_tvnorms + norm;
/* check interleave, even+odd fields */
if (height > (tvnorm->sheight >> 1)) {
field = VBUF_FIELD_ODD | VBUF_FIELD_EVEN | VBUF_FIELD_INTER;
} else {
if (field & def_field) {
field = def_field;
} else {
field = (def_field & VBUF_FIELD_EVEN)
? VBUF_FIELD_ODD : VBUF_FIELD_EVEN;
}
}
return field;
}
/* calculate geometry, build risc code */
int
bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
{
const struct bttv_tvnorm *tvnorm = bttv_tvnorms + buf->tvnorm;
buf->vb.field = bttv_buffer_field(btv,buf->vb.field, VBUF_FIELD_EVEN,
buf->tvnorm,buf->vb.height);
dprintk(KERN_DEBUG
"bttv%d: buffer flags:%s%s%s format: %s size: %dx%d\n",
btv->nr,
(buf->vb.field & VBUF_FIELD_INTER) ? " interleave" : "",
(buf->vb.field & VBUF_FIELD_ODD) ? " odd" : "",
(buf->vb.field & VBUF_FIELD_EVEN) ? " even" : "",
buf->fmt->name,buf->vb.width,buf->vb.height);
"bttv%d: buffer field: %s format: %s size: %dx%d\n",
btv->nr, v4l2_field_names[buf->vb.field],
buf->fmt->name, buf->vb.width, buf->vb.height);
/* packed pixel modes */
if (buf->fmt->flags & FORMAT_FLAGS_PACKED) {
int bpl, padding, lines;
bpl = (buf->fmt->depth >> 3) * buf->vb.width;
int bpl = (buf->fmt->depth >> 3) * buf->vb.width;
int bpf = bpl * (buf->vb.height >> 1);
/* calculate geometry */
if (buf->vb.field & VBUF_FIELD_INTER) {
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
buf->vb.height,1,buf->tvnorm);
lines = buf->vb.height >> 1;
padding = bpl;
} else {
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
buf->vb.height,0,buf->tvnorm);
lines = buf->vb.height;
padding = 0;
}
bttv_calc_geo(btv,&buf->geo,buf->vb.width,buf->vb.height,
V4L2_FIELD_HAS_BOTH(buf->vb.field),buf->tvnorm);
/* build risc code */
if (buf->vb.field & VBUF_FIELD_ODD)
bttv_risc_packed(btv,&buf->odd,buf->vb.dma.sglist,
0,bpl,padding,lines);
if (buf->vb.field & VBUF_FIELD_EVEN)
bttv_risc_packed(btv,&buf->even,buf->vb.dma.sglist,
padding,bpl,padding,lines);
switch (buf->vb.field) {
case V4L2_FIELD_TOP:
bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
0,bpl,0,buf->vb.height);
break;
case V4L2_FIELD_BOTTOM:
bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
0,bpl,0,buf->vb.height);
break;
case V4L2_FIELD_INTERLACED:
bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
0,bpl,bpl,buf->vb.height >> 1);
bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
bpl,bpl,bpl,buf->vb.height >> 1);
break;
case V4L2_FIELD_SEQ_TB:
bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
0,bpl,0,buf->vb.height >> 1);
bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
bpf,bpl,0,buf->vb.height >> 1);
break;
default:
BUG();
}
}
/* planar modes */
if (buf->fmt->flags & FORMAT_FLAGS_PLANAR) {
struct bttv_riscmem *risc;
int uoffset, voffset;
int ypadding, cpadding, lines;
......@@ -755,54 +744,59 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
voffset += uoffset;
}
if (buf->vb.field & VBUF_FIELD_INTER) {
switch (buf->vb.field) {
case V4L2_FIELD_TOP:
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
buf->vb.height,0,buf->tvnorm);
bttv_risc_planar(btv, &buf->top, buf->vb.dma.sglist,
0,buf->vb.width,0,buf->vb.height,
uoffset,voffset,buf->fmt->hshift,
buf->fmt->vshift,0);
break;
case V4L2_FIELD_BOTTOM:
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
buf->vb.height,0,buf->tvnorm);
bttv_risc_planar(btv, &buf->bottom, buf->vb.dma.sglist,
0,buf->vb.width,0,buf->vb.height,
uoffset,voffset,buf->fmt->hshift,
buf->fmt->vshift,0);
break;
case V4L2_FIELD_INTERLACED:
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
buf->vb.height,1,buf->tvnorm);
lines = buf->vb.height >> 1;
ypadding = buf->vb.width;
if (!buf->fmt->vshift) {
/* chroma planes are interleaved too */
cpadding = buf->vb.width >> buf->fmt->hshift;
} else {
cpadding = 0;
}
bttv_risc_planar(btv,&buf->odd,
cpadding = buf->vb.width >> buf->fmt->hshift;
bttv_risc_planar(btv,&buf->top,
buf->vb.dma.sglist,
0,buf->vb.width,ypadding,lines,
uoffset,voffset,buf->fmt->hshift,
uoffset,voffset,
buf->fmt->hshift,
buf->fmt->vshift >> 1,
cpadding);
bttv_risc_planar(btv,&buf->even,
bttv_risc_planar(btv,&buf->bottom,
buf->vb.dma.sglist,
ypadding,buf->vb.width,ypadding,lines,
uoffset+cpadding,
voffset+cpadding,
buf->fmt->hshift,
cpadding ? (buf->fmt->vshift>>1) : -1,
buf->fmt->vshift >> 1,
cpadding);
} else {
if (buf->vb.field & VBUF_FIELD_ODD)
risc = &buf->odd;
else
risc = &buf->even;
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
buf->vb.height,0,buf->tvnorm);
bttv_risc_planar(btv, risc, buf->vb.dma.sglist,
0,buf->vb.width,0,buf->vb.height,
uoffset,voffset,buf->fmt->hshift,
buf->fmt->vshift,0);
break;
default:
BUG();
}
}
/* raw data */
if (buf->fmt->flags & FORMAT_FLAGS_RAW) {
/* build risc code */
buf->vb.field = VBUF_FIELD_INTER | VBUF_FIELD_ODD | VBUF_FIELD_EVEN;
buf->vb.field = V4L2_FIELD_SEQ_TB;
bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight,
1,buf->tvnorm);
bttv_risc_packed(btv, &buf->odd, buf->vb.dma.sglist,
bttv_risc_packed(btv, &buf->top, buf->vb.dma.sglist,
0, RAW_BPL, 0, RAW_LINES);
bttv_risc_packed(btv, &buf->even, buf->vb.dma.sglist,
bttv_risc_packed(btv, &buf->bottom, buf->vb.dma.sglist,
buf->vb.size/2 , RAW_BPL, 0, RAW_LINES);
}
......@@ -821,35 +815,41 @@ bttv_overlay_risc(struct bttv *btv,
const struct bttv_format *fmt,
struct bttv_buffer *buf)
{
int interleave;
/* check interleave, even+odd fields */
buf->vb.field = bttv_buffer_field(btv, 0, VBUF_FIELD_ODD,
ov->tvnorm,ov->height);
/* check interleave, bottom+top fields */
dprintk(KERN_DEBUG
"bttv%d: overlay flags:%s%s%s format: %s size: %dx%d\n",
btv->nr,
(buf->vb.field & VBUF_FIELD_INTER) ? " interleave" : "",
(buf->vb.field & VBUF_FIELD_ODD) ? " odd" : "",
(buf->vb.field & VBUF_FIELD_EVEN) ? " even" : "",
fmt->name,ov->width,ov->height);
"bttv%d: overlay fields: %s format: %s size: %dx%d\n",
btv->nr, v4l2_field_names[buf->vb.field],
fmt->name,ov->w.width,ov->w.height);
/* calculate geometry */
interleave = buf->vb.field & VBUF_FIELD_INTER;
bttv_calc_geo(btv,&buf->geo,ov->width,ov->height,
interleave, ov->tvnorm);
bttv_calc_geo(btv,&buf->geo,ov->w.width,ov->w.height,
V4L2_FIELD_HAS_BOTH(ov->field), ov->tvnorm);
/* build risc code */
if (buf->vb.field & VBUF_FIELD_ODD)
bttv_risc_overlay(btv, &buf->odd, fmt, ov,
interleave | VBUF_FIELD_ODD);
if (buf->vb.field & VBUF_FIELD_EVEN)
bttv_risc_overlay(btv, &buf->even,fmt, ov,
interleave | VBUF_FIELD_EVEN);
switch (ov->field) {
case V4L2_FIELD_TOP:
bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 0);
break;
case V4L2_FIELD_BOTTOM:
bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 0, 0);
break;
case V4L2_FIELD_INTERLACED:
#if 0
bttv_risc_overlay(btv, &buf->top, fmt, ov, 1, 0);
bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 0, 1);
#else
bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 1);
bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 1, 0);
#endif
break;
default:
BUG();
}
/* copy format info */
buf->btformat = fmt->btformat;
buf->btswap = fmt->btswap;
buf->vb.field = ov->field;
return 0;
}
......
......@@ -47,58 +47,51 @@ MODULE_PARM_DESC(vbi_debug,"vbi code debug messages, default is 0 (no)");
#define dprintk(fmt, arg...) if (vbi_debug) \
printk(KERN_DEBUG "bttv%d/vbi: " fmt, btv->nr, ## arg)
#ifndef HAVE_V4L2
/* some dummy defines to avoid cluttering up the source code with
a huge number of ifdef's for V4L2 */
# define V4L2_BUF_TYPE_CAPTURE -1
# define V4L2_BUF_TYPE_VBI -1
#endif
/* ----------------------------------------------------------------------- */
/* vbi risc code + mm */
static int
vbi_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
vbi_buffer_risc(struct bttv *btv, struct bttv_buffer *buf, int lines)
{
int bpl = 2048;
bttv_risc_packed(btv, &buf->odd, buf->vb.dma.sglist,
0, bpl-4, 4, btv->vbi.lines);
bttv_risc_packed(btv, &buf->even, buf->vb.dma.sglist,
btv->vbi.lines * bpl, bpl-4, 4, btv->vbi.lines);
bttv_risc_packed(btv, &buf->top, buf->vb.dma.sglist,
0, bpl-4, 4, lines);
bttv_risc_packed(btv, &buf->bottom, buf->vb.dma.sglist,
lines * bpl, bpl-4, 4, lines);
return 0;
}
static int vbi_buffer_setup(struct file *file, int *count, int *size)
{
struct bttv *btv = file->private_data;
struct bttv_fh *fh = file->private_data;
if (0 == *count)
*count = vbibufs;
*size = btv->vbi.lines * 2 * 2048;
*size = fh->lines * 2 * 2048;
return 0;
}
static int vbi_buffer_prepare(struct file *file, struct videobuf_buffer *vb,
int fields)
static int vbi_buffer_prepare(struct file *file, struct videobuf_buffer *vb)
{
struct bttv *btv = file->private_data;
struct bttv_fh *fh = file->private_data;
struct bttv *btv = fh->btv;
struct bttv_buffer *buf = (struct bttv_buffer*)vb;
int rc;
buf->vb.size = btv->vbi.lines * 2 * 2048;
buf->vb.size = fh->lines * 2 * 2048;
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
return -EINVAL;
if (STATE_NEEDS_INIT == buf->vb.state) {
if (0 != (rc = videobuf_iolock(btv->dev,&buf->vb)))
goto fail;
if (0 != (rc = vbi_buffer_risc(btv,buf)))
if (0 != (rc = vbi_buffer_risc(btv,buf,fh->lines)))
goto fail;
}
buf->vb.state = STATE_PREPARED;
dprintk("buf prepare %p: odd=%p even=%p\n",
vb,&buf->odd,&buf->even);
dprintk("buf prepare %p: top=%p bottom=%p\n",
vb,&buf->top,&buf->bottom);
return 0;
fail:
......@@ -109,7 +102,8 @@ static int vbi_buffer_prepare(struct file *file, struct videobuf_buffer *vb,
static void
vbi_buffer_queue(struct file *file, struct videobuf_buffer *vb)
{
struct bttv *btv = file->private_data;
struct bttv_fh *fh = file->private_data;
struct bttv *btv = fh->btv;
struct bttv_buffer *buf = (struct bttv_buffer*)vb;
dprintk("queue %p\n",vb);
......@@ -120,14 +114,15 @@ vbi_buffer_queue(struct file *file, struct videobuf_buffer *vb)
static void vbi_buffer_release(struct file *file, struct videobuf_buffer *vb)
{
struct bttv *btv = file->private_data;
struct bttv_fh *fh = file->private_data;
struct bttv *btv = fh->btv;
struct bttv_buffer *buf = (struct bttv_buffer*)vb;
dprintk("free %p\n",vb);
bttv_dma_free(btv,buf);
bttv_dma_free(fh->btv,buf);
}
struct videobuf_queue_ops vbi_qops = {
struct videobuf_queue_ops bttv_vbi_qops = {
buf_setup: vbi_buffer_setup,
buf_prepare: vbi_buffer_prepare,
buf_queue: vbi_buffer_queue,
......@@ -136,7 +131,7 @@ struct videobuf_queue_ops vbi_qops = {
/* ----------------------------------------------------------------------- */
static void vbi_setlines(struct bttv *btv, int lines)
void bttv_vbi_setlines(struct bttv_fh *fh, struct bttv *btv, int lines)
{
int vdelay;
......@@ -144,7 +139,7 @@ static void vbi_setlines(struct bttv *btv, int lines)
lines = 1;
if (lines > VBI_MAXLINES)
lines = VBI_MAXLINES;
btv->vbi.lines = lines;
fh->lines = lines;
vdelay = btread(BT848_E_VDELAY_LO);
if (vdelay < lines*2) {
......@@ -154,19 +149,18 @@ static void vbi_setlines(struct bttv *btv, int lines)
}
}
#ifdef HAVE_V4L2
static void vbi_fmt(struct bttv *btv, struct v4l2_format *f)
void bttv_vbi_fmt(struct bttv_fh *fh, struct v4l2_format *f)
{
memset(f,0,sizeof(*f));
f->type = V4L2_BUF_TYPE_VBI;
f->type = V4L2_BUF_TYPE_VBI_CAPTURE;
f->fmt.vbi.sampling_rate = 35468950;
f->fmt.vbi.samples_per_line = 2048;
f->fmt.vbi.sample_format = V4L2_VBI_SF_UBYTE;
f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
f->fmt.vbi.offset = 244;
f->fmt.vbi.count[0] = btv->vbi.lines;
f->fmt.vbi.count[1] = btv->vbi.lines;
f->fmt.vbi.count[0] = fh->lines;
f->fmt.vbi.count[1] = fh->lines;
f->fmt.vbi.flags = 0;
switch (btv->tvnorm) {
switch (fh->btv->tvnorm) {
case 1: /* NTSC */
f->fmt.vbi.start[0] = 10;
f->fmt.vbi.start[1] = 273;
......@@ -178,212 +172,8 @@ static void vbi_fmt(struct bttv *btv, struct v4l2_format *f)
f->fmt.vbi.start[1] = 319;
}
}
#endif
/* ----------------------------------------------------------------------- */
/* vbi interface */
static int vbi_open(struct inode *inode, struct file *file)
{
unsigned int minor = minor(inode->i_rdev);
struct bttv *btv = NULL;
int i;
for (i = 0; i < bttv_num; i++) {
if (bttvs[i].vbi_dev.minor == minor) {
btv = &bttvs[i];
break;
}
}
if (NULL == btv)
return -ENODEV;
down(&btv->vbi.q.lock);
if (btv->vbi.users) {
up(&btv->vbi.q.lock);
return -EBUSY;
}
dprintk("open minor=%d\n",minor);
file->private_data = btv;
btv->vbi.users++;
vbi_setlines(btv,VBI_DEFLINES);
bttv_field_count(btv);
up(&btv->vbi.q.lock);
return 0;
}
static int vbi_release(struct inode *inode, struct file *file)
{
struct bttv *btv = file->private_data;
if (btv->vbi.q.streaming)
videobuf_streamoff(file,&btv->vbi.q);
down(&btv->vbi.q.lock);
if (btv->vbi.q.reading)
videobuf_read_stop(file,&btv->vbi.q);
btv->vbi.users--;
bttv_field_count(btv);
vbi_setlines(btv,0);
up(&btv->vbi.q.lock);
return 0;
}
static int vbi_do_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *arg)
{
struct bttv *btv = file->private_data;
if (btv->errors)
bttv_reinit_bt848(btv);
switch (cmd) {
case VIDIOCGCAP:
{
struct video_capability *cap = arg;
memset(cap,0,sizeof(*cap));
strcpy(cap->name,btv->vbi_dev.name);
cap->type = VID_TYPE_TUNER|VID_TYPE_TELETEXT;
return 0;
}
/* vbi/teletext ioctls */
case BTTV_VBISIZE:
return btv->vbi.lines * 2 * 2048;
case BTTV_VERSION:
case VIDIOCGFREQ:
case VIDIOCSFREQ:
case VIDIOCGTUNER:
case VIDIOCSTUNER:
case VIDIOCGCHAN:
case VIDIOCSCHAN:
return bttv_common_ioctls(btv,cmd,arg);
#ifdef HAVE_V4L2
case VIDIOC_QUERYCAP:
{
struct v4l2_capability *cap = arg;
memset(cap,0,sizeof(*cap));
strcpy(cap->name, btv->name);
cap->type = V4L2_TYPE_VBI;
cap->flags = V4L2_FLAG_TUNER | V4L2_FLAG_READ |
V4L2_FLAG_STREAMING | V4L2_FLAG_SELECT;
return 0;
}
case VIDIOC_G_FMT:
{
struct v4l2_format *f = arg;
vbi_fmt(btv,f);
return 0;
}
case VIDIOC_S_FMT:
{
struct v4l2_format *f = arg;
if (btv->vbi.q.reading || btv->vbi.q.streaming)
return -EBUSY;
vbi_setlines(btv,f->fmt.vbi.count[0]);
vbi_fmt(btv,f);
return 0;
}
case VIDIOC_REQBUFS:
return videobuf_reqbufs(file,&btv->vbi.q,arg);
case VIDIOC_QUERYBUF:
return videobuf_querybuf(&btv->vbi.q, arg);
case VIDIOC_QBUF:
return videobuf_qbuf(file, &btv->vbi.q, arg);
case VIDIOC_DQBUF:
return videobuf_dqbuf(file, &btv->vbi.q, arg);
case VIDIOC_STREAMON:
return videobuf_streamon(file, &btv->vbi.q);
case VIDIOC_STREAMOFF:
return videobuf_streamoff(file, &btv->vbi.q);
case VIDIOC_ENUMSTD:
case VIDIOC_G_STD:
case VIDIOC_S_STD:
case VIDIOC_ENUMINPUT:
case VIDIOC_G_INPUT:
case VIDIOC_S_INPUT:
case VIDIOC_G_TUNER:
case VIDIOC_S_TUNER:
case VIDIOC_G_FREQ:
case VIDIOC_S_FREQ:
return bttv_common_ioctls(btv,cmd,arg);
#endif /* HAVE_V4L2 */
default:
return -ENOIOCTLCMD;
}
return 0;
}
static int vbi_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
return video_usercopy(inode, file, cmd, arg, vbi_do_ioctl);
}
static ssize_t vbi_read(struct file *file, char *data,
size_t count, loff_t *ppos)
{
struct bttv *btv = file->private_data;
if (btv->errors)
bttv_reinit_bt848(btv);
dprintk("read %d\n",count);
return videobuf_read_stream(file, &btv->vbi.q, data, count, ppos, 1);
}
static unsigned int vbi_poll(struct file *file, poll_table *wait)
{
struct bttv *btv = file->private_data;
dprintk("poll%s\n","");
return videobuf_poll_stream(file, &btv->vbi.q, wait);
}
static int
vbi_mmap(struct file *file, struct vm_area_struct * vma)
{
struct bttv *btv = file->private_data;
dprintk("mmap 0x%lx+%ld\n",vma->vm_start,
vma->vm_end - vma->vm_start);
return videobuf_mmap_mapper(vma, &btv->vbi.q);
}
static struct file_operations vbi_fops =
{
owner: THIS_MODULE,
open: vbi_open,
release: vbi_release,
ioctl: vbi_ioctl,
llseek: no_llseek,
read: vbi_read,
poll: vbi_poll,
mmap: vbi_mmap,
};
struct video_device bttv_vbi_template =
{
name: "bt848/878 vbi",
type: VID_TYPE_TUNER|VID_TYPE_TELETEXT,
hardware: VID_HARDWARE_BT848,
fops: &vbi_fops,
minor: -1,
};
/*
* Local variables:
* c-basic-offset: 8
......
......@@ -90,10 +90,26 @@
#define BTTV_SENSORAY311 0x49
#define BTTV_RV605 0x4a
#define BTTV_WINDVR 0x4c
#define BTTV_HAUPPAUGEPVR 0x50
#define BTTV_GVBCTV5PCI 0x51
#define BTTV_OSPREY1x0 0x52
#define BTTV_OSPREY1x0_848 0x53
#define BTTV_OSPREY101_848 0x54
#define BTTV_OSPREY1x1 0x55
#define BTTV_OSPREY1x1_SVID 0x56
#define BTTV_OSPREY2xx 0x57
#define BTTV_OSPREY2x0_SVID 0x58
#define BTTV_OSPREY2x0 0x59
#define BTTV_OSPREY500 0x5a
#define BTTV_OSPREY540 0x5b
#define BTTV_OSPREY2000 0x5c
#define BTTV_IDS_EAGLE 0x5d
/* i2c address list */
#define I2C_TSA5522 0xc2
#define I2C_TDA7432 0x8a
#define I2C_BT832_ALT1 0x88
#define I2C_BT832_ALT2 0x8a // alternate setting
#define I2C_TDA8425 0x82
#define I2C_TDA9840 0x84
#define I2C_TDA9850 0xb6 /* also used by 9855,9873 */
......@@ -105,6 +121,7 @@
#define I2C_MSP3400 0x80
#define I2C_TEA6300 0x80
#define I2C_DPL3518 0x84
#define I2C_TDA9887 0x86
/* more card-specific defines */
#define PT2254_L_CHANNEL 0x10
......@@ -132,6 +149,7 @@ struct tvcard
/* i2c audio flags */
int no_msp34xx:1;
int no_tda9875:1;
int no_tda7432:1;
int needs_tvaudio:1;
/* other settings */
......@@ -174,6 +192,7 @@ extern int bttv_handle_chipset(struct bttv *btv);
returns negative value if error occurred
*/
extern int bttv_get_cardinfo(unsigned int card, int *type, int *cardid);
extern struct pci_dev* bttv_get_pcidev(unsigned int card);
/* obsolete, use bttv_get_cardinfo instead */
extern int bttv_get_id(unsigned int card);
......@@ -208,6 +227,11 @@ extern int bttv_write_gpio(unsigned int card,
*/
extern wait_queue_head_t* bttv_get_gpio_queue(unsigned int card);
/* call i2c clients
*/
extern void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg);
/* i2c */
#define I2C_CLIENTS_MAX 16
extern void bttv_bit_setscl(void *data, int state);
......
......@@ -24,7 +24,7 @@
#ifndef _BTTVP_H_
#define _BTTVP_H_
#define BTTV_VERSION_CODE KERNEL_VERSION(0,8,42)
#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,1)
#include <linux/types.h>
#include <linux/wait.h>
......@@ -54,7 +54,8 @@
#define RISC_SLOT_LOOP 14
#define RESOURCE_OVERLAY 1
#define RESOURCE_STREAMING 2
#define RESOURCE_VIDEO 2
#define RESOURCE_VBI 3
#define RAW_LINES 640
#define RAW_BPL 1024
......@@ -63,15 +64,17 @@
struct bttv_tvnorm
{
int v4l2_id;
u32 Fsc;
u16 swidth, sheight; /* scaled standard width, height */
u16 totalwidth;
u8 adelay, bdelay, iform;
u32 scaledtwidth;
u16 hdelayx1, hactivex1;
u16 vdelay;
u8 vbipack;
int v4l2_id;
char *name;
u32 Fsc;
u16 swidth, sheight; /* scaled standard width, height */
u16 totalwidth;
u8 adelay, bdelay, iform;
u32 scaledtwidth;
u16 hdelayx1, hactivex1;
u16 vdelay;
u8 vbipack;
int sram;
};
extern const struct bttv_tvnorm bttv_tvnorms[];
extern const int BTTV_TVNORMS;
......@@ -99,8 +102,8 @@ struct bttv_geometry {
struct bttv_riscmem {
unsigned int size;
unsigned long *cpu;
unsigned long *jmp;
u32 *cpu;
u32 *jmp;
dma_addr_t dma;
};
......@@ -114,32 +117,34 @@ struct bttv_buffer {
int btformat;
int btswap;
struct bttv_geometry geo;
struct bttv_riscmem even;
struct bttv_riscmem odd;
struct bttv_riscmem top;
struct bttv_riscmem bottom;
};
struct bttv_overlay {
int tvnorm;
int x,y,width,height;
struct video_clip *clips;
struct v4l2_rect w;
enum v4l2_field field;
struct v4l2_clip *clips;
int nclips;
};
struct bttv_vbi {
int users;
int lines;
struct videobuf_queue q;
};
struct bttv_fh {
struct bttv *btv;
struct videobuf_queue q;
int resources;
enum v4l2_buf_type type;
/* video capture */
struct videobuf_queue cap;
struct bttv_buffer buf;
/* current settings */
const struct bttv_format *ovfmt;
struct bttv_overlay ov;
struct bttv_buffer buf;
/* video overlay */
struct videobuf_queue vbi;
int lines;
};
/* ---------------------------------------------------------- */
......@@ -163,18 +168,18 @@ int bttv_risc_planar(struct bttv *btv, struct bttv_riscmem *risc,
int cpadding);
/* risc code generator + helpers - screen overlay */
int bttv_screen_clips(struct video_buffer *fbuf,
int x, int y, int width, int height,
struct video_clip *clips, int n);
void bttv_sort_clips(struct video_clip *clips, int nclips);
int bttv_screen_clips(int swidth, int sheight, struct v4l2_rect *win,
struct v4l2_clip *clips, int n);
void bttv_sort_clips(struct v4l2_clip *clips, int nclips);
int bttv_risc_overlay(struct bttv *btv, struct bttv_riscmem *risc,
const struct bttv_format *fmt,
struct bttv_overlay *ov, int flags);
struct bttv_overlay *ov,
int skip_top, int skip_bottom);
/* calculate / apply geometry settings */
void bttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo,
int width, int height, int interleaved, int norm);
void bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd);
void bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int top);
/* control dma register + risc main loop */
void bttv_set_dma(struct bttv *btv, int override, int irqflags);
......@@ -183,11 +188,9 @@ int bttv_risc_hook(struct bttv *btv, int slot, struct bttv_riscmem *risc,
int irqflags);
/* capture buffer handling */
int bttv_buffer_field(struct bttv *btv, int field, int def_field,
int tvnorm, int height);
int bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf);
int bttv_buffer_activate(struct bttv *btv, struct bttv_buffer *odd,
struct bttv_buffer *even);
int bttv_buffer_activate(struct bttv *btv, struct bttv_buffer *top,
struct bttv_buffer *bottom);
void bttv_dma_free(struct bttv *btv, struct bttv_buffer *buf);
/* overlay handling */
......@@ -199,8 +202,10 @@ int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov,
/* ---------------------------------------------------------- */
/* bttv-vbi.c */
extern struct video_device bttv_vbi_template;
extern struct videobuf_queue_ops vbi_qops;
void bttv_vbi_fmt(struct bttv_fh *fh, struct v4l2_format *f);
void bttv_vbi_setlines(struct bttv_fh *fh, struct bttv *btv, int lines);
extern struct videobuf_queue_ops bttv_vbi_qops;
/* ---------------------------------------------------------- */
......@@ -212,6 +217,7 @@ extern unsigned int bttv_debug;
extern unsigned int bttv_gpio;
extern void bttv_gpio_tracking(struct bttv *btv, char *comment);
extern int init_bttv_i2c(struct bttv *btv);
extern int pvr_boot(struct bttv *btv);
extern int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg);
extern void bttv_reinit_bt848(struct bttv *btv);
......@@ -285,6 +291,7 @@ struct bttv {
int tvnorm,hue,contrast,bright,saturation;
struct video_buffer fbuf;
int field_count;
int digital_video;
/* various options */
int opt_combfilter;
......@@ -293,27 +300,32 @@ struct bttv {
int opt_chroma_agc;
int opt_adc_crush;
/* vbi data/state */
struct bttv_vbi vbi;
/* radio data/state */
int has_radio;
int radio_user;
/* miro/pinnacle + Aimslab VHX
philips matchbox (tea5757 radio tuner) support */
int has_matchbox;
int mbox_we;
int mbox_we;
int mbox_data;
int mbox_clk;
int mbox_most;
int mbox_mask;
int radio_user;
/* ISA stuff (Terratec Active Radio Upgrade) */
int mbox_ior;
int mbox_iow;
int mbox_csel;
/* risc memory management data
- must aquire s_lock before changing these
- only the irq handler is supported to touch odd + even */
struct bttv_riscmem main;
struct bttv_buffer *odd; /* current active odd field */
struct bttv_buffer *even; /* current active even field */
struct bttv_buffer *screen; /* overlay */
struct list_head capture; /* capture buffer queue */
struct bttv_buffer *top; /* current active top field */
struct bttv_buffer *bottom; /* current active bottom field */
struct bttv_buffer *screen; /* overlay */
struct list_head capture; /* capture buffer queue */
struct bttv_buffer *vcurr;
struct list_head vcapture;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment