aboutsummaryrefslogtreecommitdiff
path: root/drivers/media/video
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video')
-rw-r--r--drivers/media/video/Kconfig77
-rw-r--r--drivers/media/video/Makefile10
-rw-r--r--drivers/media/video/arv.c13
-rw-r--r--drivers/media/video/bt832.c89
-rw-r--r--drivers/media/video/bt832.h4
-rw-r--r--drivers/media/video/bttv-cards.c5329
-rw-r--r--drivers/media/video/bttv-driver.c389
-rw-r--r--drivers/media/video/bttv-gpio.c20
-rw-r--r--drivers/media/video/bttv-i2c.c61
-rw-r--r--drivers/media/video/bttv-if.c4
-rw-r--r--drivers/media/video/bttv-risc.c110
-rw-r--r--drivers/media/video/bttv.h285
-rw-r--r--drivers/media/video/bttvp.h16
-rw-r--r--drivers/media/video/cs53l32a.c240
-rw-r--r--drivers/media/video/cx25840/Makefile6
-rw-r--r--drivers/media/video/cx25840/cx25840-audio.c368
-rw-r--r--drivers/media/video/cx25840/cx25840-core.c1020
-rw-r--r--drivers/media/video/cx25840/cx25840-firmware.c167
-rw-r--r--drivers/media/video/cx25840/cx25840-vbi.c315
-rw-r--r--drivers/media/video/cx25840/cx25840.h85
-rw-r--r--drivers/media/video/cx88/Kconfig91
-rw-r--r--drivers/media/video/cx88/Makefile6
-rw-r--r--drivers/media/video/cx88/cx88-blackbird.c677
-rw-r--r--drivers/media/video/cx88/cx88-cards.c474
-rw-r--r--drivers/media/video/cx88/cx88-core.c55
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c56
-rw-r--r--drivers/media/video/cx88/cx88-i2c.c22
-rw-r--r--drivers/media/video/cx88/cx88-input.c2
-rw-r--r--drivers/media/video/cx88/cx88-mpeg.c25
-rw-r--r--drivers/media/video/cx88/cx88-reg.h12
-rw-r--r--drivers/media/video/cx88/cx88-tvaudio.c1184
-rw-r--r--drivers/media/video/cx88/cx88-video.c38
-rw-r--r--drivers/media/video/cx88/cx88.h55
-rw-r--r--drivers/media/video/em28xx/Kconfig12
-rw-r--r--drivers/media/video/em28xx/Makefile6
-rw-r--r--drivers/media/video/em28xx/em28xx-cards.c292
-rw-r--r--drivers/media/video/em28xx/em28xx-core.c817
-rw-r--r--drivers/media/video/em28xx/em28xx-i2c.c586
-rw-r--r--drivers/media/video/em28xx/em28xx-input.c181
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c1933
-rw-r--r--drivers/media/video/em28xx/em28xx.h513
-rw-r--r--drivers/media/video/indycam.c262
-rw-r--r--drivers/media/video/indycam.h88
-rw-r--r--drivers/media/video/ir-kbd-gpio.c391
-rw-r--r--drivers/media/video/ir-kbd-i2c.c196
-rw-r--r--drivers/media/video/msp3400.c966
-rw-r--r--drivers/media/video/mt20xx.c206
-rw-r--r--drivers/media/video/saa6588.c11
-rw-r--r--drivers/media/video/saa7115.c1376
-rw-r--r--drivers/media/video/saa711x.c592
-rw-r--r--drivers/media/video/saa7127.c849
-rw-r--r--drivers/media/video/saa7134/Kconfig69
-rw-r--r--drivers/media/video/saa7134/Makefile14
-rw-r--r--drivers/media/video/saa7134/saa6752hs.c187
-rw-r--r--drivers/media/video/saa7134/saa7134-alsa.c1013
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c619
-rw-r--r--drivers/media/video/saa7134/saa7134-core.c173
-rw-r--r--drivers/media/video/saa7134/saa7134-dvb.c370
-rw-r--r--drivers/media/video/saa7134/saa7134-empress.c6
-rw-r--r--drivers/media/video/saa7134/saa7134-i2c.c28
-rw-r--r--drivers/media/video/saa7134/saa7134-input.c294
-rw-r--r--drivers/media/video/saa7134/saa7134-oss.c534
-rw-r--r--drivers/media/video/saa7134/saa7134-reg.h27
-rw-r--r--drivers/media/video/saa7134/saa7134-ts.c29
-rw-r--r--drivers/media/video/saa7134/saa7134-tvaudio.c27
-rw-r--r--drivers/media/video/saa7134/saa7134-video.c185
-rw-r--r--drivers/media/video/saa7134/saa7134.h64
-rw-r--r--drivers/media/video/saa7191.c533
-rw-r--r--drivers/media/video/saa7191.h172
-rw-r--r--drivers/media/video/tda7432.c17
-rw-r--r--drivers/media/video/tda8290.c685
-rw-r--r--drivers/media/video/tda9875.c57
-rw-r--r--drivers/media/video/tda9887.c163
-rw-r--r--drivers/media/video/tea5767.c8
-rw-r--r--drivers/media/video/tuner-core.c85
-rw-r--r--drivers/media/video/tuner-simple.c145
-rw-r--r--drivers/media/video/tvaudio.c23
-rw-r--r--drivers/media/video/tveeprom.c458
-rw-r--r--drivers/media/video/tvmixer.c54
-rw-r--r--drivers/media/video/tvp5150.c829
-rw-r--r--drivers/media/video/tvp5150_reg.h173
-rw-r--r--drivers/media/video/v4l1-compat.c12
-rw-r--r--drivers/media/video/video-buf.c18
-rw-r--r--drivers/media/video/videocodec.c6
-rw-r--r--drivers/media/video/videodev.c3
-rw-r--r--drivers/media/video/vino.c1170
-rw-r--r--drivers/media/video/wm8775.c259
-rw-r--r--drivers/media/video/zoran_card.c14
-rw-r--r--drivers/media/video/zoran_driver.c4
-rw-r--r--drivers/media/video/zr36016.c1
-rw-r--r--drivers/media/video/zr36050.c1
-rw-r--r--drivers/media/video/zr36060.c1
92 files changed, 22769 insertions, 6343 deletions
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index bbb989df4cf..1a3b3c7e5e9 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -25,6 +25,16 @@ config VIDEO_BT848
To compile this driver as a module, choose M here: the
module will be called bttv.
+config VIDEO_BT848_DVB
+ tristate "DVB/ATSC Support for bt878 based TV cards"
+ depends on VIDEO_BT848 && DVB_CORE
+ select DVB_BT8XX
+ ---help---
+ This adds support for DVB/ATSC cards based on the BT878 chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called dvb-bt8xx.
+
config VIDEO_SAA6588
tristate "SAA6588 Radio Chip RDS decoder support on BT848 cards"
depends on VIDEO_DEV && I2C && VIDEO_BT848
@@ -243,29 +253,7 @@ config VIDEO_MEYE
To compile this driver as a module, choose M here: the
module will be called meye.
-config VIDEO_SAA7134
- tristate "Philips SAA7134 support"
- depends on VIDEO_DEV && PCI && I2C && SOUND
- select VIDEO_BUF
- select VIDEO_IR
- select VIDEO_TUNER
- select CRC32
- ---help---
- This is a video4linux driver for Philips SAA7130/7134 based
- TV cards.
-
- To compile this driver as a module, choose M here: the
- module will be called saa7134.
-
-config VIDEO_SAA7134_DVB
- tristate "DVB Support for saa7134 based TV cards"
- depends on VIDEO_SAA7134 && DVB_CORE
- select VIDEO_BUF_DVB
- select DVB_MT352
- select DVB_TDA1004X
- ---help---
- This adds support for DVB cards based on the
- Philips saa7134 chip.
+source "drivers/media/video/saa7134/Kconfig"
config VIDEO_MXB
tristate "Siemens-Nixdorf 'Multimedia eXtension Board'"
@@ -316,34 +304,9 @@ config VIDEO_HEXIUM_GEMINI
To compile this driver as a module, choose M here: the
module will be called hexium_gemini.
-config VIDEO_CX88
- tristate "Conexant 2388x (bt878 successor) support"
- depends on VIDEO_DEV && PCI && I2C && EXPERIMENTAL
- select I2C_ALGOBIT
- select FW_LOADER
- select VIDEO_BTCX
- select VIDEO_BUF
- select VIDEO_TUNER
- select VIDEO_TVEEPROM
- select VIDEO_IR
- ---help---
- This is a video4linux driver for Conexant 2388x based
- TV cards.
+source "drivers/media/video/cx88/Kconfig"
- To compile this driver as a module, choose M here: the
- module will be called cx8800
-
-config VIDEO_CX88_DVB
- tristate "DVB Support for cx2388x based TV cards"
- depends on VIDEO_CX88 && DVB_CORE
- select VIDEO_BUF_DVB
- select DVB_MT352
- select DVB_OR51132
- select DVB_CX22702
- select DVB_LGDT330X
- ---help---
- This adds support for DVB/ATSC cards based on the
- Connexant 2388x chip.
+source "drivers/media/video/em28xx/Kconfig"
config VIDEO_OVCAMCHIP
tristate "OmniVision Camera Chip support"
@@ -370,4 +333,18 @@ config VIDEO_M32R_AR_M64278
Say Y here to use the Renesas M64278E-800 camera module,
which supports VGA(640x480 pixcels) size of images.
+config VIDEO_AUDIO_DECODER
+ tristate "Add support for additional audio chipsets"
+ depends on VIDEO_DEV && I2C && EXPERIMENTAL
+ ---help---
+ Say Y here to compile drivers for WM8775 and CS53L32A audio
+ decoders.
+
+config VIDEO_DECODER
+ tristate "Add support for additional video chipsets"
+ depends on VIDEO_DEV && I2C && EXPERIMENTAL
+ ---help---
+ Say Y here to compile drivers for SAA7115, SAA7127 and CX25840
+ video decoders.
+
endmenu
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 046b82de928..82060f9909d 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -5,7 +5,6 @@
bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \
bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o
zoran-objs := zr36120.o zr36120_i2c.o zr36120_mem.o
-rds-objs := saa6588.o
zr36067-objs := zoran_procfs.o zoran_device.o \
zoran_driver.o zoran_card.o
tuner-objs := tuner-core.o tuner-simple.o mt20xx.o tda8290.o tea5767.o
@@ -16,7 +15,7 @@ obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tvaudio.o \
obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o
obj-$(CONFIG_VIDEO_ZR36120) += zoran.o
-obj-$(CONFIG_VIDEO_SAA6588) += rds.o
+obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o
obj-$(CONFIG_VIDEO_SAA5246A) += saa5246a.o
obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o
obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o
@@ -37,8 +36,11 @@ obj-$(CONFIG_VIDEO_CPIA) += cpia.o
obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o
obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o
obj-$(CONFIG_VIDEO_MEYE) += meye.o
-obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
+obj-$(CONFIG_VIDEO_SAA7134) += ir-kbd-i2c.o saa7134/
obj-$(CONFIG_VIDEO_CX88) += cx88/
+obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
+obj-$(CONFIG_VIDEO_EM28XX) += saa711x.o tvp5150.o
+obj-$(CONFIG_VIDEO_AUDIO_DECODER) += wm8775.o cs53l32a.o
obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/
obj-$(CONFIG_VIDEO_MXB) += saa7111.o tuner.o tda9840.o tea6415c.o tea6420.o mxb.o
obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o
@@ -54,4 +56,6 @@ obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o
+obj-$(CONFIG_VIDEO_DECODER) += saa7115.o cx25840/ saa7127.o
+
EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core
diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c
index 87fd3a7bb39..881cdcb1875 100644
--- a/drivers/media/video/arv.c
+++ b/drivers/media/video/arv.c
@@ -22,7 +22,6 @@
#include <linux/init.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/fs.h>
@@ -865,10 +864,8 @@ out_dev:
out_irq:
#endif
- for (i = 0; i < MAX_AR_HEIGHT; i++) {
- if (ar->frame[i])
- kfree(ar->frame[i]);
- }
+ for (i = 0; i < MAX_AR_HEIGHT; i++)
+ kfree(ar->frame[i]);
out_line_buff:
#if USE_INT
@@ -899,10 +896,8 @@ static void __exit ar_cleanup_module(void)
#if USE_INT
free_irq(M32R_IRQ_INT3, ar);
#endif
- for (i = 0; i < MAX_AR_HEIGHT; i++) {
- if (ar->frame[i])
- kfree(ar->frame[i]);
- }
+ for (i = 0; i < MAX_AR_HEIGHT; i++)
+ kfree(ar->frame[i]);
#if USE_INT
kfree(ar->line_buff);
#endif
diff --git a/drivers/media/video/bt832.c b/drivers/media/video/bt832.c
index 76c1b63ebdf..e4063950ae5 100644
--- a/drivers/media/video/bt832.c
+++ b/drivers/media/video/bt832.c
@@ -32,7 +32,6 @@
#include <linux/slab.h>
#include <media/audiochip.h>
-#include <media/id.h>
#include "bttv.h"
#include "bt832.h"
@@ -54,36 +53,36 @@ static struct i2c_driver driver;
static struct i2c_client client_template;
struct bt832 {
- struct i2c_client client;
+ struct i2c_client client;
};
int bt832_hexdump(struct i2c_client *i2c_client_s, unsigned char *buf)
{
int i,rc;
buf[0]=0x80; // start at register 0 with auto-increment
- if (1 != (rc = i2c_master_send(i2c_client_s,buf,1)))
- printk("bt832: i2c i/o error: rc == %d (should be 1)\n",rc);
+ if (1 != (rc = i2c_master_send(i2c_client_s,buf,1)))
+ printk("bt832: i2c i/o error: rc == %d (should be 1)\n",rc);
- for(i=0;i<65;i++)
- buf[i]=0;
- if (65 != (rc=i2c_master_recv(i2c_client_s,buf,65)))
- printk("bt832: i2c i/o error: rc == %d (should be 65)\n",rc);
+ for(i=0;i<65;i++)
+ buf[i]=0;
+ if (65 != (rc=i2c_master_recv(i2c_client_s,buf,65)))
+ printk("bt832: i2c i/o error: rc == %d (should be 65)\n",rc);
- // Note: On READ the first byte is the current index
- // (e.g. 0x80, what we just wrote)
+ // Note: On READ the first byte is the current index
+ // (e.g. 0x80, what we just wrote)
- if(1) {
- int i;
- printk("BT832 hexdump:\n");
- for(i=1;i<65;i++) {
+ if(1) {
+ int i;
+ printk("BT832 hexdump:\n");
+ for(i=1;i<65;i++) {
if(i!=1) {
if(((i-1)%8)==0) printk(" ");
- if(((i-1)%16)==0) printk("\n");
+ if(((i-1)%16)==0) printk("\n");
}
- printk(" %02x",buf[i]);
- }
- printk("\n");
- }
+ printk(" %02x",buf[i]);
+ }
+ printk("\n");
+ }
return 0;
}
@@ -102,13 +101,13 @@ int bt832_init(struct i2c_client *i2c_client_s)
return 0;
}
- printk("Write 0 tp VPSTATUS\n");
- buf[0]=BT832_VP_STATUS; // Reg.52
- buf[1]= 0x00;
- if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
- printk("bt832: i2c i/o error VPS: rc == %d (should be 2)\n",rc);
+ printk("Write 0 tp VPSTATUS\n");
+ buf[0]=BT832_VP_STATUS; // Reg.52
+ buf[1]= 0x00;
+ if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
+ printk("bt832: i2c i/o error VPS: rc == %d (should be 2)\n",rc);
- bt832_hexdump(i2c_client_s,buf);
+ bt832_hexdump(i2c_client_s,buf);
// Leave low power mode:
@@ -116,17 +115,17 @@ int bt832_init(struct i2c_client *i2c_client_s)
buf[0]=BT832_CAM_SETUP0; //0x39 57
buf[1]=0x08;
if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
- printk("bt832: i2c i/o error LLPM: rc == %d (should be 2)\n",rc);
+ printk("bt832: i2c i/o error LLPM: rc == %d (should be 2)\n",rc);
- bt832_hexdump(i2c_client_s,buf);
+ bt832_hexdump(i2c_client_s,buf);
printk("Write 0 tp VPSTATUS\n");
- buf[0]=BT832_VP_STATUS; // Reg.52
- buf[1]= 0x00;
- if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
- printk("bt832: i2c i/o error VPS: rc == %d (should be 2)\n",rc);
+ buf[0]=BT832_VP_STATUS; // Reg.52
+ buf[1]= 0x00;
+ if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
+ printk("bt832: i2c i/o error VPS: rc == %d (should be 2)\n",rc);
- bt832_hexdump(i2c_client_s,buf);
+ bt832_hexdump(i2c_client_s,buf);
// Enable Output
@@ -134,22 +133,22 @@ int bt832_init(struct i2c_client *i2c_client_s)
buf[0]=BT832_VP_CONTROL1; // Reg.40
buf[1]= 0x27 & (~0x01); // Default | !skip
if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
- printk("bt832: i2c i/o error EO: rc == %d (should be 2)\n",rc);
+ printk("bt832: i2c i/o error EO: rc == %d (should be 2)\n",rc);
- bt832_hexdump(i2c_client_s,buf);
+ bt832_hexdump(i2c_client_s,buf);
// for testing (even works when no camera attached)
printk("bt832: *** Generate NTSC M Bars *****\n");
buf[0]=BT832_VP_TESTCONTROL0; // Reg. 42
buf[1]=3; // Generate NTSC System M bars, Generate Frame timing internally
- if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
- printk("bt832: i2c i/o error MBAR: rc == %d (should be 2)\n",rc);
+ if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
+ printk("bt832: i2c i/o error MBAR: rc == %d (should be 2)\n",rc);
printk("Bt832: Camera Present: %s\n",
(buf[1+BT832_CAM_STATUS] & BT832_56_CAMERA_PRESENT) ? "yes":"no");
- bt832_hexdump(i2c_client_s,buf);
+ bt832_hexdump(i2c_client_s,buf);
kfree(buf);
return 1;
}
@@ -162,17 +161,17 @@ static int bt832_attach(struct i2c_adapter *adap, int addr, int kind)
printk("bt832_attach\n");
- client_template.adapter = adap;
- client_template.addr = addr;
+ client_template.adapter = adap;
+ client_template.addr = addr;
- printk("bt832: chip found @ 0x%x\n", addr<<1);
+ printk("bt832: chip found @ 0x%x\n", addr<<1);
- if (NULL == (t = kmalloc(sizeof(*t), GFP_KERNEL)))
- return -ENOMEM;
+ if (NULL == (t = kmalloc(sizeof(*t), GFP_KERNEL)))
+ return -ENOMEM;
memset(t,0,sizeof(*t));
t->client = client_template;
- i2c_set_clientdata(&t->client, t);
- i2c_attach_client(&t->client);
+ i2c_set_clientdata(&t->client, t);
+ i2c_attach_client(&t->client);
if(! bt832_init(&t->client)) {
bt832_detach(&t->client);
@@ -211,7 +210,7 @@ bt832_command(struct i2c_client *client, unsigned int cmd, void *arg)
printk("bt832: command %x\n",cmd);
- switch (cmd) {
+ switch (cmd) {
case BT832_HEXDUMP: {
unsigned char *buf;
buf=kmalloc(65,GFP_KERNEL);
diff --git a/drivers/media/video/bt832.h b/drivers/media/video/bt832.h
index 9b6a8d2c96b..1ce8fa71f7d 100644
--- a/drivers/media/video/bt832.h
+++ b/drivers/media/video/bt832.h
@@ -233,8 +233,8 @@ SetInterlaceMode( spec.interlace );
/* from web:
Video Sampling
Digital video is a sampled form of analog video. The most common sampling schemes in use today are:
- Pixel Clock Horiz Horiz Vert
- Rate Total Active
+ Pixel Clock Horiz Horiz Vert
+ Rate Total Active
NTSC square pixel 12.27 MHz 780 640 525
NTSC CCIR-601 13.5 MHz 858 720 525
NTSC 4FSc 14.32 MHz 910 768 525
diff --git a/drivers/media/video/bttv-cards.c b/drivers/media/video/bttv-cards.c
index 0881a17d522..e31ebb11c46 100644
--- a/drivers/media/video/bttv-cards.c
+++ b/drivers/media/video/bttv-cards.c
@@ -6,7 +6,7 @@
like the big tvcards array for the most part
Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
- & Marcus Metzler (mocm@thp.uni-koeln.de)
+ & Marcus Metzler (mocm@thp.uni-koeln.de)
(c) 1999-2001 Gerd Knorr <kraxel@goldbach.in-berlin.de>
This program is free software; you can redistribute it and/or modify
@@ -145,162 +145,163 @@ static struct CARD {
int cardnr;
char *name;
} cards[] __devinitdata = {
- { 0x13eb0070, BTTV_HAUPPAUGE878, "Hauppauge WinTV" },
- { 0x39000070, BTTV_HAUPPAUGE878, "Hauppauge WinTV-D" },
- { 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_WINFASTVC100, "Leadtek WinFast VC 100" },
- { 0x6609107d, BTTV_WINFAST2000, "Leadtek TV 2000 XP" },
- { 0x263610b4, BTTV_STB2, "STB TV PCI FM, Gateway P/N 6000704" },
- { 0x264510b4, BTTV_STB2, "STB TV PCI FM, Gateway P/N 6000704" },
- { 0x402010fc, BTTV_GVBCTV3PCI, "I-O Data Co. GV-BCTV3/PCI" },
- { 0x405010fc, BTTV_GVBCTV4PCI, "I-O Data Co. GV-BCTV4/PCI" },
- { 0x407010fc, BTTV_GVBCTV5PCI, "I-O Data Co. GV-BCTV5/PCI" },
- { 0xd01810fc, BTTV_GVBCTV5PCI, "I-O Data Co. GV-BCTV5/PCI" },
-
- { 0x001211bd, BTTV_PINNACLE, "Pinnacle PCTV" },
+ { 0x13eb0070, BTTV_BOARD_HAUPPAUGE878, "Hauppauge WinTV" },
+ { 0x39000070, BTTV_BOARD_HAUPPAUGE878, "Hauppauge WinTV-D" },
+ { 0x45000070, BTTV_BOARD_HAUPPAUGEPVR, "Hauppauge WinTV/PVR" },
+ { 0xff000070, BTTV_BOARD_OSPREY1x0, "Osprey-100" },
+ { 0xff010070, BTTV_BOARD_OSPREY2x0_SVID,"Osprey-200" },
+ { 0xff020070, BTTV_BOARD_OSPREY500, "Osprey-500" },
+ { 0xff030070, BTTV_BOARD_OSPREY2000, "Osprey-2000" },
+ { 0xff040070, BTTV_BOARD_OSPREY540, "Osprey-540" },
+ { 0xff070070, BTTV_BOARD_OSPREY440, "Osprey-440" },
+
+ { 0x00011002, BTTV_BOARD_ATI_TVWONDER, "ATI TV Wonder" },
+ { 0x00031002, BTTV_BOARD_ATI_TVWONDERVE,"ATI TV Wonder/VE" },
+
+ { 0x6606107d, BTTV_BOARD_WINFAST2000, "Leadtek WinFast TV 2000" },
+ { 0x6607107d, BTTV_BOARD_WINFASTVC100, "Leadtek WinFast VC 100" },
+ { 0x6609107d, BTTV_BOARD_WINFAST2000, "Leadtek TV 2000 XP" },
+ { 0x263610b4, BTTV_BOARD_STB2, "STB TV PCI FM, Gateway P/N 6000704" },
+ { 0x264510b4, BTTV_BOARD_STB2, "STB TV PCI FM, Gateway P/N 6000704" },
+ { 0x402010fc, BTTV_BOARD_GVBCTV3PCI, "I-O Data Co. GV-BCTV3/PCI" },
+ { 0x405010fc, BTTV_BOARD_GVBCTV4PCI, "I-O Data Co. GV-BCTV4/PCI" },
+ { 0x407010fc, BTTV_BOARD_GVBCTV5PCI, "I-O Data Co. GV-BCTV5/PCI" },
+ { 0xd01810fc, BTTV_BOARD_GVBCTV5PCI, "I-O Data Co. GV-BCTV5/PCI" },
+
+ { 0x001211bd, BTTV_BOARD_PINNACLE, "Pinnacle PCTV" },
/* some cards ship with byteswapped IDs ... */
- { 0x1200bd11, BTTV_PINNACLE, "Pinnacle PCTV [bswap]" },
- { 0xff00bd11, BTTV_PINNACLE, "Pinnacle PCTV [bswap]" },
+ { 0x1200bd11, BTTV_BOARD_PINNACLE, "Pinnacle PCTV [bswap]" },
+ { 0xff00bd11, BTTV_BOARD_PINNACLE, "Pinnacle PCTV [bswap]" },
/* this seems to happen as well ... */
- { 0xff1211bd, BTTV_PINNACLE, "Pinnacle PCTV" },
-
- { 0x3000121a, BTTV_VOODOOTV_FM, "3Dfx VoodooTV FM/ VoodooTV 200" },
- { 0x263710b4, BTTV_VOODOOTV_FM, "3Dfx VoodooTV FM/ VoodooTV 200" },
- { 0x3060121a, BTTV_STB2, "3Dfx VoodooTV 100/ STB OEM" },
-
- { 0x3000144f, BTTV_MAGICTVIEW063, "(Askey Magic/others) TView99 CPH06x" },
- { 0xa005144f, BTTV_MAGICTVIEW063, "CPH06X TView99-Card" },
- { 0x3002144f, BTTV_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH05x" },
- { 0x3005144f, BTTV_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH061/06L (T1/LC)" },
- { 0x5000144f, BTTV_MAGICTVIEW061, "Askey CPH050" },
- { 0x300014ff, BTTV_MAGICTVIEW061, "TView 99 (CPH061)" },
- { 0x300214ff, BTTV_PHOEBE_TVMAS, "Phoebe TV Master (CPH060)" },
-
- { 0x00011461, BTTV_AVPHONE98, "AVerMedia TVPhone98" },
- { 0x00021461, BTTV_AVERMEDIA98, "AVermedia TVCapture 98" },
- { 0x00031461, BTTV_AVPHONE98, "AVerMedia TVPhone98" },
- { 0x00041461, BTTV_AVERMEDIA98, "AVerMedia TVCapture 98" },
- { 0x03001461, BTTV_AVERMEDIA98, "VDOMATE TV TUNER CARD" },
-
- { 0x1117153b, BTTV_TERRATVALUE, "Terratec TValue (Philips PAL B/G)" },
- { 0x1118153b, BTTV_TERRATVALUE, "Terratec TValue (Temic PAL B/G)" },
- { 0x1119153b, BTTV_TERRATVALUE, "Terratec TValue (Philips PAL I)" },
- { 0x111a153b, BTTV_TERRATVALUE, "Terratec TValue (Temic PAL I)" },
-
- { 0x1123153b, BTTV_TERRATVRADIO, "Terratec TV Radio+" },
- { 0x1127153b, BTTV_TERRATV, "Terratec TV+ (V1.05)" },
+ { 0xff1211bd, BTTV_BOARD_PINNACLE, "Pinnacle PCTV" },
+
+ { 0x3000121a, BTTV_BOARD_VOODOOTV_FM, "3Dfx VoodooTV FM/ VoodooTV 200" },
+ { 0x263710b4, BTTV_BOARD_VOODOOTV_FM, "3Dfx VoodooTV FM/ VoodooTV 200" },
+ { 0x3060121a, BTTV_BOARD_STB2, "3Dfx VoodooTV 100/ STB OEM" },
+
+ { 0x3000144f, BTTV_BOARD_MAGICTVIEW063, "(Askey Magic/others) TView99 CPH06x" },
+ { 0xa005144f, BTTV_BOARD_MAGICTVIEW063, "CPH06X TView99-Card" },
+ { 0x3002144f, BTTV_BOARD_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH05x" },
+ { 0x3005144f, BTTV_BOARD_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH061/06L (T1/LC)" },
+ { 0x5000144f, BTTV_BOARD_MAGICTVIEW061, "Askey CPH050" },
+ { 0x300014ff, BTTV_BOARD_MAGICTVIEW061, "TView 99 (CPH061)" },
+ { 0x300214ff, BTTV_BOARD_PHOEBE_TVMAS, "Phoebe TV Master (CPH060)" },
+
+ { 0x00011461, BTTV_BOARD_AVPHONE98, "AVerMedia TVPhone98" },
+ { 0x00021461, BTTV_BOARD_AVERMEDIA98, "AVermedia TVCapture 98" },
+ { 0x00031461, BTTV_BOARD_AVPHONE98, "AVerMedia TVPhone98" },
+ { 0x00041461, BTTV_BOARD_AVERMEDIA98, "AVerMedia TVCapture 98" },
+ { 0x03001461, BTTV_BOARD_AVERMEDIA98, "VDOMATE TV TUNER CARD" },
+
+ { 0x1117153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue (Philips PAL B/G)" },
+ { 0x1118153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue (Temic PAL B/G)" },
+ { 0x1119153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue (Philips PAL I)" },
+ { 0x111a153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue (Temic PAL I)" },
+
+ { 0x1123153b, BTTV_BOARD_TERRATVRADIO, "Terratec TV Radio+" },
+ { 0x1127153b, BTTV_BOARD_TERRATV, "Terratec TV+ (V1.05)" },
/* clashes with FlyVideo
- *{ 0x18521852, BTTV_TERRATV, "Terratec TV+ (V1.10)" }, */
- { 0x1134153b, BTTV_TERRATVALUE, "Terratec TValue (LR102)" },
- { 0x1135153b, BTTV_TERRATVALUER, "Terratec TValue Radio" }, /* LR102 */
- { 0x5018153b, BTTV_TERRATVALUE, "Terratec TValue" }, /* ?? */
- { 0xff3b153b, BTTV_TERRATVALUER, "Terratec TValue Radio" }, /* ?? */
-
- { 0x400015b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
- { 0x400a15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
- { 0x400d15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
- { 0x401015b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
- { 0x401615b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
-
- { 0x1430aa00, BTTV_PV143, "Provideo PV143A" },
- { 0x1431aa00, BTTV_PV143, "Provideo PV143B" },
- { 0x1432aa00, BTTV_PV143, "Provideo PV143C" },
- { 0x1433aa00, BTTV_PV143, "Provideo PV143D" },
- { 0x1433aa03, BTTV_PV143, "Security Eyes" },
-
- { 0x1460aa00, BTTV_PV150, "Provideo PV150A-1" },
- { 0x1461aa01, BTTV_PV150, "Provideo PV150A-2" },
- { 0x1462aa02, BTTV_PV150, "Provideo PV150A-3" },
- { 0x1463aa03, BTTV_PV150, "Provideo PV150A-4" },
-
- { 0x1464aa04, BTTV_PV150, "Provideo PV150B-1" },
- { 0x1465aa05, BTTV_PV150, "Provideo PV150B-2" },
- { 0x1466aa06, BTTV_PV150, "Provideo PV150B-3" },
- { 0x1467aa07, BTTV_PV150, "Provideo PV150B-4" },
-
- { 0xa132ff00, BTTV_IVC100, "IVC-100" },
- { 0xa1550000, BTTV_IVC200, "IVC-200" },
- { 0xa1550001, BTTV_IVC200, "IVC-200" },
- { 0xa1550002, BTTV_IVC200, "IVC-200" },
- { 0xa1550003, BTTV_IVC200, "IVC-200" },
- { 0xa1550100, BTTV_IVC200, "IVC-200G" },
- { 0xa1550101, BTTV_IVC200, "IVC-200G" },
- { 0xa1550102, BTTV_IVC200, "IVC-200G" },
- { 0xa1550103, BTTV_IVC200, "IVC-200G" },
- { 0xa182ff00, BTTV_IVC120, "IVC-120G" },
- { 0xa182ff01, BTTV_IVC120, "IVC-120G" },
- { 0xa182ff02, BTTV_IVC120, "IVC-120G" },
- { 0xa182ff03, BTTV_IVC120, "IVC-120G" },
- { 0xa182ff04, BTTV_IVC120, "IVC-120G" },
- { 0xa182ff05, BTTV_IVC120, "IVC-120G" },
- { 0xa182ff06, BTTV_IVC120, "IVC-120G" },
- { 0xa182ff07, BTTV_IVC120, "IVC-120G" },
- { 0xa182ff08, BTTV_IVC120, "IVC-120G" },
- { 0xa182ff09, BTTV_IVC120, "IVC-120G" },
- { 0xa182ff0a, BTTV_IVC120, "IVC-120G" },
- { 0xa182ff0b, BTTV_IVC120, "IVC-120G" },
- { 0xa182ff0c, BTTV_IVC120, "IVC-120G" },
- { 0xa182ff0d, BTTV_IVC120, "IVC-120G" },
- { 0xa182ff0e, BTTV_IVC120, "IVC-120G" },
- { 0xa182ff0f, BTTV_IVC120, "IVC-120G" },
-
- { 0x41424344, BTTV_GRANDTEC, "GrandTec Multi Capture" },
- { 0x01020304, BTTV_XGUARD, "Grandtec Grand X-Guard" },
-
- { 0x18501851, BTTV_CHRONOS_VS2, "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" },
- { 0xa0501851, BTTV_CHRONOS_VS2, "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" },
- { 0x18511851, BTTV_FLYVIDEO98EZ, "FlyVideo 98EZ (LR51)/ CyberMail AV" },
- { 0x18521852, BTTV_TYPHOON_TVIEW, "FlyVideo 98FM (LR50)/ Typhoon TView TV/FM Tuner" },
- { 0x41a0a051, BTTV_FLYVIDEO_98FM, "Lifeview FlyVideo 98 LR50 Rev Q" },
- { 0x18501f7f, BTTV_FLYVIDEO_98, "Lifeview Flyvideo 98" },
-
- { 0x010115cb, BTTV_GMV1, "AG GMV1" },
- { 0x010114c7, BTTV_MODTEC_205, "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV" },
-
- { 0x10b42636, BTTV_HAUPPAUGE878, "STB ???" },
- { 0x217d6606, BTTV_WINFAST2000, "Leadtek WinFast TV 2000" },
- { 0xfff6f6ff, BTTV_WINFAST2000, "Leadtek WinFast TV 2000" },
- { 0x03116000, BTTV_SENSORAY311, "Sensoray 311" },
- { 0x00790e11, BTTV_WINDVR, "Canopus WinDVR PCI" },
- { 0xa0fca1a0, BTTV_ZOLTRIX, "Face to Face Tvmax" },
- { 0x20007063, BTTV_PC_HDTV, "pcHDTV HD-2000 TV"},
- { 0x82b2aa6a, BTTV_SIMUS_GVC1100, "SIMUS GVC1100" },
- { 0x146caa0c, BTTV_PV951, "ituner spectra8" },
- { 0x200a1295, BTTV_PXC200, "ImageNation PXC200A" },
-
- { 0x40111554, BTTV_PV_BT878P_9B, "Prolink Pixelview PV-BT" },
- { 0x17de0a01, BTTV_KWORLD, "Mecer TV/FM/Video Tuner" },
-
- { 0x01051805, BTTV_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #1" },
- { 0x01061805, BTTV_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #2" },
- { 0x01071805, BTTV_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #3" },
- { 0x01081805, BTTV_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #4" },
-
- { 0x15409511, BTTV_ACORP_Y878F, "Acorp Y878F" },
+ *{ 0x18521852, BTTV_BOARD_TERRATV, "Terratec TV+ (V1.10)" }, */
+ { 0x1134153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue (LR102)" },
+ { 0x1135153b, BTTV_BOARD_TERRATVALUER, "Terratec TValue Radio" }, /* LR102 */
+ { 0x5018153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue" }, /* ?? */
+ { 0xff3b153b, BTTV_BOARD_TERRATVALUER, "Terratec TValue Radio" }, /* ?? */
+
+ { 0x400015b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
+ { 0x400a15b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
+ { 0x400d15b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
+ { 0x401015b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
+ { 0x401615b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
+
+ { 0x1430aa00, BTTV_BOARD_PV143, "Provideo PV143A" },
+ { 0x1431aa00, BTTV_BOARD_PV143, "Provideo PV143B" },
+ { 0x1432aa00, BTTV_BOARD_PV143, "Provideo PV143C" },
+ { 0x1433aa00, BTTV_BOARD_PV143, "Provideo PV143D" },
+ { 0x1433aa03, BTTV_BOARD_PV143, "Security Eyes" },
+
+ { 0x1460aa00, BTTV_BOARD_PV150, "Provideo PV150A-1" },
+ { 0x1461aa01, BTTV_BOARD_PV150, "Provideo PV150A-2" },
+ { 0x1462aa02, BTTV_BOARD_PV150, "Provideo PV150A-3" },
+ { 0x1463aa03, BTTV_BOARD_PV150, "Provideo PV150A-4" },
+
+ { 0x1464aa04, BTTV_BOARD_PV150, "Provideo PV150B-1" },
+ { 0x1465aa05, BTTV_BOARD_PV150, "Provideo PV150B-2" },
+ { 0x1466aa06, BTTV_BOARD_PV150, "Provideo PV150B-3" },
+ { 0x1467aa07, BTTV_BOARD_PV150, "Provideo PV150B-4" },
+
+ { 0xa132ff00, BTTV_BOARD_IVC100, "IVC-100" },
+ { 0xa1550000, BTTV_BOARD_IVC200, "IVC-200" },
+ { 0xa1550001, BTTV_BOARD_IVC200, "IVC-200" },
+ { 0xa1550002, BTTV_BOARD_IVC200, "IVC-200" },
+ { 0xa1550003, BTTV_BOARD_IVC200, "IVC-200" },
+ { 0xa1550100, BTTV_BOARD_IVC200, "IVC-200G" },
+ { 0xa1550101, BTTV_BOARD_IVC200, "IVC-200G" },
+ { 0xa1550102, BTTV_BOARD_IVC200, "IVC-200G" },
+ { 0xa1550103, BTTV_BOARD_IVC200, "IVC-200G" },
+ { 0xa182ff00, BTTV_BOARD_IVC120, "IVC-120G" },
+ { 0xa182ff01, BTTV_BOARD_IVC120, "IVC-120G" },
+ { 0xa182ff02, BTTV_BOARD_IVC120, "IVC-120G" },
+ { 0xa182ff03, BTTV_BOARD_IVC120, "IVC-120G" },
+ { 0xa182ff04, BTTV_BOARD_IVC120, "IVC-120G" },
+ { 0xa182ff05, BTTV_BOARD_IVC120, "IVC-120G" },
+ { 0xa182ff06, BTTV_BOARD_IVC120, "IVC-120G" },
+ { 0xa182ff07, BTTV_BOARD_IVC120, "IVC-120G" },
+ { 0xa182ff08, BTTV_BOARD_IVC120, "IVC-120G" },
+ { 0xa182ff09, BTTV_BOARD_IVC120, "IVC-120G" },
+ { 0xa182ff0a, BTTV_BOARD_IVC120, "IVC-120G" },
+ { 0xa182ff0b, BTTV_BOARD_IVC120, "IVC-120G" },
+ { 0xa182ff0c, BTTV_BOARD_IVC120, "IVC-120G" },
+ { 0xa182ff0d, BTTV_BOARD_IVC120, "IVC-120G" },
+ { 0xa182ff0e, BTTV_BOARD_IVC120, "IVC-120G" },
+ { 0xa182ff0f, BTTV_BOARD_IVC120, "IVC-120G" },
+
+ { 0x41424344, BTTV_BOARD_GRANDTEC, "GrandTec Multi Capture" },
+ { 0x01020304, BTTV_BOARD_XGUARD, "Grandtec Grand X-Guard" },
+
+ { 0x18501851, BTTV_BOARD_CHRONOS_VS2, "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" },
+ { 0xa0501851, BTTV_BOARD_CHRONOS_VS2, "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" },
+ { 0x18511851, BTTV_BOARD_FLYVIDEO98EZ, "FlyVideo 98EZ (LR51)/ CyberMail AV" },
+ { 0x18521852, BTTV_BOARD_TYPHOON_TVIEW, "FlyVideo 98FM (LR50)/ Typhoon TView TV/FM Tuner" },
+ { 0x41a0a051, BTTV_BOARD_FLYVIDEO_98FM, "Lifeview FlyVideo 98 LR50 Rev Q" },
+ { 0x18501f7f, BTTV_BOARD_FLYVIDEO_98, "Lifeview Flyvideo 98" },
+
+ { 0x010115cb, BTTV_BOARD_GMV1, "AG GMV1" },
+ { 0x010114c7, BTTV_BOARD_MODTEC_205, "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV" },
+
+ { 0x10b42636, BTTV_BOARD_HAUPPAUGE878, "STB ???" },
+ { 0x217d6606, BTTV_BOARD_WINFAST2000, "Leadtek WinFast TV 2000" },
+ { 0xfff6f6ff, BTTV_BOARD_WINFAST2000, "Leadtek WinFast TV 2000" },
+ { 0x03116000, BTTV_BOARD_SENSORAY311, "Sensoray 311" },
+ { 0x00790e11, BTTV_BOARD_WINDVR, "Canopus WinDVR PCI" },
+ { 0xa0fca1a0, BTTV_BOARD_ZOLTRIX, "Face to Face Tvmax" },
+ { 0x20007063, BTTV_BOARD_PC_HDTV, "pcHDTV HD-2000 TV"},
+ { 0x82b2aa6a, BTTV_BOARD_SIMUS_GVC1100, "SIMUS GVC1100" },
+ { 0x146caa0c, BTTV_BOARD_PV951, "ituner spectra8" },
+ { 0x200a1295, BTTV_BOARD_PXC200, "ImageNation PXC200A" },
+
+ { 0x40111554, BTTV_BOARD_PV_BT878P_9B, "Prolink Pixelview PV-BT" },
+ { 0x17de0a01, BTTV_BOARD_KWORLD, "Mecer TV/FM/Video Tuner" },
+
+ { 0x01051805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #1" },
+ { 0x01061805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #2" },
+ { 0x01071805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #3" },
+ { 0x01081805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #4" },
+
+ { 0x15409511, BTTV_BOARD_ACORP_Y878F, "Acorp Y878F" },
/* likely broken, vendor id doesn't match the other magic views ...
- * { 0xa0fca04f, BTTV_MAGICTVIEW063, "Guillemot Maxi TV Video 3" }, */
+ * { 0xa0fca04f, BTTV_BOARD_MAGICTVIEW063, "Guillemot Maxi TV Video 3" }, */
/* DVB cards (using pci function .1 for mpeg data xfer) */
- { 0x01010071, BTTV_NEBULA_DIGITV, "Nebula Electronics DigiTV" },
- { 0x07611461, BTTV_AVDVBT_761, "AverMedia AverTV DVB-T 761" },
- { 0x001c11bd, BTTV_PINNACLESAT, "Pinnacle PCTV Sat" },
- { 0x002611bd, BTTV_TWINHAN_DST, "Pinnacle PCTV SAT CI" },
- { 0x00011822, BTTV_TWINHAN_DST, "Twinhan VisionPlus DVB" },
- { 0xfc00270f, BTTV_TWINHAN_DST, "ChainTech digitop DST-1000 DVB-S" },
- { 0x07711461, BTTV_AVDVBT_771, "AVermedia AverTV DVB-T 771" },
- { 0xdb1018ac, BTTV_DVICO_DVBT_LITE, "DViCO FusionHDTV DVB-T Lite" },
- { 0xd50018ac, BTTV_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" },
+ { 0x01010071, BTTV_BOARD_NEBULA_DIGITV, "Nebula Electronics DigiTV" },
+ { 0x07611461, BTTV_BOARD_AVDVBT_761, "AverMedia AverTV DVB-T 761" },
+ { 0x001c11bd, BTTV_BOARD_PINNACLESAT, "Pinnacle PCTV Sat" },
+ { 0x002611bd, BTTV_BOARD_TWINHAN_DST, "Pinnacle PCTV SAT CI" },
+ { 0x00011822, BTTV_BOARD_TWINHAN_DST, "Twinhan VisionPlus DVB" },
+ { 0xfc00270f, BTTV_BOARD_TWINHAN_DST, "ChainTech digitop DST-1000 DVB-S" },
+ { 0x07711461, BTTV_BOARD_AVDVBT_771, "AVermedia AverTV DVB-T 771" },
+ { 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE, "DViCO FusionHDTV DVB-T Lite" },
+ { 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" },
{ 0, -1, NULL }
};
@@ -309,2116 +310,2514 @@ static struct CARD {
/* array with description for bt848 / bt878 tv/grabber cards */
struct tvcard bttv_tvcards[] = {
-{
-/* ---- card 0x00 ---------------------------------- */
- .name = " *** UNKNOWN/GENERIC *** ",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .muxsel = { 2, 3, 1, 0},
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "MIRO PCTV",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 15,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 2, 0, 0, 0, 10},
- .needs_tvaudio = 1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Hauppauge (bt848)",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 7,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0, 1, 2, 3, 4},
- .needs_tvaudio = 1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "STB, Gateway P/N 6000699 (bt848)",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 7,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 4, 0, 2, 3, 1},
- .no_msp34xx = 1,
- .needs_tvaudio = 1,
- .tuner_type = TUNER_PHILIPS_NTSC,
- .tuner_addr = ADDR_UNSET,
- .pll = PLL_28,
- .has_radio = 1,
-},{
-
-/* ---- card 0x04 ---------------------------------- */
- .name = "Intel Create and Share PCI/ Smart Video Recorder III",
- .video_inputs = 4,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = 2,
- .gpiomask = 0,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0 },
- .needs_tvaudio = 0,
- .tuner_type = 4,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Diamond DTV2000",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 3,
- .muxsel = { 2, 3, 1, 0},
- .audiomux = { 0, 1, 0, 1, 3},
- .needs_tvaudio = 1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "AVerMedia TVPhone",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 3,
- .muxsel = { 2, 3, 1, 1},
- .gpiomask = 0x0f,
- .audiomux = { 0x0c, 0x04, 0x08, 0x04, 0},
- /* 0x04 for some cards ?? */
- .needs_tvaudio = 1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .audio_hook = avermedia_tvphone_audio,
- .has_remote = 1,
-},{
- .name = "MATRIX-Vision MV-Delta",
- .video_inputs = 5,
- .audio_inputs = 1,
- .tuner = -1,
- .svhs = 3,
- .gpiomask = 0,
- .muxsel = { 2, 3, 1, 0, 0},
- .audiomux = {0 },
- .needs_tvaudio = 1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
-
-/* ---- card 0x08 ---------------------------------- */
- .name = "Lifeview FlyVideo II (Bt848) LR26 / MAXI TV Video PCI2 LR26",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0xc00,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0, 0xc00, 0x800, 0x400, 0xc00, 0},
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "IMS/IXmicro TurboTV",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 3,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 1, 1, 2, 3, 0},
- .needs_tvaudio = 0,
- .pll = PLL_28,
- .tuner_type = TUNER_TEMIC_PAL,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Hauppauge (bt878)",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x0f, /* old: 7 */
- .muxsel = { 2, 0, 1, 1},
- .audiomux = { 0, 1, 2, 3, 4},
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "MIRO PCTV pro",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x3014f,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0x20001,0x10001, 0, 0,10},
- .needs_tvaudio = 1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
-
-/* ---- card 0x0c ---------------------------------- */
- .name = "ADS Technologies Channel Surfer TV (bt848)",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 15,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 13, 14, 11, 7, 0, 0},
- .needs_tvaudio = 1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "AVerMedia TVCapture 98",
- .video_inputs = 3,
- .audio_inputs = 4,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 15,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 13, 14, 11, 7, 0, 0},
- .needs_tvaudio = 1,
- .msp34xx_alt = 1,
- .pll = PLL_28,
- .tuner_type = TUNER_PHILIPS_PAL,
- .tuner_addr = ADDR_UNSET,
- .audio_hook = avermedia_tv_stereo_audio,
-},{
- .name = "Aimslab Video Highway Xtreme (VHX)",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 7,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0, 2, 1, 3, 4}, /* old: { 0, 1, 2, 3, 4} */
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Zoltrix TV-Max",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 15,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = {0 , 0, 1 , 0, 10},
- .needs_tvaudio = 1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
-
-/* ---- card 0x10 ---------------------------------- */
- .name = "Prolink Pixelview PlayTV (bt878)",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x01fe00,
- .muxsel = { 2, 3, 1, 1},
- /* 2003-10-20 by "Anton A. Arapov" <arapov@mail.ru> */
- .audiomux = { 0x001e00, 0, 0x018000, 0x014000, 0x002000, 0 },
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = -1,
-},{
- .name = "Leadtek WinView 601",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x8300f8,
- .muxsel = { 2, 3, 1, 1,0},
- .audiomux = { 0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007},
- .needs_tvaudio = 1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .audio_hook = winview_audio,
- .has_radio = 1,
-},{
- .name = "AVEC Intercapture",
- .video_inputs = 3,
- .audio_inputs = 2,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0,
- .muxsel = {2, 3, 1, 1},
- .audiomux = {1, 0, 0, 0, 0},
- .needs_tvaudio = 1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = -1,
- .svhs = -1,
- .gpiomask = 0x8dff00,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0 },
- .no_msp34xx = 1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
-
-/* ---- card 0x14 ---------------------------------- */
- .name = "CEI Raffles Card",
- .video_inputs = 3,
- .audio_inputs = 3,
- .tuner = 0,
- .svhs = 2,
- .muxsel = {2, 3, 1, 1},
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50",
- .video_inputs = 4,
- .audio_inputs = 2, /* tuner, line in */
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x1800,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0, 0x800, 0x1000, 0x1000, 0x1800},
- .pll = PLL_28,
- .tuner_type = TUNER_PHILIPS_PAL_I,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Askey CPH050/ Phoebe Tv Master + FM",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0xc00,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = {0, 1, 0x800, 0x400, 0xc00, 0},
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV, bt878",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = -1,
- .gpiomask = 7,
- .muxsel = { 2, 3, -1 },
- .digital_mode = DIGITAL_MODE_CAMERA,
- .audiomux = { 0, 0, 0, 0, 0 },
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = TUNER_ALPS_TSBB5_PAL_I,
- .tuner_addr = ADDR_UNSET,
-},{
-
-/* ---- card 0x18 ---------------------------------- */
- .name = "Askey CPH05X/06X (bt878) [many vendors]",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0xe00,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = {0x400, 0x400, 0x400, 0x400, 0xc00},
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .has_remote = 1,
-},{
- .name = "Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x1f0fff,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0x20000, 0x30000, 0x10000, 0, 0x40000},
- .needs_tvaudio = 0,
- .tuner_type = TUNER_PHILIPS_PAL,
- .tuner_addr = ADDR_UNSET,
- .audio_hook = terratv_audio,
-},{
- .name = "Hauppauge WinCam newer (bt878)",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 3,
- .gpiomask = 7,
- .muxsel = { 2, 0, 1, 1},
- .audiomux = { 0, 1, 2, 3, 4},
- .needs_tvaudio = 1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50",
- .video_inputs = 4,
- .audio_inputs = 2,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x1800,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0, 0x800, 0x1000, 0x1000, 0x1800},
- .pll = PLL_28,
- .tuner_type = TUNER_PHILIPS_SECAM,
- .tuner_addr = ADDR_UNSET,
-},{
-
-/* ---- card 0x1c ---------------------------------- */
- .name = "Terratec TerraTV+ Version 1.1 (bt878)",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x1f0fff,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0x20000, 0x30000, 0x10000, 0x00000, 0x40000},
- .needs_tvaudio = 0,
- .tuner_type = TUNER_PHILIPS_PAL,
- .tuner_addr = ADDR_UNSET,
- .audio_hook = terratv_audio,
- /* GPIO wiring:
- External 20 pin connector (for Active Radio Upgrade board)
- gpio00: i2c-sda
- gpio01: i2c-scl
- gpio02: om5610-data
- gpio03: om5610-clk
- gpio04: om5610-wre
- gpio05: om5610-stereo
- gpio06: rds6588-davn
- gpio07: Pin 7 n.c.
- gpio08: nIOW
- gpio09+10: nIOR, nSEL ?? (bt878)
- gpio09: nIOR (bt848)
- gpio10: nSEL (bt848)
- Sound Routing:
- gpio16: u2-A0 (1st 4052bt)
- gpio17: u2-A1
- gpio18: u2-nEN
- gpio19: u4-A0 (2nd 4052)
- gpio20: u4-A1
- u4-nEN - GND
- Btspy:
- 00000 : Cdrom (internal audio input)
- 10000 : ext. Video audio input
- 20000 : TV Mono
- a0000 : TV Mono/2
- 1a0000 : TV Stereo
- 30000 : Radio
- 40000 : Mute
-*/
-
-},{
- /* Jannik Fritsch <jannik@techfak.uni-bielefeld.de> */
- .name = "Imagenation PXC200",
- .video_inputs = 5,
- .audio_inputs = 1,
- .tuner = -1,
- .svhs = 1, /* was: 4 */
- .gpiomask = 0,
- .muxsel = { 2, 3, 1, 0, 0},
- .audiomux = { 0 },
- .needs_tvaudio = 1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .muxsel_hook = PXC200_muxsel,
-
-},{
- .name = "Lifeview FlyVideo 98 LR50",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x1800, /* 0x8dfe00 */
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0, 0x0800, 0x1000, 0x1000, 0x1800, 0 },
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Formac iProTV, Formac ProTV I (bt848)",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 3,
- .gpiomask = 1,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 1, 0, 0, 0, 0 },
- .pll = PLL_28,
- .tuner_type = TUNER_PHILIPS_PAL,
- .tuner_addr = ADDR_UNSET,
-},{
-
-/* ---- card 0x20 ---------------------------------- */
- .name = "Intel Create and Share PCI/ Smart Video Recorder III",
- .video_inputs = 4,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = 2,
- .gpiomask = 0,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0 },
- .needs_tvaudio = 0,
- .tuner_type = 4,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Terratec TerraTValue Version Bt878",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0xffff00,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0x500, 0, 0x300, 0x900, 0x900},
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = TUNER_PHILIPS_PAL,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Leadtek WinFast 2000/ WinFast 2000 XP",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .muxsel = { 2, 3, 1, 1, 0}, /* TV, CVid, SVid, CVid over SVid connector */
- /* Alexander Varakin <avarakin@hotmail.com> [stereo version] */
- .gpiomask = 0xb33000,
- .audiomux = { 0x122000,0x1000,0x0000,0x620000,0x800000 },
- /* Audio Routing for "WinFast 2000 XP" (no tv stereo !)
- gpio23 -- hef4052:nEnable (0x800000)
- gpio12 -- hef4052:A1
- gpio13 -- hef4052:A0
- 0x0000: external audio
- 0x1000: FM
- 0x2000: TV
- 0x3000: n.c.
- Note: There exists another variant "Winfast 2000" with tv stereo !?
- Note: eeprom only contains FF and pci subsystem id 107d:6606
- */
- .needs_tvaudio = 0,
- .pll = PLL_28,
- .has_radio = 1,
- .tuner_type = 5, /* default for now, gpio reads BFFF06 for Pal bg+dk */
- .tuner_addr = ADDR_UNSET,
- .audio_hook = winfast2000_audio,
- .has_remote = 1,
-},{
- .name = "Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II",
- .video_inputs = 4,
- .audio_inputs = 3,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x1800,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0, 0x800, 0x1000, 0x1000, 0x1800},
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
-
-/* ---- card 0x24 ---------------------------------- */
- .name = "Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner",
- .video_inputs = 4,
- .audio_inputs = 3,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x1800,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0, 0x800, 0x1000, 0x1000, 0x1800, 0 },
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .has_radio = 1,
-},{
- .name = "Prolink PixelView PlayTV pro",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0xff,
- .muxsel = { 2, 3, 1, 1 },
- .audiomux = { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 },
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Askey CPH06X TView99",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x551e00,
- .muxsel = { 2, 3, 1, 0},
- .audiomux = { 0x551400, 0x551200, 0, 0, 0x551c00, 0x551200 },
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = 1,
- .tuner_addr = ADDR_UNSET,
- .has_remote = 1,
-},{
- .name = "Pinnacle PCTV Studio/Rave",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x03000F,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 2, 0xd0001, 0, 0, 1},
- .needs_tvaudio = 0,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
-
-/* ---- card 0x28 ---------------------------------- */
- .name = "STB TV PCI FM, Gateway P/N 6000704 (bt878), 3Dfx VoodooTV 100",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 7,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 4, 0, 2, 3, 1},
- .no_msp34xx = 1,
- .needs_tvaudio = 1,
- .tuner_type = TUNER_PHILIPS_NTSC,
- .tuner_addr = ADDR_UNSET,
- .pll = PLL_28,
- .has_radio = 1,
-},{
- .name = "AVerMedia TVPhone 98",
- .video_inputs = 3,
- .audio_inputs = 4,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 15,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 13, 4, 11, 7, 0, 0},
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .has_radio = 1,
- .audio_hook = avermedia_tvphone_audio,
-},{
- .name = "ProVideo PV951", /* pic16c54 */
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0, 0, 0, 0, 0},
- .needs_tvaudio = 1,
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = 1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Little OnAir TV",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0xe00b,
- .muxsel = {2, 3, 1, 1},
- .audiomux = {0xff9ff6, 0xff9ff6, 0xff1ff7, 0, 0xff3ffc},
- .no_msp34xx = 1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
-
-/* ---- card 0x2c ---------------------------------- */
- .name = "Sigma TVII-FM",
- .video_inputs = 2,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = -1,
- .gpiomask = 3,
- .muxsel = {2, 3, 1, 1},
- .audiomux = {1, 1, 0, 2, 3},
- .no_msp34xx = 1,
- .pll = PLL_NONE,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "MATRIX-Vision MV-Delta 2",
- .video_inputs = 5,
- .audio_inputs = 1,
- .tuner = -1,
- .svhs = 3,
- .gpiomask = 0,
- .muxsel = { 2, 3, 1, 0, 0},
- .audiomux = {0 },
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Zoltrix Genie TV/FM",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0xbcf03f,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0xbc803f, 0xbc903f, 0xbcb03f, 0, 0xbcb03f},
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = 21,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Terratec TV/Radio+",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x70000,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0x20000, 0x30000, 0x10000, 0, 0x40000, 0x20000 },
- .needs_tvaudio = 1,
- .no_msp34xx = 1,
- .pll = PLL_35,
- .tuner_type = 1,
- .tuner_addr = ADDR_UNSET,
- .has_radio = 1,
-},{
-
-/* ---- card 0x30 ---------------------------------- */
- .name = "Askey CPH03x/ Dynalink Magic TView",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 15,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = {2,0,0,0,1},
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "IODATA GV-BCTV3/PCI",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x010f00,
- .muxsel = {2, 3, 0, 0},
- .audiomux = {0x10000, 0, 0x10000, 0, 0, 0},
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = TUNER_ALPS_TSHC6_NTSC,
- .tuner_addr = ADDR_UNSET,
- .audio_hook = gvbctv3pci_audio,
-},{
- .name = "Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP",
- .video_inputs = 5,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 3,
- .gpiomask = 0xAA0000,
- .muxsel = { 2,3,1,1,-1 },
- .digital_mode = DIGITAL_MODE_CAMERA,
- .audiomux = { 0x20000, 0, 0x80000, 0x80000, 0xa8000, 0x46000 },
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = TUNER_PHILIPS_PAL_I,
- .tuner_addr = ADDR_UNSET,
- .has_remote = 1,
- /* GPIO wiring: (different from Rev.4C !)
- GPIO17: U4.A0 (first hef4052bt)
- GPIO19: U4.A1
- GPIO20: U5.A1 (second hef4052bt)
- GPIO21: U4.nEN
- GPIO22: BT832 Reset Line
- GPIO23: A5,A0, U5,nEN
- Note: At i2c=0x8a is a Bt832 chip, which changes to 0x88 after being reset via GPIO22
- */
-},{
- .name = "Eagle Wireless Capricorn2 (bt878A)",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 7,
- .muxsel = { 2, 0, 1, 1},
- .audiomux = { 0, 1, 2, 3, 4},
- .pll = PLL_28,
- .tuner_type = -1 /* TUNER_ALPS_TMDH2_NTSC */,
- .tuner_addr = ADDR_UNSET,
-},{
-
-/* ---- card 0x34 ---------------------------------- */
- /* David Härdeman <david@2gen.com> */
- .name = "Pinnacle PCTV Studio Pro",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 3,
- .gpiomask = 0x03000F,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 1, 0xd0001, 0, 0, 10},
- /* sound path (5 sources):
- MUX1 (mask 0x03), Enable Pin 0x08 (0=enable, 1=disable)
- 0= ext. Audio IN
- 1= from MUX2
- 2= Mono TV sound from Tuner
- 3= not connected
- MUX2 (mask 0x30000):
- 0,2,3= from MSP34xx
- 1= FM stereo Radio from Tuner */
- .needs_tvaudio = 0,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- /* Claas Langbehn <claas@bigfoot.com>,
- Sven Grothklags <sven@upb.de> */
- .name = "Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS",
- .video_inputs = 4,
- .audio_inputs = 3,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x1c,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0, 0, 0x10, 8, 4 },
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = TUNER_PHILIPS_PAL,
- .tuner_addr = ADDR_UNSET,
- .has_radio = 1,
-},{
- /* Tim Röstermundt <rosterm@uni-muenster.de>
- in de.comp.os.unix.linux.hardware:
- options bttv card=0 pll=1 radio=1 gpiomask=0x18e0
- audiomux=0x44c71f,0x44d71f,0,0x44d71f,0x44dfff
- options tuner type=5 */
- .name = "Lifeview FlyVideo 2000 /FlyVideo A2/ Lifetec LT 9415 TV [LR90]",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x18e0,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0x0000,0x0800,0x1000,0x1000,0x18e0 },
- /* For cards with tda9820/tda9821:
- 0x0000: Tuner normal stereo
- 0x0080: Tuner A2 SAP (second audio program = Zweikanalton)
- 0x0880: Tuner A2 stereo */
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- /* Miguel Angel Alvarez <maacruz@navegalia.com>
- old Easy TV BT848 version (model CPH031) */
- .name = "Askey CPH031/ BESTBUY Easy TV",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0xF,
- .muxsel = { 2, 3, 1, 0},
- .audiomux = { 2, 0, 0, 0, 10},
- .needs_tvaudio = 0,
- .pll = PLL_28,
- .tuner_type = TUNER_TEMIC_PAL,
- .tuner_addr = ADDR_UNSET,
-},{
-
-/* ---- card 0x38 ---------------------------------- */
- /* Gordon Heydon <gjheydon@bigfoot.com ('98) */
- .name = "Lifeview FlyVideo 98FM LR50",
- .video_inputs = 4,
- .audio_inputs = 3,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x1800,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0, 0x800, 0x1000, 0x1000, 0x1800, 0 },
- .pll = PLL_28,
- .tuner_type = 5,
- .tuner_addr = ADDR_UNSET,
-},{
- /* This is the ultimate cheapo capture card
- * just a BT848A on a small PCB!
- * Steve Hosgood <steve@equiinet.com> */
- .name = "GrandTec 'Grand Video Capture' (Bt848)",
- .video_inputs = 2,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = 1,
- .gpiomask = 0,
- .muxsel = { 3, 1 },
- .audiomux = { 0 },
- .needs_tvaudio = 0,
- .no_msp34xx = 1,
- .pll = PLL_35,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- /* Daniel Herrington <daniel.herrington@home.com> */
- .name = "Askey CPH060/ Phoebe TV Master Only (No FM)",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0xe00,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0x400, 0x400, 0x400, 0x400, 0x800, 0x400 },
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = TUNER_TEMIC_4036FY5_NTSC,
- .tuner_addr = ADDR_UNSET,
-},{
- /* Matti Mottus <mottus@physic.ut.ee> */
- .name = "Askey CPH03x TV Capturer",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x03000F,
- .muxsel = { 2, 3, 1, 0},
- .audiomux = { 2,0,0,0,1 },
- .pll = PLL_28,
- .tuner_type = 0,
- .tuner_addr = ADDR_UNSET,
-},{
-
-/* ---- card 0x3c ---------------------------------- */
- /* Philip Blundell <philb@gnu.org> */
- .name = "Modular Technology MM100PCTV",
- .video_inputs = 2,
- .audio_inputs = 2,
- .tuner = 0,
- .svhs = -1,
- .gpiomask = 11,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 2, 0, 0, 1, 8},
- .pll = PLL_35,
- .tuner_type = TUNER_TEMIC_PAL,
- .tuner_addr = ADDR_UNSET,
-},{
- /* Adrian Cox <adrian@humboldt.co.uk */
- .name = "AG Electronics GMV1",
- .video_inputs = 2,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = 1,
- .gpiomask = 0xF,
- .muxsel = { 2, 2},
- .audiomux = { },
- .no_msp34xx = 1,
- .needs_tvaudio = 0,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- /* Miguel Angel Alvarez <maacruz@navegalia.com>
- new Easy TV BT878 version (model CPH061)
- special thanks to Informatica Mieres for providing the card */
- .name = "Askey CPH061/ BESTBUY Easy TV (bt878)",
- .video_inputs = 3,
- .audio_inputs = 2,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0xFF,
- .muxsel = { 2, 3, 1, 0},
- .audiomux = { 1, 0, 4, 4, 9},
- .needs_tvaudio = 0,
- .pll = PLL_28,
- .tuner_type = TUNER_PHILIPS_PAL,
- .tuner_addr = ADDR_UNSET,
-},{
- /* Lukas Gebauer <geby@volny.cz> */
- .name = "ATI TV-Wonder",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0xf03f,
- .muxsel = { 2, 3, 1, 0 },
- .audiomux = { 0xbffe, 0, 0xbfff, 0, 0xbffe},
- .pll = PLL_28,
- .tuner_type = TUNER_TEMIC_4006FN5_MULTI_PAL,
- .tuner_addr = ADDR_UNSET,
-},{
-
-/* ---- card 0x40 ---------------------------------- */
- /* Lukas Gebauer <geby@volny.cz> */
- .name = "ATI TV-Wonder VE",
- .video_inputs = 2,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = -1,
- .gpiomask = 1,
- .muxsel = { 2, 3, 0, 1},
- .audiomux = { 0, 0, 1, 0, 0},
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = TUNER_TEMIC_4006FN5_MULTI_PAL,
- .tuner_addr = ADDR_UNSET,
-},{
- /* DeeJay <deejay@westel900.net (2000S) */
- .name = "Lifeview FlyVideo 2000S LR90",
- .video_inputs = 3,
- .audio_inputs = 3,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x18e0,
- .muxsel = { 2, 3, 0, 1},
- /* Radio changed from 1e80 to 0x800 to make
- FlyVideo2000S in .hu happy (gm)*/
- /* -dk-???: set mute=0x1800 for tda9874h daughterboard */
- .audiomux = { 0x0000,0x0800,0x1000,0x1000,0x1800, 0x1080 },
- .audio_hook = fv2000s_audio,
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = 5,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Terratec TValueRadio",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0xffff00,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0x500, 0x500, 0x300, 0x900, 0x900},
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = TUNER_PHILIPS_PAL,
- .tuner_addr = ADDR_UNSET,
- .has_radio = 1,
-},{
- /* TANAKA Kei <peg00625@nifty.com> */
- .name = "IODATA GV-BCTV4/PCI",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x010f00,
- .muxsel = {2, 3, 0, 0},
- .audiomux = {0x10000, 0, 0x10000, 0, 0, 0},
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = TUNER_SHARP_2U5JF5540_NTSC,
- .tuner_addr = ADDR_UNSET,
- .audio_hook = gvbctv3pci_audio,
-},{
-
-/* ---- card 0x44 ---------------------------------- */
- .name = "3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)",
- /* try "insmod msp3400 simple=0" if you have
- * sound problems with this card. */
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = -1,
- .gpiomask = 0x4f8a00,
- /* 0x100000: 1=MSP enabled (0=disable again)
- * 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */
- .audiomux = {0x947fff, 0x987fff,0x947fff,0x947fff, 0x947fff},
- /* tvtuner, radio, external,internal, mute, stereo
- * tuner, Composit, SVid, Composit-on-Svid-adapter */
- .muxsel = { 2, 3 ,0 ,1},
- .tuner_type = TUNER_MT2032,
- .tuner_addr = ADDR_UNSET,
- .pll = PLL_28,
- .has_radio = 1,
-},{
- /* Philip Blundell <pb@nexus.co.uk> */
- .name = "Active Imaging AIMMS",
- .video_inputs = 1,
- .audio_inputs = 0,
- .tuner = -1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .pll = PLL_28,
- .muxsel = { 2 },
- .gpiomask = 0
-},{
- /* Tomasz Pyra <hellfire@sedez.iq.pl> */
- .name = "Prolink Pixelview PV-BT878P+ (Rev.4C,8E)",
- .video_inputs = 3,
- .audio_inputs = 4,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 15,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0, 0, 11, 7, 13, 0}, /* TV and Radio with same GPIO ! */
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = 25,
- .tuner_addr = ADDR_UNSET,
- .has_remote = 1,
- /* GPIO wiring:
- GPIO0: U4.A0 (hef4052bt)
- GPIO1: U4.A1
- GPIO2: U4.A1 (second hef4052bt)
- GPIO3: U4.nEN, U5.A0, A5.nEN
- GPIO8-15: vrd866b ?
+ /* ---- card 0x00 ---------------------------------- */
+ [BTTV_BOARD_UNKNOWN] = {
+ .name = " *** UNKNOWN/GENERIC *** ",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .muxsel = { 2, 3, 1, 0},
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_MIRO] = {
+ .name = "MIRO PCTV",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 15,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 2, 0, 0, 0, 10},
+ .needs_tvaudio = 1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_HAUPPAUGE] = {
+ .name = "Hauppauge (bt848)",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 7,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0, 1, 2, 3, 4},
+ .needs_tvaudio = 1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_STB] = {
+ .name = "STB, Gateway P/N 6000699 (bt848)",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 7,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 4, 0, 2, 3, 1},
+ .no_msp34xx = 1,
+ .needs_tvaudio = 1,
+ .tuner_type = TUNER_PHILIPS_NTSC,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .pll = PLL_28,
+ .has_radio = 1,
+ },
+
+ /* ---- card 0x04 ---------------------------------- */
+ [BTTV_BOARD_INTEL] = {
+ .name = "Intel Create and Share PCI/ Smart Video Recorder III",
+ .video_inputs = 4,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = 2,
+ .gpiomask = 0,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0 },
+ .needs_tvaudio = 0,
+ .tuner_type = 4,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_DIAMOND] = {
+ .name = "Diamond DTV2000",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 3,
+ .muxsel = { 2, 3, 1, 0},
+ .audiomux = { 0, 1, 0, 1, 3},
+ .needs_tvaudio = 1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_AVERMEDIA] = {
+ .name = "AVerMedia TVPhone",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 3,
+ .muxsel = { 2, 3, 1, 1},
+ .gpiomask = 0x0f,
+ .audiomux = { 0x0c, 0x04, 0x08, 0x04, 0},
+ /* 0x04 for some cards ?? */
+ .needs_tvaudio = 1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .audio_hook = avermedia_tvphone_audio,
+ .has_remote = 1,
+ },
+ [BTTV_BOARD_MATRIX_VISION] = {
+ .name = "MATRIX-Vision MV-Delta",
+ .video_inputs = 5,
+ .audio_inputs = 1,
+ .tuner = -1,
+ .svhs = 3,
+ .gpiomask = 0,
+ .muxsel = { 2, 3, 1, 0, 0},
+ .audiomux = {0 },
+ .needs_tvaudio = 1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x08 ---------------------------------- */
+ [BTTV_BOARD_FLYVIDEO] = {
+ .name = "Lifeview FlyVideo II (Bt848) LR26 / MAXI TV Video PCI2 LR26",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0xc00,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0, 0xc00, 0x800, 0x400, 0xc00, 0},
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_TURBOTV] = {
+ .name = "IMS/IXmicro TurboTV",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 3,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 1, 1, 2, 3, 0},
+ .needs_tvaudio = 0,
+ .pll = PLL_28,
+ .tuner_type = TUNER_TEMIC_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_HAUPPAUGE878] = {
+ .name = "Hauppauge (bt878)",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x0f, /* old: 7 */
+ .muxsel = { 2, 0, 1, 1},
+ .audiomux = { 0, 1, 2, 3, 4},
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_MIROPRO] = {
+ .name = "MIRO PCTV pro",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x3014f,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0x20001,0x10001, 0, 0,10},
+ .needs_tvaudio = 1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x0c ---------------------------------- */
+ [BTTV_BOARD_ADSTECH_TV] = {
+ .name = "ADS Technologies Channel Surfer TV (bt848)",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 15,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 13, 14, 11, 7, 0, 0},
+ .needs_tvaudio = 1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_AVERMEDIA98] = {
+ .name = "AVerMedia TVCapture 98",
+ .video_inputs = 3,
+ .audio_inputs = 4,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 15,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 13, 14, 11, 7, 0, 0},
+ .needs_tvaudio = 1,
+ .msp34xx_alt = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .audio_hook = avermedia_tv_stereo_audio,
+ .no_gpioirq = 1,
+ },
+ [BTTV_BOARD_VHX] = {
+ .name = "Aimslab Video Highway Xtreme (VHX)",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 7,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0, 2, 1, 3, 4}, /* old: { 0, 1, 2, 3, 4} */
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_ZOLTRIX] = {
+ .name = "Zoltrix TV-Max",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 15,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = {0 , 0, 1 , 0, 10},
+ .needs_tvaudio = 1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x10 ---------------------------------- */
+ [BTTV_BOARD_PIXVIEWPLAYTV] = {
+ .name = "Prolink Pixelview PlayTV (bt878)",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x01fe00,
+ .muxsel = { 2, 3, 1, 1},
+ #if 0
+ /* old */
+ .audiomux = { 0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 },
+ #else
+ /* 2003-10-20 by "Anton A. Arapov" <arapov@mail.ru> */
+ .audiomux = { 0x001e00, 0, 0x018000, 0x014000, 0x002000, 0 },
+ #endif
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ },
+ [BTTV_BOARD_WINVIEW_601] = {
+ .name = "Leadtek WinView 601",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x8300f8,
+ .muxsel = { 2, 3, 1, 1,0},
+ .audiomux = { 0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007},
+ .needs_tvaudio = 1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .audio_hook = winview_audio,
+ .has_radio = 1,
+ },
+ [BTTV_BOARD_AVEC_INTERCAP] = {
+ .name = "AVEC Intercapture",
+ .video_inputs = 3,
+ .audio_inputs = 2,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0,
+ .muxsel = {2, 3, 1, 1},
+ .audiomux = {1, 0, 0, 0, 0},
+ .needs_tvaudio = 1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_LIFE_FLYKIT] = {
+ .name = "Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = -1,
+ .svhs = -1,
+ .gpiomask = 0x8dff00,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0 },
+ .no_msp34xx = 1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x14 ---------------------------------- */
+ [BTTV_BOARD_CEI_RAFFLES] = {
+ .name = "CEI Raffles Card",
+ .video_inputs = 3,
+ .audio_inputs = 3,
+ .tuner = 0,
+ .svhs = 2,
+ .muxsel = {2, 3, 1, 1},
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_CONFERENCETV] = {
+ .name = "Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50",
+ .video_inputs = 4,
+ .audio_inputs = 2, /* tuner, line in */
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x1800,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0, 0x800, 0x1000, 0x1000, 0x1800},
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL_I,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_PHOEBE_TVMAS] = {
+ .name = "Askey CPH050/ Phoebe Tv Master + FM",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0xc00,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = {0, 1, 0x800, 0x400, 0xc00, 0},
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_MODTEC_205] = {
+ .name = "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV, bt878",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = -1,
+ .gpiomask = 7,
+ .muxsel = { 2, 3, -1 },
+ .digital_mode = DIGITAL_MODE_CAMERA,
+ .audiomux = { 0, 0, 0, 0, 0 },
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_ALPS_TSBB5_PAL_I,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x18 ---------------------------------- */
+ [BTTV_BOARD_MAGICTVIEW061] = {
+ .name = "Askey CPH05X/06X (bt878) [many vendors]",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0xe00,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = {0x400, 0x400, 0x400, 0x400, 0xc00},
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_remote = 1,
+ },
+ [BTTV_BOARD_VOBIS_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 = 0x1f0fff,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0x20000, 0x30000, 0x10000, 0, 0x40000},
+ .needs_tvaudio = 0,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .audio_hook = terratv_audio,
+ },
+ [BTTV_BOARD_HAUPPAUG_WCAM] = {
+ .name = "Hauppauge WinCam newer (bt878)",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 3,
+ .gpiomask = 7,
+ .muxsel = { 2, 0, 1, 1},
+ .audiomux = { 0, 1, 2, 3, 4},
+ .needs_tvaudio = 1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_MAXI] = {
+ .name = "Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50",
+ .video_inputs = 4,
+ .audio_inputs = 2,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x1800,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0, 0x800, 0x1000, 0x1000, 0x1800},
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_SECAM,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x1c ---------------------------------- */
+ [BTTV_BOARD_TERRATV] = {
+ .name = "Terratec TerraTV+ Version 1.1 (bt878)",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x1f0fff,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0x20000, 0x30000, 0x10000, 0x00000, 0x40000},
+ .needs_tvaudio = 0,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .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
*/
-},{
- .name = "Lifeview FlyVideo 98EZ (capture only) LR51",
- .video_inputs = 4,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = 2,
- .muxsel = { 2, 3, 1, 1}, /* AV1, AV2, SVHS, CVid adapter on SVHS */
- .pll = PLL_28,
- .no_msp34xx = 1,
- .tuner_type = UNSET,
- .tuner_addr = ADDR_UNSET,
-},{
-
-/* ---- card 0x48 ---------------------------------- */
- /* Dariusz Kowalewski <darekk@automex.pl> */
- .name = "Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x3f,
- .muxsel = { 2, 3, 1, 1 },
- .audiomux = { 0x01, 0x00, 0x03, 0x03, 0x09, 0x02 },
- .needs_tvaudio = 1,
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .pll = PLL_28,
- .tuner_type = 5,
- .tuner_addr = ADDR_UNSET,
- .audio_hook = pvbt878p9b_audio, /* Note: not all cards have stereo */
- .has_radio = 1, /* Note: not all cards have radio */
- .has_remote = 1,
- /* GPIO wiring:
- GPIO0: A0 hef4052
- GPIO1: A1 hef4052
- GPIO3: nEN hef4052
- GPIO8-15: vrd866b
- GPIO20,22,23: R30,R29,R28
- */
-},{
- /* Clay Kunz <ckunz@mail.arc.nasa.gov> */
- /* you must jumper JP5 for the card to work */
- .name = "Sensoray 311",
- .video_inputs = 5,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = 4,
- .gpiomask = 0,
- .muxsel = { 2, 3, 1, 0, 0},
- .audiomux = { 0 },
- .needs_tvaudio = 0,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- /* Miguel Freitas <miguel@cetuc.puc-rio.br> */
- .name = "RemoteVision MX (RV605)",
- .video_inputs = 16,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
- .gpiomask = 0x00,
- .gpiomask2 = 0x07ff,
- .muxsel = { 0x33, 0x13, 0x23, 0x43, 0xf3, 0x73, 0xe3, 0x03,
- 0xd3, 0xb3, 0xc3, 0x63, 0x93, 0x53, 0x83, 0xa3 },
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .muxsel_hook = rv605_muxsel,
-},{
- .name = "Powercolor MTV878/ MTV878R/ MTV878F",
- .video_inputs = 3,
- .audio_inputs = 2,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x1C800F, /* Bit0-2: Audio select, 8-12:remote control 14:remote valid 15:remote reset */
- .muxsel = { 2, 1, 1, },
- .audiomux = { 0, 1, 2, 2, 4 },
- .needs_tvaudio = 0,
- .tuner_type = TUNER_PHILIPS_PAL,
- .tuner_addr = ADDR_UNSET,
- .pll = PLL_28,
- .has_radio = 1,
-},{
-
-/* ---- card 0x4c ---------------------------------- */
- /* Masaki Suzuki <masaki@btree.org> */
- .name = "Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP)",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x140007,
- .muxsel = { 2, 3, 1, 1 },
- .audiomux = { 0, 1, 2, 3, 4, 0 },
- .tuner_type = TUNER_PHILIPS_NTSC,
- .tuner_addr = ADDR_UNSET,
- .audio_hook = windvr_audio,
-},{
- .name = "GrandTec Multi Capture Card (Bt878)",
- .video_inputs = 4,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
- .gpiomask = 0,
- .muxsel = { 2, 3, 1, 0 },
- .audiomux = { 0 },
- .needs_tvaudio = 0,
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF",
- .video_inputs = 4,
- .audio_inputs = 3,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 7,
- .muxsel = { 2, 3, 1, 1 }, /* Tuner, SVid, SVHS, SVid to SVHS connector */
- .audiomux = { 0 ,0 ,4, 4,4,4},/* Yes, this tuner uses the same audio output for TV and FM radio!
- * This card lacks external Audio In, so we mute it on Ext. & Int.
- * The PCB can take a sbx1637/sbx1673, wiring unknown.
- * This card lacks PCI subsystem ID, sigh.
- * audiomux=1: lower volume, 2+3: mute
- * btwincap uses 0x80000/0x80003
- */
- .needs_tvaudio = 0,
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = 5,
- .tuner_addr = ADDR_UNSET,
- /* Samsung TCPA9095PC27A (BG+DK), philips compatible, w/FM, stereo and
- radio signal strength indicators work fine. */
- .has_radio = 1,
- /* GPIO Info:
- GPIO0,1: HEF4052 A0,A1
- GPIO2: HEF4052 nENABLE
- GPIO3-7: n.c.
- GPIO8-13: IRDC357 data0-5 (data6 n.c. ?) [chip not present on my card]
- GPIO14,15: ??
- GPIO16-21: n.c.
- GPIO22,23: ??
- ?? : mtu8b56ep microcontroller for IR (GPIO wiring unknown)*/
-},{
- /* Arthur Tetzlaff-Deas, DSP Design Ltd <software@dspdesign.com> */
- .name = "DSP Design TCVIDEO",
- .video_inputs = 4,
- .svhs = -1,
- .muxsel = { 2, 3, 1, 0},
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
-
- /* ---- 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,
- .tuner_addr = ADDR_UNSET,
-
- .gpiomask = 7,
- .audiomux = {7},
-},{
- .name = "IODATA GV-BCTV5/PCI",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x0f0f80,
- .muxsel = {2, 3, 1, 0},
- .audiomux = {0x030000, 0x010000, 0, 0, 0x020000, 0},
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = TUNER_PHILIPS_NTSC_M,
- .tuner_addr = ADDR_UNSET,
- .audio_hook = gvbctv5pci_audio,
- .has_radio = 1,
-},{
- .name = "Osprey 100/150 (878)", /* 0x1(2|3)-45C6-C1 */
- .video_inputs = 4, /* id-inputs-clock */
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = 3,
- .muxsel = { 3, 2, 0, 1 },
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .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,
- .tuner_addr = ADDR_UNSET,
- .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,
- .tuner_addr = ADDR_UNSET,
- .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,
- .tuner_addr = ADDR_UNSET,
- .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,
- .tuner_addr = ADDR_UNSET,
- .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 = UNSET,
- .tuner_addr = ADDR_UNSET,
- .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 = UNSET,
- .tuner_addr = ADDR_UNSET,
- .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 = UNSET,
- .tuner_addr = ADDR_UNSET,
- .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,
- .tuner_addr = ADDR_UNSET,
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
-},{
- .name = "Osprey 540", /* 540 */
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = -1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
-},{
-
- /* ---- card 0x5C ---------------------------------- */
- .name = "Osprey 2000", /* 2000 */
- .video_inputs = 2,
- .audio_inputs = 1,
- .tuner = -1,
- .svhs = 1,
- .muxsel = { 2, 3 },
- .pll = PLL_28,
- .tuner_type = UNSET,
- .tuner_addr = ADDR_UNSET,
- .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,
- .tuner_addr = ADDR_UNSET,
- .svhs = -1,
- .gpiomask = 0,
- .muxsel = { 0, 1, 2, 3 },
- .muxsel_hook = eagle_muxsel,
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .pll = PLL_28,
-},{
- .name = "Pinnacle PCTV Sat",
- .video_inputs = 2,
- .audio_inputs = 0,
- .svhs = 1,
- .tuner = -1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
- .gpiomask = 0x01,
- .audiomux = { 0, 0, 0, 0, 1 },
- .muxsel = { 3, 0, 1, 2},
- .needs_tvaudio = 0,
- .pll = PLL_28,
- .no_gpioirq = 1,
- .has_dvb = 1,
-},{
- .name = "Formac ProTV II (bt878)",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 3,
- .gpiomask = 2,
- /* TV, Comp1, Composite over SVID con, SVID */
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 2, 2, 0, 0, 0 },
- .pll = PLL_28,
- .has_radio = 1,
- .tuner_type = TUNER_PHILIPS_PAL,
- .tuner_addr = ADDR_UNSET,
-/* sound routing:
- GPIO=0x00,0x01,0x03: mute (?)
- 0x02: both TV and radio (tuner: FM1216/I)
- The card has onboard audio connectors labeled "cdrom" and "board",
- not soldered here, though unknown wiring.
- Card lacks: external audio in, pci subsystem id.
-*/
-},{
-
- /* ---- card 0x60 ---------------------------------- */
- .name = "MachTV",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = -1,
- .gpiomask = 7,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0, 1, 2, 3, 4},
- .needs_tvaudio = 1,
- .tuner_type = 5,
- .tuner_addr = ADDR_UNSET,
- .pll = 1,
-},{
- .name = "Euresys Picolo",
- .video_inputs = 3,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = 2,
- .gpiomask = 0,
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
- .muxsel = { 2, 0, 1},
- .pll = PLL_28,
- .tuner_type = UNSET,
- .tuner_addr = ADDR_UNSET,
-},{
- /* Luc Van Hoeylandt <luc@e-magic.be> */
- .name = "ProVideo PV150", /* 0x4f */
- .video_inputs = 2,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
- .gpiomask = 0,
- .muxsel = { 2, 3 },
- .audiomux = { 0 },
- .needs_tvaudio = 0,
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = UNSET,
- .tuner_addr = ADDR_UNSET,
-},{
- /* Hiroshi Takekawa <sian@big.or.jp> */
- /* This card lacks subsystem ID */
- .name = "AD-TVK503", /* 0x63 */
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x001e8007,
- .muxsel = { 2, 3, 1, 0 },
- /* Tuner, Radio, external, internal, off, on */
- .audiomux = { 0x08, 0x0f, 0x0a, 0x08, 0x0f, 0x08 },
- .needs_tvaudio = 0,
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = 2,
- .tuner_addr = ADDR_UNSET,
- .audio_hook = adtvk503_audio,
-},{
-
- /* ---- card 0x64 ---------------------------------- */
- .name = "Hercules Smart TV Stereo",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x00,
- .muxsel = { 2, 3, 1, 1 },
- .needs_tvaudio = 1,
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = 5,
- .tuner_addr = ADDR_UNSET,
- /* Notes:
- - card lacks subsystem ID
- - stereo variant w/ daughter board with tda9874a @0xb0
- - Audio Routing:
- always from tda9874 independent of GPIO (?)
- external line in: unknown
- - Other chips: em78p156elp @ 0x96 (probably IR remote control)
- hef4053 (instead 4052) for unknown function
- */
-},{
- .name = "Pace TV & Radio Card",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .muxsel = { 2, 3, 1, 1}, /* Tuner, CVid, SVid, CVid over SVid connector */
- .gpiomask = 0,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
- .tuner_type = 1,
- .tuner_addr = ADDR_UNSET,
- .has_radio = 1,
- .pll = PLL_28,
- /* Bt878, Bt832, FI1246 tuner; no pci subsystem id
- only internal line out: (4pin header) RGGL
- Radio must be decoded by msp3410d (not routed through)*/
- /*
- .digital_mode = DIGITAL_MODE_CAMERA, todo!
- */
-},{
- /* Chris Willing <chris@vislab.usyd.edu.au> */
- .name = "IVC-200",
- .video_inputs = 1,
- .audio_inputs = 0,
- .tuner = -1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .svhs = -1,
- .gpiomask = 0xdf,
- .muxsel = { 2 },
- .pll = PLL_28,
-},{
- .name = "Grand X-Guard / Trust 814PCI",
- .video_inputs = 16,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
- .tuner_type = 4,
- .tuner_addr = ADDR_UNSET,
- .gpiomask2 = 0xff,
- .muxsel = { 2,2,2,2, 3,3,3,3, 1,1,1,1, 0,0,0,0 },
- .muxsel_hook = xguard_muxsel,
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
- .pll = PLL_28,
-},{
-
- /* ---- card 0x68 ---------------------------------- */
- .name = "Nebula Electronics DigiTV",
- .video_inputs = 1,
- .tuner = -1,
- .svhs = -1,
- .muxsel = { 2, 3, 1, 0},
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .has_dvb = 1,
- .no_gpioirq = 1,
-},{
- /* Jorge Boncompte - DTI2 <jorge@dti2.net> */
- .name = "ProVideo PV143",
- .video_inputs = 4,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
- .gpiomask = 0,
- .muxsel = { 2, 3, 1, 0 },
- .audiomux = { 0 },
- .needs_tvaudio = 0,
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- /* M.Klahr@phytec.de */
- .name = "PHYTEC VD-009-X1 MiniDIN (bt878)",
- .video_inputs = 4,
- .audio_inputs = 0,
- .tuner = -1, /* card has no tuner */
- .svhs = 3,
- .gpiomask = 0x00,
- .muxsel = { 2, 3, 1, 0},
- .audiomux = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "PHYTEC VD-009-X1 Combi (bt878)",
- .video_inputs = 4,
- .audio_inputs = 0,
- .tuner = -1, /* card has no tuner */
- .svhs = 3,
- .gpiomask = 0x00,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
-
- /* ---- card 0x6c ---------------------------------- */
- .name = "PHYTEC VD-009 MiniDIN (bt878)",
- .video_inputs = 10,
- .audio_inputs = 0,
- .tuner = -1, /* card has no tuner */
- .svhs = 9,
- .gpiomask = 0x00,
- .gpiomask2 = 0x03, /* gpiomask2 defines the bits used to switch audio
- via the upper nibble of muxsel. here: used for
- xternal video-mux */
- .muxsel = { 0x02, 0x12, 0x22, 0x32, 0x03, 0x13, 0x23, 0x33, 0x01, 0x00 },
- .audiomux = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "PHYTEC VD-009 Combi (bt878)",
- .video_inputs = 10,
- .audio_inputs = 0,
- .tuner = -1, /* card has no tuner */
- .svhs = 9,
- .gpiomask = 0x00,
- .gpiomask2 = 0x03, /* gpiomask2 defines the bits used to switch audio
- via the upper nibble of muxsel. here: used for
- xternal video-mux */
- .muxsel = { 0x02, 0x12, 0x22, 0x32, 0x03, 0x13, 0x23, 0x33, 0x01, 0x01 },
- .audiomux = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "IVC-100",
- .video_inputs = 4,
- .audio_inputs = 0,
- .tuner = -1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .svhs = -1,
- .gpiomask = 0xdf,
- .muxsel = { 2, 3, 1, 0 },
- .pll = PLL_28,
-},{
- /* IVC-120G - Alan Garfield <alan@fromorbit.com> */
- .name = "IVC-120G",
- .video_inputs = 16,
- .audio_inputs = 0, /* card has no audio */
- .tuner = -1, /* card has no tuner */
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .svhs = -1, /* card has no svhs */
- .needs_tvaudio = 0,
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
- .gpiomask = 0x00,
- .muxsel = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
- 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 },
- .muxsel_hook = ivc120_muxsel,
- .pll = PLL_28,
-},{
-
- /* ---- card 0x70 ---------------------------------- */
- .name = "pcHDTV HD-2000 TV",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .muxsel = { 2, 3, 1, 0},
- .tuner_type = TUNER_PHILIPS_ATSC,
- .tuner_addr = ADDR_UNSET,
- .has_dvb = 1,
-},{
- .name = "Twinhan DST + clones",
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
- .tuner_type = TUNER_ABSENT,
- .tuner_addr = ADDR_UNSET,
- .no_video = 1,
- .has_dvb = 1,
-},{
- .name = "Winfast VC100",
- .video_inputs = 3,
- .audio_inputs = 0,
- .svhs = 1,
- .tuner = -1,
- .muxsel = { 3, 1, 1, 3}, /* Vid In, SVid In, Vid over SVid in connector */
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
- .tuner_type = TUNER_ABSENT,
- .tuner_addr = ADDR_UNSET,
- .pll = PLL_28,
-},{
- .name = "Teppro TEV-560/InterVision IV-560",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 3,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 1, 1, 1, 1, 0},
- .needs_tvaudio = 1,
- .tuner_type = TUNER_PHILIPS_PAL,
- .tuner_addr = ADDR_UNSET,
- .pll = PLL_35,
-},{
-
- /* ---- card 0x74 ---------------------------------- */
- .name = "SIMUS GVC1100",
- .video_inputs = 4,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .pll = PLL_28,
- .muxsel = { 2, 2, 2, 2},
- .gpiomask = 0x3F,
- .muxsel_hook = gvc1100_muxsel,
-},{
- /* Carlos Silva r3pek@r3pek.homelinux.org || card 0x75 */
- .name = "NGS NGSTV+",
- .video_inputs = 3,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x008007,
- .muxsel = {2, 3, 0, 0},
- .audiomux = {0, 0, 0, 0, 0x000003, 0},
- .pll = PLL_28,
- .tuner_type = TUNER_PHILIPS_PAL,
- .tuner_addr = ADDR_UNSET,
- .has_remote = 1,
-},{
- /* http://linuxmedialabs.com */
- .name = "LMLBT4",
- .video_inputs = 4, /* IN1,IN2,IN3,IN4 */
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
- .muxsel = { 2, 3, 1, 0 },
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
- .needs_tvaudio = 0,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- /* Helmroos Harri <harri.helmroos@pp.inet.fi> */
- .name = "Tekram M205 PRO",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .tuner_type = TUNER_PHILIPS_PAL,
- .tuner_addr = ADDR_UNSET,
- .svhs = 2,
- .needs_tvaudio = 0,
- .gpiomask = 0x68,
- .muxsel = { 2, 3, 1},
- .audiomux = { 0x68, 0x68, 0x61, 0x61, 0x00 },
- .pll = PLL_28,
-},{
-
- /* ---- card 0x78 ---------------------------------- */
- /* Javier Cendan Ares <jcendan@lycos.es> */
- /* bt878 TV + FM without subsystem ID */
- .name = "Conceptronic CONTVFMi",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x008007,
- .muxsel = { 2, 3, 1, 1 },
- .audiomux = { 0, 1, 2, 2, 3 },
- .needs_tvaudio = 0,
- .pll = PLL_28,
- .tuner_type = TUNER_PHILIPS_PAL,
- .tuner_addr = ADDR_UNSET,
- .has_remote = 1,
- .has_radio = 1,
-},{
- /*Eric DEBIEF <debief@telemsa.com>*/
- /*EURESYS Picolo Tetra : 4 Conexant Fusion 878A, no audio, video input set with analog multiplexers GPIO controled*/
- /* adds picolo_tetra_muxsel(), picolo_tetra_init(), the folowing declaration strucure, and #define BTTV_PICOLO_TETRA_CHIP*/
- /*0x79 in bttv.h*/
- .name = "Euresys Picolo Tetra",
- .video_inputs = 4,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
- .gpiomask = 0,
- .gpiomask2 = 0x3C<<16,/*Set the GPIO[18]->GPIO[21] as output pin.==> drive the video inputs through analog multiplexers*/
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
- .muxsel = {2,2,2,2},/*878A input is always MUX0, see above.*/
- .audiomux = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
- .pll = PLL_28,
- .needs_tvaudio = 0,
- .muxsel_hook = picolo_tetra_muxsel,/*Required as it doesn't follow the classic input selection policy*/
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- /* Spirit TV Tuner from http://spiritmodems.com.au */
- /* Stafford Goodsell <surge@goliath.homeunix.org> */
- .name = "Spirit TV Tuner",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x0000000f,
- .muxsel = { 2, 1, 1 },
- .audiomux = { 0x02, 0x00, 0x00, 0x00, 0x00},
- .tuner_type = TUNER_TEMIC_PAL,
- .tuner_addr = ADDR_UNSET,
- .no_msp34xx = 1,
- .no_tda9875 = 1,
-},{
- /* Wolfram Joost <wojo@frokaschwei.de> */
- .name = "AVerMedia AVerTV DVB-T 771",
- .video_inputs = 2,
- .svhs = 1,
- .tuner = -1,
- .tuner_type = TUNER_ABSENT,
- .tuner_addr = ADDR_UNSET,
- .muxsel = { 3 , 3 },
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
- .pll = PLL_28,
- .has_dvb = 1,
- .no_gpioirq = 1,
- .has_remote = 1,
-},{
- /* ---- card 0x7c ---------------------------------- */
- /* Matt Jesson <dvb@jesson.eclipse.co.uk> */
- /* Based on the Nebula card data - added remote and new card number - BTTV_AVDVBT_761, see also ir-kbd-gpio.c */
- .name = "AverMedia AverTV DVB-T 761",
- .video_inputs = 2,
- .tuner = -1,
- .svhs = 1,
- .muxsel = { 3, 1, 2, 0}, /* Comp0, S-Video, ?, ? */
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .has_dvb = 1,
- .no_gpioirq = 1,
- .has_remote = 1,
-},{
- /* andre.schwarz@matrix-vision.de */
- .name = "MATRIX Vision Sigma-SQ",
- .video_inputs = 16,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
- .gpiomask = 0x0,
- .muxsel = { 2, 2, 2, 2, 2, 2, 2, 2,
- 3, 3, 3, 3, 3, 3, 3, 3 },
- .muxsel_hook = sigmaSQ_muxsel,
- .audiomux = { 0 },
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- /* andre.schwarz@matrix-vision.de */
- .name = "MATRIX Vision Sigma-SLC",
- .video_inputs = 4,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
- .gpiomask = 0x0,
- .muxsel = { 2, 2, 2, 2 },
- .muxsel_hook = sigmaSLC_muxsel,
- .audiomux = { 0 },
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- /* BTTV_APAC_VIEWCOMP */
- /* Attila Kondoros <attila.kondoros@chello.hu> */
- /* bt878 TV + FM 0x00000000 subsystem ID */
- .name = "APAC Viewcomp 878(AMAX)",
- .video_inputs = 2,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = -1,
- .gpiomask = 0xFF,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 2, 0, 0, 0, 10},
- .needs_tvaudio = 0,
- .pll = PLL_28,
- .tuner_type = TUNER_PHILIPS_PAL,
- .tuner_addr = ADDR_UNSET,
- .has_remote = 1, /* miniremote works, see ir-kbd-gpio.c */
- .has_radio = 1, /* not every card has radio */
-},{
-
- /* ---- card 0x80 ---------------------------------- */
- /* Chris Pascoe <c.pascoe@itee.uq.edu.au> */
- .name = "DViCO FusionHDTV DVB-T Lite",
- .tuner = -1,
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
- .pll = PLL_28,
- .no_video = 1,
- .has_dvb = 1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- /* Steven <photon38@pchome.com.tw> */
- .name = "V-Gear MyVCD",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x3f,
- .muxsel = {2, 3, 1, 0},
- .audiomux = {0x31, 0x31, 0x31, 0x31, 0x31, 0x31},
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = TUNER_PHILIPS_NTSC_M,
- .tuner_addr = ADDR_UNSET,
- .has_radio = 0,
-},{
- /* Rick C <cryptdragoon@gmail.com> */
- .name = "Super TV Tuner",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .muxsel = { 2, 3, 1, 0},
- .tuner_type = TUNER_PHILIPS_NTSC,
- .tuner_addr = ADDR_UNSET,
- .gpiomask = 0x008007,
- .audiomux = { 0, 0x000001,0,0, 0},
- .needs_tvaudio = 1,
- .has_radio = 1,
-},{
- /* Chris Fanning <video4linux@haydon.net> */
- .name = "Tibet Systems 'Progress DVR' CS16",
- .video_inputs = 16,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
- .muxsel = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
- .pll = PLL_28,
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .muxsel_hook = tibetCS16_muxsel,
-},
-{
- /* Bill Brack <wbrack@mmm.com.hk> */
- /*
- * Note that, because of the card's wiring, the "master"
- * BT878A chip (i.e. the one which controls the analog switch
- * and must use this card type) is the 2nd one detected. The
- * other 3 chips should use card type 0x85, whose description
- * follows this one. There is a EEPROM on the card (which is
- * connected to the I2C of one of those other chips), but is
- * not currently handled. There is also a facility for a
- * "monitor", which is also not currently implemented.
- */
- .name = "Kodicom 4400R (master)",
- .video_inputs = 16,
- .audio_inputs = 0,
- .tuner = -1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .svhs = -1,
- /* GPIO bits 0-9 used for analog switch:
- * 00 - 03: camera selector
- * 04 - 06: channel (controller) selector
- * 07: data (1->on, 0->off)
- * 08: strobe
- * 09: reset
- * bit 16 is input from sync separator for the channel
- */
- .gpiomask = 0x0003ff,
- .no_gpioirq = 1,
- .muxsel = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
- .pll = PLL_28,
- .no_msp34xx = 1,
- .no_tda7432 = 1,
- .no_tda9875 = 1,
- .muxsel_hook = kodicom4400r_muxsel,
-},
-{
- /* Bill Brack <wbrack@mmm.com.hk> */
- /* Note that, for reasons unknown, the "master" BT878A chip (i.e. the
- * one which controls the analog switch, and must use the card type)
- * is the 2nd one detected. The other 3 chips should use this card
- * type
+
+ },
+ [BTTV_BOARD_PXC200] = {
+ /* Jannik Fritsch <jannik@techfak.uni-bielefeld.de> */
+ .name = "Imagenation PXC200",
+ .video_inputs = 5,
+ .audio_inputs = 1,
+ .tuner = -1,
+ .svhs = 1, /* was: 4 */
+ .gpiomask = 0,
+ .muxsel = { 2, 3, 1, 0, 0},
+ .audiomux = { 0 },
+ .needs_tvaudio = 1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .muxsel_hook = PXC200_muxsel,
+
+ },
+ [BTTV_BOARD_FLYVIDEO_98] = {
+ .name = "Lifeview FlyVideo 98 LR50",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x1800, /* 0x8dfe00 */
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0, 0x0800, 0x1000, 0x1000, 0x1800, 0 },
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_IPROTV] = {
+ .name = "Formac iProTV, Formac ProTV I (bt848)",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 3,
+ .gpiomask = 1,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 1, 0, 0, 0, 0 },
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x20 ---------------------------------- */
+ [BTTV_BOARD_INTEL_C_S_PCI] = {
+ .name = "Intel Create and Share PCI/ Smart Video Recorder III",
+ .video_inputs = 4,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = 2,
+ .gpiomask = 0,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0 },
+ .needs_tvaudio = 0,
+ .tuner_type = 4,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_TERRATVALUE] = {
+ .name = "Terratec TerraTValue Version Bt878",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0xffff00,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0x500, 0, 0x300, 0x900, 0x900},
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_WINFAST2000] = {
+ .name = "Leadtek WinFast 2000/ WinFast 2000 XP",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .muxsel = { 2, 3, 1, 1, 0}, /* TV, CVid, SVid, CVid over SVid connector */
+ #if 0
+ .gpiomask = 0xc33000,
+ .audiomux = { 0x422000,0x1000,0x0000,0x620000,0x800000 },
+ #else
+ /* Alexander Varakin <avarakin@hotmail.com> [stereo version] */
+ .gpiomask = 0xb33000,
+ .audiomux = { 0x122000,0x1000,0x0000,0x620000,0x800000 },
+ #endif
+ /* Audio Routing for "WinFast 2000 XP" (no tv stereo !)
+ gpio23 -- hef4052:nEnable (0x800000)
+ gpio12 -- hef4052:A1
+ gpio13 -- hef4052:A0
+ 0x0000: external audio
+ 0x1000: FM
+ 0x2000: TV
+ 0x3000: n.c.
+ Note: There exists another variant "Winfast 2000" with tv stereo !?
+ Note: eeprom only contains FF and pci subsystem id 107d:6606
+ */
+ .needs_tvaudio = 0,
+ .pll = PLL_28,
+ .has_radio = 1,
+ .tuner_type = 5, /* default for now, gpio reads BFFF06 for Pal bg+dk */
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .audio_hook = winfast2000_audio,
+ .has_remote = 1,
+ },
+ [BTTV_BOARD_CHRONOS_VS2] = {
+ .name = "Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II",
+ .video_inputs = 4,
+ .audio_inputs = 3,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x1800,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0, 0x800, 0x1000, 0x1000, 0x1800},
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x24 ---------------------------------- */
+ [BTTV_BOARD_TYPHOON_TVIEW] = {
+ .name = "Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner",
+ .video_inputs = 4,
+ .audio_inputs = 3,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x1800,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0, 0x800, 0x1000, 0x1000, 0x1800, 0 },
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_radio = 1,
+ },
+ [BTTV_BOARD_PXELVWPLTVPRO] = {
+ .name = "Prolink PixelView PlayTV pro",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0xff,
+ .muxsel = { 2, 3, 1, 1 },
+ .audiomux = { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 },
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_MAGICTVIEW063] = {
+ .name = "Askey CPH06X TView99",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x551e00,
+ .muxsel = { 2, 3, 1, 0},
+ .audiomux = { 0x551400, 0x551200, 0, 0, 0x551c00, 0x551200 },
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = 1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_remote = 1,
+ },
+ [BTTV_BOARD_PINNACLE] = {
+ .name = "Pinnacle PCTV Studio/Rave",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x03000F,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 2, 0xd0001, 0, 0, 1},
+ .needs_tvaudio = 0,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x28 ---------------------------------- */
+ [BTTV_BOARD_STB2] = {
+ .name = "STB TV PCI FM, Gateway P/N 6000704 (bt878), 3Dfx VoodooTV 100",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 7,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 4, 0, 2, 3, 1},
+ .no_msp34xx = 1,
+ .needs_tvaudio = 1,
+ .tuner_type = TUNER_PHILIPS_NTSC,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .pll = PLL_28,
+ .has_radio = 1,
+ },
+ [BTTV_BOARD_AVPHONE98] = {
+ .name = "AVerMedia TVPhone 98",
+ .video_inputs = 3,
+ .audio_inputs = 4,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 15,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 13, 4, 11, 7, 0, 0},
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_radio = 1,
+ .audio_hook = avermedia_tvphone_audio,
+ },
+ [BTTV_BOARD_PV951] = {
+ .name = "ProVideo PV951", /* pic16c54 */
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0, 0, 0, 0, 0},
+ .needs_tvaudio = 1,
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = 1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_ONAIR_TV] = {
+ .name = "Little OnAir TV",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0xe00b,
+ .muxsel = {2, 3, 1, 1},
+ .audiomux = {0xff9ff6, 0xff9ff6, 0xff1ff7, 0, 0xff3ffc},
+ .no_msp34xx = 1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x2c ---------------------------------- */
+ [BTTV_BOARD_SIGMA_TVII_FM] = {
+ .name = "Sigma TVII-FM",
+ .video_inputs = 2,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = -1,
+ .gpiomask = 3,
+ .muxsel = {2, 3, 1, 1},
+ .audiomux = {1, 1, 0, 2, 3},
+ .no_msp34xx = 1,
+ .pll = PLL_NONE,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_MATRIX_VISION2] = {
+ .name = "MATRIX-Vision MV-Delta 2",
+ .video_inputs = 5,
+ .audio_inputs = 1,
+ .tuner = -1,
+ .svhs = 3,
+ .gpiomask = 0,
+ .muxsel = { 2, 3, 1, 0, 0},
+ .audiomux = {0 },
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_ZOLTRIX_GENIE] = {
+ .name = "Zoltrix Genie TV/FM",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0xbcf03f,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0xbc803f, 0xbc903f, 0xbcb03f, 0, 0xbcb03f},
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = 21,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_TERRATVRADIO] = {
+ .name = "Terratec TV/Radio+",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x70000,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0x20000, 0x30000, 0x10000, 0, 0x40000, 0x20000 },
+ .needs_tvaudio = 1,
+ .no_msp34xx = 1,
+ .pll = PLL_35,
+ .tuner_type = 1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_radio = 1,
+ },
+
+ /* ---- card 0x30 ---------------------------------- */
+ [BTTV_BOARD_DYNALINK] = {
+ .name = "Askey CPH03x/ Dynalink Magic TView",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 15,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = {2,0,0,0,1},
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_GVBCTV3PCI] = {
+ .name = "IODATA GV-BCTV3/PCI",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x010f00,
+ .muxsel = {2, 3, 0, 0},
+ .audiomux = {0x10000, 0, 0x10000, 0, 0, 0},
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_ALPS_TSHC6_NTSC,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .audio_hook = gvbctv3pci_audio,
+ },
+ [BTTV_BOARD_PXELVWPLTVPAK] = {
+ .name = "Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP",
+ .video_inputs = 5,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 3,
+ .gpiomask = 0xAA0000,
+ .muxsel = { 2,3,1,1,-1 },
+ .digital_mode = DIGITAL_MODE_CAMERA,
+ .audiomux = { 0x20000, 0, 0x80000, 0x80000, 0xa8000, 0x46000 },
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL_I,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_remote = 1,
+ /* 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
+ */
+ },
+ [BTTV_BOARD_EAGLE] = {
+ .name = "Eagle Wireless Capricorn2 (bt878A)",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 7,
+ .muxsel = { 2, 0, 1, 1},
+ .audiomux = { 0, 1, 2, 3, 4},
+ .pll = PLL_28,
+ .tuner_type = -1 /* TUNER_ALPS_TMDH2_NTSC */,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x34 ---------------------------------- */
+ [BTTV_BOARD_PINNACLEPRO] = {
+ /* David Härdeman <david@2gen.com> */
+ .name = "Pinnacle PCTV Studio Pro",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 3,
+ .gpiomask = 0x03000F,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 1, 0xd0001, 0, 0, 10},
+ /* sound path (5 sources):
+ MUX1 (mask 0x03), Enable Pin 0x08 (0=enable, 1=disable)
+ 0= ext. Audio IN
+ 1= from MUX2
+ 2= Mono TV sound from Tuner
+ 3= not connected
+ MUX2 (mask 0x30000):
+ 0,2,3= from MSP34xx
+ 1= FM stereo Radio from Tuner */
+ .needs_tvaudio = 0,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_TVIEW_RDS_FM] = {
+ /* Claas Langbehn <claas@bigfoot.com>,
+ Sven Grothklags <sven@upb.de> */
+ .name = "Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS",
+ .video_inputs = 4,
+ .audio_inputs = 3,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x1c,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0, 0, 0x10, 8, 4 },
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_radio = 1,
+ },
+ [BTTV_BOARD_LIFETEC_9415] = {
+ /* Tim Röstermundt <rosterm@uni-muenster.de>
+ in de.comp.os.unix.linux.hardware:
+ options bttv card=0 pll=1 radio=1 gpiomask=0x18e0
+ audiomux=0x44c71f,0x44d71f,0,0x44d71f,0x44dfff
+ options tuner type=5 */
+ .name = "Lifeview FlyVideo 2000 /FlyVideo A2/ Lifetec LT 9415 TV [LR90]",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x18e0,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0x0000,0x0800,0x1000,0x1000,0x18e0 },
+ /* For cards with tda9820/tda9821:
+ 0x0000: Tuner normal stereo
+ 0x0080: Tuner A2 SAP (second audio program = Zweikanalton)
+ 0x0880: Tuner A2 stereo */
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_BESTBUY_EASYTV] = {
+ /* Miguel Angel Alvarez <maacruz@navegalia.com>
+ old Easy TV BT848 version (model CPH031) */
+ .name = "Askey CPH031/ BESTBUY Easy TV",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0xF,
+ .muxsel = { 2, 3, 1, 0},
+ .audiomux = { 2, 0, 0, 0, 10},
+ .needs_tvaudio = 0,
+ .pll = PLL_28,
+ .tuner_type = TUNER_TEMIC_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x38 ---------------------------------- */
+ [BTTV_BOARD_FLYVIDEO_98FM] = {
+ /* Gordon Heydon <gjheydon@bigfoot.com ('98) */
+ .name = "Lifeview FlyVideo 98FM LR50",
+ .video_inputs = 4,
+ .audio_inputs = 3,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x1800,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0, 0x800, 0x1000, 0x1000, 0x1800, 0 },
+ .pll = PLL_28,
+ .tuner_type = 5,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ /* This is the ultimate cheapo capture card
+ * just a BT848A on a small PCB!
+ * Steve Hosgood <steve@equiinet.com> */
+ [BTTV_BOARD_GRANDTEC] = {
+ .name = "GrandTec 'Grand Video Capture' (Bt848)",
+ .video_inputs = 2,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = 1,
+ .gpiomask = 0,
+ .muxsel = { 3, 1 },
+ .audiomux = { 0 },
+ .needs_tvaudio = 0,
+ .no_msp34xx = 1,
+ .pll = PLL_35,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_ASKEY_CPH060] = {
+ /* Daniel Herrington <daniel.herrington@home.com> */
+ .name = "Askey CPH060/ Phoebe TV Master Only (No FM)",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0xe00,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0x400, 0x400, 0x400, 0x400, 0x800, 0x400 },
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_TEMIC_4036FY5_NTSC,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_ASKEY_CPH03X] = {
+ /* Matti Mottus <mottus@physic.ut.ee> */
+ .name = "Askey CPH03x TV Capturer",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x03000F,
+ .muxsel = { 2, 3, 1, 0},
+ .audiomux = { 2,0,0,0,1 },
+ .pll = PLL_28,
+ .tuner_type = 0,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x3c ---------------------------------- */
+ [BTTV_BOARD_MM100PCTV] = {
+ /* Philip Blundell <philb@gnu.org> */
+ .name = "Modular Technology MM100PCTV",
+ .video_inputs = 2,
+ .audio_inputs = 2,
+ .tuner = 0,
+ .svhs = -1,
+ .gpiomask = 11,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 2, 0, 0, 1, 8},
+ .pll = PLL_35,
+ .tuner_type = TUNER_TEMIC_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_GMV1] = {
+ /* Adrian Cox <adrian@humboldt.co.uk */
+ .name = "AG Electronics GMV1",
+ .video_inputs = 2,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = 1,
+ .gpiomask = 0xF,
+ .muxsel = { 2, 2},
+ .audiomux = { },
+ .no_msp34xx = 1,
+ .needs_tvaudio = 0,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_BESTBUY_EASYTV2] = {
+ /* Miguel Angel Alvarez <maacruz@navegalia.com>
+ new Easy TV BT878 version (model CPH061)
+ special thanks to Informatica Mieres for providing the card */
+ .name = "Askey CPH061/ BESTBUY Easy TV (bt878)",
+ .video_inputs = 3,
+ .audio_inputs = 2,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0xFF,
+ .muxsel = { 2, 3, 1, 0},
+ .audiomux = { 1, 0, 4, 4, 9},
+ .needs_tvaudio = 0,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_ATI_TVWONDER] = {
+ /* Lukas Gebauer <geby@volny.cz> */
+ .name = "ATI TV-Wonder",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0xf03f,
+ .muxsel = { 2, 3, 1, 0 },
+ .audiomux = { 0xbffe, 0, 0xbfff, 0, 0xbffe},
+ .pll = PLL_28,
+ .tuner_type = TUNER_TEMIC_4006FN5_MULTI_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x40 ---------------------------------- */
+ [BTTV_BOARD_ATI_TVWONDERVE] = {
+ /* Lukas Gebauer <geby@volny.cz> */
+ .name = "ATI TV-Wonder VE",
+ .video_inputs = 2,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = -1,
+ .gpiomask = 1,
+ .muxsel = { 2, 3, 0, 1},
+ .audiomux = { 0, 0, 1, 0, 0},
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_TEMIC_4006FN5_MULTI_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_FLYVIDEO2000] = {
+ /* DeeJay <deejay@westel900.net (2000S) */
+ .name = "Lifeview FlyVideo 2000S LR90",
+ .video_inputs = 3,
+ .audio_inputs = 3,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x18e0,
+ .muxsel = { 2, 3, 0, 1},
+ /* Radio changed from 1e80 to 0x800 to make
+ FlyVideo2000S in .hu happy (gm)*/
+ /* -dk-???: set mute=0x1800 for tda9874h daughterboard */
+ .audiomux = { 0x0000,0x0800,0x1000,0x1000,0x1800, 0x1080 },
+ .audio_hook = fv2000s_audio,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = 5,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_TERRATVALUER] = {
+ .name = "Terratec TValueRadio",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0xffff00,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0x500, 0x500, 0x300, 0x900, 0x900},
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_radio = 1,
+ },
+ [BTTV_BOARD_GVBCTV4PCI] = {
+ /* TANAKA Kei <peg00625@nifty.com> */
+ .name = "IODATA GV-BCTV4/PCI",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x010f00,
+ .muxsel = {2, 3, 0, 0},
+ .audiomux = {0x10000, 0, 0x10000, 0, 0, 0},
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_SHARP_2U5JF5540_NTSC,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .audio_hook = gvbctv3pci_audio,
+ },
+
+ /* ---- card 0x44 ---------------------------------- */
+ [BTTV_BOARD_VOODOOTV_FM] = {
+ .name = "3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)",
+ /* try "insmod msp3400 simple=0" if you have
+ * sound problems with this card. */
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = -1,
+ .gpiomask = 0x4f8a00,
+ /* 0x100000: 1=MSP enabled (0=disable again)
+ * 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */
+ .audiomux = {0x947fff, 0x987fff,0x947fff,0x947fff, 0x947fff},
+ /* tvtuner, radio, external,internal, mute, stereo
+ * tuner, Composit, SVid, Composit-on-Svid-adapter */
+ .muxsel = { 2, 3 ,0 ,1},
+ .tuner_type = TUNER_MT2032,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .pll = PLL_28,
+ .has_radio = 1,
+ },
+ [BTTV_BOARD_AIMMS] = {
+ /* Philip Blundell <pb@nexus.co.uk> */
+ .name = "Active Imaging AIMMS",
+ .video_inputs = 1,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .pll = PLL_28,
+ .muxsel = { 2 },
+ .gpiomask = 0
+ },
+ [BTTV_BOARD_PV_BT878P_PLUS] = {
+ /* Tomasz Pyra <hellfire@sedez.iq.pl> */
+ .name = "Prolink Pixelview PV-BT878P+ (Rev.4C,8E)",
+ .video_inputs = 3,
+ .audio_inputs = 4,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 15,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0, 0, 11, 7, 13, 0}, /* TV and Radio with same GPIO ! */
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = 25,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_remote = 1,
+ /* GPIO wiring:
+ GPIO0: U4.A0 (hef4052bt)
+ GPIO1: U4.A1
+ GPIO2: U4.A1 (second hef4052bt)
+ GPIO3: U4.nEN, U5.A0, A5.nEN
+ GPIO8-15: vrd866b ?
+ */
+ },
+ [BTTV_BOARD_FLYVIDEO98EZ] = {
+ .name = "Lifeview FlyVideo 98EZ (capture only) LR51",
+ .video_inputs = 4,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = 2,
+ .muxsel = { 2, 3, 1, 1}, /* AV1, AV2, SVHS, CVid adapter on SVHS */
+ .pll = PLL_28,
+ .no_msp34xx = 1,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x48 ---------------------------------- */
+ [BTTV_BOARD_PV_BT878P_9B] = {
+ /* Dariusz Kowalewski <darekk@automex.pl> */
+ .name = "Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x3f,
+ .muxsel = { 2, 3, 1, 1 },
+ .audiomux = { 0x01, 0x00, 0x03, 0x03, 0x09, 0x02 },
+ .needs_tvaudio = 1,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .pll = PLL_28,
+ .tuner_type = 5,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .audio_hook = pvbt878p9b_audio, /* Note: not all cards have stereo */
+ .has_radio = 1, /* Note: not all cards have radio */
+ .has_remote = 1,
+ /* GPIO wiring:
+ GPIO0: A0 hef4052
+ GPIO1: A1 hef4052
+ GPIO3: nEN hef4052
+ GPIO8-15: vrd866b
+ GPIO20,22,23: R30,R29,R28
+ */
+ },
+ [BTTV_BOARD_SENSORAY311] = {
+ /* Clay Kunz <ckunz@mail.arc.nasa.gov> */
+ /* you must jumper JP5 for the card to work */
+ .name = "Sensoray 311",
+ .video_inputs = 5,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = 4,
+ .gpiomask = 0,
+ .muxsel = { 2, 3, 1, 0, 0},
+ .audiomux = { 0 },
+ .needs_tvaudio = 0,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_RV605] = {
+ /* Miguel Freitas <miguel@cetuc.puc-rio.br> */
+ .name = "RemoteVision MX (RV605)",
+ .video_inputs = 16,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = -1,
+ .gpiomask = 0x00,
+ .gpiomask2 = 0x07ff,
+ .muxsel = { 0x33, 0x13, 0x23, 0x43, 0xf3, 0x73, 0xe3, 0x03,
+ 0xd3, 0xb3, 0xc3, 0x63, 0x93, 0x53, 0x83, 0xa3 },
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .muxsel_hook = rv605_muxsel,
+ },
+ [BTTV_BOARD_POWERCLR_MTV878] = {
+ .name = "Powercolor MTV878/ MTV878R/ MTV878F",
+ .video_inputs = 3,
+ .audio_inputs = 2,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x1C800F, /* Bit0-2: Audio select, 8-12:remote control 14:remote valid 15:remote reset */
+ .muxsel = { 2, 1, 1, },
+ .audiomux = { 0, 1, 2, 2, 4 },
+ .needs_tvaudio = 0,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .pll = PLL_28,
+ .has_radio = 1,
+ },
+
+ /* ---- card 0x4c ---------------------------------- */
+ [BTTV_BOARD_WINDVR] = {
+ /* Masaki Suzuki <masaki@btree.org> */
+ .name = "Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP)",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x140007,
+ .muxsel = { 2, 3, 1, 1 },
+ .audiomux = { 0, 1, 2, 3, 4, 0 },
+ .tuner_type = TUNER_PHILIPS_NTSC,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .audio_hook = windvr_audio,
+ },
+ [BTTV_BOARD_GRANDTEC_MULTI] = {
+ .name = "GrandTec Multi Capture Card (Bt878)",
+ .video_inputs = 4,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = -1,
+ .gpiomask = 0,
+ .muxsel = { 2, 3, 1, 0 },
+ .audiomux = { 0 },
+ .needs_tvaudio = 0,
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_KWORLD] = {
+ .name = "Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF",
+ .video_inputs = 4,
+ .audio_inputs = 3,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 7,
+ .muxsel = { 2, 3, 1, 1 }, /* Tuner, SVid, SVHS, SVid to SVHS connector */
+ .audiomux = { 0 ,0 ,4, 4,4,4},/* Yes, this tuner uses the same audio output for TV and FM radio!
+ * This card lacks external Audio In, so we mute it on Ext. & Int.
+ * The PCB can take a sbx1637/sbx1673, wiring unknown.
+ * This card lacks PCI subsystem ID, sigh.
+ * audiomux=1: lower volume, 2+3: mute
+ * btwincap uses 0x80000/0x80003
+ */
+ .needs_tvaudio = 0,
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = 5,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ /* Samsung TCPA9095PC27A (BG+DK), philips compatible, w/FM, stereo and
+ radio signal strength indicators work fine. */
+ .has_radio = 1,
+ /* GPIO Info:
+ GPIO0,1: HEF4052 A0,A1
+ GPIO2: HEF4052 nENABLE
+ GPIO3-7: n.c.
+ GPIO8-13: IRDC357 data0-5 (data6 n.c. ?) [chip not present on my card]
+ GPIO14,15: ??
+ GPIO16-21: n.c.
+ GPIO22,23: ??
+ ?? : mtu8b56ep microcontroller for IR (GPIO wiring unknown)*/
+ },
+ [BTTV_BOARD_DSP_TCVIDEO] = {
+ /* Arthur Tetzlaff-Deas, DSP Design Ltd <software@dspdesign.com> */
+ .name = "DSP Design TCVIDEO",
+ .video_inputs = 4,
+ .svhs = -1,
+ .muxsel = { 2, 3, 1, 0},
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x50 ---------------------------------- */
+ [BTTV_BOARD_HAUPPAUGEPVR] = {
+ .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,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+
+ .gpiomask = 7,
+ .audiomux = {7},
+ },
+ [BTTV_BOARD_GVBCTV5PCI] = {
+ .name = "IODATA GV-BCTV5/PCI",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x0f0f80,
+ .muxsel = {2, 3, 1, 0},
+ .audiomux = {0x030000, 0x010000, 0, 0, 0x020000, 0},
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .audio_hook = gvbctv5pci_audio,
+ .has_radio = 1,
+ },
+ [BTTV_BOARD_OSPREY1x0] = {
+ .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,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ },
+ [BTTV_BOARD_OSPREY1x0_848] = {
+ .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,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ },
+
+ /* ---- card 0x54 ---------------------------------- */
+ [BTTV_BOARD_OSPREY101_848] = {
+ .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,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ },
+ [BTTV_BOARD_OSPREY1x1] = {
+ .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,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ },
+ [BTTV_BOARD_OSPREY1x1_SVID] = {
+ .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,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ },
+ [BTTV_BOARD_OSPREY2xx] = {
+ .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 = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ },
+
+ /* ---- card 0x58 ---------------------------------- */
+ [BTTV_BOARD_OSPREY2x0_SVID] = {
+ .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 = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ },
+ [BTTV_BOARD_OSPREY2x0] = {
+ .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 = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ },
+ [BTTV_BOARD_OSPREY500] = {
+ .name = "Osprey 500", /* 500 */
+ .video_inputs = 2,
+ .audio_inputs = 1,
+ .tuner = -1,
+ .svhs = 1,
+ .muxsel = { 2, 3 },
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ },
+ [BTTV_BOARD_OSPREY540] = {
+ .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,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .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 ---------------------------------- */
+ [BTTV_BOARD_OSPREY2000] = {
+ .name = "Osprey 2000", /* 2000 */
+ .video_inputs = 2,
+ .audio_inputs = 1,
+ .tuner = -1,
+ .svhs = 1,
+ .muxsel = { 2, 3 },
+ .pll = PLL_28,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1, /* must avoid, conflicts with the bt860 */
+ },
+ [BTTV_BOARD_IDS_EAGLE] = {
+ /* M G Berberich <berberic@forwiss.uni-passau.de> */
+ .name = "IDS Eagle",
+ .video_inputs = 4,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .svhs = -1,
+ .gpiomask = 0,
+ .muxsel = { 0, 1, 2, 3 },
+ .muxsel_hook = eagle_muxsel,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .pll = PLL_28,
+ },
+ [BTTV_BOARD_PINNACLESAT] = {
+ .name = "Pinnacle PCTV Sat",
+ .video_inputs = 2,
+ .audio_inputs = 0,
+ .svhs = 1,
+ .tuner = -1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .muxsel = { 3, 0, 1, 2},
+ .pll = PLL_28,
+ .no_gpioirq = 1,
+ .has_dvb = 1,
+ },
+ [BTTV_BOARD_FORMAC_PROTV] = {
+ .name = "Formac ProTV II (bt878)",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 3,
+ .gpiomask = 2,
+ /* TV, Comp1, Composite over SVID con, SVID */
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 2, 2, 0, 0, 0 },
+ .pll = PLL_28,
+ .has_radio = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ /* sound routing:
+ GPIO=0x00,0x01,0x03: mute (?)
+ 0x02: both TV and radio (tuner: FM1216/I)
+ The card has onboard audio connectors labeled "cdrom" and "board",
+ not soldered here, though unknown wiring.
+ Card lacks: external audio in, pci subsystem id.
*/
- .name = "Kodicom 4400R (slave)",
- .video_inputs = 16,
- .audio_inputs = 0,
- .tuner = -1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .svhs = -1,
- .gpiomask = 0x010000,
- .no_gpioirq = 1,
- .muxsel = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
- .pll = PLL_28,
- .no_msp34xx = 1,
- .no_tda7432 = 1,
- .no_tda9875 = 1,
- .muxsel_hook = kodicom4400r_muxsel,
-},
-{
- /* ---- card 0x86---------------------------------- */
- /* Michael Henson <mhenson@clarityvi.com> */
- /* Adlink RTV24 with special unlock codes */
- .name = "Adlink RTV24",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .muxsel = { 2, 3, 1, 0},
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .pll = PLL_28,
-},
-{
- /* ---- card 0x87---------------------------------- */
- /* Michael Krufky <mkrufky@m1k.net> */
- .name = "DViCO FusionHDTV 5 Lite",
- .tuner = 0,
- .tuner_type = TUNER_LG_TDVS_H062F,
- .tuner_addr = ADDR_UNSET,
- .video_inputs = 3,
- .audio_inputs = 1,
- .svhs = 2,
- .muxsel = { 2, 3, 1 },
- .gpiomask = 0x00e00007,
- .audiomux = { 0x00400005, 0, 0x00000001, 0, 0x00c00007, 0 },
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
-},{
- /* ---- card 0x88---------------------------------- */
- /* Mauro Carvalho Chehab <mchehab@brturbo.com.br> */
- .name = "Acorp Y878F",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x01fe00,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0x001e00, 0, 0x018000, 0x014000, 0x002000, 0 },
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = TUNER_YMEC_TVF66T5_B_DFF,
- .tuner_addr = 0xc1 >>1,
- .has_radio = 1,
-}};
+ },
+
+ /* ---- card 0x60 ---------------------------------- */
+ [BTTV_BOARD_MACHTV] = {
+ .name = "MachTV",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = -1,
+ .gpiomask = 7,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0, 1, 2, 3, 4},
+ .needs_tvaudio = 1,
+ .tuner_type = 5,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .pll = PLL_28,
+ },
+ [BTTV_BOARD_EURESYS_PICOLO] = {
+ .name = "Euresys Picolo",
+ .video_inputs = 3,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = 2,
+ .gpiomask = 0,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .muxsel = { 2, 0, 1},
+ .pll = PLL_28,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_PV150] = {
+ /* Luc Van Hoeylandt <luc@e-magic.be> */
+ .name = "ProVideo PV150", /* 0x4f */
+ .video_inputs = 2,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = -1,
+ .gpiomask = 0,
+ .muxsel = { 2, 3 },
+ .audiomux = { 0 },
+ .needs_tvaudio = 0,
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_AD_TVK503] = {
+ /* Hiroshi Takekawa <sian@big.or.jp> */
+ /* This card lacks subsystem ID */
+ .name = "AD-TVK503", /* 0x63 */
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x001e8007,
+ .muxsel = { 2, 3, 1, 0 },
+ /* Tuner, Radio, external, internal, off, on */
+ .audiomux = { 0x08, 0x0f, 0x0a, 0x08, 0x0f, 0x08 },
+ .needs_tvaudio = 0,
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = 2,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .audio_hook = adtvk503_audio,
+ },
+
+ /* ---- card 0x64 ---------------------------------- */
+ [BTTV_BOARD_HERCULES_SM_TV] = {
+ .name = "Hercules Smart TV Stereo",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x00,
+ .muxsel = { 2, 3, 1, 1 },
+ .needs_tvaudio = 1,
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = 5,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ /* Notes:
+ - card lacks subsystem ID
+ - stereo variant w/ daughter board with tda9874a @0xb0
+ - Audio Routing:
+ always from tda9874 independent of GPIO (?)
+ external line in: unknown
+ - Other chips: em78p156elp @ 0x96 (probably IR remote control)
+ hef4053 (instead 4052) for unknown function
+ */
+ },
+ [BTTV_BOARD_PACETV] = {
+ .name = "Pace TV & Radio Card",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .muxsel = { 2, 3, 1, 1}, /* Tuner, CVid, SVid, CVid over SVid connector */
+ .gpiomask = 0,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .tuner_type = 1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_radio = 1,
+ .pll = PLL_28,
+ /* Bt878, Bt832, FI1246 tuner; no pci subsystem id
+ only internal line out: (4pin header) RGGL
+ Radio must be decoded by msp3410d (not routed through)*/
+ /*
+ .digital_mode = DIGITAL_MODE_CAMERA, todo!
+ */
+ },
+ [BTTV_BOARD_IVC200] = {
+ /* Chris Willing <chris@vislab.usyd.edu.au> */
+ .name = "IVC-200",
+ .video_inputs = 1,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .svhs = -1,
+ .gpiomask = 0xdf,
+ .muxsel = { 2 },
+ .pll = PLL_28,
+ },
+ [BTTV_BOARD_XGUARD] = {
+ .name = "Grand X-Guard / Trust 814PCI",
+ .video_inputs = 16,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = -1,
+ .tuner_type = 4,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask2 = 0xff,
+ .muxsel = { 2,2,2,2, 3,3,3,3, 1,1,1,1, 0,0,0,0 },
+ .muxsel_hook = xguard_muxsel,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .pll = PLL_28,
+ },
+
+ /* ---- card 0x68 ---------------------------------- */
+ [BTTV_BOARD_NEBULA_DIGITV] = {
+ .name = "Nebula Electronics DigiTV",
+ .video_inputs = 1,
+ .tuner = -1,
+ .svhs = -1,
+ .muxsel = { 2, 3, 1, 0},
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_dvb = 1,
+ .has_remote = 1,
+ .gpiomask = 0x1b,
+ .no_gpioirq = 1,
+ .any_irq = 1,
+ },
+ [BTTV_BOARD_PV143] = {
+ /* Jorge Boncompte - DTI2 <jorge@dti2.net> */
+ .name = "ProVideo PV143",
+ .video_inputs = 4,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = -1,
+ .gpiomask = 0,
+ .muxsel = { 2, 3, 1, 0 },
+ .audiomux = { 0 },
+ .needs_tvaudio = 0,
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_VD009X1_MINIDIN] = {
+ /* M.Klahr@phytec.de */
+ .name = "PHYTEC VD-009-X1 MiniDIN (bt878)",
+ .video_inputs = 4,
+ .audio_inputs = 0,
+ .tuner = -1, /* card has no tuner */
+ .svhs = 3,
+ .gpiomask = 0x00,
+ .muxsel = { 2, 3, 1, 0},
+ .audiomux = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_VD009X1_COMBI] = {
+ .name = "PHYTEC VD-009-X1 Combi (bt878)",
+ .video_inputs = 4,
+ .audio_inputs = 0,
+ .tuner = -1, /* card has no tuner */
+ .svhs = 3,
+ .gpiomask = 0x00,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x6c ---------------------------------- */
+ [BTTV_BOARD_VD009_MINIDIN] = {
+ .name = "PHYTEC VD-009 MiniDIN (bt878)",
+ .video_inputs = 10,
+ .audio_inputs = 0,
+ .tuner = -1, /* card has no tuner */
+ .svhs = 9,
+ .gpiomask = 0x00,
+ .gpiomask2 = 0x03, /* gpiomask2 defines the bits used to switch audio
+ via the upper nibble of muxsel. here: used for
+ xternal video-mux */
+ .muxsel = { 0x02, 0x12, 0x22, 0x32, 0x03, 0x13, 0x23, 0x33, 0x01, 0x00 },
+ .audiomux = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_VD009_COMBI] = {
+ .name = "PHYTEC VD-009 Combi (bt878)",
+ .video_inputs = 10,
+ .audio_inputs = 0,
+ .tuner = -1, /* card has no tuner */
+ .svhs = 9,
+ .gpiomask = 0x00,
+ .gpiomask2 = 0x03, /* gpiomask2 defines the bits used to switch audio
+ via the upper nibble of muxsel. here: used for
+ xternal video-mux */
+ .muxsel = { 0x02, 0x12, 0x22, 0x32, 0x03, 0x13, 0x23, 0x33, 0x01, 0x01 },
+ .audiomux = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_IVC100] = {
+ .name = "IVC-100",
+ .video_inputs = 4,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .svhs = -1,
+ .gpiomask = 0xdf,
+ .muxsel = { 2, 3, 1, 0 },
+ .pll = PLL_28,
+ },
+ [BTTV_BOARD_IVC120] = {
+ /* IVC-120G - Alan Garfield <alan@fromorbit.com> */
+ .name = "IVC-120G",
+ .video_inputs = 16,
+ .audio_inputs = 0, /* card has no audio */
+ .tuner = -1, /* card has no tuner */
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .svhs = -1, /* card has no svhs */
+ .needs_tvaudio = 0,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .gpiomask = 0x00,
+ .muxsel = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 },
+ .muxsel_hook = ivc120_muxsel,
+ .pll = PLL_28,
+ },
+
+ /* ---- card 0x70 ---------------------------------- */
+ [BTTV_BOARD_PC_HDTV] = {
+ .name = "pcHDTV HD-2000 TV",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .muxsel = { 2, 3, 1, 0},
+ .tuner_type = TUNER_PHILIPS_ATSC,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_dvb = 1,
+ },
+ [BTTV_BOARD_TWINHAN_DST] = {
+ .name = "Twinhan DST + clones",
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .no_video = 1,
+ .has_dvb = 1,
+ },
+ [BTTV_BOARD_WINFASTVC100] = {
+ .name = "Winfast VC100",
+ .video_inputs = 3,
+ .audio_inputs = 0,
+ .svhs = 1,
+ .tuner = -1,
+ .muxsel = { 3, 1, 1, 3}, /* Vid In, SVid In, Vid over SVid in connector */
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .pll = PLL_28,
+ },
+ [BTTV_BOARD_TEV560] = {
+ .name = "Teppro TEV-560/InterVision IV-560",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 3,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 1, 1, 1, 1, 0},
+ .needs_tvaudio = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .pll = PLL_35,
+ },
+
+ /* ---- card 0x74 ---------------------------------- */
+ [BTTV_BOARD_SIMUS_GVC1100] = {
+ .name = "SIMUS GVC1100",
+ .video_inputs = 4,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = -1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .pll = PLL_28,
+ .muxsel = { 2, 2, 2, 2},
+ .gpiomask = 0x3F,
+ .muxsel_hook = gvc1100_muxsel,
+ },
+ [BTTV_BOARD_NGSTV_PLUS] = {
+ /* Carlos Silva r3pek@r3pek.homelinux.org || card 0x75 */
+ .name = "NGS NGSTV+",
+ .video_inputs = 3,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x008007,
+ .muxsel = {2, 3, 0, 0},
+ .audiomux = {0, 0, 0, 0, 0x000003, 0},
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_remote = 1,
+ },
+ [BTTV_BOARD_LMLBT4] = {
+ /* http://linuxmedialabs.com */
+ .name = "LMLBT4",
+ .video_inputs = 4, /* IN1,IN2,IN3,IN4 */
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = -1,
+ .muxsel = { 2, 3, 1, 0 },
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .needs_tvaudio = 0,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_TEKRAM_M205] = {
+ /* Helmroos Harri <harri.helmroos@pp.inet.fi> */
+ .name = "Tekram M205 PRO",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .svhs = 2,
+ .needs_tvaudio = 0,
+ .gpiomask = 0x68,
+ .muxsel = { 2, 3, 1},
+ .audiomux = { 0x68, 0x68, 0x61, 0x61, 0x00 },
+ .pll = PLL_28,
+ },
+
+ /* ---- card 0x78 ---------------------------------- */
+ [BTTV_BOARD_CONTVFMI] = {
+ /* Javier Cendan Ares <jcendan@lycos.es> */
+ /* bt878 TV + FM without subsystem ID */
+ .name = "Conceptronic CONTVFMi",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x008007,
+ .muxsel = { 2, 3, 1, 1 },
+ .audiomux = { 0, 1, 2, 2, 3 },
+ .needs_tvaudio = 0,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_remote = 1,
+ .has_radio = 1,
+ },
+ [BTTV_BOARD_PICOLO_TETRA_CHIP] = {
+ /*Eric DEBIEF <debief@telemsa.com>*/
+ /*EURESYS Picolo Tetra : 4 Conexant Fusion 878A, no audio, video input set with analog multiplexers GPIO controled*/
+ /* adds picolo_tetra_muxsel(), picolo_tetra_init(), the folowing declaration strucure, and #define BTTV_BOARD_PICOLO_TETRA_CHIP*/
+ /*0x79 in bttv.h*/
+ .name = "Euresys Picolo Tetra",
+ .video_inputs = 4,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = -1,
+ .gpiomask = 0,
+ .gpiomask2 = 0x3C<<16,/*Set the GPIO[18]->GPIO[21] as output pin.==> drive the video inputs through analog multiplexers*/
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .muxsel = {2,2,2,2},/*878A input is always MUX0, see above.*/
+ .audiomux = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
+ .pll = PLL_28,
+ .needs_tvaudio = 0,
+ .muxsel_hook = picolo_tetra_muxsel,/*Required as it doesn't follow the classic input selection policy*/
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_SPIRIT_TV] = {
+ /* Spirit TV Tuner from http://spiritmodems.com.au */
+ /* Stafford Goodsell <surge@goliath.homeunix.org> */
+ .name = "Spirit TV Tuner",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x0000000f,
+ .muxsel = { 2, 1, 1 },
+ .audiomux = { 0x02, 0x00, 0x00, 0x00, 0x00},
+ .tuner_type = TUNER_TEMIC_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ },
+ [BTTV_BOARD_AVDVBT_771] = {
+ /* Wolfram Joost <wojo@frokaschwei.de> */
+ .name = "AVerMedia AVerTV DVB-T 771",
+ .video_inputs = 2,
+ .svhs = 1,
+ .tuner = -1,
+ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .muxsel = { 3 , 3 },
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .pll = PLL_28,
+ .has_dvb = 1,
+ .no_gpioirq = 1,
+ .has_remote = 1,
+ },
+ /* ---- card 0x7c ---------------------------------- */
+ [BTTV_BOARD_AVDVBT_761] = {
+ /* Matt Jesson <dvb@jesson.eclipse.co.uk> */
+ /* Based on the Nebula card data - added remote and new card number - BTTV_BOARD_AVDVBT_761, see also ir-kbd-gpio.c */
+ .name = "AverMedia AverTV DVB-T 761",
+ .video_inputs = 2,
+ .tuner = -1,
+ .svhs = 1,
+ .muxsel = { 3, 1, 2, 0}, /* Comp0, S-Video, ?, ? */
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_dvb = 1,
+ .no_gpioirq = 1,
+ .has_remote = 1,
+ },
+ [BTTV_BOARD_MATRIX_VISIONSQ] = {
+ /* andre.schwarz@matrix-vision.de */
+ .name = "MATRIX Vision Sigma-SQ",
+ .video_inputs = 16,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = -1,
+ .gpiomask = 0x0,
+ .muxsel = { 2, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 3, 3, 3 },
+ .muxsel_hook = sigmaSQ_muxsel,
+ .audiomux = { 0 },
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_MATRIX_VISIONSLC] = {
+ /* andre.schwarz@matrix-vision.de */
+ .name = "MATRIX Vision Sigma-SLC",
+ .video_inputs = 4,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = -1,
+ .gpiomask = 0x0,
+ .muxsel = { 2, 2, 2, 2 },
+ .muxsel_hook = sigmaSLC_muxsel,
+ .audiomux = { 0 },
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ /* BTTV_BOARD_APAC_VIEWCOMP */
+ [BTTV_BOARD_APAC_VIEWCOMP] = {
+ /* Attila Kondoros <attila.kondoros@chello.hu> */
+ /* bt878 TV + FM 0x00000000 subsystem ID */
+ .name = "APAC Viewcomp 878(AMAX)",
+ .video_inputs = 2,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = -1,
+ .gpiomask = 0xFF,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 2, 0, 0, 0, 10},
+ .needs_tvaudio = 0,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_remote = 1, /* miniremote works, see ir-kbd-gpio.c */
+ .has_radio = 1, /* not every card has radio */
+ },
+
+ /* ---- card 0x80 ---------------------------------- */
+ [BTTV_BOARD_DVICO_DVBT_LITE] = {
+ /* Chris Pascoe <c.pascoe@itee.uq.edu.au> */
+ .name = "DViCO FusionHDTV DVB-T Lite",
+ .tuner = -1,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .pll = PLL_28,
+ .no_video = 1,
+ .has_dvb = 1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_VGEAR_MYVCD] = {
+ /* Steven <photon38@pchome.com.tw> */
+ .name = "V-Gear MyVCD",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x3f,
+ .muxsel = {2, 3, 1, 0},
+ .audiomux = {0x31, 0x31, 0x31, 0x31, 0x31, 0x31},
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_radio = 0,
+ #if 0
+ .has_remote = 1,
+ #endif
+ },
+ [BTTV_BOARD_SUPER_TV] = {
+ /* Rick C <cryptdragoon@gmail.com> */
+ .name = "Super TV Tuner",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .muxsel = { 2, 3, 1, 0},
+ .tuner_type = TUNER_PHILIPS_NTSC,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x008007,
+ .audiomux = { 0, 0x000001,0,0, 0},
+ .needs_tvaudio = 1,
+ .has_radio = 1,
+ },
+ [BTTV_BOARD_TIBET_CS16] = {
+ /* Chris Fanning <video4linux@haydon.net> */
+ .name = "Tibet Systems 'Progress DVR' CS16",
+ .video_inputs = 16,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = -1,
+ .muxsel = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
+ .pll = PLL_28,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .muxsel_hook = tibetCS16_muxsel,
+ },
+ [BTTV_BOARD_KODICOM_4400R] = {
+ /* Bill Brack <wbrack@mmm.com.hk> */
+ /*
+ * Note that, because of the card's wiring, the "master"
+ * BT878A chip (i.e. the one which controls the analog switch
+ * and must use this card type) is the 2nd one detected. The
+ * other 3 chips should use card type 0x85, whose description
+ * follows this one. There is a EEPROM on the card (which is
+ * connected to the I2C of one of those other chips), but is
+ * not currently handled. There is also a facility for a
+ * "monitor", which is also not currently implemented.
+ */
+ .name = "Kodicom 4400R (master)",
+ .video_inputs = 16,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .svhs = -1,
+ /* GPIO bits 0-9 used for analog switch:
+ * 00 - 03: camera selector
+ * 04 - 06: channel (controller) selector
+ * 07: data (1->on, 0->off)
+ * 08: strobe
+ * 09: reset
+ * bit 16 is input from sync separator for the channel
+ */
+ .gpiomask = 0x0003ff,
+ .no_gpioirq = 1,
+ .muxsel = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
+ .pll = PLL_28,
+ .no_msp34xx = 1,
+ .no_tda7432 = 1,
+ .no_tda9875 = 1,
+ .muxsel_hook = kodicom4400r_muxsel,
+ },
+ [BTTV_BOARD_KODICOM_4400R_SL] = {
+ /* Bill Brack <wbrack@mmm.com.hk> */
+ /* Note that, for reasons unknown, the "master" BT878A chip (i.e. the
+ * one which controls the analog switch, and must use the card type)
+ * is the 2nd one detected. The other 3 chips should use this card
+ * type
+ */
+ .name = "Kodicom 4400R (slave)",
+ .video_inputs = 16,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .svhs = -1,
+ .gpiomask = 0x010000,
+ .no_gpioirq = 1,
+ .muxsel = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
+ .pll = PLL_28,
+ .no_msp34xx = 1,
+ .no_tda7432 = 1,
+ .no_tda9875 = 1,
+ .muxsel_hook = kodicom4400r_muxsel,
+ },
+ /* ---- card 0x86---------------------------------- */
+ [BTTV_BOARD_ADLINK_RTV24] = {
+ /* Michael Henson <mhenson@clarityvi.com> */
+ /* Adlink RTV24 with special unlock codes */
+ .name = "Adlink RTV24",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .muxsel = { 2, 3, 1, 0},
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .pll = PLL_28,
+ },
+ /* ---- card 0x87---------------------------------- */
+ [BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE] = {
+ /* Michael Krufky <mkrufky@m1k.net> */
+ .name = "DViCO FusionHDTV 5 Lite",
+ .tuner = 0,
+ .tuner_type = TUNER_LG_TDVS_H062F,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .svhs = 2,
+ .muxsel = { 2, 3, 1 },
+ .gpiomask = 0x00e00007,
+ .audiomux = { 0x00400005, 0, 0x00000001, 0, 0x00c00007, 0 },
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .has_dvb = 1,
+ },
+ /* ---- card 0x88---------------------------------- */
+ [BTTV_BOARD_ACORP_Y878F] = {
+ /* Mauro Carvalho Chehab <mchehab@brturbo.com.br> */
+ .name = "Acorp Y878F",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x01fe00,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0x001e00, 0, 0x018000, 0x014000, 0x002000, 0 },
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_YMEC_TVF66T5_B_DFF,
+ .tuner_addr = 0xc1 >>1,
+ .radio_addr = 0xc1 >>1,
+ .has_radio = 1,
+ },
+ /* ---- card 0x89 ---------------------------------- */
+ [BTTV_BOARD_CONCEPTRONIC_CTVFMI2] = {
+ .name = "Conceptronic CTVFMi v2",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x001c0007,
+ .muxsel = { 2, 3, 1, 1 },
+ .audiomux = { 0, 1, 2, 2, 3 },
+ .needs_tvaudio = 0,
+ .pll = PLL_28,
+ .tuner_type = TUNER_TENA_9533_DI,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_remote = 1,
+ .has_radio = 1,
+ },
+ /* ---- card 0x8a ---------------------------------- */
+ [BTTV_BOARD_PV_BT878P_2E] = {
+ .name = "Prolink Pixelview PV-BT878P+ (Rev.2E)",
+ .video_inputs = 5,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 3,
+ .gpiomask = 0x01fe00,
+ .muxsel = { 2,3,1,1,-1 },
+ .digital_mode = DIGITAL_MODE_CAMERA,
+ .audiomux = { 0x00400, 0x10400, 0x04400, 0x80000, 0x12400, 0x46000 },
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_LG_PAL_FM,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_remote = 1,
+ },
+ /* ---- card 0x8b ---------------------------------- */
+ [BTTV_BOARD_PV_M4900] = {
+ /* Sérgio Fortier <sergiofortier@yahoo.com.br> */
+ .name = "Prolink PixelView PlayTV MPEG2 PV-M4900",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x3f,
+ .muxsel = { 2, 3, 1, 1 },
+ .audiomux = { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 },
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_YMEC_TVF_5533MF,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_radio = 1,
+ .has_remote = 1,
+ },
+ /* ---- card 0x8c ---------------------------------- */
+ [BTTV_BOARD_OSPREY440] = {
+ .name = "Osprey 440",
+ .video_inputs = 1,
+ .audio_inputs = 1,
+ .tuner = -1,
+ .svhs = 1,
+ .muxsel = { 2 },
+ .pll = PLL_28,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ },
+ /* ---- card 0x8d ---------------------------------- */
+ [BTTV_BOARD_ASOUND_SKYEYE] = {
+ .name = "Asound Skyeye PCTV",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 15,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = {2,0,0,0,1},
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = 2,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ /* ---- card 0x8e ---------------------------------- */
+ [BTTV_BOARD_SABRENT_TVFM] = {
+ .name = "Sabrent TV-FM (bttv version)",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x108007,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 100000, 100002, 100002, 100000},
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_TNF_5335MF,
+ .tuner_addr = ADDR_UNSET,
+ .has_radio = 1,
+ },
+};
static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
@@ -2461,7 +2860,7 @@ void __devinit bttv_idcard(struct bttv *btv)
btv->c.nr, btv->cardid & 0xffff,
(btv->cardid >> 16) & 0xffff);
printk(KERN_DEBUG "please mail id, board name and "
- "the correct card= insmod option to kraxel@bytesex.org\n");
+ "the correct card= insmod option to video4linux-list@redhat.com\n");
}
}
@@ -2510,11 +2909,11 @@ void identify_by_eeprom(struct bttv *btv, unsigned char eeprom_data[256])
int type = -1;
if (0 == strncmp(eeprom_data,"GET MM20xPCTV",13))
- type = BTTV_MODTEC_205;
+ type = BTTV_BOARD_MODTEC_205;
else if (0 == strncmp(eeprom_data+20,"Picolo",7))
- type = BTTV_EURESYS_PICOLO;
+ type = BTTV_BOARD_EURESYS_PICOLO;
else if (eeprom_data[0] == 0x84 && eeprom_data[2]== 0)
- type = BTTV_HAUPPAUGE; /* old bt848 */
+ type = BTTV_BOARD_HAUPPAUGE; /* old bt848 */
if (-1 != type) {
btv->c.type = type;
@@ -2548,7 +2947,7 @@ static void flyvideo_gpio(struct bttv *btv)
switch(ttype) {
case 0x0: tuner=2; /* NTSC, e.g. TPI8NSR11P */
break;
- case 0x2: tuner=39;/* LG NTSC (newer TAPC series) TAPC-H701P */
+ case 0x2: tuner=39;/* LG NTSC (newer TAPC series) TAPC-H701P */
break;
case 0x4: tuner=5; /* Philips PAL TPI8PSB02P, TPI8PSB12P, TPI8PSB12D or FI1216, FM1216 */
break;
@@ -2564,7 +2963,7 @@ static void flyvideo_gpio(struct bttv *btv)
has_radio = gpio & 0x400000;
/* unknown 0x200000;
* unknown2 0x100000; */
- is_capture_only = !(gpio & 0x008000); /* GPIO15 */
+ is_capture_only = !(gpio & 0x008000); /* GPIO15 */
has_tda9820_tda9821 = !(gpio & 0x004000);
is_lr90 = !(gpio & 0x002000); /* else LR26/LR50 (LR38/LR51 f. capture only) */
/*
@@ -2601,7 +3000,7 @@ static void miro_pinnacle_gpio(struct bttv *btv)
char *info;
gpio_inout(0xffffff, 0);
- gpio = gpio_read();
+ gpio = gpio_read();
id = ((gpio>>10) & 63) -1;
msp = bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx");
if (id < 32) {
@@ -2620,10 +3019,10 @@ static void miro_pinnacle_gpio(struct bttv *btv)
btv->has_radio = 0;
}
if (-1 != msp) {
- if (btv->c.type == BTTV_MIRO)
- btv->c.type = BTTV_MIROPRO;
- if (btv->c.type == BTTV_PINNACLE)
- btv->c.type = BTTV_PINNACLEPRO;
+ if (btv->c.type == BTTV_BOARD_MIRO)
+ btv->c.type = BTTV_BOARD_MIROPRO;
+ if (btv->c.type == BTTV_BOARD_PINNACLE)
+ btv->c.type = BTTV_BOARD_PINNACLEPRO;
}
printk(KERN_INFO
"bttv%d: miro: id=%d tuner=%d radio=%s stereo=%s\n",
@@ -2664,7 +3063,7 @@ static void miro_pinnacle_gpio(struct bttv *btv)
break;
}
if (-1 != msp)
- btv->c.type = BTTV_PINNACLEPRO;
+ btv->c.type = BTTV_BOARD_PINNACLEPRO;
printk(KERN_INFO
"bttv%d: pinnacle/mt: id=%d info=\"%s\" radio=%s\n",
btv->c.nr, id, info, btv->has_radio ? "yes" : "no");
@@ -2712,7 +3111,7 @@ static void eagle_muxsel(struct bttv *btv, unsigned int input)
static void gvc1100_muxsel(struct bttv *btv, unsigned int input)
{
- static const int masks[] = {0x30, 0x01, 0x12, 0x23};
+ static const int masks[] = {0x30, 0x01, 0x12, 0x23};
gpio_write(masks[input%4]);
}
@@ -2778,26 +3177,27 @@ static void bttv_reset_audio(struct bttv *btv)
void __devinit bttv_init_card1(struct bttv *btv)
{
switch (btv->c.type) {
- case BTTV_HAUPPAUGE:
- case BTTV_HAUPPAUGE878:
- boot_msp34xx(btv,5);
+ case BTTV_BOARD_HAUPPAUGE:
+ case BTTV_BOARD_HAUPPAUGE878:
+ boot_msp34xx(btv,5);
break;
- case BTTV_VOODOOTV_FM:
- boot_msp34xx(btv,20);
+ case BTTV_BOARD_VOODOOTV_FM:
+ boot_msp34xx(btv,20);
break;
- case BTTV_AVERMEDIA98:
+ case BTTV_BOARD_AVERMEDIA98:
boot_msp34xx(btv,11);
break;
- case BTTV_HAUPPAUGEPVR:
+ case BTTV_BOARD_HAUPPAUGEPVR:
pvr_boot(btv);
break;
- case BTTV_TWINHAN_DST:
- case BTTV_AVDVBT_771:
+ case BTTV_BOARD_TWINHAN_DST:
+ case BTTV_BOARD_AVDVBT_771:
+ case BTTV_BOARD_PINNACLESAT:
btv->use_i2c_hw = 1;
break;
- case BTTV_ADLINK_RTV24:
- init_RTV24( btv );
- break;
+ case BTTV_BOARD_ADLINK_RTV24:
+ init_RTV24( btv );
+ break;
}
if (!bttv_tvcards[btv->c.type].has_dvb)
@@ -2810,53 +3210,53 @@ void __devinit bttv_init_card2(struct bttv *btv)
int tda9887;
int addr=ADDR_UNSET;
- btv->tuner_type = -1;
+ btv->tuner_type = -1;
- if (BTTV_UNKNOWN == btv->c.type) {
+ if (BTTV_BOARD_UNKNOWN == btv->c.type) {
bttv_readee(btv,eeprom_data,0xa0);
identify_by_eeprom(btv,eeprom_data);
}
switch (btv->c.type) {
- case BTTV_MIRO:
- case BTTV_MIROPRO:
- case BTTV_PINNACLE:
- case BTTV_PINNACLEPRO:
+ case BTTV_BOARD_MIRO:
+ case BTTV_BOARD_MIROPRO:
+ case BTTV_BOARD_PINNACLE:
+ case BTTV_BOARD_PINNACLEPRO:
/* miro/pinnacle */
miro_pinnacle_gpio(btv);
break;
- case BTTV_FLYVIDEO_98:
- case BTTV_MAXI:
- case BTTV_LIFE_FLYKIT:
- case BTTV_FLYVIDEO:
- case BTTV_TYPHOON_TVIEW:
- case BTTV_CHRONOS_VS2:
- case BTTV_FLYVIDEO_98FM:
- case BTTV_FLYVIDEO2000:
- case BTTV_FLYVIDEO98EZ:
- case BTTV_CONFERENCETV:
- case BTTV_LIFETEC_9415:
+ case BTTV_BOARD_FLYVIDEO_98:
+ case BTTV_BOARD_MAXI:
+ case BTTV_BOARD_LIFE_FLYKIT:
+ case BTTV_BOARD_FLYVIDEO:
+ case BTTV_BOARD_TYPHOON_TVIEW:
+ case BTTV_BOARD_CHRONOS_VS2:
+ case BTTV_BOARD_FLYVIDEO_98FM:
+ case BTTV_BOARD_FLYVIDEO2000:
+ case BTTV_BOARD_FLYVIDEO98EZ:
+ case BTTV_BOARD_CONFERENCETV:
+ case BTTV_BOARD_LIFETEC_9415:
flyvideo_gpio(btv);
break;
- case BTTV_HAUPPAUGE:
- case BTTV_HAUPPAUGE878:
- case BTTV_HAUPPAUGEPVR:
+ case BTTV_BOARD_HAUPPAUGE:
+ case BTTV_BOARD_HAUPPAUGE878:
+ case BTTV_BOARD_HAUPPAUGEPVR:
/* pick up some config infos from the eeprom */
bttv_readee(btv,eeprom_data,0xa0);
- hauppauge_eeprom(btv);
+ hauppauge_eeprom(btv);
break;
- case BTTV_AVERMEDIA98:
- case BTTV_AVPHONE98:
+ case BTTV_BOARD_AVERMEDIA98:
+ case BTTV_BOARD_AVPHONE98:
bttv_readee(btv,eeprom_data,0xa0);
avermedia_eeprom(btv);
break;
- case BTTV_PXC200:
+ case BTTV_BOARD_PXC200:
init_PXC200(btv);
break;
- case BTTV_PICOLO_TETRA_CHIP:
+ case BTTV_BOARD_PICOLO_TETRA_CHIP:
picolo_tetra_init(btv);
break;
- case BTTV_VHX:
+ case BTTV_BOARD_VHX:
btv->has_radio = 1;
btv->has_matchbox = 1;
btv->mbox_we = 0x20;
@@ -2865,58 +3265,58 @@ void __devinit bttv_init_card2(struct bttv *btv)
btv->mbox_data = 0x10;
btv->mbox_mask = 0x38;
break;
- case BTTV_VOBIS_BOOSTAR:
- case BTTV_TERRATV:
+ case BTTV_BOARD_VOBIS_BOOSTAR:
+ case BTTV_BOARD_TERRATV:
terratec_active_radio_upgrade(btv);
break;
- case BTTV_MAGICTVIEW061:
+ case BTTV_BOARD_MAGICTVIEW061:
if (btv->cardid == 0x3002144f) {
btv->has_radio=1;
printk("bttv%d: radio detected by subsystem id (CPH05x)\n",btv->c.nr);
}
break;
- case BTTV_STB2:
- if (btv->cardid == 0x3060121a) {
+ case BTTV_BOARD_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:
+ case BTTV_BOARD_OSPREY1x0:
+ case BTTV_BOARD_OSPREY1x0_848:
+ case BTTV_BOARD_OSPREY101_848:
+ case BTTV_BOARD_OSPREY1x1:
+ case BTTV_BOARD_OSPREY1x1_SVID:
+ case BTTV_BOARD_OSPREY2xx:
+ case BTTV_BOARD_OSPREY2x0_SVID:
+ case BTTV_BOARD_OSPREY2x0:
+ case BTTV_BOARD_OSPREY500:
+ case BTTV_BOARD_OSPREY540:
+ case BTTV_BOARD_OSPREY2000:
bttv_readee(btv,eeprom_data,0xa0);
- osprey_eeprom(btv);
+ osprey_eeprom(btv);
break;
- case BTTV_IDS_EAGLE:
+ case BTTV_BOARD_IDS_EAGLE:
init_ids_eagle(btv);
break;
- case BTTV_MODTEC_205:
+ case BTTV_BOARD_MODTEC_205:
bttv_readee(btv,eeprom_data,0xa0);
modtec_eeprom(btv);
break;
- case BTTV_LMLBT4:
+ case BTTV_BOARD_LMLBT4:
init_lmlbt4x(btv);
break;
- case BTTV_TIBET_CS16:
+ case BTTV_BOARD_TIBET_CS16:
tibetCS16_init(btv);
break;
- case BTTV_KODICOM_4400R:
+ case BTTV_BOARD_KODICOM_4400R:
kodicom4400r_init(btv);
break;
}
/* pll configuration */
- if (!(btv->id==848 && btv->revision==0x11)) {
+ if (!(btv->id==848 && btv->revision==0x11)) {
/* defaults from card list */
if (PLL_28 == bttv_tvcards[btv->c.type].pll) {
btv->pll.pll_ifreq=28636363;
@@ -2927,26 +3327,26 @@ void __devinit bttv_init_card2(struct bttv *btv)
btv->pll.pll_crystal=BT848_IFORM_XT1;
}
/* insmod options can override */
- switch (pll[btv->c.nr]) {
- case 0: /* none */
+ switch (pll[btv->c.nr]) {
+ case 0: /* none */
btv->pll.pll_crystal = 0;
btv->pll.pll_ifreq = 0;
btv->pll.pll_ofreq = 0;
- break;
- case 1: /* 28 MHz */
+ break;
+ case 1: /* 28 MHz */
case 28:
- btv->pll.pll_ifreq = 28636363;
+ btv->pll.pll_ifreq = 28636363;
btv->pll.pll_ofreq = 0;
- btv->pll.pll_crystal = BT848_IFORM_XT0;
- break;
- case 2: /* 35 MHz */
+ btv->pll.pll_crystal = BT848_IFORM_XT0;
+ break;
+ case 2: /* 35 MHz */
case 35:
- btv->pll.pll_ifreq = 35468950;
+ btv->pll.pll_ifreq = 35468950;
btv->pll.pll_ofreq = 0;
- btv->pll.pll_crystal = BT848_IFORM_XT1;
- break;
- }
- }
+ btv->pll.pll_crystal = BT848_IFORM_XT1;
+ break;
+ }
+ }
btv->pll.pll_current = -1;
/* tuner configuration (from card list / autodetect / insmod option) */
@@ -2955,23 +3355,26 @@ void __devinit bttv_init_card2(struct bttv *btv)
if (UNSET != bttv_tvcards[btv->c.type].tuner_type)
if(UNSET == btv->tuner_type)
- btv->tuner_type = bttv_tvcards[btv->c.type].tuner_type;
+ btv->tuner_type = bttv_tvcards[btv->c.type].tuner_type;
if (UNSET != tuner[btv->c.nr])
btv->tuner_type = tuner[btv->c.nr];
printk("bttv%d: using tuner=%d\n",btv->c.nr,btv->tuner_type);
- if (btv->pinnacle_id != UNSET)
- bttv_call_i2c_clients(btv, AUDC_CONFIG_PINNACLE,
- &btv->pinnacle_id);
+
if (btv->tuner_type != UNSET) {
- struct tuner_setup tun_setup;
+ struct tuner_setup tun_setup;
- tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
+ tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
tun_setup.type = btv->tuner_type;
tun_setup.addr = addr;
bttv_call_i2c_clients(btv, TUNER_SET_TYPE_ADDR, &tun_setup);
}
+ if (btv->pinnacle_id != UNSET) {
+ bttv_call_i2c_clients(btv, AUDC_CONFIG_PINNACLE,
+ &btv->pinnacle_id);
+ }
+
btv->svhs = bttv_tvcards[btv->c.type].svhs;
if (svhs[btv->c.nr] != UNSET)
btv->svhs = svhs[btv->c.nr];
@@ -2982,8 +3385,10 @@ void __devinit bttv_init_card2(struct bttv *btv)
btv->has_radio=1;
if (bttv_tvcards[btv->c.type].has_remote)
btv->has_remote=1;
- if (bttv_tvcards[btv->c.type].no_gpioirq)
- btv->gpioirq=0;
+ if (!bttv_tvcards[btv->c.type].no_gpioirq)
+ btv->gpioirq=1;
+ if (bttv_tvcards[btv->c.type].any_irq)
+ btv->any_irq = 1;
if (bttv_tvcards[btv->c.type].audio_hook)
btv->audio_hook=bttv_tvcards[btv->c.type].audio_hook;
@@ -3024,6 +3429,9 @@ void __devinit bttv_init_card2(struct bttv *btv)
if (0 == tda9887 && 0 == bttv_tvcards[btv->c.type].has_dvb &&
bttv_I2CRead(btv, I2C_TDA9887, "TDA9887") >=0)
tda9887 = 1;
+ /* Hybrid DVB card, DOES have a tda9887 */
+ if (btv->c.type == BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE)
+ tda9887 = 1;
if((btv->tuner_type == TUNER_PHILIPS_FM1216ME_MK3) ||
(btv->tuner_type == TUNER_PHILIPS_FM1236_MK3) ||
(btv->tuner_type == TUNER_PHILIPS_FM1256_IH3) ||
@@ -3045,11 +3453,11 @@ static void modtec_eeprom(struct bttv *btv)
} else if (strncmp(&(eeprom_data[0x1e]),"Alps TSBB5",10) ==0) {
btv->tuner_type=TUNER_ALPS_TSBB5_PAL_I;
printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n",
- btv->c.nr,&eeprom_data[0x1e]);
- } else if (strncmp(&(eeprom_data[0x1e]),"Philips FM1246",14) ==0) {
- btv->tuner_type=TUNER_PHILIPS_NTSC;
- printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n",
- btv->c.nr,&eeprom_data[0x1e]);
+ btv->c.nr,&eeprom_data[0x1e]);
+ } else if (strncmp(&(eeprom_data[0x1e]),"Philips FM1246",14) ==0) {
+ btv->tuner_type=TUNER_PHILIPS_NTSC;
+ printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n",
+ btv->c.nr,&eeprom_data[0x1e]);
} else {
printk("bttv%d: Modtec: Unknown TunerString: %s\n",
btv->c.nr,&eeprom_data[0x1e]);
@@ -3114,7 +3522,7 @@ static int terratec_active_radio_upgrade(struct bttv *btv)
static int __devinit pvr_altera_load(struct bttv *btv, u8 *micro, u32 microlen)
{
u32 n;
- u8 bits;
+ u8 bits;
int i;
gpio_inout(0xffffff,BTTV_ALT_DATA|BTTV_ALT_DCLK|BTTV_ALT_NCONFIG);
@@ -3150,19 +3558,19 @@ static int __devinit pvr_altera_load(struct bttv *btv, u8 *micro, u32 microlen)
static int __devinit pvr_boot(struct bttv *btv)
{
- const struct firmware *fw_entry;
+ const struct firmware *fw_entry;
int rc;
rc = request_firmware(&fw_entry, "hcwamc.rbf", &btv->c.pci->dev);
if (rc != 0) {
printk(KERN_WARNING "bttv%d: no altera firmware [via hotplug]\n",
btv->c.nr);
- return rc;
- }
+ return rc;
+ }
rc = pvr_altera_load(btv, fw_entry->data, fw_entry->size);
printk(KERN_INFO "bttv%d: altera firmware upload %s\n",
btv->c.nr, (rc < 0) ? "failed" : "ok");
- release_firmware(fw_entry);
+ release_firmware(fw_entry);
return rc;
}
@@ -3176,33 +3584,33 @@ static void __devinit osprey_eeprom(struct bttv *btv)
unsigned long serial = 0;
if (btv->c.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++)
+ /* 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])
+ if (checksum != ee[21])
return;
- btv->c.type = BTTV_OSPREY1x0_848;
+ btv->c.type = BTTV_BOARD_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)
+ 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 */
@@ -3212,47 +3620,47 @@ static void __devinit osprey_eeprom(struct bttv *btv)
/* 848 based */
case 0x0004:
- btv->c.type = BTTV_OSPREY1x0_848;
+ btv->c.type = BTTV_BOARD_OSPREY1x0_848;
break;
case 0x0005:
- btv->c.type = BTTV_OSPREY101_848;
+ btv->c.type = BTTV_BOARD_OSPREY101_848;
break;
- /* 878 based */
+ /* 878 based */
case 0x0012:
case 0x0013:
- btv->c.type = BTTV_OSPREY1x0;
+ btv->c.type = BTTV_BOARD_OSPREY1x0;
break;
case 0x0014:
case 0x0015:
- btv->c.type = BTTV_OSPREY1x1;
+ btv->c.type = BTTV_BOARD_OSPREY1x1;
break;
case 0x0016:
case 0x0017:
case 0x0020:
- btv->c.type = BTTV_OSPREY1x1_SVID;
+ btv->c.type = BTTV_BOARD_OSPREY1x1_SVID;
break;
case 0x0018:
case 0x0019:
case 0x001E:
case 0x001F:
- btv->c.type = BTTV_OSPREY2xx;
+ btv->c.type = BTTV_BOARD_OSPREY2xx;
break;
case 0x001A:
case 0x001B:
- btv->c.type = BTTV_OSPREY2x0_SVID;
+ btv->c.type = BTTV_BOARD_OSPREY2x0_SVID;
break;
case 0x0040:
- btv->c.type = BTTV_OSPREY500;
+ btv->c.type = BTTV_BOARD_OSPREY500;
break;
case 0x0050:
case 0x0056:
- btv->c.type = BTTV_OSPREY540;
+ btv->c.type = BTTV_BOARD_OSPREY540;
/* bttv_osprey_540_init(btv); */
break;
case 0x0060:
case 0x0070:
- btv->c.type = BTTV_OSPREY2x0;
+ btv->c.type = BTTV_BOARD_OSPREY2x0;
/* enable output on select control lines */
gpio_inout(0xffffff,0x000303);
break;
@@ -3274,27 +3682,27 @@ static void __devinit osprey_eeprom(struct bttv *btv)
/* AVermedia specific stuff, from bktr_card.c */
static int tuner_0_table[] = {
- TUNER_PHILIPS_NTSC, TUNER_PHILIPS_PAL /* PAL-BG*/,
- TUNER_PHILIPS_PAL, TUNER_PHILIPS_PAL /* PAL-I*/,
- TUNER_PHILIPS_PAL, TUNER_PHILIPS_PAL,
- TUNER_PHILIPS_SECAM, TUNER_PHILIPS_SECAM,
- TUNER_PHILIPS_SECAM, TUNER_PHILIPS_PAL,
+ TUNER_PHILIPS_NTSC, TUNER_PHILIPS_PAL /* PAL-BG*/,
+ TUNER_PHILIPS_PAL, TUNER_PHILIPS_PAL /* PAL-I*/,
+ TUNER_PHILIPS_PAL, TUNER_PHILIPS_PAL,
+ TUNER_PHILIPS_SECAM, TUNER_PHILIPS_SECAM,
+ TUNER_PHILIPS_SECAM, TUNER_PHILIPS_PAL,
TUNER_PHILIPS_FM1216ME_MK3 };
static int tuner_1_table[] = {
- TUNER_TEMIC_NTSC, TUNER_TEMIC_PAL,
+ TUNER_TEMIC_NTSC, TUNER_TEMIC_PAL,
TUNER_TEMIC_PAL, TUNER_TEMIC_PAL,
TUNER_TEMIC_PAL, TUNER_TEMIC_PAL,
- TUNER_TEMIC_4012FY5, TUNER_TEMIC_4012FY5, /* TUNER_TEMIC_SECAM */
- TUNER_TEMIC_4012FY5, TUNER_TEMIC_PAL};
+ TUNER_TEMIC_4012FY5, TUNER_TEMIC_4012FY5, /* TUNER_TEMIC_SECAM */
+ TUNER_TEMIC_4012FY5, TUNER_TEMIC_PAL};
static void __devinit avermedia_eeprom(struct bttv *btv)
{
- int tuner_make,tuner_tv_fm,tuner_format,tuner=0;
+ int tuner_make,tuner_tv_fm,tuner_format,tuner=0;
tuner_make = (eeprom_data[0x41] & 0x7);
- tuner_tv_fm = (eeprom_data[0x41] & 0x18) >> 3;
- tuner_format = (eeprom_data[0x42] & 0xf0) >> 4;
+ tuner_tv_fm = (eeprom_data[0x41] & 0x18) >> 3;
+ tuner_format = (eeprom_data[0x42] & 0xf0) >> 4;
btv->has_remote = (eeprom_data[0x42] & 0x01);
if (tuner_make == 0 || tuner_make == 2)
@@ -3325,13 +3733,13 @@ void bttv_tda9880_setnorm(struct bttv *btv, int norm)
{
/* fix up our card entry */
if(norm==VIDEO_MODE_NTSC) {
- bttv_tvcards[BTTV_VOODOOTV_FM].audiomux[0]=0x957fff;
- bttv_tvcards[BTTV_VOODOOTV_FM].audiomux[4]=0x957fff;
+ bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].audiomux[0]=0x957fff;
+ bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].audiomux[4]=0x957fff;
dprintk("bttv_tda9880_setnorm to NTSC\n");
}
else {
- bttv_tvcards[BTTV_VOODOOTV_FM].audiomux[0]=0x947fff;
- bttv_tvcards[BTTV_VOODOOTV_FM].audiomux[4]=0x947fff;
+ bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].audiomux[0]=0x947fff;
+ bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].audiomux[4]=0x947fff;
dprintk("bttv_tda9880_setnorm to PAL\n");
}
/* set GPIO according */
@@ -3342,7 +3750,7 @@ void bttv_tda9880_setnorm(struct bttv *btv, int norm)
/*
* reset/enable the MSP on some Hauppauge cards
- * Thanks to Kyösti Mälkki (kmalkki@cc.hut.fi)!
+ * Thanks to Kyösti Mälkki (kmalkki@cc.hut.fi)!
*
* Hauppauge: pin 5
* Voodoo: pin 20
@@ -3353,7 +3761,7 @@ static void __devinit boot_msp34xx(struct bttv *btv, int pin)
gpio_inout(mask,mask);
gpio_bits(mask,0);
- udelay(2500);
+ udelay(2500);
gpio_bits(mask,mask);
if (bttv_gpio)
@@ -3429,7 +3837,7 @@ static void __devinit init_PXC200(struct bttv *btv)
udelay(10);
gpio_write(1<<2);
- for (i = 0; i < ARRAY_SIZE(vals); i++) {
+ for (i = 0; i < ARRAY_SIZE(vals); i++) {
tmp=bttv_I2CWrite(btv,0x1E,0,vals[i],1);
if (tmp != -1) {
printk(KERN_INFO
@@ -3872,30 +4280,30 @@ avermedia_tv_stereo_audio(struct bttv *btv, struct video_audio *v, int set)
static void
lt9415_audio(struct bttv *btv, struct video_audio *v, int set)
{
- int val = 0;
+ int val = 0;
- if (gpio_read() & 0x4000) {
+ if (gpio_read() & 0x4000) {
v->mode = VIDEO_SOUND_MONO;
return;
}
- if (set) {
- if (v->mode & VIDEO_SOUND_LANG2) /* A2 SAP */
- val = 0x0080;
+ if (set) {
+ if (v->mode & VIDEO_SOUND_LANG2) /* A2 SAP */
+ val = 0x0080;
if (v->mode & VIDEO_SOUND_STEREO) /* A2 stereo */
- val = 0x0880;
- if ((v->mode & VIDEO_SOUND_LANG1) ||
+ val = 0x0880;
+ if ((v->mode & VIDEO_SOUND_LANG1) ||
(v->mode & VIDEO_SOUND_MONO))
val = 0;
gpio_bits(0x0880, val);
- if (bttv_gpio)
- bttv_gpio_tracking(btv,"lt9415");
- } else {
+ if (bttv_gpio)
+ bttv_gpio_tracking(btv,"lt9415");
+ } else {
/* autodetect doesn't work with this card :-( */
- v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+ v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
- return;
- }
+ return;
+ }
}
/* TDA9821 on TerraTV+ Bt848, Bt878 */
@@ -4018,26 +4426,26 @@ fv2000s_audio(struct bttv *btv, struct video_audio *v, int set)
static void
windvr_audio(struct bttv *btv, struct video_audio *v, int set)
{
- unsigned long val = 0;
-
- if (set) {
- if (v->mode & VIDEO_SOUND_MONO)
- val = 0x040000;
- if (v->mode & VIDEO_SOUND_LANG1)
- val = 0;
- if (v->mode & VIDEO_SOUND_LANG2)
- val = 0x100000;
- if (v->mode & VIDEO_SOUND_STEREO)
- val = 0;
- if (val) {
+ unsigned long val = 0;
+
+ if (set) {
+ if (v->mode & VIDEO_SOUND_MONO)
+ val = 0x040000;
+ if (v->mode & VIDEO_SOUND_LANG1)
+ val = 0;
+ if (v->mode & VIDEO_SOUND_LANG2)
+ val = 0x100000;
+ if (v->mode & VIDEO_SOUND_STEREO)
+ val = 0;
+ if (val) {
gpio_bits(0x140000, val);
- if (bttv_gpio)
- bttv_gpio_tracking(btv,"windvr");
- }
- } else {
- v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
- VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
- }
+ if (bttv_gpio)
+ bttv_gpio_tracking(btv,"windvr");
+ }
+ } else {
+ v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+ VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+ }
}
/*
@@ -4280,10 +4688,10 @@ static void kodicom4400r_init(struct bttv *btv)
static void xguard_muxsel(struct bttv *btv, unsigned int input)
{
static const int masks[] = {
- ENB0, ENB0|IN00, ENB0|IN10, ENB0|IN00|IN10,
- ENA0, ENA0|IN00, ENA0|IN10, ENA0|IN00|IN10,
- ENB1, ENB1|IN01, ENB1|IN11, ENB1|IN01|IN11,
- ENA1, ENA1|IN01, ENA1|IN11, ENA1|IN01|IN11,
+ ENB0, ENB0|IN00, ENB0|IN10, ENB0|IN00|IN10,
+ ENA0, ENA0|IN00, ENA0|IN10, ENA0|IN00|IN10,
+ ENB1, ENB1|IN01, ENB1|IN11, ENB1|IN01|IN11,
+ ENA1, ENA1|IN01, ENA1|IN11, ENA1|IN01|IN11,
};
gpio_write(masks[input%16]);
}
@@ -4388,10 +4796,10 @@ static void ivc120_muxsel(struct bttv *btv, unsigned int input)
static void PXC200_muxsel(struct bttv *btv, unsigned int input)
{
- int rc;
+ int rc;
long mux;
int bitmask;
- unsigned char buf[2];
+ unsigned char buf[2];
/* Read PIC config to determine if this is a PXC200F */
/* PX_I2C_CMD_CFG*/
@@ -4421,14 +4829,14 @@ static void PXC200_muxsel(struct bttv *btv, unsigned int input)
/* bitmask=0x30f; */
bitmask=0x302;
/* check whether we have a PXC200A */
- if (btv->cardid == PX_PXC200A_CARDID) {
+ if (btv->cardid == PX_PXC200A_CARDID) {
bitmask ^= 0x180; /* use 7 and 9, not 8 and 9 */
bitmask |= 7<<4; /* the DAC */
}
btwrite(bitmask, BT848_GPIO_OUT_EN);
bitmask = btread(BT848_GPIO_DATA);
- if (btv->cardid == PX_PXC200A_CARDID)
+ if (btv->cardid == PX_PXC200A_CARDID)
bitmask = (bitmask & ~0x280) | ((mux & 2) << 8) | ((mux & 1) << 7);
else /* older device */
bitmask = (bitmask & ~0x300) | ((mux & 3) << 8);
@@ -4441,7 +4849,7 @@ static void PXC200_muxsel(struct bttv *btv, unsigned int input)
*
* needed because bttv-driver sets mux before calling this function
*/
- if (btv->cardid == PX_PXC200A_CARDID)
+ if (btv->cardid == PX_PXC200A_CARDID)
btaor(2<<5, ~BT848_IFORM_MUXSEL, BT848_IFORM);
else /* older device */
btand(~BT848_IFORM_MUXSEL,BT848_IFORM);
@@ -4485,10 +4893,9 @@ void __devinit bttv_check_chipset(void)
}
if (UNSET != latency)
printk(KERN_INFO "bttv: pci latency fixup [%d]\n",latency);
-
- while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+ while ((dev = pci_get_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82441, dev))) {
- unsigned char b;
+ unsigned char b;
pci_read_config_byte(dev, 0x53, &b);
if (bttv_debug)
printk(KERN_INFO "bttv: Host bridge: 82441FX Natoma, "
@@ -4498,7 +4905,7 @@ void __devinit bttv_check_chipset(void)
int __devinit bttv_handle_chipset(struct bttv *btv)
{
- unsigned char command;
+ unsigned char command;
if (!triton1 && !vsfx && UNSET == latency)
return 0;
@@ -4519,13 +4926,13 @@ int __devinit bttv_handle_chipset(struct bttv *btv)
btv->triton1 = BT848_INT_ETBF;
} else {
/* bt878 has a bit in the pci config space for it */
- pci_read_config_byte(btv->c.pci, BT878_DEVCTRL, &command);
+ pci_read_config_byte(btv->c.pci, BT878_DEVCTRL, &command);
if (triton1)
command |= BT878_EN_TBFX;
if (vsfx)
command |= BT878_EN_VSFX;
- pci_write_config_byte(btv->c.pci, BT878_DEVCTRL, command);
- }
+ pci_write_config_byte(btv->c.pci, BT878_DEVCTRL, command);
+ }
if (UNSET != latency)
pci_write_config_byte(btv->c.pci, PCI_LATENCY_TIMER, latency);
return 0;
diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c
index c062a017491..709099f03bd 100644
--- a/drivers/media/video/bttv-driver.c
+++ b/drivers/media/video/bttv-driver.c
@@ -3,7 +3,7 @@
bttv - Bt848 frame grabber driver
Copyright (C) 1996,97,98 Ralph Metzler <rjkm@thp.uni-koeln.de>
- & Marcus Metzler <mocm@thp.uni-koeln.de>
+ & Marcus Metzler <mocm@thp.uni-koeln.de>
(c) 1999-2002 Gerd Knorr <kraxel@bytesex.org>
some v4l2 code lines are taken from Justin's bttv2 driver which is
@@ -192,8 +192,8 @@ static u8 SRAM_Table[][60] =
const struct bttv_tvnorm bttv_tvnorms[] = {
/* PAL-BDGHI */
- /* max. active video is actually 922, but 924 is divisible by 4 and 3! */
- /* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */
+ /* 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",
@@ -806,9 +806,9 @@ static void bt848A_set_timing(struct bttv *btv)
btv->c.nr,table_idx);
/* timing change...reset timing generator address */
- btwrite(0x00, BT848_TGCTRL);
- btwrite(0x02, BT848_TGCTRL);
- btwrite(0x00, BT848_TGCTRL);
+ btwrite(0x00, BT848_TGCTRL);
+ btwrite(0x02, BT848_TGCTRL);
+ btwrite(0x00, BT848_TGCTRL);
len=SRAM_Table[table_idx][0];
for(i = 1; i <= len; i++)
@@ -847,7 +847,7 @@ static void bt848_hue(struct bttv *btv, int hue)
/* -128 to 127 */
value = (hue >> 8) - 128;
- btwrite(value & 0xff, BT848_HUE);
+ btwrite(value & 0xff, BT848_HUE);
}
static void bt848_contrast(struct bttv *btv, int cont)
@@ -859,9 +859,9 @@ static void bt848_contrast(struct bttv *btv, int cont)
/* 0-511 */
value = (cont >> 7);
hibit = (value >> 6) & 4;
- btwrite(value & 0xff, BT848_CONTRAST_LO);
- btaor(hibit, ~4, BT848_E_CONTROL);
- btaor(hibit, ~4, BT848_O_CONTROL);
+ btwrite(value & 0xff, BT848_CONTRAST_LO);
+ btaor(hibit, ~4, BT848_E_CONTROL);
+ btaor(hibit, ~4, BT848_O_CONTROL);
}
static void bt848_sat(struct bttv *btv, int color)
@@ -873,12 +873,12 @@ static void bt848_sat(struct bttv *btv, int color)
/* 0-511 for the color */
val_u = ((color * btv->opt_uv_ratio) / 50) >> 7;
val_v = (((color * (100 - btv->opt_uv_ratio) / 50) >>7)*180L)/254;
- hibits = (val_u >> 7) & 2;
+ hibits = (val_u >> 7) & 2;
hibits |= (val_v >> 8) & 1;
- btwrite(val_u & 0xff, BT848_SAT_U_LO);
- btwrite(val_v & 0xff, BT848_SAT_V_LO);
- btaor(hibits, ~3, BT848_E_CONTROL);
- btaor(hibits, ~3, BT848_O_CONTROL);
+ btwrite(val_u & 0xff, BT848_SAT_U_LO);
+ btwrite(val_v & 0xff, BT848_SAT_V_LO);
+ btaor(hibits, ~3, BT848_E_CONTROL);
+ btaor(hibits, ~3, BT848_O_CONTROL);
}
/* ----------------------------------------------------------------------- */
@@ -891,7 +891,7 @@ video_mux(struct bttv *btv, unsigned int input)
if (input >= bttv_tvcards[btv->c.type].video_inputs)
return -EINVAL;
- /* needed by RemoteVideo MX */
+ /* needed by RemoteVideo MX */
mask2 = bttv_tvcards[btv->c.type].gpiomask2;
if (mask2)
gpio_inout(mask2,mask2);
@@ -964,7 +964,7 @@ i2c_vidiocschan(struct bttv *btv)
c.norm = btv->tvnorm;
c.channel = btv->input;
bttv_call_i2c_clients(btv,VIDIOCSCHAN,&c);
- if (btv->c.type == BTTV_VOODOOTV_FM)
+ if (btv->c.type == BTTV_BOARD_VOODOOTV_FM)
bttv_tda9880_setnorm(btv,c.norm);
}
@@ -988,7 +988,7 @@ set_tvnorm(struct bttv *btv, unsigned int norm)
bt848A_set_timing(btv);
switch (btv->c.type) {
- case BTTV_VOODOOTV_FM:
+ case BTTV_BOARD_VOODOOTV_FM:
bttv_tda9880_setnorm(btv,norm);
break;
}
@@ -1055,22 +1055,22 @@ static void init_bt848(struct bttv *btv)
btwrite(BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL);
btwrite(BT848_IFORM_XTAUTO | BT848_IFORM_AUTO, BT848_IFORM);
- /* set planar and packed mode trigger points and */
- /* set rising edge of inverted GPINTR pin as irq trigger */
- btwrite(BT848_GPIO_DMA_CTL_PKTP_32|
- BT848_GPIO_DMA_CTL_PLTP1_16|
- BT848_GPIO_DMA_CTL_PLTP23_16|
- BT848_GPIO_DMA_CTL_GPINTC|
- BT848_GPIO_DMA_CTL_GPINTI,
- BT848_GPIO_DMA_CTL);
+ /* set planar and packed mode trigger points and */
+ /* set rising edge of inverted GPINTR pin as irq trigger */
+ btwrite(BT848_GPIO_DMA_CTL_PKTP_32|
+ BT848_GPIO_DMA_CTL_PLTP1_16|
+ BT848_GPIO_DMA_CTL_PLTP23_16|
+ BT848_GPIO_DMA_CTL_GPINTC|
+ BT848_GPIO_DMA_CTL_GPINTI,
+ BT848_GPIO_DMA_CTL);
val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
- btwrite(val, BT848_E_SCLOOP);
- btwrite(val, BT848_O_SCLOOP);
+ btwrite(val, BT848_E_SCLOOP);
+ btwrite(val, BT848_O_SCLOOP);
- btwrite(0x20, BT848_E_VSCALE_HI);
- btwrite(0x20, BT848_O_VSCALE_HI);
- btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
+ btwrite(0x20, BT848_E_VSCALE_HI);
+ btwrite(0x20, BT848_O_VSCALE_HI);
+ btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
BT848_ADC);
btwrite(whitecrush_upper, BT848_WC_UP);
@@ -1089,7 +1089,7 @@ static void init_bt848(struct bttv *btv)
bt848_contrast(btv, btv->contrast);
bt848_sat(btv, btv->saturation);
- /* interrupt */
+ /* interrupt */
init_irqreg(btv);
}
@@ -1105,7 +1105,7 @@ static void bttv_reinit_bt848(struct bttv *btv)
spin_unlock_irqrestore(&btv->s_lock,flags);
init_bt848(btv);
- btv->pll.pll_current = -1;
+ btv->pll.pll_current = -1;
set_input(btv,btv->input);
}
@@ -1398,7 +1398,7 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
/* video4linux (1) interface */
static int bttv_prepare_buffer(struct bttv *btv, struct bttv_buffer *buf,
- const struct bttv_format *fmt,
+ const struct bttv_format *fmt,
unsigned int width, unsigned int height,
enum v4l2_field field)
{
@@ -1521,8 +1521,8 @@ static const char *v4l1_ioctls[] = {
static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
{
switch (cmd) {
- case BTTV_VERSION:
- return BTTV_VERSION_CODE;
+ case BTTV_VERSION:
+ return BTTV_VERSION_CODE;
/* *** v4l1 *** ************************************************ */
case VIDIOCGFREQ:
@@ -1576,32 +1576,32 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
return 0;
}
- case VIDIOCGCHAN:
- {
- struct video_channel *v = arg;
+ case VIDIOCGCHAN:
+ {
+ struct video_channel *v = arg;
unsigned int channel = v->channel;
- if (channel >= bttv_tvcards[btv->c.type].video_inputs)
- return -EINVAL;
- v->tuners=0;
- v->flags = VIDEO_VC_AUDIO;
- v->type = VIDEO_TYPE_CAMERA;
- v->norm = btv->tvnorm;
+ if (channel >= bttv_tvcards[btv->c.type].video_inputs)
+ return -EINVAL;
+ v->tuners=0;
+ v->flags = VIDEO_VC_AUDIO;
+ v->type = VIDEO_TYPE_CAMERA;
+ v->norm = btv->tvnorm;
if (channel == bttv_tvcards[btv->c.type].tuner) {
- strcpy(v->name,"Television");
- v->flags|=VIDEO_VC_TUNER;
- v->type=VIDEO_TYPE_TV;
- v->tuners=1;
- } else if (channel == btv->svhs) {
- strcpy(v->name,"S-Video");
- } else {
- sprintf(v->name,"Composite%d",channel);
+ strcpy(v->name,"Television");
+ v->flags|=VIDEO_VC_TUNER;
+ v->type=VIDEO_TYPE_TV;
+ v->tuners=1;
+ } else if (channel == btv->svhs) {
+ strcpy(v->name,"S-Video");
+ } else {
+ sprintf(v->name,"Composite%d",channel);
}
return 0;
- }
- case VIDIOCSCHAN:
- {
- struct video_channel *v = arg;
+ }
+ case VIDIOCSCHAN:
+ {
+ struct video_channel *v = arg;
unsigned int channel = v->channel;
if (channel >= bttv_tvcards[btv->c.type].video_inputs)
@@ -1623,7 +1623,7 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
return 0;
}
- case VIDIOCGAUDIO:
+ case VIDIOCGAUDIO:
{
struct video_audio *v = arg;
@@ -1728,7 +1728,7 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
} else if (i->index == btv->svhs) {
sprintf(i->name, "S-Video");
} else {
- sprintf(i->name,"Composite%d",i->index);
+ sprintf(i->name,"Composite%d",i->index);
}
if (i->index == btv->input) {
__u32 dstatus = btread(BT848_DSTATUS);
@@ -1851,6 +1851,11 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
up(&btv->lock);
return 0;
}
+ case VIDIOC_LOG_STATUS:
+ {
+ bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, 0);
+ return 0;
+ }
default:
return -ENOIOCTLCMD;
@@ -1951,8 +1956,7 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
}
down(&fh->cap.lock);
- if (fh->ov.clips)
- kfree(fh->ov.clips);
+ kfree(fh->ov.clips);
fh->ov.clips = clips;
fh->ov.nclips = n;
@@ -2164,7 +2168,7 @@ static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
if (0 != retval)
return retval;
if (locked_btres(fh->btv, RESOURCE_VBI))
- return -EBUSY;
+ return -EBUSY;
bttv_vbi_try_fmt(fh,f);
bttv_vbi_setlines(fh,btv,f->fmt.vbi.count[0]);
bttv_vbi_get_fmt(fh,f);
@@ -2202,9 +2206,9 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
bttv_reinit_bt848(btv);
switch (cmd) {
- case VIDIOCSFREQ:
- case VIDIOCSTUNER:
- case VIDIOCSCHAN:
+ case VIDIOCSFREQ:
+ case VIDIOCSTUNER:
+ case VIDIOCSCHAN:
case VIDIOC_S_CTRL:
case VIDIOC_S_STD:
case VIDIOC_S_INPUT:
@@ -2220,10 +2224,10 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
/* *** v4l1 *** ************************************************ */
case VIDIOCGCAP:
{
- struct video_capability *cap = arg;
+ struct video_capability *cap = arg;
memset(cap,0,sizeof(*cap));
- strcpy(cap->name,btv->video_dev->name);
+ strcpy(cap->name,btv->video_dev->name);
if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
/* vbi */
cap->type = VID_TYPE_TUNER|VID_TYPE_TELETEXT;
@@ -2243,7 +2247,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
}
cap->channels = bttv_tvcards[btv->c.type].video_inputs;
cap->audios = bttv_tvcards[btv->c.type].audio_inputs;
- return 0;
+ return 0;
}
case VIDIOCGPICT:
@@ -2292,7 +2296,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
bt848_hue(btv,pic->hue);
bt848_sat(btv,pic->colour);
up(&fh->cap.lock);
- return 0;
+ return 0;
}
case VIDIOCGWIN:
@@ -2353,8 +2357,8 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
unsigned long end;
if(!capable(CAP_SYS_ADMIN) &&
- !capable(CAP_SYS_RAWIO))
- return -EPERM;
+ !capable(CAP_SYS_RAWIO))
+ return -EPERM;
end = (unsigned long)fbuf->base +
fbuf->height * fbuf->bytesperline;
down(&fh->cap.lock);
@@ -2428,7 +2432,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
}
/* switch over */
- retval = bttv_switch_overlay(btv,fh,new);
+ retval = bttv_switch_overlay(btv,fh,new);
up(&fh->cap.lock);
return retval;
}
@@ -2567,13 +2571,13 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
return 0;
}
- case BTTV_VERSION:
- case VIDIOCGFREQ:
- case VIDIOCSFREQ:
- case VIDIOCGTUNER:
- case VIDIOCSTUNER:
- case VIDIOCGCHAN:
- case VIDIOCSCHAN:
+ case BTTV_VERSION:
+ case VIDIOCGFREQ:
+ case VIDIOCSFREQ:
+ case VIDIOCGTUNER:
+ case VIDIOCSTUNER:
+ case VIDIOCGCHAN:
+ case VIDIOCSCHAN:
case VIDIOCGAUDIO:
case VIDIOCSAUDIO:
return bttv_common_ioctls(btv,cmd,arg);
@@ -2585,8 +2589,8 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
if (0 == v4l2)
return -EINVAL;
- strcpy(cap->driver,"bttv");
- strlcpy(cap->card,btv->video_dev->name,sizeof(cap->card));
+ strcpy(cap->driver,"bttv");
+ strlcpy(cap->card,btv->video_dev->name,sizeof(cap->card));
sprintf(cap->bus_info,"PCI:%s",pci_name(btv->c.pci));
cap->version = BTTV_VERSION_CODE;
cap->capabilities =
@@ -2723,8 +2727,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
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);
+ kfree(fh->ov.clips);
fh->ov.clips = NULL;
fh->ov.nclips = 0;
@@ -2858,6 +2861,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_S_TUNER:
case VIDIOC_G_FREQUENCY:
case VIDIOC_S_FREQUENCY:
+ case VIDIOC_LOG_STATUS:
return bttv_common_ioctls(btv,cmd,arg);
default:
@@ -3093,7 +3097,7 @@ static struct video_device bttv_video_template =
{
.name = "UNSET",
.type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|
- VID_TYPE_CLIPPING|VID_TYPE_SCALES,
+ VID_TYPE_CLIPPING|VID_TYPE_SCALES,
.hardware = VID_HARDWARE_BT848,
.fops = &bttv_fops,
.minor = -1,
@@ -3139,7 +3143,7 @@ static int radio_open(struct inode *inode, struct file *file)
audio_mux(btv,AUDIO_RADIO);
up(&btv->lock);
- return 0;
+ return 0;
}
static int radio_release(struct inode *inode, struct file *file)
@@ -3162,34 +3166,34 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
switch (cmd) {
case VIDIOCGCAP:
{
- struct video_capability *cap = arg;
+ struct video_capability *cap = arg;
memset(cap,0,sizeof(*cap));
- strcpy(cap->name,btv->radio_dev->name);
- cap->type = VID_TYPE_TUNER;
+ strcpy(cap->name,btv->radio_dev->name);
+ cap->type = VID_TYPE_TUNER;
cap->channels = 1;
cap->audios = 1;
- return 0;
+ return 0;
}
- case VIDIOCGTUNER:
- {
- struct video_tuner *v = arg;
+ case VIDIOCGTUNER:
+ {
+ struct video_tuner *v = arg;
- if(v->tuner)
- return -EINVAL;
+ if(v->tuner)
+ return -EINVAL;
memset(v,0,sizeof(*v));
- strcpy(v->name, "Radio");
- bttv_call_i2c_clients(btv,cmd,v);
- return 0;
- }
- case VIDIOCSTUNER:
+ strcpy(v->name, "Radio");
+ bttv_call_i2c_clients(btv,cmd,v);
+ return 0;
+ }
+ case VIDIOCSTUNER:
/* nothing to do */
return 0;
case BTTV_VERSION:
- case VIDIOCGFREQ:
- case VIDIOCSFREQ:
+ case VIDIOCGFREQ:
+ case VIDIOCSFREQ:
case VIDIOCGAUDIO:
case VIDIOCSAUDIO:
return bttv_common_ioctls(btv,cmd,arg);
@@ -3663,6 +3667,10 @@ static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
int handled = 0;
btv=(struct bttv *)dev_id;
+
+ if (btv->any_irq)
+ handled = bttv_any_irq(&btv->c);
+
count=0;
while (1) {
/* get/clear interrupt status bits */
@@ -3695,7 +3703,7 @@ static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
}
if (astat&BT848_INT_VSYNC)
- btv->field_count++;
+ btv->field_count++;
if (astat & BT848_INT_GPINT) {
wake_up(&btv->gpioq);
@@ -3707,13 +3715,13 @@ static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
wake_up(&btv->i2c_queue);
}
- if ((astat & BT848_INT_RISCI) && (stat & (4<<28)))
+ if ((astat & BT848_INT_RISCI) && (stat & (4<<28)))
bttv_irq_switch_vbi(btv);
- if ((astat & BT848_INT_RISCI) && (stat & (2<<28)))
+ if ((astat & BT848_INT_RISCI) && (stat & (2<<28)))
bttv_irq_wakeup_top(btv);
- if ((astat & BT848_INT_RISCI) && (stat & (1<<28)))
+ if ((astat & BT848_INT_RISCI) && (stat & (1<<28)))
bttv_irq_switch_video(btv);
if ((astat & BT848_INT_HLOCK) && btv->opt_automute)
@@ -3738,10 +3746,22 @@ static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
count++;
if (count > 4) {
- btwrite(0, BT848_INT_MASK);
- printk(KERN_ERR
- "bttv%d: IRQ lockup, cleared int mask [", btv->c.nr);
+
+ if (count > 8 || !(astat & BT848_INT_GPINT)) {
+ btwrite(0, BT848_INT_MASK);
+
+ printk(KERN_ERR
+ "bttv%d: IRQ lockup, cleared int mask [", btv->c.nr);
+ } else {
+ printk(KERN_ERR
+ "bttv%d: IRQ lockup, clearing GPINT from int mask [", btv->c.nr);
+
+ btwrite(btread(BT848_INT_MASK) & (-1 ^ BT848_INT_GPINT),
+ BT848_INT_MASK);
+ };
+
bttv_print_irqbits(stat,astat);
+
printk("]\n");
}
}
@@ -3810,7 +3830,7 @@ static int __devinit bttv_register_video(struct bttv *btv)
/* video */
btv->video_dev = vdev_init(btv, &bttv_video_template, "video");
- if (NULL == btv->video_dev)
+ if (NULL == btv->video_dev)
goto err;
if (video_register_device(btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
goto err;
@@ -3820,18 +3840,18 @@ static int __devinit bttv_register_video(struct bttv *btv)
/* vbi */
btv->vbi_dev = vdev_init(btv, &bttv_vbi_template, "vbi");
- if (NULL == btv->vbi_dev)
+ if (NULL == btv->vbi_dev)
goto err;
- if (video_register_device(btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0)
+ if (video_register_device(btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0)
goto err;
printk(KERN_INFO "bttv%d: registered device vbi%d\n",
btv->c.nr,btv->vbi_dev->minor & 0x1f);
- if (!btv->has_radio)
+ if (!btv->has_radio)
return 0;
/* radio */
btv->radio_dev = vdev_init(btv, &radio_template, "radio");
- if (NULL == btv->radio_dev)
+ if (NULL == btv->radio_dev)
goto err;
if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,radio_nr)<0)
goto err;
@@ -3852,11 +3872,11 @@ static int __devinit bttv_register_video(struct bttv *btv)
static void pci_set_command(struct pci_dev *dev)
{
#if defined(__powerpc__)
- unsigned int cmd;
+ unsigned int cmd;
- pci_read_config_dword(dev, PCI_COMMAND, &cmd);
- cmd = (cmd | PCI_COMMAND_MEMORY );
- pci_write_config_dword(dev, PCI_COMMAND, cmd);
+ pci_read_config_dword(dev, PCI_COMMAND, &cmd);
+ cmd = (cmd | PCI_COMMAND_MEMORY );
+ pci_write_config_dword(dev, PCI_COMMAND, cmd);
#endif
}
@@ -3870,63 +3890,62 @@ static int __devinit bttv_probe(struct pci_dev *dev,
if (bttv_num == BTTV_MAX)
return -ENOMEM;
printk(KERN_INFO "bttv: Bt8xx card found (%d).\n", bttv_num);
- btv=&bttvs[bttv_num];
+ btv=&bttvs[bttv_num];
memset(btv,0,sizeof(*btv));
btv->c.nr = bttv_num;
sprintf(btv->c.name,"bttv%d",btv->c.nr);
/* initialize structs / fill in defaults */
- init_MUTEX(&btv->lock);
- init_MUTEX(&btv->reslock);
- spin_lock_init(&btv->s_lock);
- spin_lock_init(&btv->gpio_lock);
- init_waitqueue_head(&btv->gpioq);
- init_waitqueue_head(&btv->i2c_queue);
- INIT_LIST_HEAD(&btv->c.subs);
- INIT_LIST_HEAD(&btv->capture);
- INIT_LIST_HEAD(&btv->vcapture);
+ init_MUTEX(&btv->lock);
+ init_MUTEX(&btv->reslock);
+ spin_lock_init(&btv->s_lock);
+ spin_lock_init(&btv->gpio_lock);
+ init_waitqueue_head(&btv->gpioq);
+ init_waitqueue_head(&btv->i2c_queue);
+ INIT_LIST_HEAD(&btv->c.subs);
+ INIT_LIST_HEAD(&btv->capture);
+ INIT_LIST_HEAD(&btv->vcapture);
v4l2_prio_init(&btv->prio);
init_timer(&btv->timeout);
btv->timeout.function = bttv_irq_timeout;
btv->timeout.data = (unsigned long)btv;
- btv->i2c_rc = -1;
- btv->tuner_type = UNSET;
- btv->pinnacle_id = UNSET;
+ btv->i2c_rc = -1;
+ btv->tuner_type = UNSET;
+ btv->pinnacle_id = UNSET;
btv->new_input = UNSET;
- btv->gpioirq = 1;
btv->has_radio=radio[btv->c.nr];
/* pci stuff (init, get irq/mmio, ... */
btv->c.pci = dev;
- btv->id = dev->device;
+ btv->id = dev->device;
if (pci_enable_device(dev)) {
- printk(KERN_WARNING "bttv%d: Can't enable device.\n",
+ printk(KERN_WARNING "bttv%d: Can't enable device.\n",
btv->c.nr);
return -EIO;
}
- if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
- printk(KERN_WARNING "bttv%d: No suitable DMA available.\n",
+ if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
+ printk(KERN_WARNING "bttv%d: No suitable DMA available.\n",
btv->c.nr);
return -EIO;
- }
+ }
if (!request_mem_region(pci_resource_start(dev,0),
pci_resource_len(dev,0),
btv->c.name)) {
- printk(KERN_WARNING "bttv%d: can't request iomem (0x%lx).\n",
+ printk(KERN_WARNING "bttv%d: can't request iomem (0x%lx).\n",
btv->c.nr, pci_resource_start(dev,0));
return -EBUSY;
}
- pci_set_master(dev);
+ pci_set_master(dev);
pci_set_command(dev);
pci_set_drvdata(dev,btv);
- pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
- pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
- printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ",
- bttv_num,btv->id, btv->revision, pci_name(dev));
- printk("irq: %d, latency: %d, mmio: 0x%lx\n",
+ pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
+ pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
+ printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ",
+ bttv_num,btv->id, btv->revision, pci_name(dev));
+ printk("irq: %d, latency: %d, mmio: 0x%lx\n",
btv->c.pci->irq, lat, pci_resource_start(dev,0));
schedule();
@@ -3937,23 +3956,23 @@ static int __devinit bttv_probe(struct pci_dev *dev,
goto fail1;
}
- /* identify card */
+ /* identify card */
bttv_idcard(btv);
- /* disable irqs, register irq handler */
+ /* disable irqs, register irq handler */
btwrite(0, BT848_INT_MASK);
- result = request_irq(btv->c.pci->irq, bttv_irq,
- SA_SHIRQ | SA_INTERRUPT,btv->c.name,(void *)btv);
- if (result < 0) {
- printk(KERN_ERR "bttv%d: can't get IRQ %d\n",
+ result = request_irq(btv->c.pci->irq, bttv_irq,
+ SA_SHIRQ | SA_INTERRUPT,btv->c.name,(void *)btv);
+ if (result < 0) {
+ printk(KERN_ERR "bttv%d: can't get IRQ %d\n",
bttv_num,btv->c.pci->irq);
goto fail1;
- }
+ }
if (0 != bttv_handle_chipset(btv)) {
result = -EIO;
goto fail2;
- }
+ }
/* init options from insmod args */
btv->opt_combfilter = combfilter;
@@ -3979,29 +3998,29 @@ static int __devinit bttv_probe(struct pci_dev *dev,
btv->input = 0;
/* initialize hardware */
- if (bttv_gpio)
- bttv_gpio_tracking(btv,"pre-init");
+ if (bttv_gpio)
+ bttv_gpio_tracking(btv,"pre-init");
bttv_risc_init_main(btv);
init_bt848(btv);
/* gpio */
- btwrite(0x00, BT848_GPIO_REG_INP);
- btwrite(0x00, BT848_GPIO_OUT_EN);
- if (bttv_verbose)
- bttv_gpio_tracking(btv,"init");
+ btwrite(0x00, BT848_GPIO_REG_INP);
+ btwrite(0x00, BT848_GPIO_OUT_EN);
+ if (bttv_verbose)
+ bttv_gpio_tracking(btv,"init");
- /* needs to be done before i2c is registered */
- bttv_init_card1(btv);
+ /* needs to be done before i2c is registered */
+ bttv_init_card1(btv);
- /* register i2c + gpio */
- init_bttv_i2c(btv);
+ /* register i2c + gpio */
+ init_bttv_i2c(btv);
- /* some card-specific stuff (needs working i2c) */
- bttv_init_card2(btv);
+ /* some card-specific stuff (needs working i2c) */
+ bttv_init_card2(btv);
init_irqreg(btv);
- /* register video4linux + input */
+ /* register video4linux + input */
if (!bttv_tvcards[btv->c.type].no_video) {
bttv_register_video(btv);
bt848_bright(btv,32768);
@@ -4020,10 +4039,10 @@ static int __devinit bttv_probe(struct pci_dev *dev,
/* everything is fine */
bttv_num++;
- return 0;
+ return 0;
fail2:
- free_irq(btv->c.pci->irq,btv);
+ free_irq(btv->c.pci->irq,btv);
fail1:
if (btv->bt848_mmio)
@@ -4036,12 +4055,12 @@ static int __devinit bttv_probe(struct pci_dev *dev,
static void __devexit bttv_remove(struct pci_dev *pci_dev)
{
- struct bttv *btv = pci_get_drvdata(pci_dev);
+ struct bttv *btv = pci_get_drvdata(pci_dev);
if (bttv_verbose)
printk("bttv%d: unloading\n",btv->c.nr);
- /* shutdown everything (DMA+IRQs) */
+ /* shutdown everything (DMA+IRQs) */
btand(~15, BT848_GPIO_DMA_CTL);
btwrite(0, BT848_INT_MASK);
btwrite(~0x0, BT848_INT_STAT);
@@ -4054,7 +4073,7 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev)
wake_up(&btv->gpioq);
bttv_sub_del_devices(&btv->c);
- /* unregister i2c_bus + input */
+ /* unregister i2c_bus + input */
fini_bttv_i2c(btv);
/* unregister video4linux */
@@ -4064,18 +4083,18 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev)
btcx_riscmem_free(btv->c.pci,&btv->main);
/* free ressources */
- free_irq(btv->c.pci->irq,btv);
+ free_irq(btv->c.pci->irq,btv);
iounmap(btv->bt848_mmio);
- release_mem_region(pci_resource_start(btv->c.pci,0),
- pci_resource_len(btv->c.pci,0));
+ release_mem_region(pci_resource_start(btv->c.pci,0),
+ pci_resource_len(btv->c.pci,0));
pci_set_drvdata(pci_dev, NULL);
- return;
+ return;
}
static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state)
{
- struct bttv *btv = pci_get_drvdata(pci_dev);
+ struct bttv *btv = pci_get_drvdata(pci_dev);
struct bttv_buffer_set idle;
unsigned long flags;
@@ -4110,7 +4129,7 @@ static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state)
static int bttv_resume(struct pci_dev *pci_dev)
{
- struct bttv *btv = pci_get_drvdata(pci_dev);
+ struct bttv *btv = pci_get_drvdata(pci_dev);
unsigned long flags;
int err;
@@ -4155,24 +4174,24 @@ static int bttv_resume(struct pci_dev *pci_dev)
}
static struct pci_device_id bttv_pci_tbl[] = {
- {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {0,}
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0,}
};
MODULE_DEVICE_TABLE(pci, bttv_pci_tbl);
static struct pci_driver bttv_pci_driver = {
- .name = "bttv",
- .id_table = bttv_pci_tbl,
- .probe = bttv_probe,
- .remove = __devexit_p(bttv_remove),
+ .name = "bttv",
+ .id_table = bttv_pci_tbl,
+ .probe = bttv_probe,
+ .remove = __devexit_p(bttv_remove),
.suspend = bttv_suspend,
.resume = bttv_resume,
};
diff --git a/drivers/media/video/bttv-gpio.c b/drivers/media/video/bttv-gpio.c
index 6b280c03e39..616a5b7e510 100644
--- a/drivers/media/video/bttv-gpio.c
+++ b/drivers/media/video/bttv-gpio.c
@@ -7,7 +7,7 @@
Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
- & Marcus Metzler (mocm@thp.uni-koeln.de)
+ & Marcus Metzler (mocm@thp.uni-koeln.de)
(c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
This program is free software; you can redistribute it and/or modify
@@ -113,6 +113,24 @@ void bttv_gpio_irq(struct bttv_core *core)
}
}
+int bttv_any_irq(struct bttv_core *core)
+{
+ struct bttv_sub_driver *drv;
+ struct bttv_sub_device *dev;
+ struct list_head *item;
+ int handled = 0;
+
+ list_for_each(item,&core->subs) {
+ dev = list_entry(item,struct bttv_sub_device,list);
+ drv = to_bttv_sub_drv(dev->dev.driver);
+ if (drv && drv->any_irq) {
+ if (drv->any_irq(dev))
+ handled = 1;
+ }
+ }
+ return handled;
+}
+
/* ----------------------------------------------------------------------- */
/* external: sub-driver register/unregister */
diff --git a/drivers/media/video/bttv-i2c.c b/drivers/media/video/bttv-i2c.c
index e684df37eb0..77619eb131f 100644
--- a/drivers/media/video/bttv-i2c.c
+++ b/drivers/media/video/bttv-i2c.c
@@ -5,7 +5,7 @@
bttv - Bt848 frame grabber driver
Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
- & Marcus Metzler (mocm@thp.uni-koeln.de)
+ & Marcus Metzler (mocm@thp.uni-koeln.de)
(c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
This program is free software; you can redistribute it and/or modify
@@ -237,7 +237,7 @@ bttv_i2c_readbytes(struct bttv *btv, const struct i2c_msg *msg, int last)
err:
if (i2c_debug)
printk(" ERR: %d\n",retval);
- return retval;
+ return retval;
}
static int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
@@ -290,7 +290,13 @@ static struct i2c_adapter bttv_i2c_adap_hw_template = {
static int attach_inform(struct i2c_client *client)
{
- struct bttv *btv = i2c_get_adapdata(client->adapter);
+ struct bttv *btv = i2c_get_adapdata(client->adapter);
+ int addr=ADDR_UNSET;
+
+
+ if (ADDR_UNSET != bttv_tvcards[btv->c.type].tuner_addr)
+ addr = bttv_tvcards[btv->c.type].tuner_addr;
+
if (bttv_debug)
printk(KERN_DEBUG "bttv%d: %s i2c attach [addr=0x%x,client=%s]\n",
@@ -300,19 +306,20 @@ static int attach_inform(struct i2c_client *client)
return 0;
if (btv->tuner_type != UNSET) {
- struct tuner_setup tun_setup;
+ struct tuner_setup tun_setup;
+
+ if ((addr==ADDR_UNSET) ||
+ (addr==client->addr)) {
- tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
- tun_setup.type = btv->tuner_type;
- tun_setup.addr = ADDR_UNSET;
+ tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV | T_RADIO;
+ tun_setup.type = btv->tuner_type;
+ tun_setup.addr = addr;
+ bttv_call_i2c_clients(btv, TUNER_SET_TYPE_ADDR, &tun_setup);
+ }
- client->driver->command (client, TUNER_SET_TYPE_ADDR, &tun_setup);
}
- if (btv->pinnacle_id != UNSET)
- client->driver->command(client,AUDC_CONFIG_PINNACLE,
- &btv->pinnacle_id);
- return 0;
+ return 0;
}
void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg)
@@ -330,43 +337,43 @@ static struct i2c_client bttv_i2c_client_template = {
/* read I2C */
int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for)
{
- unsigned char buffer = 0;
+ unsigned char buffer = 0;
if (0 != btv->i2c_rc)
return -1;
if (bttv_verbose && NULL != probe_for)
printk(KERN_INFO "bttv%d: i2c: checking for %s @ 0x%02x... ",
btv->c.nr,probe_for,addr);
- btv->i2c_client.addr = addr >> 1;
- if (1 != i2c_master_recv(&btv->i2c_client, &buffer, 1)) {
+ btv->i2c_client.addr = addr >> 1;
+ if (1 != i2c_master_recv(&btv->i2c_client, &buffer, 1)) {
if (NULL != probe_for) {
if (bttv_verbose)
printk("not found\n");
} else
printk(KERN_WARNING "bttv%d: i2c read 0x%x: error\n",
btv->c.nr,addr);
- return -1;
+ return -1;
}
if (bttv_verbose && NULL != probe_for)
printk("found\n");
- return buffer;
+ return buffer;
}
/* write I2C */
int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1,
- unsigned char b2, int both)
+ unsigned char b2, int both)
{
- unsigned char buffer[2];
- int bytes = both ? 2 : 1;
+ unsigned char buffer[2];
+ int bytes = both ? 2 : 1;
if (0 != btv->i2c_rc)
return -1;
- btv->i2c_client.addr = addr >> 1;
- buffer[0] = b1;
- buffer[1] = b2;
- if (bytes != i2c_master_send(&btv->i2c_client, buffer, bytes))
+ btv->i2c_client.addr = addr >> 1;
+ buffer[0] = b1;
+ buffer[1] = b2;
+ if (bytes != i2c_master_send(&btv->i2c_client, buffer, bytes))
return -1;
- return 0;
+ return 0;
}
/* read EEPROM content */
@@ -431,8 +438,8 @@ int __devinit init_bttv_i2c(struct bttv *btv)
"bt%d #%d [%s]", btv->id, btv->c.nr,
btv->use_i2c_hw ? "hw" : "sw");
- i2c_set_adapdata(&btv->c.i2c_adap, btv);
- btv->i2c_client.adapter = &btv->c.i2c_adap;
+ i2c_set_adapdata(&btv->c.i2c_adap, btv);
+ btv->i2c_client.adapter = &btv->c.i2c_adap;
#ifdef I2C_CLASS_TV_ANALOG
if (bttv_tvcards[btv->c.type].no_video)
diff --git a/drivers/media/video/bttv-if.c b/drivers/media/video/bttv-if.c
index e8aada772b8..19b564ab0e9 100644
--- a/drivers/media/video/bttv-if.c
+++ b/drivers/media/video/bttv-if.c
@@ -1,13 +1,13 @@
/*
bttv-if.c -- old gpio interface to other kernel modules
- don't use in new code, will go away in 2.7
+ don't use in new code, will go away in 2.7
have a look at bttv-gpio.c instead.
bttv - Bt848 frame grabber driver
Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
- & Marcus Metzler (mocm@thp.uni-koeln.de)
+ & Marcus Metzler (mocm@thp.uni-koeln.de)
(c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
This program is free software; you can redistribute it and/or modify
diff --git a/drivers/media/video/bttv-risc.c b/drivers/media/video/bttv-risc.c
index a5ed99b8944..b40e9734bf0 100644
--- a/drivers/media/video/bttv-risc.c
+++ b/drivers/media/video/bttv-risc.c
@@ -74,27 +74,27 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
}
if (bpl <= sg_dma_len(sg)-offset) {
/* fits into current chunk */
- *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
+ *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
BT848_RISC_EOL|bpl);
- *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
- offset+=bpl;
+ *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
+ offset+=bpl;
} else {
/* scanline needs to be splitted */
- todo = bpl;
- *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
+ todo = bpl;
+ *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
(sg_dma_len(sg)-offset));
- *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
- todo -= (sg_dma_len(sg)-offset);
- offset = 0;
- sg++;
- while (todo > sg_dma_len(sg)) {
- *(rp++)=cpu_to_le32(BT848_RISC_WRITE|
+ *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
+ todo -= (sg_dma_len(sg)-offset);
+ offset = 0;
+ sg++;
+ while (todo > sg_dma_len(sg)) {
+ *(rp++)=cpu_to_le32(BT848_RISC_WRITE|
sg_dma_len(sg));
- *(rp++)=cpu_to_le32(sg_dma_address(sg));
+ *(rp++)=cpu_to_le32(sg_dma_address(sg));
todo -= sg_dma_len(sg);
sg++;
}
- *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL|
+ *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL|
todo);
*(rp++)=cpu_to_le32(sg_dma_address(sg));
offset += todo;
@@ -201,8 +201,8 @@ bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc,
ri |= BT848_RISC_EOL;
/* write risc instruction */
- *(rp++)=cpu_to_le32(ri | ylen);
- *(rp++)=cpu_to_le32(((ylen >> hshift) << 16) |
+ *(rp++)=cpu_to_le32(ri | ylen);
+ *(rp++)=cpu_to_le32(((ylen >> hshift) << 16) |
(ylen >> hshift));
*(rp++)=cpu_to_le32(sg_dma_address(ysg)+yoffset);
yoffset += ylen;
@@ -319,7 +319,7 @@ bttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo,
int width, int height, int interleaved, int norm)
{
const struct bttv_tvnorm *tvnorm = &bttv_tvnorms[norm];
- u32 xsf, sr;
+ u32 xsf, sr;
int vdelay;
int swidth = tvnorm->swidth;
@@ -334,52 +334,52 @@ bttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo,
vdelay = tvnorm->vdelay;
- xsf = (width*scaledtwidth)/swidth;
- geo->hscale = ((totalwidth*4096UL)/xsf-4096);
- geo->hdelay = tvnorm->hdelayx1;
- geo->hdelay = (geo->hdelay*width)/swidth;
- geo->hdelay &= 0x3fe;
- sr = ((tvnorm->sheight >> (interleaved?0:1))*512)/height - 512;
- geo->vscale = (0x10000UL-sr) & 0x1fff;
- geo->crop = ((width>>8)&0x03) | ((geo->hdelay>>6)&0x0c) |
- ((tvnorm->sheight>>4)&0x30) | ((vdelay>>2)&0xc0);
- geo->vscale |= interleaved ? (BT848_VSCALE_INT<<8) : 0;
- geo->vdelay = vdelay;
- geo->width = width;
- geo->sheight = tvnorm->sheight;
+ xsf = (width*scaledtwidth)/swidth;
+ geo->hscale = ((totalwidth*4096UL)/xsf-4096);
+ geo->hdelay = tvnorm->hdelayx1;
+ geo->hdelay = (geo->hdelay*width)/swidth;
+ geo->hdelay &= 0x3fe;
+ sr = ((tvnorm->sheight >> (interleaved?0:1))*512)/height - 512;
+ geo->vscale = (0x10000UL-sr) & 0x1fff;
+ geo->crop = ((width>>8)&0x03) | ((geo->hdelay>>6)&0x0c) |
+ ((tvnorm->sheight>>4)&0x30) | ((vdelay>>2)&0xc0);
+ geo->vscale |= interleaved ? (BT848_VSCALE_INT<<8) : 0;
+ geo->vdelay = vdelay;
+ geo->width = width;
+ geo->sheight = tvnorm->sheight;
geo->vtotal = tvnorm->vtotal;
- if (btv->opt_combfilter) {
- geo->vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
- geo->comb = (width < 769) ? 1 : 0;
- } else {
- geo->vtc = 0;
- geo->comb = 0;
- }
+ if (btv->opt_combfilter) {
+ geo->vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
+ geo->comb = (width < 769) ? 1 : 0;
+ } else {
+ geo->vtc = 0;
+ geo->comb = 0;
+ }
}
static void
bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd)
{
- int off = odd ? 0x80 : 0x00;
+ int off = odd ? 0x80 : 0x00;
if (geo->comb)
btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
else
btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
- btwrite(geo->vtc, BT848_E_VTC+off);
- btwrite(geo->hscale >> 8, BT848_E_HSCALE_HI+off);
- btwrite(geo->hscale & 0xff, BT848_E_HSCALE_LO+off);
- btaor((geo->vscale>>8), 0xe0, BT848_E_VSCALE_HI+off);
- btwrite(geo->vscale & 0xff, BT848_E_VSCALE_LO+off);
- btwrite(geo->width & 0xff, BT848_E_HACTIVE_LO+off);
- btwrite(geo->hdelay & 0xff, BT848_E_HDELAY_LO+off);
- btwrite(geo->sheight & 0xff, BT848_E_VACTIVE_LO+off);
- btwrite(geo->vdelay & 0xff, BT848_E_VDELAY_LO+off);
- btwrite(geo->crop, BT848_E_CROP+off);
+ btwrite(geo->vtc, BT848_E_VTC+off);
+ btwrite(geo->hscale >> 8, BT848_E_HSCALE_HI+off);
+ btwrite(geo->hscale & 0xff, BT848_E_HSCALE_LO+off);
+ btaor((geo->vscale>>8), 0xe0, BT848_E_VSCALE_HI+off);
+ btwrite(geo->vscale & 0xff, BT848_E_VSCALE_LO+off);
+ btwrite(geo->width & 0xff, BT848_E_HACTIVE_LO+off);
+ btwrite(geo->hdelay & 0xff, BT848_E_HDELAY_LO+off);
+ btwrite(geo->sheight & 0xff, BT848_E_VACTIVE_LO+off);
+ btwrite(geo->vdelay & 0xff, BT848_E_VDELAY_LO+off);
+ btwrite(geo->crop, BT848_E_CROP+off);
btwrite(geo->vtotal>>8, BT848_VTOTAL_HI);
- btwrite(geo->vtotal & 0xff, BT848_VTOTAL_LO);
+ btwrite(geo->vtotal & 0xff, BT848_VTOTAL_LO);
}
/* ---------------------------------------------------------- */
@@ -420,7 +420,7 @@ bttv_set_dma(struct bttv *btv, int override)
} else {
del_timer(&btv->timeout);
}
- btv->main.cpu[RISC_SLOT_LOOP] = cpu_to_le32(cmd);
+ btv->main.cpu[RISC_SLOT_LOOP] = cpu_to_le32(cmd);
btaor(capctl, ~0x0f, BT848_CAP_CTL);
if (capctl) {
@@ -432,7 +432,7 @@ bttv_set_dma(struct bttv *btv, int override)
} else {
if (!btv->dma_on)
return;
- btand(~3, BT848_GPIO_DMA_CTL);
+ btand(~3, BT848_GPIO_DMA_CTL);
btv->dma_on = 0;
}
return;
@@ -460,19 +460,19 @@ bttv_risc_init_main(struct bttv *btv)
btv->main.cpu[6] = cpu_to_le32(BT848_RISC_JUMP);
btv->main.cpu[7] = cpu_to_le32(btv->main.dma + (8<<2));
- btv->main.cpu[8] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
+ btv->main.cpu[8] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
BT848_FIFO_STATUS_VRO);
- btv->main.cpu[9] = cpu_to_le32(0);
+ btv->main.cpu[9] = cpu_to_le32(0);
/* bottom field */
- btv->main.cpu[10] = cpu_to_le32(BT848_RISC_JUMP);
+ 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[12] = cpu_to_le32(BT848_RISC_JUMP);
btv->main.cpu[13] = cpu_to_le32(btv->main.dma + (14<<2));
/* jump back to top field */
btv->main.cpu[14] = cpu_to_le32(BT848_RISC_JUMP);
- btv->main.cpu[15] = cpu_to_le32(btv->main.dma + (0<<2));
+ btv->main.cpu[15] = cpu_to_le32(btv->main.dma + (0<<2));
return 0;
}
diff --git a/drivers/media/video/bttv.h b/drivers/media/video/bttv.h
index d254e90e3bb..93298f06e01 100644
--- a/drivers/media/video/bttv.h
+++ b/drivers/media/video/bttv.h
@@ -20,123 +20,149 @@
/* ---------------------------------------------------------- */
/* exported by bttv-cards.c */
-#define BTTV_UNKNOWN 0x00
-#define BTTV_MIRO 0x01
-#define BTTV_HAUPPAUGE 0x02
-#define BTTV_STB 0x03
-#define BTTV_INTEL 0x04
-#define BTTV_DIAMOND 0x05
-#define BTTV_AVERMEDIA 0x06
-#define BTTV_MATRIX_VISION 0x07
-#define BTTV_FLYVIDEO 0x08
-#define BTTV_TURBOTV 0x09
-#define BTTV_HAUPPAUGE878 0x0a
-#define BTTV_MIROPRO 0x0b
-#define BTTV_ADSTECH_TV 0x0c
-#define BTTV_AVERMEDIA98 0x0d
-#define BTTV_VHX 0x0e
-#define BTTV_ZOLTRIX 0x0f
-#define BTTV_PIXVIEWPLAYTV 0x10
-#define BTTV_WINVIEW_601 0x11
-#define BTTV_AVEC_INTERCAP 0x12
-#define BTTV_LIFE_FLYKIT 0x13
-#define BTTV_CEI_RAFFLES 0x14
-#define BTTV_CONFERENCETV 0x15
-#define BTTV_PHOEBE_TVMAS 0x16
-#define BTTV_MODTEC_205 0x17
-#define BTTV_MAGICTVIEW061 0x18
-#define BTTV_VOBIS_BOOSTAR 0x19
-#define BTTV_HAUPPAUG_WCAM 0x1a
-#define BTTV_MAXI 0x1b
-#define BTTV_TERRATV 0x1c
-#define BTTV_PXC200 0x1d
-#define BTTV_FLYVIDEO_98 0x1e
-#define BTTV_IPROTV 0x1f
-#define BTTV_INTEL_C_S_PCI 0x20
-#define BTTV_TERRATVALUE 0x21
-#define BTTV_WINFAST2000 0x22
-#define BTTV_CHRONOS_VS2 0x23
-#define BTTV_TYPHOON_TVIEW 0x24
-#define BTTV_PXELVWPLTVPRO 0x25
-#define BTTV_MAGICTVIEW063 0x26
-#define BTTV_PINNACLE 0x27
-#define BTTV_STB2 0x28
-#define BTTV_AVPHONE98 0x29
-#define BTTV_PV951 0x2a
-#define BTTV_ONAIR_TV 0x2b
-#define BTTV_SIGMA_TVII_FM 0x2c
-#define BTTV_MATRIX_VISION2 0x2d
-#define BTTV_ZOLTRIX_GENIE 0x2e
-#define BTTV_TERRATVRADIO 0x2f
-#define BTTV_DYNALINK 0x30
-#define BTTV_GVBCTV3PCI 0x31
-#define BTTV_PXELVWPLTVPAK 0x32
-#define BTTV_EAGLE 0x33
-#define BTTV_PINNACLEPRO 0x34
-#define BTTV_TVIEW_RDS_FM 0x35
-#define BTTV_LIFETEC_9415 0x36
-#define BTTV_BESTBUY_EASYTV 0x37
-#define BTTV_FLYVIDEO_98FM 0x38
-#define BTTV_GMV1 0x3d
-#define BTTV_BESTBUY_EASYTV2 0x3e
-#define BTTV_ATI_TVWONDER 0x3f
-#define BTTV_ATI_TVWONDERVE 0x40
-#define BTTV_FLYVIDEO2000 0x41
-#define BTTV_TERRATVALUER 0x42
-#define BTTV_GVBCTV4PCI 0x43
-#define BTTV_VOODOOTV_FM 0x44
-#define BTTV_AIMMS 0x45
-#define BTTV_PV_BT878P_PLUS 0x46
-#define BTTV_FLYVIDEO98EZ 0x47
-#define BTTV_PV_BT878P_9B 0x48
-#define BTTV_SENSORAY311 0x49
-#define BTTV_RV605 0x4a
-#define BTTV_WINDVR 0x4c
-#define BTTV_GRANDTEC 0x4d
-#define BTTV_KWORLD 0x4e
-#define BTTV_HAUPPAUGEPVR 0x50
-#define BTTV_GVBCTV5PCI 0x51
-#define BTTV_OSPREY1x0 0x52
-#define BTTV_OSPREY1x0_848 0x53
-#define BTTV_OSPREY101_848 0x54
-#define BTTV_OSPREY1x1 0x55
-#define BTTV_OSPREY1x1_SVID 0x56
-#define BTTV_OSPREY2xx 0x57
-#define BTTV_OSPREY2x0_SVID 0x58
-#define BTTV_OSPREY2x0 0x59
-#define BTTV_OSPREY500 0x5a
-#define BTTV_OSPREY540 0x5b
-#define BTTV_OSPREY2000 0x5c
-#define BTTV_IDS_EAGLE 0x5d
-#define BTTV_PINNACLESAT 0x5e
-#define BTTV_FORMAC_PROTV 0x5f
-#define BTTV_EURESYS_PICOLO 0x61
-#define BTTV_PV150 0x62
-#define BTTV_AD_TVK503 0x63
-#define BTTV_IVC200 0x66
-#define BTTV_XGUARD 0x67
-#define BTTV_NEBULA_DIGITV 0x68
-#define BTTV_PV143 0x69
-#define BTTV_IVC100 0x6e
-#define BTTV_IVC120 0x6f
-#define BTTV_PC_HDTV 0x70
-#define BTTV_TWINHAN_DST 0x71
-#define BTTV_WINFASTVC100 0x72
-#define BTTV_SIMUS_GVC1100 0x74
-#define BTTV_NGSTV_PLUS 0x75
-#define BTTV_LMLBT4 0x76
-#define BTTV_PICOLO_TETRA_CHIP 0x79
-#define BTTV_AVDVBT_771 0x7b
-#define BTTV_AVDVBT_761 0x7c
-#define BTTV_MATRIX_VISIONSQ 0x7d
-#define BTTV_MATRIX_VISIONSLC 0x7e
-#define BTTV_APAC_VIEWCOMP 0x7f
-#define BTTV_DVICO_DVBT_LITE 0x80
-#define BTTV_TIBET_CS16 0x83
-#define BTTV_KODICOM_4400R 0x84
-#define BTTV_ADLINK_RTV24 0x86
-#define BTTV_DVICO_FUSIONHDTV_5_LITE 0x87
-#define BTTV_ACORP_Y878F 0x88
+#define BTTV_BOARD_UNKNOWN 0x00
+#define BTTV_BOARD_MIRO 0x01
+#define BTTV_BOARD_HAUPPAUGE 0x02
+#define BTTV_BOARD_STB 0x03
+#define BTTV_BOARD_INTEL 0x04
+#define BTTV_BOARD_DIAMOND 0x05
+#define BTTV_BOARD_AVERMEDIA 0x06
+#define BTTV_BOARD_MATRIX_VISION 0x07
+#define BTTV_BOARD_FLYVIDEO 0x08
+#define BTTV_BOARD_TURBOTV 0x09
+#define BTTV_BOARD_HAUPPAUGE878 0x0a
+#define BTTV_BOARD_MIROPRO 0x0b
+#define BTTV_BOARD_ADSTECH_TV 0x0c
+#define BTTV_BOARD_AVERMEDIA98 0x0d
+#define BTTV_BOARD_VHX 0x0e
+#define BTTV_BOARD_ZOLTRIX 0x0f
+#define BTTV_BOARD_PIXVIEWPLAYTV 0x10
+#define BTTV_BOARD_WINVIEW_601 0x11
+#define BTTV_BOARD_AVEC_INTERCAP 0x12
+#define BTTV_BOARD_LIFE_FLYKIT 0x13
+#define BTTV_BOARD_CEI_RAFFLES 0x14
+#define BTTV_BOARD_CONFERENCETV 0x15
+#define BTTV_BOARD_PHOEBE_TVMAS 0x16
+#define BTTV_BOARD_MODTEC_205 0x17
+#define BTTV_BOARD_MAGICTVIEW061 0x18
+#define BTTV_BOARD_VOBIS_BOOSTAR 0x19
+#define BTTV_BOARD_HAUPPAUG_WCAM 0x1a
+#define BTTV_BOARD_MAXI 0x1b
+#define BTTV_BOARD_TERRATV 0x1c
+#define BTTV_BOARD_PXC200 0x1d
+#define BTTV_BOARD_FLYVIDEO_98 0x1e
+#define BTTV_BOARD_IPROTV 0x1f
+#define BTTV_BOARD_INTEL_C_S_PCI 0x20
+#define BTTV_BOARD_TERRATVALUE 0x21
+#define BTTV_BOARD_WINFAST2000 0x22
+#define BTTV_BOARD_CHRONOS_VS2 0x23
+#define BTTV_BOARD_TYPHOON_TVIEW 0x24
+#define BTTV_BOARD_PXELVWPLTVPRO 0x25
+#define BTTV_BOARD_MAGICTVIEW063 0x26
+#define BTTV_BOARD_PINNACLE 0x27
+#define BTTV_BOARD_STB2 0x28
+#define BTTV_BOARD_AVPHONE98 0x29
+#define BTTV_BOARD_PV951 0x2a
+#define BTTV_BOARD_ONAIR_TV 0x2b
+#define BTTV_BOARD_SIGMA_TVII_FM 0x2c
+#define BTTV_BOARD_MATRIX_VISION2 0x2d
+#define BTTV_BOARD_ZOLTRIX_GENIE 0x2e
+#define BTTV_BOARD_TERRATVRADIO 0x2f
+#define BTTV_BOARD_DYNALINK 0x30
+#define BTTV_BOARD_GVBCTV3PCI 0x31
+#define BTTV_BOARD_PXELVWPLTVPAK 0x32
+#define BTTV_BOARD_EAGLE 0x33
+#define BTTV_BOARD_PINNACLEPRO 0x34
+#define BTTV_BOARD_TVIEW_RDS_FM 0x35
+#define BTTV_BOARD_LIFETEC_9415 0x36
+#define BTTV_BOARD_BESTBUY_EASYTV 0x37
+#define BTTV_BOARD_FLYVIDEO_98FM 0x38
+#define BTTV_BOARD_GRANDTEC 0x39
+#define BTTV_BOARD_ASKEY_CPH060 0x3a
+#define BTTV_BOARD_ASKEY_CPH03X 0x3b
+#define BTTV_BOARD_MM100PCTV 0x3c
+#define BTTV_BOARD_GMV1 0x3d
+#define BTTV_BOARD_BESTBUY_EASYTV2 0x3e
+#define BTTV_BOARD_ATI_TVWONDER 0x3f
+#define BTTV_BOARD_ATI_TVWONDERVE 0x40
+#define BTTV_BOARD_FLYVIDEO2000 0x41
+#define BTTV_BOARD_TERRATVALUER 0x42
+#define BTTV_BOARD_GVBCTV4PCI 0x43
+#define BTTV_BOARD_VOODOOTV_FM 0x44
+#define BTTV_BOARD_AIMMS 0x45
+#define BTTV_BOARD_PV_BT878P_PLUS 0x46
+#define BTTV_BOARD_FLYVIDEO98EZ 0x47
+#define BTTV_BOARD_PV_BT878P_9B 0x48
+#define BTTV_BOARD_SENSORAY311 0x49
+#define BTTV_BOARD_RV605 0x4a
+#define BTTV_BOARD_POWERCLR_MTV878 0x4b
+#define BTTV_BOARD_WINDVR 0x4c
+#define BTTV_BOARD_GRANDTEC_MULTI 0x4d
+#define BTTV_BOARD_KWORLD 0x4e
+#define BTTV_BOARD_DSP_TCVIDEO 0x4f
+#define BTTV_BOARD_HAUPPAUGEPVR 0x50
+#define BTTV_BOARD_GVBCTV5PCI 0x51
+#define BTTV_BOARD_OSPREY1x0 0x52
+#define BTTV_BOARD_OSPREY1x0_848 0x53
+#define BTTV_BOARD_OSPREY101_848 0x54
+#define BTTV_BOARD_OSPREY1x1 0x55
+#define BTTV_BOARD_OSPREY1x1_SVID 0x56
+#define BTTV_BOARD_OSPREY2xx 0x57
+#define BTTV_BOARD_OSPREY2x0_SVID 0x58
+#define BTTV_BOARD_OSPREY2x0 0x59
+#define BTTV_BOARD_OSPREY500 0x5a
+#define BTTV_BOARD_OSPREY540 0x5b
+#define BTTV_BOARD_OSPREY2000 0x5c
+#define BTTV_BOARD_IDS_EAGLE 0x5d
+#define BTTV_BOARD_PINNACLESAT 0x5e
+#define BTTV_BOARD_FORMAC_PROTV 0x5f
+#define BTTV_BOARD_MACHTV 0x60
+#define BTTV_BOARD_EURESYS_PICOLO 0x61
+#define BTTV_BOARD_PV150 0x62
+#define BTTV_BOARD_AD_TVK503 0x63
+#define BTTV_BOARD_HERCULES_SM_TV 0x64
+#define BTTV_BOARD_PACETV 0x65
+#define BTTV_BOARD_IVC200 0x66
+#define BTTV_BOARD_XGUARD 0x67
+#define BTTV_BOARD_NEBULA_DIGITV 0x68
+#define BTTV_BOARD_PV143 0x69
+#define BTTV_BOARD_VD009X1_MINIDIN 0x6a
+#define BTTV_BOARD_VD009X1_COMBI 0x6b
+#define BTTV_BOARD_VD009_MINIDIN 0x6c
+#define BTTV_BOARD_VD009_COMBI 0x6d
+#define BTTV_BOARD_IVC100 0x6e
+#define BTTV_BOARD_IVC120 0x6f
+#define BTTV_BOARD_PC_HDTV 0x70
+#define BTTV_BOARD_TWINHAN_DST 0x71
+#define BTTV_BOARD_WINFASTVC100 0x72
+#define BTTV_BOARD_TEV560 0x73
+#define BTTV_BOARD_SIMUS_GVC1100 0x74
+#define BTTV_BOARD_NGSTV_PLUS 0x75
+#define BTTV_BOARD_LMLBT4 0x76
+#define BTTV_BOARD_TEKRAM_M205 0x77
+#define BTTV_BOARD_CONTVFMI 0x78
+#define BTTV_BOARD_PICOLO_TETRA_CHIP 0x79
+#define BTTV_BOARD_SPIRIT_TV 0x7a
+#define BTTV_BOARD_AVDVBT_771 0x7b
+#define BTTV_BOARD_AVDVBT_761 0x7c
+#define BTTV_BOARD_MATRIX_VISIONSQ 0x7d
+#define BTTV_BOARD_MATRIX_VISIONSLC 0x7e
+#define BTTV_BOARD_APAC_VIEWCOMP 0x7f
+#define BTTV_BOARD_DVICO_DVBT_LITE 0x80
+#define BTTV_BOARD_VGEAR_MYVCD 0x81
+#define BTTV_BOARD_SUPER_TV 0x82
+#define BTTV_BOARD_TIBET_CS16 0x83
+#define BTTV_BOARD_KODICOM_4400R 0x84
+#define BTTV_BOARD_KODICOM_4400R_SL 0x85
+#define BTTV_BOARD_ADLINK_RTV24 0x86
+#define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87
+#define BTTV_BOARD_ACORP_Y878F 0x88
+#define BTTV_BOARD_CONCEPTRONIC_CTVFMI2 0x89
+#define BTTV_BOARD_PV_BT878P_2E 0x8a
+#define BTTV_BOARD_PV_M4900 0x8b
+#define BTTV_BOARD_OSPREY440 0x8c
+#define BTTV_BOARD_ASOUND_SKYEYE 0x8d
+#define BTTV_BOARD_SABRENT_TVFM 0x8e
/* i2c address list */
#define I2C_TSA5522 0xc2
@@ -177,7 +203,7 @@ struct bttv_core {
struct list_head subs; /* struct bttv_sub_device */
/* device config */
- unsigned int nr; /* dev nr (for printk("bttv%d: ..."); */
+ unsigned int nr; /* dev nr (for printk("bttv%d: ..."); */
unsigned int type; /* card type (pointer into tvcards[]) */
char name[8]; /* dev name */
};
@@ -186,16 +212,16 @@ struct bttv;
struct tvcard
{
- char *name;
- unsigned int video_inputs;
- unsigned int audio_inputs;
- unsigned int tuner;
- unsigned int svhs;
+ char *name;
+ unsigned int video_inputs;
+ unsigned int audio_inputs;
+ unsigned int tuner;
+ unsigned int svhs;
unsigned int digital_mode; // DIGITAL_MODE_CAMERA or DIGITAL_MODE_VIDEO
- u32 gpiomask;
- u32 muxsel[16];
- u32 audiomux[6]; /* Tuner, Radio, external, internal, mute, stereo */
- u32 gpiomask2; /* GPIO MUX mask */
+ u32 gpiomask;
+ u32 muxsel[16];
+ u32 audiomux[6]; /* Tuner, Radio, external, internal, mute, stereo */
+ u32 gpiomask2; /* GPIO MUX mask */
/* i2c audio flags */
unsigned int no_msp34xx:1;
@@ -209,6 +235,7 @@ struct tvcard
unsigned int has_dvb:1;
unsigned int has_remote:1;
unsigned int no_gpioirq:1;
+ unsigned int any_irq:1;
/* other settings */
unsigned int pll;
@@ -218,6 +245,7 @@ struct tvcard
unsigned int tuner_type;
unsigned int tuner_addr;
+ unsigned int radio_addr;
unsigned int has_radio;
void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set);
@@ -246,7 +274,7 @@ extern int bttv_handle_chipset(struct bttv *btv);
interface below for new code */
/* returns card type + card ID (for bt878-based ones)
- for possible values see lines below beginning with #define BTTV_UNKNOWN
+ for possible values see lines below beginning with #define BTTV_BOARD_UNKNOWN
returns negative value if error occurred
*/
extern int bttv_get_cardinfo(unsigned int card, int *type,
@@ -307,6 +335,7 @@ struct bttv_sub_driver {
struct device_driver drv;
char wanted[BUS_ID_SIZE];
void (*gpio_irq)(struct bttv_sub_device *sub);
+ int (*any_irq)(struct bttv_sub_device *sub);
};
#define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv)
diff --git a/drivers/media/video/bttvp.h b/drivers/media/video/bttvp.h
index e0e7c7a84bc..3aa9c6e4fc3 100644
--- a/drivers/media/video/bttvp.h
+++ b/drivers/media/video/bttvp.h
@@ -77,14 +77,14 @@
struct bttv_tvnorm {
int v4l2_id;
char *name;
- u32 Fsc;
- u16 swidth, sheight; /* scaled standard width, height */
+ u32 Fsc;
+ u16 swidth, sheight; /* scaled standard width, height */
u16 totalwidth;
u8 adelay, bdelay, iform;
u32 scaledtwidth;
u16 hdelayx1, hactivex1;
u16 vdelay;
- u8 vbipack;
+ u8 vbipack;
u16 vtotal;
int sram;
};
@@ -208,6 +208,7 @@ extern struct bus_type bttv_sub_bus_type;
int bttv_sub_add_device(struct bttv_core *core, char *name);
int bttv_sub_del_devices(struct bttv_core *core);
void bttv_gpio_irq(struct bttv_core *core);
+int bttv_any_irq(struct bttv_core *core);
/* ---------------------------------------------------------- */
@@ -267,12 +268,13 @@ struct bttv {
/* card configuration info */
unsigned int cardid; /* pci subsystem id (bt878 based ones) */
- unsigned int tuner_type; /* tuner chip type */
- unsigned int pinnacle_id;
+ unsigned int tuner_type; /* tuner chip type */
+ unsigned int pinnacle_id;
unsigned int svhs;
struct bttv_pll_info pll;
int triton1;
int gpioirq;
+ int any_irq;
int use_i2c_hw;
/* old gpio interface */
@@ -301,9 +303,9 @@ struct bttv {
/* locking */
spinlock_t s_lock;
- struct semaphore lock;
+ struct semaphore lock;
int resources;
- struct semaphore reslock;
+ struct semaphore reslock;
#ifdef VIDIOC_G_PRIORITY
struct v4l2_prio_state prio;
#endif
diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c
new file mode 100644
index 00000000000..780b352ec11
--- /dev/null
+++ b/drivers/media/video/cs53l32a.c
@@ -0,0 +1,240 @@
+/*
+ * cs53l32a (Adaptec AVC-2010 and AVC-2410) i2c ivtv driver.
+ * Copyright (C) 2005 Martin Vaughan
+ *
+ * Audio source switching for Adaptec AVC-2410 added by Trev Jackson
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <asm/uaccess.h>
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/videodev.h>
+#include <media/audiochip.h>
+
+MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC");
+MODULE_AUTHOR("Martin Vaughan");
+MODULE_LICENSE("GPL");
+
+static int debug = 0;
+
+module_param(debug, bool, 0644);
+
+MODULE_PARM_DESC(debug, "Debugging messages\n\t\t\t0=Off (default), 1=On");
+
+#define cs53l32a_dbg(fmt, arg...) \
+ do { \
+ if (debug) \
+ printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); \
+ } while (0)
+
+#define cs53l32a_err(fmt, arg...) do { \
+ printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+#define cs53l32a_info(fmt, arg...) do { \
+ printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+
+static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END };
+
+
+I2C_CLIENT_INSMOD;
+
+/* ----------------------------------------------------------------------- */
+
+static int cs53l32a_write(struct i2c_client *client, u8 reg, u8 value)
+{
+ return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int cs53l32a_read(struct i2c_client *client, u8 reg)
+{
+ return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int cs53l32a_command(struct i2c_client *client, unsigned int cmd,
+ void *arg)
+{
+ int *input = arg;
+
+ switch (cmd) {
+ case AUDC_SET_INPUT:
+ switch (*input) {
+ case AUDIO_TUNER:
+ cs53l32a_write(client, 0x01, 0x01);
+ break;
+ case AUDIO_EXTERN:
+ cs53l32a_write(client, 0x01, 0x21);
+ break;
+ case AUDIO_MUTE:
+ cs53l32a_write(client, 0x03, 0xF0);
+ break;
+ case AUDIO_UNMUTE:
+ cs53l32a_write(client, 0x03, 0x30);
+ break;
+ default:
+ cs53l32a_err("Invalid input %d.\n", *input);
+ return -EINVAL;
+ }
+ break;
+
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *ctrl = arg;
+
+ if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
+ return -EINVAL;
+ if (ctrl->value > 12 || ctrl->value < -90)
+ return -EINVAL;
+ cs53l32a_write(client, 0x04, (u8) ctrl->value);
+ cs53l32a_write(client, 0x05, (u8) ctrl->value);
+ break;
+ }
+
+ case VIDIOC_LOG_STATUS:
+ {
+ u8 v = cs53l32a_read(client, 0x01);
+ u8 m = cs53l32a_read(client, 0x03);
+
+ cs53l32a_info("Input: %s%s\n",
+ v == 0x21 ? "external line in" : "tuner",
+ (m & 0xC0) ? " (muted)" : "");
+ break;
+ }
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+
+static struct i2c_driver i2c_driver;
+
+static int cs53l32a_attach(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct i2c_client *client;
+ int i;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return 0;
+
+ client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (client == 0)
+ return -ENOMEM;
+
+ memset(client, 0, sizeof(struct i2c_client));
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &i2c_driver;
+ client->flags = I2C_CLIENT_ALLOW_USE;
+ snprintf(client->name, sizeof(client->name) - 1, "cs53l32a");
+
+ cs53l32a_info("chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+
+ for (i = 1; i <= 7; i++) {
+ u8 v = cs53l32a_read(client, i);
+
+ cs53l32a_dbg("Read Reg %d %02x\n", i, v);
+ }
+
+ /* Set cs53l32a internal register for Adaptec 2010/2410 setup */
+
+ cs53l32a_write(client, 0x01, (u8) 0x21);
+ cs53l32a_write(client, 0x02, (u8) 0x29);
+ cs53l32a_write(client, 0x03, (u8) 0x30);
+ cs53l32a_write(client, 0x04, (u8) 0x00);
+ cs53l32a_write(client, 0x05, (u8) 0x00);
+ cs53l32a_write(client, 0x06, (u8) 0x00);
+ cs53l32a_write(client, 0x07, (u8) 0x00);
+
+ /* Display results, should be 0x21,0x29,0x30,0x00,0x00,0x00,0x00 */
+
+ for (i = 1; i <= 7; i++) {
+ u8 v = cs53l32a_read(client, i);
+
+ cs53l32a_dbg("Read Reg %d %02x\n", i, v);
+ }
+
+ i2c_attach_client(client);
+
+ return 0;
+}
+
+static int cs53l32a_probe(struct i2c_adapter *adapter)
+{
+#ifdef I2C_CLASS_TV_ANALOG
+ if (adapter->class & I2C_CLASS_TV_ANALOG)
+#else
+ if (adapter->id == I2C_HW_B_BT848)
+#endif
+ return i2c_probe(adapter, &addr_data, cs53l32a_attach);
+ return 0;
+}
+
+static int cs53l32a_detach(struct i2c_client *client)
+{
+ int err;
+
+ err = i2c_detach_client(client);
+ if (err) {
+ return err;
+ }
+ kfree(client);
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+static struct i2c_driver i2c_driver = {
+ .name = "cs53l32a",
+ .id = I2C_DRIVERID_CS53L32A,
+ .flags = I2C_DF_NOTIFY,
+ .attach_adapter = cs53l32a_probe,
+ .detach_client = cs53l32a_detach,
+ .command = cs53l32a_command,
+ .owner = THIS_MODULE,
+};
+
+
+static int __init cs53l32a_init_module(void)
+{
+ return i2c_add_driver(&i2c_driver);
+}
+
+static void __exit cs53l32a_cleanup_module(void)
+{
+ i2c_del_driver(&i2c_driver);
+}
+
+module_init(cs53l32a_init_module);
+module_exit(cs53l32a_cleanup_module);
diff --git a/drivers/media/video/cx25840/Makefile b/drivers/media/video/cx25840/Makefile
new file mode 100644
index 00000000000..543ebacdc9d
--- /dev/null
+++ b/drivers/media/video/cx25840/Makefile
@@ -0,0 +1,6 @@
+cx25840-objs := cx25840-core.o cx25840-audio.o cx25840-firmware.o \
+ cx25840-vbi.o
+
+obj-$(CONFIG_VIDEO_DECODER) += cx25840.o
+
+EXTRA_CFLAGS += -I$(src)/..
diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c
new file mode 100644
index 00000000000..740908f8027
--- /dev/null
+++ b/drivers/media/video/cx25840/cx25840-audio.c
@@ -0,0 +1,368 @@
+/* cx25840 audio functions
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+#include <media/audiochip.h>
+#include <media/v4l2-common.h>
+
+#include "cx25840.h"
+
+inline static int set_audclk_freq(struct i2c_client *client,
+ enum v4l2_audio_clock_freq freq)
+{
+ struct cx25840_state *state = i2c_get_clientdata(client);
+
+ /* assert soft reset */
+ cx25840_and_or(client, 0x810, ~0x1, 0x01);
+
+ /* common for all inputs and rates */
+ /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
+ cx25840_write(client, 0x127, 0x50);
+
+ switch (state->audio_input) {
+ case AUDIO_TUNER:
+ switch (freq) {
+ case V4L2_AUDCLK_32_KHZ:
+ /* VID_PLL and AUX_PLL */
+ cx25840_write4(client, 0x108, 0x0f040610);
+
+ /* AUX_PLL_FRAC */
+ cx25840_write4(client, 0x110, 0xee39bb01);
+
+ /* src3/4/6_ctl = 0x0801f77f */
+ cx25840_write4(client, 0x900, 0x7ff70108);
+ cx25840_write4(client, 0x904, 0x7ff70108);
+ cx25840_write4(client, 0x90c, 0x7ff70108);
+ break;
+
+ case V4L2_AUDCLK_441_KHZ:
+ /* VID_PLL and AUX_PLL */
+ cx25840_write4(client, 0x108, 0x0f040910);
+
+ /* AUX_PLL_FRAC */
+ cx25840_write4(client, 0x110, 0xd66bec00);
+
+ /* src3/4/6_ctl = 0x08016d59 */
+ cx25840_write4(client, 0x900, 0x596d0108);
+ cx25840_write4(client, 0x904, 0x596d0108);
+ cx25840_write4(client, 0x90c, 0x596d0108);
+ break;
+
+ case V4L2_AUDCLK_48_KHZ:
+ /* VID_PLL and AUX_PLL */
+ cx25840_write4(client, 0x108, 0x0f040a10);
+
+ /* AUX_PLL_FRAC */
+ cx25840_write4(client, 0x110, 0xe5d69800);
+
+ /* src3/4/6_ctl = 0x08014faa */
+ cx25840_write4(client, 0x900, 0xaa4f0108);
+ cx25840_write4(client, 0x904, 0xaa4f0108);
+ cx25840_write4(client, 0x90c, 0xaa4f0108);
+ break;
+ }
+ break;
+
+ case AUDIO_EXTERN_1:
+ case AUDIO_EXTERN_2:
+ case AUDIO_INTERN:
+ case AUDIO_RADIO:
+ switch (freq) {
+ case V4L2_AUDCLK_32_KHZ:
+ /* VID_PLL and AUX_PLL */
+ cx25840_write4(client, 0x108, 0x0f04081e);
+
+ /* AUX_PLL_FRAC */
+ cx25840_write4(client, 0x110, 0x69082a01);
+
+ /* src1_ctl = 0x08010000 */
+ cx25840_write4(client, 0x8f8, 0x00000108);
+
+ /* src3/4/6_ctl = 0x08020000 */
+ cx25840_write4(client, 0x900, 0x00000208);
+ cx25840_write4(client, 0x904, 0x00000208);
+ cx25840_write4(client, 0x90c, 0x00000208);
+
+ /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */
+ cx25840_write(client, 0x127, 0x54);
+ break;
+
+ case V4L2_AUDCLK_441_KHZ:
+ /* VID_PLL and AUX_PLL */
+ cx25840_write4(client, 0x108, 0x0f040918);
+
+ /* AUX_PLL_FRAC */
+ cx25840_write4(client, 0x110, 0xd66bec00);
+
+ /* src1_ctl = 0x08010000 */
+ cx25840_write4(client, 0x8f8, 0xcd600108);
+
+ /* src3/4/6_ctl = 0x08020000 */
+ cx25840_write4(client, 0x900, 0x85730108);
+ cx25840_write4(client, 0x904, 0x85730108);
+ cx25840_write4(client, 0x90c, 0x85730108);
+ break;
+
+ case V4L2_AUDCLK_48_KHZ:
+ /* VID_PLL and AUX_PLL */
+ cx25840_write4(client, 0x108, 0x0f040a18);
+
+ /* AUX_PLL_FRAC */
+ cx25840_write4(client, 0x110, 0xe5d69800);
+
+ /* src1_ctl = 0x08010000 */
+ cx25840_write4(client, 0x8f8, 0x00800108);
+
+ /* src3/4/6_ctl = 0x08020000 */
+ cx25840_write4(client, 0x900, 0x55550108);
+ cx25840_write4(client, 0x904, 0x55550108);
+ cx25840_write4(client, 0x90c, 0x55550108);
+ break;
+ }
+ break;
+ }
+
+ /* deassert soft reset */
+ cx25840_and_or(client, 0x810, ~0x1, 0x00);
+
+ state->audclk_freq = freq;
+
+ return 0;
+}
+
+static int set_input(struct i2c_client *client, int audio_input)
+{
+ struct cx25840_state *state = i2c_get_clientdata(client);
+
+ cx25840_dbg("set audio input (%d)\n", audio_input);
+
+ /* stop microcontroller */
+ cx25840_and_or(client, 0x803, ~0x10, 0);
+
+ /* Mute everything to prevent the PFFT! */
+ cx25840_write(client, 0x8d3, 0x1f);
+
+ switch (audio_input) {
+ case AUDIO_TUNER:
+ /* Set Path1 to Analog Demod Main Channel */
+ cx25840_write4(client, 0x8d0, 0x7038061f);
+
+ /* When the microcontroller detects the
+ * audio format, it will unmute the lines */
+ cx25840_and_or(client, 0x803, ~0x10, 0x10);
+ break;
+
+ case AUDIO_EXTERN_1:
+ case AUDIO_EXTERN_2:
+ case AUDIO_INTERN:
+ case AUDIO_RADIO:
+ /* Set Path1 to Serial Audio Input */
+ cx25840_write4(client, 0x8d0, 0x12100101);
+
+ /* The microcontroller should not be started for the
+ * non-tuner inputs: autodetection is specific for
+ * TV audio. */
+ break;
+
+ default:
+ cx25840_dbg("Invalid audio input selection %d\n", audio_input);
+ return -EINVAL;
+ }
+
+ state->audio_input = audio_input;
+
+ return set_audclk_freq(client, state->audclk_freq);
+}
+
+inline static int get_volume(struct i2c_client *client)
+{
+ /* Volume runs +18dB to -96dB in 1/2dB steps
+ * change to fit the msp3400 -114dB to +12dB range */
+
+ /* check PATH1_VOLUME */
+ int vol = 228 - cx25840_read(client, 0x8d4);
+ vol = (vol / 2) + 23;
+ return vol << 9;
+}
+
+inline static void set_volume(struct i2c_client *client, int volume)
+{
+ /* First convert the volume to msp3400 values (0-127) */
+ int vol = volume >> 9;
+ /* now scale it up to cx25840 values
+ * -114dB to -96dB maps to 0
+ * this should be 19, but in my testing that was 4dB too loud */
+ if (vol <= 23) {
+ vol = 0;
+ } else {
+ vol -= 23;
+ }
+
+ /* PATH1_VOLUME */
+ cx25840_write(client, 0x8d4, 228 - (vol * 2));
+}
+
+inline static int get_bass(struct i2c_client *client)
+{
+ /* bass is 49 steps +12dB to -12dB */
+
+ /* check PATH1_EQ_BASS_VOL */
+ int bass = cx25840_read(client, 0x8d9) & 0x3f;
+ bass = (((48 - bass) * 0xffff) + 47) / 48;
+ return bass;
+}
+
+inline static void set_bass(struct i2c_client *client, int bass)
+{
+ /* PATH1_EQ_BASS_VOL */
+ cx25840_and_or(client, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff));
+}
+
+inline static int get_treble(struct i2c_client *client)
+{
+ /* treble is 49 steps +12dB to -12dB */
+
+ /* check PATH1_EQ_TREBLE_VOL */
+ int treble = cx25840_read(client, 0x8db) & 0x3f;
+ treble = (((48 - treble) * 0xffff) + 47) / 48;
+ return treble;
+}
+
+inline static void set_treble(struct i2c_client *client, int treble)
+{
+ /* PATH1_EQ_TREBLE_VOL */
+ cx25840_and_or(client, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff));
+}
+
+inline static int get_balance(struct i2c_client *client)
+{
+ /* balance is 7 bit, 0 to -96dB */
+
+ /* check PATH1_BAL_LEVEL */
+ int balance = cx25840_read(client, 0x8d5) & 0x7f;
+ /* check PATH1_BAL_LEFT */
+ if ((cx25840_read(client, 0x8d5) & 0x80) == 0)
+ balance = 0x80 - balance;
+ else
+ balance = 0x80 + balance;
+ return balance << 8;
+}
+
+inline static void set_balance(struct i2c_client *client, int balance)
+{
+ int bal = balance >> 8;
+ if (bal > 0x80) {
+ /* PATH1_BAL_LEFT */
+ cx25840_and_or(client, 0x8d5, 0x7f, 0x80);
+ /* PATH1_BAL_LEVEL */
+ cx25840_and_or(client, 0x8d5, ~0x7f, bal & 0x7f);
+ } else {
+ /* PATH1_BAL_LEFT */
+ cx25840_and_or(client, 0x8d5, 0x7f, 0x00);
+ /* PATH1_BAL_LEVEL */
+ cx25840_and_or(client, 0x8d5, ~0x7f, 0x80 - bal);
+ }
+}
+
+inline static int get_mute(struct i2c_client *client)
+{
+ /* check SRC1_MUTE_EN */
+ return cx25840_read(client, 0x8d3) & 0x2 ? 1 : 0;
+}
+
+inline static void set_mute(struct i2c_client *client, int mute)
+{
+ struct cx25840_state *state = i2c_get_clientdata(client);
+
+ if (state->audio_input == AUDIO_TUNER) {
+ /* Must turn off microcontroller in order to mute sound.
+ * Not sure if this is the best method, but it does work.
+ * If the microcontroller is running, then it will undo any
+ * changes to the mute register. */
+ if (mute) {
+ /* disable microcontroller */
+ cx25840_and_or(client, 0x803, ~0x10, 0x00);
+ cx25840_write(client, 0x8d3, 0x1f);
+ } else {
+ /* enable microcontroller */
+ cx25840_and_or(client, 0x803, ~0x10, 0x10);
+ }
+ } else {
+ /* SRC1_MUTE_EN */
+ cx25840_and_or(client, 0x8d3, ~0x2, mute ? 0x02 : 0x00);
+ }
+}
+
+int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+ struct v4l2_control *ctrl = arg;
+
+ switch (cmd) {
+ case AUDC_SET_INPUT:
+ return set_input(client, *(int *)arg);
+ case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+ return set_audclk_freq(client, *(enum v4l2_audio_clock_freq *)arg);
+ case VIDIOC_G_CTRL:
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_VOLUME:
+ ctrl->value = get_volume(client);
+ break;
+ case V4L2_CID_AUDIO_BASS:
+ ctrl->value = get_bass(client);
+ break;
+ case V4L2_CID_AUDIO_TREBLE:
+ ctrl->value = get_treble(client);
+ break;
+ case V4L2_CID_AUDIO_BALANCE:
+ ctrl->value = get_balance(client);
+ break;
+ case V4L2_CID_AUDIO_MUTE:
+ ctrl->value = get_mute(client);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case VIDIOC_S_CTRL:
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_VOLUME:
+ set_volume(client, ctrl->value);
+ break;
+ case V4L2_CID_AUDIO_BASS:
+ set_bass(client, ctrl->value);
+ break;
+ case V4L2_CID_AUDIO_TREBLE:
+ set_treble(client, ctrl->value);
+ break;
+ case V4L2_CID_AUDIO_BALANCE:
+ set_balance(client, ctrl->value);
+ break;
+ case V4L2_CID_AUDIO_MUTE:
+ set_mute(client, ctrl->value);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
new file mode 100644
index 00000000000..f6afeec499c
--- /dev/null
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -0,0 +1,1020 @@
+/* cx25840 - Conexant CX25840 audio/video decoder driver
+ *
+ * Copyright (C) 2004 Ulf Eklund
+ *
+ * Based on the saa7115 driver and on the first verison of Chris Kennedy's
+ * cx25840 driver.
+ *
+ * Changes by Tyler Trafford <tatrafford@comcast.net>
+ * - cleanup/rewrite for V4L2 API (2005)
+ *
+ * VBI support by Hans Verkuil <hverkuil@xs4all.nl>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+#include <media/audiochip.h>
+#include <media/v4l2-common.h>
+
+#include "cx25840.h"
+
+MODULE_DESCRIPTION("Conexant CX25840 audio/video decoder driver");
+MODULE_AUTHOR("Ulf Eklund, Chris Kennedy, Hans Verkuil, Tyler Trafford");
+MODULE_LICENSE("GPL");
+
+static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
+
+
+int cx25840_debug = 0;
+
+module_param(cx25840_debug, bool, 0644);
+
+MODULE_PARM_DESC(cx25840_debug, "Debugging messages [0=Off (default) 1=On]");
+
+I2C_CLIENT_INSMOD;
+
+/* ----------------------------------------------------------------------- */
+
+int cx25840_write(struct i2c_client *client, u16 addr, u8 value)
+{
+ u8 buffer[3];
+ buffer[0] = addr >> 8;
+ buffer[1] = addr & 0xff;
+ buffer[2] = value;
+ return i2c_master_send(client, buffer, 3);
+}
+
+int cx25840_write4(struct i2c_client *client, u16 addr, u32 value)
+{
+ u8 buffer[6];
+ buffer[0] = addr >> 8;
+ buffer[1] = addr & 0xff;
+ buffer[2] = value >> 24;
+ buffer[3] = (value >> 16) & 0xff;
+ buffer[4] = (value >> 8) & 0xff;
+ buffer[5] = value & 0xff;
+ return i2c_master_send(client, buffer, 6);
+}
+
+u8 cx25840_read(struct i2c_client * client, u16 addr)
+{
+ u8 buffer[2];
+ buffer[0] = addr >> 8;
+ buffer[1] = addr & 0xff;
+
+ if (i2c_master_send(client, buffer, 2) < 2)
+ return 0;
+
+ if (i2c_master_recv(client, buffer, 1) < 1)
+ return 0;
+
+ return buffer[0];
+}
+
+u32 cx25840_read4(struct i2c_client * client, u16 addr)
+{
+ u8 buffer[4];
+ buffer[0] = addr >> 8;
+ buffer[1] = addr & 0xff;
+
+ if (i2c_master_send(client, buffer, 2) < 2)
+ return 0;
+
+ if (i2c_master_recv(client, buffer, 4) < 4)
+ return 0;
+
+ return (buffer[0] << 24) | (buffer[1] << 16) |
+ (buffer[2] << 8) | buffer[3];
+}
+
+int cx25840_and_or(struct i2c_client *client, u16 addr, u8 and_mask,
+ u8 or_value)
+{
+ return cx25840_write(client, addr,
+ (cx25840_read(client, addr) & and_mask) |
+ or_value);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int set_input(struct i2c_client *, enum cx25840_input);
+static void input_change(struct i2c_client *);
+static void log_status(struct i2c_client *client);
+
+/* ----------------------------------------------------------------------- */
+
+static inline void init_dll1(struct i2c_client *client)
+{
+ /* This is the Hauppauge sequence used to
+ * initialize the Delay Lock Loop 1 (ADC DLL). */
+ cx25840_write(client, 0x159, 0x23);
+ cx25840_write(client, 0x15a, 0x87);
+ cx25840_write(client, 0x15b, 0x06);
+ cx25840_write(client, 0x159, 0xe1);
+ cx25840_write(client, 0x15a, 0x86);
+ cx25840_write(client, 0x159, 0xe0);
+ cx25840_write(client, 0x159, 0xe1);
+ cx25840_write(client, 0x15b, 0x10);
+}
+
+static inline void init_dll2(struct i2c_client *client)
+{
+ /* This is the Hauppauge sequence used to
+ * initialize the Delay Lock Loop 2 (ADC DLL). */
+ cx25840_write(client, 0x15d, 0xe3);
+ cx25840_write(client, 0x15e, 0x86);
+ cx25840_write(client, 0x15f, 0x06);
+ cx25840_write(client, 0x15d, 0xe1);
+ cx25840_write(client, 0x15d, 0xe0);
+ cx25840_write(client, 0x15d, 0xe1);
+}
+
+static void cx25840_initialize(struct i2c_client *client, int loadfw)
+{
+ struct cx25840_state *state = i2c_get_clientdata(client);
+
+ /* datasheet startup in numbered steps, refer to page 3-77 */
+ /* 2. */
+ cx25840_and_or(client, 0x803, ~0x10, 0x00);
+ /* The default of this register should be 4, but I get 0 instead.
+ * Set this register to 4 manually. */
+ cx25840_write(client, 0x000, 0x04);
+ /* 3. */
+ init_dll1(client);
+ init_dll2(client);
+ cx25840_write(client, 0x136, 0x0a);
+ /* 4. */
+ cx25840_write(client, 0x13c, 0x01);
+ cx25840_write(client, 0x13c, 0x00);
+ /* 5. */
+ if (loadfw)
+ cx25840_loadfw(client);
+ /* 6. */
+ cx25840_write(client, 0x115, 0x8c);
+ cx25840_write(client, 0x116, 0x07);
+ cx25840_write(client, 0x118, 0x02);
+ /* 7. */
+ cx25840_write(client, 0x4a5, 0x80);
+ cx25840_write(client, 0x4a5, 0x00);
+ cx25840_write(client, 0x402, 0x00);
+ /* 8. */
+ cx25840_write(client, 0x401, 0x18);
+ cx25840_write(client, 0x4a2, 0x10);
+ cx25840_write(client, 0x402, 0x04);
+ /* 10. */
+ cx25840_write(client, 0x8d3, 0x1f);
+ cx25840_write(client, 0x8e3, 0x03);
+
+ cx25840_vbi_setup(client);
+
+ /* trial and error says these are needed to get audio */
+ cx25840_write(client, 0x914, 0xa0);
+ cx25840_write(client, 0x918, 0xa0);
+ cx25840_write(client, 0x919, 0x01);
+
+ /* stereo prefered */
+ cx25840_write(client, 0x809, 0x04);
+ /* AC97 shift */
+ cx25840_write(client, 0x8cf, 0x0f);
+
+ /* (re)set video input */
+ set_input(client, state->input);
+ /* (re)set audio input */
+ cx25840_audio(client, AUDC_SET_INPUT, &state->audio_input);
+
+ /* start microcontroller */
+ cx25840_and_or(client, 0x803, ~0x10, 0x10);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void input_change(struct i2c_client *client)
+{
+ v4l2_std_id std = cx25840_get_v4lstd(client);
+
+ if (std & V4L2_STD_PAL) {
+ /* Follow tuner change procedure for PAL */
+ cx25840_write(client, 0x808, 0xff);
+ cx25840_write(client, 0x80b, 0x10);
+ } else if (std & V4L2_STD_SECAM) {
+ /* Select autodetect for SECAM */
+ cx25840_write(client, 0x808, 0xff);
+ cx25840_write(client, 0x80b, 0x10);
+ } else if (std & V4L2_STD_NTSC) {
+ /* NTSC */
+ cx25840_write(client, 0x808, 0xf6);
+ cx25840_write(client, 0x80b, 0x00);
+ }
+
+ if (cx25840_read(client, 0x803) & 0x10) {
+ /* restart audio decoder microcontroller */
+ cx25840_and_or(client, 0x803, ~0x10, 0x00);
+ cx25840_and_or(client, 0x803, ~0x10, 0x10);
+ }
+}
+
+static int set_input(struct i2c_client *client, enum cx25840_input input)
+{
+ struct cx25840_state *state = i2c_get_clientdata(client);
+
+ cx25840_dbg("decoder set input (%d)\n", input);
+
+ switch (input) {
+ case CX25840_TUNER:
+ cx25840_dbg("now setting Tuner input\n");
+
+ if (state->cardtype == CARDTYPE_PVR150) {
+ /* CH_SEL_ADC2=1 */
+ cx25840_and_or(client, 0x102, ~0x2, 0x02);
+ }
+
+ /* Video Input Control */
+ if (state->cardtype == CARDTYPE_PG600) {
+ cx25840_write(client, 0x103, 0x11);
+ } else {
+ cx25840_write(client, 0x103, 0x46);
+ }
+
+ /* INPUT_MODE=0 */
+ cx25840_and_or(client, 0x401, ~0x6, 0x00);
+ break;
+
+ case CX25840_COMPOSITE0:
+ case CX25840_COMPOSITE1:
+ cx25840_dbg("now setting Composite input\n");
+
+ /* Video Input Control */
+ if (state->cardtype == CARDTYPE_PG600) {
+ cx25840_write(client, 0x103, 0x00);
+ } else {
+ cx25840_write(client, 0x103, 0x02);
+ }
+
+ /* INPUT_MODE=0 */
+ cx25840_and_or(client, 0x401, ~0x6, 0x00);
+ break;
+
+ case CX25840_SVIDEO0:
+ case CX25840_SVIDEO1:
+ cx25840_dbg("now setting S-Video input\n");
+
+ /* CH_SEL_ADC2=0 */
+ cx25840_and_or(client, 0x102, ~0x2, 0x00);
+
+ /* Video Input Control */
+ if (state->cardtype == CARDTYPE_PG600) {
+ cx25840_write(client, 0x103, 0x02);
+ } else {
+ cx25840_write(client, 0x103, 0x10);
+ }
+
+ /* INPUT_MODE=1 */
+ cx25840_and_or(client, 0x401, ~0x6, 0x02);
+ break;
+
+ default:
+ cx25840_err("%d is not a valid input!\n", input);
+ return -EINVAL;
+ }
+
+ state->input = input;
+ input_change(client);
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int set_v4lstd(struct i2c_client *client, v4l2_std_id std)
+{
+ u8 fmt;
+
+ switch (std) {
+ /* zero is autodetect */
+ case 0: fmt = 0x0; break;
+ /* default ntsc to ntsc-m */
+ case V4L2_STD_NTSC:
+ case V4L2_STD_NTSC_M: fmt = 0x1; break;
+ case V4L2_STD_NTSC_M_JP: fmt = 0x2; break;
+ case V4L2_STD_NTSC_443: fmt = 0x3; break;
+ case V4L2_STD_PAL: fmt = 0x4; break;
+ case V4L2_STD_PAL_M: fmt = 0x5; break;
+ case V4L2_STD_PAL_N: fmt = 0x6; break;
+ case V4L2_STD_PAL_Nc: fmt = 0x7; break;
+ case V4L2_STD_PAL_60: fmt = 0x8; break;
+ case V4L2_STD_SECAM: fmt = 0xc; break;
+ default:
+ return -ERANGE;
+ }
+
+ cx25840_and_or(client, 0x400, ~0xf, fmt);
+ cx25840_vbi_setup(client);
+ return 0;
+}
+
+v4l2_std_id cx25840_get_v4lstd(struct i2c_client * client)
+{
+ /* check VID_FMT_SEL first */
+ u8 fmt = cx25840_read(client, 0x400) & 0xf;
+
+ if (!fmt) {
+ /* check AFD_FMT_STAT if set to autodetect */
+ fmt = cx25840_read(client, 0x40d) & 0xf;
+ }
+
+ switch (fmt) {
+ case 0x1: return V4L2_STD_NTSC_M;
+ case 0x2: return V4L2_STD_NTSC_M_JP;
+ case 0x3: return V4L2_STD_NTSC_443;
+ case 0x4: return V4L2_STD_PAL;
+ case 0x5: return V4L2_STD_PAL_M;
+ case 0x6: return V4L2_STD_PAL_N;
+ case 0x7: return V4L2_STD_PAL_Nc;
+ case 0x8: return V4L2_STD_PAL_60;
+ case 0xc: return V4L2_STD_SECAM;
+ default: return V4L2_STD_UNKNOWN;
+ }
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+{
+ struct cx25840_state *state = i2c_get_clientdata(client);
+
+ switch (ctrl->id) {
+ case CX25840_CID_CARDTYPE:
+ switch (ctrl->value) {
+ case CARDTYPE_PVR150:
+ case CARDTYPE_PG600:
+ state->cardtype = ctrl->value;
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ set_input(client, state->input);
+ break;
+
+ case V4L2_CID_BRIGHTNESS:
+ if (ctrl->value < 0 || ctrl->value > 255) {
+ cx25840_err("invalid brightness setting %d\n",
+ ctrl->value);
+ return -ERANGE;
+ }
+
+ cx25840_write(client, 0x414, ctrl->value - 128);
+ break;
+
+ case V4L2_CID_CONTRAST:
+ if (ctrl->value < 0 || ctrl->value > 127) {
+ cx25840_err("invalid contrast setting %d\n",
+ ctrl->value);
+ return -ERANGE;
+ }
+
+ cx25840_write(client, 0x415, ctrl->value << 1);
+ break;
+
+ case V4L2_CID_SATURATION:
+ if (ctrl->value < 0 || ctrl->value > 127) {
+ cx25840_err("invalid saturation setting %d\n",
+ ctrl->value);
+ return -ERANGE;
+ }
+
+ cx25840_write(client, 0x420, ctrl->value << 1);
+ cx25840_write(client, 0x421, ctrl->value << 1);
+ break;
+
+ case V4L2_CID_HUE:
+ if (ctrl->value < -127 || ctrl->value > 127) {
+ cx25840_err("invalid hue setting %d\n", ctrl->value);
+ return -ERANGE;
+ }
+
+ cx25840_write(client, 0x422, ctrl->value);
+ break;
+
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_MUTE:
+ return cx25840_audio(client, VIDIOC_S_CTRL, ctrl);
+ }
+
+ return 0;
+}
+
+static int get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+{
+ struct cx25840_state *state = i2c_get_clientdata(client);
+
+ switch (ctrl->id) {
+ case CX25840_CID_CARDTYPE:
+ ctrl->value = state->cardtype;
+ break;
+ case V4L2_CID_BRIGHTNESS:
+ ctrl->value = cx25840_read(client, 0x414) + 128;
+ break;
+ case V4L2_CID_CONTRAST:
+ ctrl->value = cx25840_read(client, 0x415) >> 1;
+ break;
+ case V4L2_CID_SATURATION:
+ ctrl->value = cx25840_read(client, 0x420) >> 1;
+ break;
+ case V4L2_CID_HUE:
+ ctrl->value = cx25840_read(client, 0x422);
+ break;
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_MUTE:
+ return cx25840_audio(client, VIDIOC_G_CTRL, ctrl);
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
+{
+ switch (fmt->type) {
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ return cx25840_vbi(client, VIDIOC_G_FMT, fmt);
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
+{
+ struct v4l2_pix_format *pix;
+ int HSC, VSC, Vsrc, Hsrc, filter, Vlines;
+ int is_pal = !(cx25840_get_v4lstd(client) & V4L2_STD_NTSC);
+
+ switch (fmt->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ pix = &(fmt->fmt.pix);
+
+ Vsrc = (cx25840_read(client, 0x476) & 0x3f) << 4;
+ Vsrc |= (cx25840_read(client, 0x475) & 0xf0) >> 4;
+
+ Hsrc = (cx25840_read(client, 0x472) & 0x3f) << 4;
+ Hsrc |= (cx25840_read(client, 0x471) & 0xf0) >> 4;
+
+ Vlines = pix->height + (is_pal ? 4 : 7);
+
+ if ((pix->width * 16 < Hsrc) || (Hsrc < pix->width) ||
+ (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) {
+ cx25840_err("%dx%d is not a valid size!\n",
+ pix->width, pix->height);
+ return -ERANGE;
+ }
+
+ HSC = (Hsrc * (1 << 20)) / pix->width - (1 << 20);
+ VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9));
+ VSC &= 0x1fff;
+
+ if (pix->width >= 385)
+ filter = 0;
+ else if (pix->width > 192)
+ filter = 1;
+ else if (pix->width > 96)
+ filter = 2;
+ else
+ filter = 3;
+
+ cx25840_dbg("decoder set size %dx%d -> scale %ux%u\n",
+ pix->width, pix->height, HSC, VSC);
+
+ /* HSCALE=HSC */
+ cx25840_write(client, 0x418, HSC & 0xff);
+ cx25840_write(client, 0x419, (HSC >> 8) & 0xff);
+ cx25840_write(client, 0x41a, HSC >> 16);
+ /* VSCALE=VSC */
+ cx25840_write(client, 0x41c, VSC & 0xff);
+ cx25840_write(client, 0x41d, VSC >> 8);
+ /* VS_INTRLACE=1 VFILT=filter */
+ cx25840_write(client, 0x41e, 0x8 | filter);
+ break;
+
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ return cx25840_vbi(client, VIDIOC_S_FMT, fmt);
+
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ return cx25840_vbi(client, VIDIOC_S_FMT, fmt);
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int cx25840_command(struct i2c_client *client, unsigned int cmd,
+ void *arg)
+{
+ struct cx25840_state *state = i2c_get_clientdata(client);
+ struct v4l2_tuner *vt = arg;
+ int result = 0;
+
+ switch (cmd) {
+ case 0:
+ break;
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ /* ioctls to allow direct access to the
+ * cx25840 registers for testing */
+ case VIDIOC_INT_G_REGISTER:
+ {
+ struct v4l2_register *reg = arg;
+
+ if (reg->i2c_id != I2C_DRIVERID_CX25840)
+ return -EINVAL;
+ reg->val = cx25840_read(client, reg->reg & 0x0fff);
+ break;
+ }
+
+ case VIDIOC_INT_S_REGISTER:
+ {
+ struct v4l2_register *reg = arg;
+
+ if (reg->i2c_id != I2C_DRIVERID_CX25840)
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ cx25840_write(client, reg->reg & 0x0fff, reg->val & 0xff);
+ break;
+ }
+#endif
+
+ case VIDIOC_INT_DECODE_VBI_LINE:
+ return cx25840_vbi(client, cmd, arg);
+
+ case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+ case AUDC_SET_INPUT:
+ result = cx25840_audio(client, cmd, arg);
+ break;
+
+ case VIDIOC_STREAMON:
+ cx25840_dbg("enable output\n");
+ cx25840_write(client, 0x115, 0x8c);
+ cx25840_write(client, 0x116, 0x07);
+ break;
+
+ case VIDIOC_STREAMOFF:
+ cx25840_dbg("disable output\n");
+ cx25840_write(client, 0x115, 0x00);
+ cx25840_write(client, 0x116, 0x00);
+ break;
+
+ case VIDIOC_LOG_STATUS:
+ log_status(client);
+ break;
+
+ case VIDIOC_G_CTRL:
+ result = get_v4lctrl(client, (struct v4l2_control *)arg);
+ break;
+
+ case VIDIOC_S_CTRL:
+ result = set_v4lctrl(client, (struct v4l2_control *)arg);
+ break;
+
+ case VIDIOC_G_STD:
+ *(v4l2_std_id *)arg = cx25840_get_v4lstd(client);
+ break;
+
+ case VIDIOC_S_STD:
+ result = set_v4lstd(client, *(v4l2_std_id *)arg);
+ break;
+
+ case VIDIOC_G_INPUT:
+ *(int *)arg = state->input;
+ break;
+
+ case VIDIOC_S_INPUT:
+ result = set_input(client, *(int *)arg);
+ break;
+
+ case VIDIOC_S_FREQUENCY:
+ input_change(client);
+ break;
+
+ case VIDIOC_G_TUNER:
+ {
+ u8 mode = cx25840_read(client, 0x804);
+ u8 pref = cx25840_read(client, 0x809) & 0xf;
+ u8 vpres = cx25840_read(client, 0x80a) & 0x10;
+ int val = 0;
+
+ vt->capability |=
+ V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
+ V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
+
+ vt->signal = vpres ? 0xffff : 0x0;
+
+ /* get rxsubchans and audmode */
+ if ((mode & 0xf) == 1)
+ val |= V4L2_TUNER_SUB_STEREO;
+ else
+ val |= V4L2_TUNER_SUB_MONO;
+
+ if (mode == 2 || mode == 4)
+ val |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+
+ if (mode & 0x10)
+ val |= V4L2_TUNER_SUB_SAP;
+
+ vt->rxsubchans = val;
+
+ switch (pref) {
+ case 0:
+ vt->audmode = V4L2_TUNER_MODE_MONO;
+ break;
+ case 1:
+ case 2:
+ vt->audmode = V4L2_TUNER_MODE_LANG2;
+ break;
+ case 4:
+ default:
+ vt->audmode = V4L2_TUNER_MODE_STEREO;
+ }
+ break;
+ }
+
+ case VIDIOC_S_TUNER:
+ switch (vt->audmode) {
+ case V4L2_TUNER_MODE_MONO:
+ case V4L2_TUNER_MODE_LANG1:
+ /* Force PREF_MODE to MONO */
+ cx25840_and_or(client, 0x809, ~0xf, 0x00);
+ break;
+ case V4L2_TUNER_MODE_STEREO:
+ /* Force PREF_MODE to STEREO */
+ cx25840_and_or(client, 0x809, ~0xf, 0x04);
+ break;
+ case V4L2_TUNER_MODE_LANG2:
+ /* Force PREF_MODE to LANG2 */
+ cx25840_and_or(client, 0x809, ~0xf, 0x01);
+ break;
+ }
+ break;
+
+ case VIDIOC_G_FMT:
+ result = get_v4lfmt(client, (struct v4l2_format *)arg);
+ break;
+
+ case VIDIOC_S_FMT:
+ result = set_v4lfmt(client, (struct v4l2_format *)arg);
+ break;
+
+ case VIDIOC_INT_RESET:
+ cx25840_initialize(client, 0);
+ break;
+
+ case VIDIOC_INT_G_CHIP_IDENT:
+ *(enum v4l2_chip_ident *)arg =
+ V4L2_IDENT_CX25840 + ((cx25840_read(client, 0x100) >> 4) & 0xf);
+ break;
+
+ default:
+ cx25840_err("invalid ioctl %x\n", cmd);
+ return -EINVAL;
+ }
+
+ return result;
+}
+
+/* ----------------------------------------------------------------------- */
+
+struct i2c_driver i2c_driver_cx25840;
+
+static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
+ int kind)
+{
+ struct i2c_client *client;
+ struct cx25840_state *state;
+ u16 device_id;
+
+ /* Check if the adapter supports the needed features
+ * Not until kernel version 2.6.11 did the bit-algo
+ * correctly report that it would do an I2C-level xfer */
+ if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
+ return 0;
+
+ client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (client == 0)
+ return -ENOMEM;
+
+ memset(client, 0, sizeof(struct i2c_client));
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &i2c_driver_cx25840;
+ client->flags = I2C_CLIENT_ALLOW_USE;
+ snprintf(client->name, sizeof(client->name) - 1, "cx25840");
+
+ cx25840_dbg("detecting cx25840 client on address 0x%x\n", address << 1);
+
+ device_id = cx25840_read(client, 0x101) << 8;
+ device_id |= cx25840_read(client, 0x100);
+
+ /* The high byte of the device ID should be
+ * 0x84 if chip is present */
+ if ((device_id & 0xff00) != 0x8400) {
+ cx25840_dbg("cx25840 not found\n");
+ kfree(client);
+ return 0;
+ }
+
+ cx25840_info("cx25%3x-2%x found @ 0x%x (%s)\n",
+ (device_id & 0xfff0) >> 4,
+ (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : 3,
+ address << 1, adapter->name);
+
+ state = kmalloc(sizeof(struct cx25840_state), GFP_KERNEL);
+ if (state == NULL) {
+ kfree(client);
+ return -ENOMEM;
+ }
+
+ i2c_set_clientdata(client, state);
+ memset(state, 0, sizeof(struct cx25840_state));
+ state->input = CX25840_TUNER;
+ state->audclk_freq = V4L2_AUDCLK_48_KHZ;
+ state->audio_input = AUDIO_TUNER;
+ state->cardtype = CARDTYPE_PVR150;
+
+ cx25840_initialize(client, 1);
+
+ i2c_attach_client(client);
+
+ return 0;
+}
+
+static int cx25840_attach_adapter(struct i2c_adapter *adapter)
+{
+#ifdef I2C_CLASS_TV_ANALOG
+ if (adapter->class & I2C_CLASS_TV_ANALOG)
+#else
+ if (adapter->id == I2C_HW_B_BT848)
+#endif
+ return i2c_probe(adapter, &addr_data, &cx25840_detect_client);
+ return 0;
+}
+
+static int cx25840_detach_client(struct i2c_client *client)
+{
+ struct cx25840_state *state = i2c_get_clientdata(client);
+ int err;
+
+ err = i2c_detach_client(client);
+ if (err) {
+ return err;
+ }
+
+ kfree(state);
+ kfree(client);
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+struct i2c_driver i2c_driver_cx25840 = {
+ .name = "cx25840",
+
+ .id = I2C_DRIVERID_CX25840,
+ .flags = I2C_DF_NOTIFY,
+
+ .attach_adapter = cx25840_attach_adapter,
+ .detach_client = cx25840_detach_client,
+ .command = cx25840_command,
+ .owner = THIS_MODULE,
+};
+
+
+static int __init m__init(void)
+{
+ return i2c_add_driver(&i2c_driver_cx25840);
+}
+
+static void __exit m__exit(void)
+{
+ i2c_del_driver(&i2c_driver_cx25840);
+}
+
+module_init(m__init);
+module_exit(m__exit);
+
+/* ----------------------------------------------------------------------- */
+
+static void log_status(struct i2c_client *client)
+{
+ static const char *const fmt_strs[] = {
+ "0x0",
+ "NTSC-M", "NTSC-J", "NTSC-4.43",
+ "PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60",
+ "0x9", "0xA", "0xB",
+ "SECAM",
+ "0xD", "0xE", "0xF"
+ };
+
+ struct cx25840_state *state = i2c_get_clientdata(client);
+ u8 microctrl_vidfmt = cx25840_read(client, 0x80a);
+ u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf;
+ u8 gen_stat1 = cx25840_read(client, 0x40d);
+ u8 download_ctl = cx25840_read(client, 0x803);
+ u8 mod_det_stat0 = cx25840_read(client, 0x804);
+ u8 mod_det_stat1 = cx25840_read(client, 0x805);
+ u8 audio_config = cx25840_read(client, 0x808);
+ u8 pref_mode = cx25840_read(client, 0x809);
+ u8 afc0 = cx25840_read(client, 0x80b);
+ u8 mute_ctl = cx25840_read(client, 0x8d3);
+ char *p;
+
+ cx25840_info("Video signal: %spresent\n",
+ (microctrl_vidfmt & 0x10) ? "" : "not ");
+ cx25840_info("Detected format: %s\n",
+ fmt_strs[gen_stat1 & 0xf]);
+
+ switch (mod_det_stat0) {
+ case 0x00: p = "mono"; break;
+ case 0x01: p = "stereo"; break;
+ case 0x02: p = "dual"; break;
+ case 0x04: p = "tri"; break;
+ case 0x10: p = "mono with SAP"; break;
+ case 0x11: p = "stereo with SAP"; break;
+ case 0x12: p = "dual with SAP"; break;
+ case 0x14: p = "tri with SAP"; break;
+ case 0xfe: p = "forced mode"; break;
+ default: p = "not defined";
+ }
+ cx25840_info("Detected audio mode: %s\n", p);
+
+ switch (mod_det_stat1) {
+ case 0x00: p = "not defined"; break;
+ case 0x01: p = "EIAJ"; break;
+ case 0x02: p = "A2-M"; break;
+ case 0x03: p = "A2-BG"; break;
+ case 0x04: p = "A2-DK1"; break;
+ case 0x05: p = "A2-DK2"; break;
+ case 0x06: p = "A2-DK3"; break;
+ case 0x07: p = "A1 (6.0 MHz FM Mono)"; break;
+ case 0x08: p = "AM-L"; break;
+ case 0x09: p = "NICAM-BG"; break;
+ case 0x0a: p = "NICAM-DK"; break;
+ case 0x0b: p = "NICAM-I"; break;
+ case 0x0c: p = "NICAM-L"; break;
+ case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break;
+ case 0x0e: p = "IF FM Radio"; break;
+ case 0x0f: p = "BTSC"; break;
+ case 0x10: p = "high-deviation FM"; break;
+ case 0x11: p = "very high-deviation FM"; break;
+ case 0xfd: p = "unknown audio standard"; break;
+ case 0xfe: p = "forced audio standard"; break;
+ case 0xff: p = "no detected audio standard"; break;
+ default: p = "not defined";
+ }
+ cx25840_info("Detected audio standard: %s\n", p);
+ cx25840_info("Audio muted: %s\n",
+ (mute_ctl & 0x2) ? "yes" : "no");
+ cx25840_info("Audio microcontroller: %s\n",
+ (download_ctl & 0x10) ? "running" : "stopped");
+
+ switch (audio_config >> 4) {
+ case 0x00: p = "undefined"; break;
+ case 0x01: p = "BTSC"; break;
+ case 0x02: p = "EIAJ"; break;
+ case 0x03: p = "A2-M"; break;
+ case 0x04: p = "A2-BG"; break;
+ case 0x05: p = "A2-DK1"; break;
+ case 0x06: p = "A2-DK2"; break;
+ case 0x07: p = "A2-DK3"; break;
+ case 0x08: p = "A1 (6.0 MHz FM Mono)"; break;
+ case 0x09: p = "AM-L"; break;
+ case 0x0a: p = "NICAM-BG"; break;
+ case 0x0b: p = "NICAM-DK"; break;
+ case 0x0c: p = "NICAM-I"; break;
+ case 0x0d: p = "NICAM-L"; break;
+ case 0x0e: p = "FM radio"; break;
+ case 0x0f: p = "automatic detection"; break;
+ default: p = "undefined";
+ }
+ cx25840_info("Configured audio standard: %s\n", p);
+
+ if ((audio_config >> 4) < 0xF) {
+ switch (audio_config & 0xF) {
+ case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break;
+ case 0x01: p = "MONO2 (LANGUAGE B)"; break;
+ case 0x02: p = "MONO3 (STEREO forced MONO)"; break;
+ case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break;
+ case 0x04: p = "STEREO"; break;
+ case 0x05: p = "DUAL1 (AB)"; break;
+ case 0x06: p = "DUAL2 (AC) (FM)"; break;
+ case 0x07: p = "DUAL3 (BC) (FM)"; break;
+ case 0x08: p = "DUAL4 (AC) (AM)"; break;
+ case 0x09: p = "DUAL5 (BC) (AM)"; break;
+ case 0x0a: p = "SAP"; break;
+ default: p = "undefined";
+ }
+ cx25840_info("Configured audio mode: %s\n", p);
+ } else {
+ switch (audio_config & 0xF) {
+ case 0x00: p = "BG"; break;
+ case 0x01: p = "DK1"; break;
+ case 0x02: p = "DK2"; break;
+ case 0x03: p = "DK3"; break;
+ case 0x04: p = "I"; break;
+ case 0x05: p = "L"; break;
+ case 0x06: p = "BTSC"; break;
+ case 0x07: p = "EIAJ"; break;
+ case 0x08: p = "A2-M"; break;
+ case 0x09: p = "FM Radio"; break;
+ case 0x0f: p = "automatic standard and mode detection"; break;
+ default: p = "undefined";
+ }
+ cx25840_info("Configured audio system: %s\n", p);
+ }
+
+ cx25840_info("Specified standard: %s\n",
+ vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");
+
+ switch (state->input) {
+ case CX25840_COMPOSITE0: p = "Composite 0"; break;
+ case CX25840_COMPOSITE1: p = "Composite 1"; break;
+ case CX25840_SVIDEO0: p = "S-Video 0"; break;
+ case CX25840_SVIDEO1: p = "S-Video 1"; break;
+ case CX25840_TUNER: p = "Tuner"; break;
+ }
+ cx25840_info("Specified input: %s\n", p);
+ cx25840_info("Specified audio input: %s\n",
+ state->audio_input == 0 ? "Tuner" : "External");
+
+ switch (state->audclk_freq) {
+ case V4L2_AUDCLK_441_KHZ: p = "44.1 kHz"; break;
+ case V4L2_AUDCLK_48_KHZ: p = "48 kHz"; break;
+ case V4L2_AUDCLK_32_KHZ: p = "32 kHz"; break;
+ default: p = "undefined";
+ }
+ cx25840_info("Specified audioclock freq: %s\n", p);
+
+ switch (pref_mode & 0xf) {
+ case 0: p = "mono/language A"; break;
+ case 1: p = "language B"; break;
+ case 2: p = "language C"; break;
+ case 3: p = "analog fallback"; break;
+ case 4: p = "stereo"; break;
+ case 5: p = "language AC"; break;
+ case 6: p = "language BC"; break;
+ case 7: p = "language AB"; break;
+ default: p = "undefined";
+ }
+ cx25840_info("Preferred audio mode: %s\n", p);
+
+ if ((audio_config & 0xf) == 0xf) {
+ switch ((afc0 >> 3) & 0x3) {
+ case 0: p = "system DK"; break;
+ case 1: p = "system L"; break;
+ case 2: p = "autodetect"; break;
+ default: p = "undefined";
+ }
+ cx25840_info("Selected 65 MHz format: %s\n", p);
+
+ switch (afc0 & 0x7) {
+ case 0: p = "chroma"; break;
+ case 1: p = "BTSC"; break;
+ case 2: p = "EIAJ"; break;
+ case 3: p = "A2-M"; break;
+ case 4: p = "autodetect"; break;
+ default: p = "undefined";
+ }
+ cx25840_info("Selected 45 MHz format: %s\n", p);
+ }
+}
diff --git a/drivers/media/video/cx25840/cx25840-firmware.c b/drivers/media/video/cx25840/cx25840-firmware.c
new file mode 100644
index 00000000000..df9d50a7554
--- /dev/null
+++ b/drivers/media/video/cx25840/cx25840-firmware.c
@@ -0,0 +1,167 @@
+/* cx25840 firmware functions
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/firmware.h>
+#include <media/v4l2-common.h>
+
+#include "cx25840.h"
+
+#define FWFILE "v4l-cx25840.fw"
+#define FWSEND 1024
+
+#define FWDEV(x) &((x)->adapter->dev)
+
+static int fastfw = 1;
+static char *firmware = FWFILE;
+
+module_param(fastfw, bool, 0444);
+module_param(firmware, charp, 0444);
+
+MODULE_PARM_DESC(fastfw, "Load firmware fast [0=100MHz 1=333MHz (default)]");
+MODULE_PARM_DESC(firmware, "Firmware image [default: " FWFILE "]");
+
+static inline void set_i2c_delay(struct i2c_client *client, int delay)
+{
+ struct i2c_algo_bit_data *algod = client->adapter->algo_data;
+
+ /* We aren't guaranteed to be using algo_bit,
+ * so avoid the null pointer dereference
+ * and disable the 'fast firmware load' */
+ if (algod) {
+ algod->udelay = delay;
+ } else {
+ fastfw = 0;
+ }
+}
+
+static inline void start_fw_load(struct i2c_client *client)
+{
+ /* DL_ADDR_LB=0 DL_ADDR_HB=0 */
+ cx25840_write(client, 0x800, 0x00);
+ cx25840_write(client, 0x801, 0x00);
+ // DL_MAP=3 DL_AUTO_INC=0 DL_ENABLE=1
+ cx25840_write(client, 0x803, 0x0b);
+ /* AUTO_INC_DIS=1 */
+ cx25840_write(client, 0x000, 0x20);
+
+ if (fastfw)
+ set_i2c_delay(client, 3);
+}
+
+static inline void end_fw_load(struct i2c_client *client)
+{
+ if (fastfw)
+ set_i2c_delay(client, 10);
+
+ /* AUTO_INC_DIS=0 */
+ cx25840_write(client, 0x000, 0x00);
+ /* DL_ENABLE=0 */
+ cx25840_write(client, 0x803, 0x03);
+}
+
+static inline int check_fw_load(struct i2c_client *client, int size)
+{
+ /* DL_ADDR_HB DL_ADDR_LB */
+ int s = cx25840_read(client, 0x801) << 8;
+ s |= cx25840_read(client, 0x800);
+
+ if (size != s) {
+ cx25840_err("firmware %s load failed\n", firmware);
+ return -EINVAL;
+ }
+
+ cx25840_info("loaded %s firmware (%d bytes)\n", firmware, size);
+ return 0;
+}
+
+static inline int fw_write(struct i2c_client *client, u8 * data, int size)
+{
+ if (i2c_master_send(client, data, size) < size) {
+
+ if (fastfw) {
+ cx25840_err("333MHz i2c firmware load failed\n");
+ fastfw = 0;
+ set_i2c_delay(client, 10);
+
+ if (i2c_master_send(client, data, size) < size) {
+ cx25840_err
+ ("100MHz i2c firmware load failed\n");
+ return -ENOSYS;
+ }
+
+ } else {
+ cx25840_err("firmware load i2c failure\n");
+ return -ENOSYS;
+ }
+
+ }
+
+ return 0;
+}
+
+int cx25840_loadfw(struct i2c_client *client)
+{
+ const struct firmware *fw = NULL;
+ u8 buffer[4], *ptr;
+ int size, send, retval;
+
+ if (request_firmware(&fw, firmware, FWDEV(client)) != 0) {
+ cx25840_err("unable to open firmware %s\n", firmware);
+ return -EINVAL;
+ }
+
+ start_fw_load(client);
+
+ buffer[0] = 0x08;
+ buffer[1] = 0x02;
+ buffer[2] = fw->data[0];
+ buffer[3] = fw->data[1];
+ retval = fw_write(client, buffer, 4);
+
+ if (retval < 0) {
+ release_firmware(fw);
+ return retval;
+ }
+
+ size = fw->size - 2;
+ ptr = fw->data;
+ while (size > 0) {
+ ptr[0] = 0x08;
+ ptr[1] = 0x02;
+ send = size > (FWSEND - 2) ? FWSEND : size + 2;
+ retval = fw_write(client, ptr, send);
+
+ if (retval < 0) {
+ release_firmware(fw);
+ return retval;
+ }
+
+ size -= FWSEND - 2;
+ ptr += FWSEND - 2;
+ }
+
+ end_fw_load(client);
+
+ size = fw->size;
+ release_firmware(fw);
+
+ return check_fw_load(client, size);
+}
diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c
new file mode 100644
index 00000000000..13ba4e15dde
--- /dev/null
+++ b/drivers/media/video/cx25840/cx25840-vbi.c
@@ -0,0 +1,315 @@
+/* cx25840 VBI functions
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+#include <media/v4l2-common.h>
+
+#include "cx25840.h"
+
+static inline int odd_parity(u8 c)
+{
+ c ^= (c >> 4);
+ c ^= (c >> 2);
+ c ^= (c >> 1);
+
+ return c & 1;
+}
+
+static inline int decode_vps(u8 * dst, u8 * p)
+{
+ static const u8 biphase_tbl[] = {
+ 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+ 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+ 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
+ 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
+ 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
+ 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
+ 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+ 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+ 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
+ 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
+ 0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87,
+ 0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3,
+ 0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85,
+ 0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1,
+ 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
+ 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
+ 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
+ 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
+ 0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86,
+ 0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2,
+ 0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84,
+ 0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0,
+ 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
+ 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
+ 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+ 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+ 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
+ 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
+ 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
+ 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
+ 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+ 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+ };
+
+ u8 c, err = 0;
+ int i;
+
+ for (i = 0; i < 2 * 13; i += 2) {
+ err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]];
+ c = (biphase_tbl[p[i + 1]] & 0xf) |
+ ((biphase_tbl[p[i]] & 0xf) << 4);
+ dst[i / 2] = c;
+ }
+
+ return err & 0xf0;
+}
+
+void cx25840_vbi_setup(struct i2c_client *client)
+{
+ v4l2_std_id std = cx25840_get_v4lstd(client);
+
+ if (std & ~V4L2_STD_NTSC) {
+ /* datasheet startup, step 8d */
+ cx25840_write(client, 0x49f, 0x11);
+
+ cx25840_write(client, 0x470, 0x84);
+ cx25840_write(client, 0x471, 0x00);
+ cx25840_write(client, 0x472, 0x2d);
+ cx25840_write(client, 0x473, 0x5d);
+
+ cx25840_write(client, 0x474, 0x24);
+ cx25840_write(client, 0x475, 0x40);
+ cx25840_write(client, 0x476, 0x24);
+ cx25840_write(client, 0x477, 0x28);
+
+ cx25840_write(client, 0x478, 0x1f);
+ cx25840_write(client, 0x479, 0x02);
+
+ if (std & V4L2_STD_SECAM) {
+ cx25840_write(client, 0x47a, 0x80);
+ cx25840_write(client, 0x47b, 0x00);
+ cx25840_write(client, 0x47c, 0x5f);
+ cx25840_write(client, 0x47d, 0x42);
+ } else {
+ cx25840_write(client, 0x47a, 0x90);
+ cx25840_write(client, 0x47b, 0x20);
+ cx25840_write(client, 0x47c, 0x63);
+ cx25840_write(client, 0x47d, 0x82);
+ }
+
+ cx25840_write(client, 0x47e, 0x0a);
+ cx25840_write(client, 0x47f, 0x01);
+ } else {
+ /* datasheet startup, step 8d */
+ cx25840_write(client, 0x49f, 0x14);
+
+ cx25840_write(client, 0x470, 0x7a);
+ cx25840_write(client, 0x471, 0x00);
+ cx25840_write(client, 0x472, 0x2d);
+ cx25840_write(client, 0x473, 0x5b);
+
+ cx25840_write(client, 0x474, 0x1a);
+ cx25840_write(client, 0x475, 0x70);
+ cx25840_write(client, 0x476, 0x1e);
+ cx25840_write(client, 0x477, 0x1e);
+
+ cx25840_write(client, 0x478, 0x1f);
+ cx25840_write(client, 0x479, 0x02);
+ cx25840_write(client, 0x47a, 0x50);
+ cx25840_write(client, 0x47b, 0x66);
+
+ cx25840_write(client, 0x47c, 0x1f);
+ cx25840_write(client, 0x47d, 0x7c);
+ cx25840_write(client, 0x47e, 0x08);
+ cx25840_write(client, 0x47f, 0x00);
+ }
+}
+
+int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+ struct v4l2_format *fmt;
+ struct v4l2_sliced_vbi_format *svbi;
+
+ switch (cmd) {
+ case VIDIOC_G_FMT:
+ {
+ static u16 lcr2vbi[] = {
+ 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */
+ 0, V4L2_SLICED_WSS_625, 0, /* 4 */
+ V4L2_SLICED_CAPTION_525, /* 6 */
+ 0, 0, V4L2_SLICED_VPS, 0, 0, /* 9 */
+ 0, 0, 0, 0
+ };
+ int i;
+
+ fmt = arg;
+ if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+ return -EINVAL;
+ svbi = &fmt->fmt.sliced;
+ memset(svbi, 0, sizeof(*svbi));
+ /* we're done if raw VBI is active */
+ if ((cx25840_read(client, 0x404) & 0x10) == 0)
+ break;
+
+ for (i = 7; i <= 23; i++) {
+ u8 v = cx25840_read(client, 0x424 + i - 7);
+
+ svbi->service_lines[0][i] = lcr2vbi[v >> 4];
+ svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
+ svbi->service_set |=
+ svbi->service_lines[0][i] | svbi->service_lines[1][i];
+ }
+ break;
+ }
+
+ case VIDIOC_S_FMT:
+ {
+ int is_pal = !(cx25840_get_v4lstd(client) & V4L2_STD_NTSC);
+ int vbi_offset = is_pal ? 1 : 0;
+ int i, x;
+ u8 lcr[24];
+
+ fmt = arg;
+ if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+ return -EINVAL;
+ svbi = &fmt->fmt.sliced;
+ if (svbi->service_set == 0) {
+ /* raw VBI */
+ memset(svbi, 0, sizeof(*svbi));
+
+ /* Setup VBI */
+ cx25840_vbi_setup(client);
+
+ /* VBI Offset */
+ cx25840_write(client, 0x47f, vbi_offset);
+ cx25840_write(client, 0x404, 0x2e);
+ break;
+ }
+
+ for (x = 0; x <= 23; x++)
+ lcr[x] = 0x00;
+
+ /* Setup VBI */
+ cx25840_vbi_setup(client);
+
+ /* Sliced VBI */
+ cx25840_write(client, 0x404, 0x36); /* Ancillery data */
+ cx25840_write(client, 0x406, 0x13);
+ cx25840_write(client, 0x47f, vbi_offset);
+
+ if (is_pal) {
+ for (i = 0; i <= 6; i++)
+ svbi->service_lines[0][i] =
+ svbi->service_lines[1][i] = 0;
+ } else {
+ for (i = 0; i <= 9; i++)
+ svbi->service_lines[0][i] =
+ svbi->service_lines[1][i] = 0;
+
+ for (i = 22; i <= 23; i++)
+ svbi->service_lines[0][i] =
+ svbi->service_lines[1][i] = 0;
+ }
+
+ for (i = 7; i <= 23; i++) {
+ for (x = 0; x <= 1; x++) {
+ switch (svbi->service_lines[1-x][i]) {
+ case V4L2_SLICED_TELETEXT_B:
+ lcr[i] |= 1 << (4 * x);
+ break;
+ case V4L2_SLICED_WSS_625:
+ lcr[i] |= 4 << (4 * x);
+ break;
+ case V4L2_SLICED_CAPTION_525:
+ lcr[i] |= 6 << (4 * x);
+ break;
+ case V4L2_SLICED_VPS:
+ lcr[i] |= 9 << (4 * x);
+ break;
+ }
+ }
+ }
+
+ for (x = 1, i = 0x424; i <= 0x434; i++, x++) {
+ cx25840_write(client, i, lcr[6 + x]);
+ }
+
+ cx25840_write(client, 0x43c, 0x16);
+
+ if (is_pal) {
+ cx25840_write(client, 0x474, 0x2a);
+ } else {
+ cx25840_write(client, 0x474, 0x1a + 6);
+ }
+ break;
+ }
+
+ case VIDIOC_INT_DECODE_VBI_LINE:
+ {
+ struct v4l2_decode_vbi_line *vbi = arg;
+ u8 *p = vbi->p;
+ int id1, id2, l, err = 0;
+
+ if (p[0] || p[1] != 0xff || p[2] != 0xff ||
+ (p[3] != 0x55 && p[3] != 0x91)) {
+ vbi->line = vbi->type = 0;
+ break;
+ }
+
+ p += 4;
+ id1 = p[-1];
+ id2 = p[0] & 0xf;
+ l = p[2] & 0x3f;
+ l += 5;
+ p += 4;
+
+ switch (id2) {
+ case 1:
+ id2 = V4L2_SLICED_TELETEXT_B;
+ break;
+ case 4:
+ id2 = V4L2_SLICED_WSS_625;
+ break;
+ case 6:
+ id2 = V4L2_SLICED_CAPTION_525;
+ err = !odd_parity(p[0]) || !odd_parity(p[1]);
+ break;
+ case 9:
+ id2 = V4L2_SLICED_VPS;
+ if (decode_vps(p, p) != 0) {
+ err = 1;
+ }
+ break;
+ default:
+ id2 = 0;
+ err = 1;
+ break;
+ }
+
+ vbi->type = err ? 0 : id2;
+ vbi->line = err ? 0 : l;
+ vbi->is_second_field = err ? 0 : (id1 == 0x55);
+ vbi->p = p;
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/drivers/media/video/cx25840/cx25840.h b/drivers/media/video/cx25840/cx25840.h
new file mode 100644
index 00000000000..5c3f0639fb7
--- /dev/null
+++ b/drivers/media/video/cx25840/cx25840.h
@@ -0,0 +1,85 @@
+/* cx25840 API header
+ *
+ * Copyright (C) 2003-2004 Chris Kennedy
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _CX25840_H_
+#define _CX25840_H_
+
+
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+
+extern int cx25840_debug;
+
+#define cx25840_dbg(fmt, arg...) do { if (cx25840_debug) \
+ printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+
+#define cx25840_err(fmt, arg...) do { \
+ printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+
+#define cx25840_info(fmt, arg...) do { \
+ printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+
+#define CX25840_CID_CARDTYPE (V4L2_CID_PRIVATE_BASE+0)
+
+enum cx25840_cardtype {
+ CARDTYPE_PVR150,
+ CARDTYPE_PG600
+};
+
+enum cx25840_input {
+ CX25840_TUNER,
+ CX25840_COMPOSITE0,
+ CX25840_COMPOSITE1,
+ CX25840_SVIDEO0,
+ CX25840_SVIDEO1
+};
+
+struct cx25840_state {
+ enum cx25840_cardtype cardtype;
+ enum cx25840_input input;
+ int audio_input;
+ enum v4l2_audio_clock_freq audclk_freq;
+};
+
+/* ----------------------------------------------------------------------- */
+/* cx25850-core.c */
+int cx25840_write(struct i2c_client *client, u16 addr, u8 value);
+int cx25840_write4(struct i2c_client *client, u16 addr, u32 value);
+u8 cx25840_read(struct i2c_client *client, u16 addr);
+u32 cx25840_read4(struct i2c_client *client, u16 addr);
+int cx25840_and_or(struct i2c_client *client, u16 addr, u8 mask, u8 value);
+v4l2_std_id cx25840_get_v4lstd(struct i2c_client *client);
+
+/* ----------------------------------------------------------------------- */
+/* cx25850-firmware.c */
+int cx25840_loadfw(struct i2c_client *client);
+
+/* ----------------------------------------------------------------------- */
+/* cx25850-audio.c */
+int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg);
+
+/* ----------------------------------------------------------------------- */
+/* cx25850-vbi.c */
+void cx25840_vbi_setup(struct i2c_client *client);
+int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg);
+
+#endif
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
new file mode 100644
index 00000000000..41818b6205b
--- /dev/null
+++ b/drivers/media/video/cx88/Kconfig
@@ -0,0 +1,91 @@
+config VIDEO_CX88
+ tristate "Conexant 2388x (bt878 successor) support"
+ depends on VIDEO_DEV && PCI && I2C
+ select I2C_ALGOBIT
+ select FW_LOADER
+ select VIDEO_BTCX
+ select VIDEO_BUF
+ select VIDEO_TUNER
+ select VIDEO_TVEEPROM
+ select VIDEO_IR
+ ---help---
+ This is a video4linux driver for Conexant 2388x based
+ TV cards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cx8800
+
+config VIDEO_CX88_DVB
+ tristate "DVB/ATSC Support for cx2388x based TV cards"
+ depends on VIDEO_CX88 && DVB_CORE
+ select VIDEO_BUF_DVB
+ ---help---
+ This adds support for DVB/ATSC cards based on the
+ Connexant 2388x chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cx88-dvb.
+
+ You must also select one or more DVB/ATSC demodulators.
+ If you are unsure which you need, choose all of them.
+
+config VIDEO_CX88_DVB_ALL_FRONTENDS
+ bool "Build all supported frontends for cx2388x based TV cards"
+ default y
+ depends on VIDEO_CX88_DVB
+ select DVB_MT352
+ select DVB_OR51132
+ select DVB_CX22702
+ select DVB_LGDT330X
+ select DVB_NXT200X
+ ---help---
+ This builds cx88-dvb with all currently supported frontend
+ demodulators. If you wish to tweak your configuration, and
+ only include support for the hardware that you need, choose N here.
+
+ If you are unsure, choose Y.
+
+config VIDEO_CX88_DVB_MT352
+ tristate "Zarlink MT352 DVB-T Support"
+ default m
+ depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
+ select DVB_MT352
+ ---help---
+ This adds DVB-T support for cards based on the
+ Connexant 2388x chip and the MT352 demodulator.
+
+config VIDEO_CX88_DVB_OR51132
+ tristate "OR51132 ATSC Support"
+ default m
+ depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
+ select DVB_OR51132
+ ---help---
+ This adds ATSC 8VSB and QAM64/256 support for cards based on the
+ Connexant 2388x chip and the OR51132 demodulator.
+
+config VIDEO_CX88_DVB_CX22702
+ tristate "Conexant CX22702 DVB-T Support"
+ default m
+ depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
+ select DVB_CX22702
+ ---help---
+ This adds DVB-T support for cards based on the
+ Connexant 2388x chip and the CX22702 demodulator.
+
+config VIDEO_CX88_DVB_LGDT330X
+ tristate "LG Electronics DT3302/DT3303 ATSC Support"
+ default m
+ depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
+ select DVB_LGDT330X
+ ---help---
+ This adds ATSC 8VSB and QAM64/256 support for cards based on the
+ Connexant 2388x chip and the LGDT3302/LGDT3303 demodulator.
+
+config VIDEO_CX88_DVB_NXT200X
+ tristate "NXT2002/NXT2004 ATSC Support"
+ default m
+ depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
+ select DVB_NXT200X
+ ---help---
+ This adds ATSC 8VSB and QAM64/256 support for cards based on the
+ Connexant 2388x chip and the NXT2002/NXT2004 demodulator.
diff --git a/drivers/media/video/cx88/Makefile b/drivers/media/video/cx88/Makefile
index 107e48645e3..0df40b77345 100644
--- a/drivers/media/video/cx88/Makefile
+++ b/drivers/media/video/cx88/Makefile
@@ -9,6 +9,9 @@ obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o
EXTRA_CFLAGS += -I$(src)/..
EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core
EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/frontends
+ifneq ($(CONFIG_VIDEO_BUF_DVB),n)
+ EXTRA_CFLAGS += -DHAVE_VIDEO_BUF_DVB=1
+endif
ifneq ($(CONFIG_DVB_CX22702),n)
EXTRA_CFLAGS += -DHAVE_CX22702=1
endif
@@ -21,3 +24,6 @@ endif
ifneq ($(CONFIG_DVB_MT352),n)
EXTRA_CFLAGS += -DHAVE_MT352=1
endif
+ifneq ($(CONFIG_DVB_NXT200X),n)
+ EXTRA_CFLAGS += -DHAVE_NXT200X=1
+endif
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index 0c0c59e9477..4ae3f78cccf 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -38,7 +38,7 @@ MODULE_AUTHOR("Jelle Foks <jelle@foks.8m.com>");
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
MODULE_LICENSE("GPL");
-static unsigned int mpegbufs = 8;
+static unsigned int mpegbufs = 32;
module_param(mpegbufs,int,0644);
MODULE_PARM_DESC(mpegbufs,"number of mpeg buffers, range 2-32");
@@ -436,7 +436,7 @@ static int memory_write(struct cx88_core *core, u32 address, u32 value)
static int memory_read(struct cx88_core *core, u32 address, u32 *value)
{
- int retval;
+ int retval;
u32 val;
/* Warning: address is dword address (4 bytes) */
@@ -605,11 +605,11 @@ static int blackbird_load_firmware(struct cx8802_dev *dev)
u32 *dataptr;
retval = register_write(dev->core, IVTV_REG_VPU, 0xFFFFFFED);
- retval |= register_write(dev->core, IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
- retval |= register_write(dev->core, IVTV_REG_ENC_SDRAM_REFRESH, 0x80000640);
- retval |= register_write(dev->core, IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A);
+ retval |= register_write(dev->core, IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
+ retval |= register_write(dev->core, IVTV_REG_ENC_SDRAM_REFRESH, 0x80000640);
+ retval |= register_write(dev->core, IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A);
msleep(1);
- retval |= register_write(dev->core, IVTV_REG_APU, 0);
+ retval |= register_write(dev->core, IVTV_REG_APU, 0);
if (retval < 0)
dprintk(0, "Error with register_write\n");
@@ -657,13 +657,13 @@ static int blackbird_load_firmware(struct cx8802_dev *dev)
release_firmware(firmware);
dprintk(0, "Firmware upload successful.\n");
- retval |= register_write(dev->core, IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
- retval |= register_read(dev->core, IVTV_REG_SPU, &value);
- retval |= register_write(dev->core, IVTV_REG_SPU, value & 0xFFFFFFFE);
+ retval |= register_write(dev->core, IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
+ retval |= register_read(dev->core, IVTV_REG_SPU, &value);
+ retval |= register_write(dev->core, IVTV_REG_SPU, value & 0xFFFFFFFE);
msleep(1);
retval |= register_read(dev->core, IVTV_REG_VPU, &value);
- retval |= register_write(dev->core, IVTV_REG_VPU, value & 0xFFFFFFE8);
+ retval |= register_write(dev->core, IVTV_REG_VPU, value & 0xFFFFFFE8);
if (retval < 0)
dprintk(0, "Error with register_write\n");
@@ -683,84 +683,560 @@ DB* DVD | MPEG2 | 720x576PAL | CBR | 600 :Good | 6000 Kbps | 25fps | M
=================================================================================================================
*DB: "DirectBurn"
*/
-static void blackbird_codec_settings(struct cx8802_dev *dev)
+
+static struct blackbird_dnr default_dnr_params = {
+ .mode = BLACKBIRD_DNR_BITS_MANUAL,
+ .type = BLACKBIRD_MEDIAN_FILTER_DISABLED,
+ .spatial = 0,
+ .temporal = 0
+};
+static struct v4l2_mpeg_compression default_mpeg_params = {
+ .st_type = V4L2_MPEG_PS_2,
+ .st_bitrate = {
+ .mode = V4L2_BITRATE_CBR,
+ .min = 0,
+ .target = 0,
+ .max = 0
+ },
+ .ts_pid_pmt = 16,
+ .ts_pid_audio = 260,
+ .ts_pid_video = 256,
+ .ts_pid_pcr = 259,
+ .ps_size = 0,
+ .au_type = V4L2_MPEG_AU_2_II,
+ .au_bitrate = {
+ .mode = V4L2_BITRATE_CBR,
+ .min = 224,
+ .target = 224,
+ .max = 224
+ },
+ .au_sample_rate = 44100,
+ .au_pesid = 0,
+ .vi_type = V4L2_MPEG_VI_2,
+ .vi_aspect_ratio = V4L2_MPEG_ASPECT_4_3,
+ .vi_bitrate = {
+ .mode = V4L2_BITRATE_CBR,
+ .min = 4000,
+ .target = 4500,
+ .max = 6000
+ },
+ .vi_frame_rate = 25,
+ .vi_frames_per_gop = 15,
+ .vi_bframes_count = 2,
+ .vi_pesid = 0,
+ .closed_gops = 0,
+ .pulldown = 0
+};
+
+static enum blackbird_stream_type mpeg_stream_types[] = {
+ [V4L2_MPEG_SS_1] = BLACKBIRD_STREAM_MPEG1,
+ [V4L2_MPEG_PS_2] = BLACKBIRD_STREAM_PROGRAM,
+ [V4L2_MPEG_TS_2] = BLACKBIRD_STREAM_TRANSPORT,
+ [V4L2_MPEG_PS_DVD] = BLACKBIRD_STREAM_DVD,
+};
+static enum blackbird_aspect_ratio mpeg_stream_ratios[] = {
+ [V4L2_MPEG_ASPECT_SQUARE] = BLACKBIRD_ASPECT_RATIO_1_1_SQUARE,
+ [V4L2_MPEG_ASPECT_4_3] = BLACKBIRD_ASPECT_RATIO_4_3,
+ [V4L2_MPEG_ASPECT_16_9] = BLACKBIRD_ASPECT_RATIO_16_9,
+ [V4L2_MPEG_ASPECT_1_221] = BLACKBIRD_ASPECT_RATIO_221_100,
+};
+static enum blackbird_video_bitrate_type mpeg_video_bitrates[] = {
+ [V4L2_BITRATE_NONE] = BLACKBIRD_VIDEO_CBR,
+ [V4L2_BITRATE_CBR] = BLACKBIRD_VIDEO_CBR,
+ [V4L2_BITRATE_VBR] = BLACKBIRD_VIDEO_VBR,
+};
+/* find the best layer I/II bitrate to fit a given numeric value */
+struct bitrate_bits {
+ u32 bits; /* layer bits for the best fit */
+ u32 rate; /* actual numeric value for the layer best fit */
+};
+struct bitrate_approximation {
+ u32 target; /* numeric value of the rate we want */
+ struct bitrate_bits layer[2];
+};
+static struct bitrate_approximation mpeg_audio_bitrates[] = {
+ /* target layer[0].bits layer[0].rate layer[1].bits layer[1].rate */
+ { 0, { { 0, 0, }, { 0, 0, }, }, },
+ { 32, { { BLACKBIRD_AUDIO_BITS_LAYER_1_32 , 32, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_32 , 32, }, }, },
+ { 48, { { BLACKBIRD_AUDIO_BITS_LAYER_1_64 , 64, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_48 , 48, }, }, },
+ { 56, { { BLACKBIRD_AUDIO_BITS_LAYER_1_64 , 64, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_56 , 56, }, }, },
+ { 64, { { BLACKBIRD_AUDIO_BITS_LAYER_1_64 , 64, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_64 , 64, }, }, },
+ { 80, { { BLACKBIRD_AUDIO_BITS_LAYER_1_96 , 96, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_80 , 80, }, }, },
+ { 96, { { BLACKBIRD_AUDIO_BITS_LAYER_1_96 , 96, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_96 , 96, }, }, },
+ { 112, { { BLACKBIRD_AUDIO_BITS_LAYER_1_128, 128, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_112, 112, }, }, },
+ { 128, { { BLACKBIRD_AUDIO_BITS_LAYER_1_128, 128, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_128, 128, }, }, },
+ { 160, { { BLACKBIRD_AUDIO_BITS_LAYER_1_160, 160, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_160, 160, }, }, },
+ { 192, { { BLACKBIRD_AUDIO_BITS_LAYER_1_192, 192, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_192, 192, }, }, },
+ { 224, { { BLACKBIRD_AUDIO_BITS_LAYER_1_224, 224, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_224, 224, }, }, },
+ { 256, { { BLACKBIRD_AUDIO_BITS_LAYER_1_256, 256, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_256, 256, }, }, },
+ { 288, { { BLACKBIRD_AUDIO_BITS_LAYER_1_288, 288, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_320, 320, }, }, },
+ { 320, { { BLACKBIRD_AUDIO_BITS_LAYER_1_320, 320, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_320, 320, }, }, },
+ { 352, { { BLACKBIRD_AUDIO_BITS_LAYER_1_352, 352, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_384, 384, }, }, },
+ { 384, { { BLACKBIRD_AUDIO_BITS_LAYER_1_384, 384, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_384, 384, }, }, },
+ { 416, { { BLACKBIRD_AUDIO_BITS_LAYER_1_416, 416, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_384, 384, }, }, },
+ { 448, { { BLACKBIRD_AUDIO_BITS_LAYER_1_448, 448, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_384, 384, }, }, },
+};
+static const int BITRATES_SIZE = ARRAY_SIZE(mpeg_audio_bitrates);
+
+static void blackbird_set_default_params(struct cx8802_dev *dev)
{
- int bitrate_mode = 1;
- int bitrate = 7500000;
- int bitrate_peak = 7500000;
- bitrate_mode = BLACKBIRD_VIDEO_CBR;
- bitrate = 4000*1024;
- bitrate_peak = 4000*1024;
+ struct v4l2_mpeg_compression *params = &dev->params;
+ u32 au_params;
/* assign stream type */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_STREAM_TYPE, 1, 0, BLACKBIRD_STREAM_PROGRAM);
-
- /* assign output port */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_OUTPUT_PORT, 1, 0, BLACKBIRD_OUTPUT_PORT_STREAMING); /* Host */
+ if( params->st_type >= ARRAY_SIZE(mpeg_stream_types) )
+ params->st_type = V4L2_MPEG_PS_2;
+ if( params->st_type == V4L2_MPEG_SS_1 )
+ params->vi_type = V4L2_MPEG_VI_1;
+ else
+ params->vi_type = V4L2_MPEG_VI_2;
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_STREAM_TYPE, 1, 0, mpeg_stream_types[params->st_type]);
/* assign framerate */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_FRAMERATE, 1, 0, BLACKBIRD_FRAMERATE_PAL_25);
-
- /* assign frame size */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_RESOLUTION, 2, 0,
- dev->height, dev->width);
+ if( params->vi_frame_rate <= 25 )
+ {
+ params->vi_frame_rate = 25;
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_FRAMERATE, 1, 0, BLACKBIRD_FRAMERATE_PAL_25);
+ }
+ else
+ {
+ params->vi_frame_rate = 30;
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_FRAMERATE, 1, 0, BLACKBIRD_FRAMERATE_NTSC_30);
+ }
/* assign aspect ratio */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_ASPECT_RATIO, 1, 0, BLACKBIRD_ASPECT_RATIO_4_3);
-
- /* assign bitrates */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_VIDEO_BITRATE, 5, 0,
- bitrate_mode, /* mode */
- bitrate, /* bps */
- bitrate_peak / BLACKBIRD_PEAK_RATE_DIVISOR, /* peak/400 */
- BLACKBIRD_MUX_RATE_DEFAULT /*, 0x70*/); /* encoding buffer, ckennedy */
+ if( params->vi_aspect_ratio >= ARRAY_SIZE(mpeg_stream_ratios) )
+ params->vi_aspect_ratio = V4L2_MPEG_ASPECT_4_3;
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_ASPECT_RATIO, 1, 0, mpeg_stream_ratios[params->vi_aspect_ratio]);
/* assign gop properties */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_STRUCTURE, 2, 0, 15, 3);
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_STRUCTURE, 2, 0, params->vi_frames_per_gop, params->vi_bframes_count+1);
+
+ /* assign gop closure */
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_CLOSURE, 1, 0, params->closed_gops);
/* assign 3 2 pulldown */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_3_2_PULLDOWN, 1, 0, BLACKBIRD_3_2_PULLDOWN_DISABLED);
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_3_2_PULLDOWN, 1, 0, params->pulldown);
+
+ /* make sure the params are within bounds */
+ if( params->st_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
+ params->vi_bitrate.mode = V4L2_BITRATE_NONE;
+ if( params->vi_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
+ params->vi_bitrate.mode = V4L2_BITRATE_NONE;
+ if( params->au_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
+ params->au_bitrate.mode = V4L2_BITRATE_NONE;
/* assign audio properties */
/* note: it's not necessary to set the samplerate, the mpeg encoder seems to autodetect/adjust */
- /* blackbird_api_cmd(dev, IVTV_API_ASSIGN_AUDIO_PROPERTIES, 1, 0, (2<<2) | (8<<4));
- blackbird_api_cmd(dev, IVTV_API_ASSIGN_AUDIO_PROPERTIES, 1, 0, 0 | (2 << 2) | (14 << 4)); */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_AUDIO_PARAMS, 1, 0,
- BLACKBIRD_AUDIO_BITS_44100HZ |
- BLACKBIRD_AUDIO_BITS_LAYER_2 |
- BLACKBIRD_AUDIO_BITS_LAYER_2_224 |
- BLACKBIRD_AUDIO_BITS_STEREO |
+ au_params = BLACKBIRD_AUDIO_BITS_STEREO |
/* BLACKBIRD_AUDIO_BITS_BOUND_4 | */
BLACKBIRD_AUDIO_BITS_EMPHASIS_NONE |
BLACKBIRD_AUDIO_BITS_CRC_OFF |
BLACKBIRD_AUDIO_BITS_COPYRIGHT_OFF |
- BLACKBIRD_AUDIO_BITS_COPY
- );
+ BLACKBIRD_AUDIO_BITS_COPY |
+ 0;
+ if( params->au_sample_rate <= 32000 )
+ {
+ params->au_sample_rate = 32000;
+ au_params |= BLACKBIRD_AUDIO_BITS_32000HZ;
+ }
+ else if( params->au_sample_rate <= 44100 )
+ {
+ params->au_sample_rate = 44100;
+ au_params |= BLACKBIRD_AUDIO_BITS_44100HZ;
+ }
+ else
+ {
+ params->au_sample_rate = 48000;
+ au_params |= BLACKBIRD_AUDIO_BITS_48000HZ;
+ }
+ if( params->au_type == V4L2_MPEG_AU_2_I )
+ {
+ au_params |= BLACKBIRD_AUDIO_BITS_LAYER_1;
+ }
+ else
+ {
+ /* TODO: try to handle the other formats more gracefully */
+ params->au_type = V4L2_MPEG_AU_2_II;
+ au_params |= BLACKBIRD_AUDIO_BITS_LAYER_2;
+ }
+ if( params->au_bitrate.mode )
+ {
+ int layer;
+
+ if( params->au_bitrate.mode == V4L2_BITRATE_CBR )
+ params->au_bitrate.max = params->vi_bitrate.target;
+ else
+ params->au_bitrate.target = params->vi_bitrate.max;
+
+ layer = params->au_type;
+ if( params->au_bitrate.target == 0 )
+ {
+ /* TODO: use the minimum possible bitrate instead of 0 ? */
+ au_params |= 0;
+ }
+ else if( params->au_bitrate.target >=
+ mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].rate )
+ {
+ /* clamp the bitrate to the max supported by the standard */
+ params->au_bitrate.target = mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].rate;
+ params->au_bitrate.max = params->au_bitrate.target;
+ au_params |= mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].bits;
+ }
+ else
+ {
+ /* round up to the nearest supported bitrate */
+ int i;
+ for(i = 1; i < BITRATES_SIZE; i++)
+ {
+ if( params->au_bitrate.target > mpeg_audio_bitrates[i-1].layer[layer].rate &&
+ params->au_bitrate.target <= mpeg_audio_bitrates[i].layer[layer].rate )
+ {
+ params->au_bitrate.target = mpeg_audio_bitrates[i].layer[layer].rate;
+ params->au_bitrate.max = params->au_bitrate.target;
+ au_params |= mpeg_audio_bitrates[i].layer[layer].bits;
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ /* TODO: ??? */
+ params->au_bitrate.target = params->au_bitrate.max = 0;
+ au_params |= 0;
+ }
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_AUDIO_PARAMS, 1, 0, au_params );
+
+ /* assign bitrates */
+ if( params->vi_bitrate.mode )
+ {
+ /* bitrate is set, let's figure out the cbr/vbr mess */
+ if( params->vi_bitrate.max < params->vi_bitrate.target )
+ {
+ if( params->vi_bitrate.mode == V4L2_BITRATE_CBR )
+ params->vi_bitrate.max = params->vi_bitrate.target;
+ else
+ params->vi_bitrate.target = params->vi_bitrate.max;
+ }
+ }
+ else
+ {
+ if( params->st_bitrate.max < params->st_bitrate.target )
+ {
+ if( params->st_bitrate.mode == V4L2_BITRATE_VBR )
+ params->st_bitrate.target = params->st_bitrate.max;
+ else
+ params->st_bitrate.max = params->st_bitrate.target;
+ }
+ /* calculate vi_bitrate = st_bitrate - au_bitrate */
+ params->vi_bitrate.max = params->st_bitrate.max - params->au_bitrate.max;
+ params->vi_bitrate.target = params->st_bitrate.target - params->au_bitrate.target;
+ }
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_VIDEO_BITRATE, 4, 0,
+ mpeg_video_bitrates[params->vi_bitrate.mode],
+ params->vi_bitrate.target * 1000, /* kbps -> bps */
+ params->vi_bitrate.max * 1000 / BLACKBIRD_PEAK_RATE_DIVISOR, /* peak/400 */
+ BLACKBIRD_MUX_RATE_DEFAULT /*, 0x70*/); /* encoding buffer, ckennedy */
+
+ /* TODO: implement the stream ID stuff:
+ ts_pid_pmt, ts_pid_audio, ts_pid_video, ts_pid_pcr,
+ ps_size, au_pesid, vi_pesid
+ */
+}
+#define CHECK_PARAM( name ) ( dev->params.name != params->name )
+#define IF_PARAM( name ) if( CHECK_PARAM( name ) )
+#define UPDATE_PARAM( name ) dev->params.name = params->name
+void blackbird_set_params(struct cx8802_dev *dev, struct v4l2_mpeg_compression *params)
+{
+ u32 au_params;
+
+ /* assign stream type */
+ if( params->st_type >= ARRAY_SIZE(mpeg_stream_types) )
+ params->st_type = V4L2_MPEG_PS_2;
+ if( params->st_type == V4L2_MPEG_SS_1 )
+ params->vi_type = V4L2_MPEG_VI_1;
+ else
+ params->vi_type = V4L2_MPEG_VI_2;
+ if( CHECK_PARAM( st_type ) || CHECK_PARAM( vi_type ) )
+ {
+ UPDATE_PARAM( st_type );
+ UPDATE_PARAM( vi_type );
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_STREAM_TYPE, 1, 0, mpeg_stream_types[params->st_type]);
+ }
+
+ /* assign framerate */
+ if( params->vi_frame_rate <= 25 )
+ params->vi_frame_rate = 25;
+ else
+ params->vi_frame_rate = 30;
+ IF_PARAM( vi_frame_rate )
+ {
+ UPDATE_PARAM( vi_frame_rate );
+ if( params->vi_frame_rate == 25 )
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_FRAMERATE, 1, 0, BLACKBIRD_FRAMERATE_PAL_25);
+ else
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_FRAMERATE, 1, 0, BLACKBIRD_FRAMERATE_NTSC_30);
+ }
+
+ /* assign aspect ratio */
+ if( params->vi_aspect_ratio >= ARRAY_SIZE(mpeg_stream_ratios) )
+ params->vi_aspect_ratio = V4L2_MPEG_ASPECT_4_3;
+ IF_PARAM( vi_aspect_ratio )
+ {
+ UPDATE_PARAM( vi_aspect_ratio );
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_ASPECT_RATIO, 1, 0, mpeg_stream_ratios[params->vi_aspect_ratio]);
+ }
+
+ /* assign gop properties */
+ if( CHECK_PARAM( vi_frames_per_gop ) || CHECK_PARAM( vi_bframes_count ) )
+ {
+ UPDATE_PARAM( vi_frames_per_gop );
+ UPDATE_PARAM( vi_bframes_count );
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_STRUCTURE, 2, 0, params->vi_frames_per_gop, params->vi_bframes_count+1);
+ }
/* assign gop closure */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_CLOSURE, 1, 0, BLACKBIRD_GOP_CLOSURE_OFF);
+ IF_PARAM( closed_gops )
+ {
+ UPDATE_PARAM( closed_gops );
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_CLOSURE, 1, 0, params->closed_gops);
+ }
+
+ /* assign 3 2 pulldown */
+ IF_PARAM( pulldown )
+ {
+ UPDATE_PARAM( pulldown );
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_3_2_PULLDOWN, 1, 0, params->pulldown);
+ }
+
+ /* make sure the params are within bounds */
+ if( params->st_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
+ params->vi_bitrate.mode = V4L2_BITRATE_NONE;
+ if( params->vi_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
+ params->vi_bitrate.mode = V4L2_BITRATE_NONE;
+ if( params->au_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
+ params->au_bitrate.mode = V4L2_BITRATE_NONE;
+
+ /* assign audio properties */
+ /* note: it's not necessary to set the samplerate, the mpeg encoder seems to autodetect/adjust */
+ au_params = BLACKBIRD_AUDIO_BITS_STEREO |
+ /* BLACKBIRD_AUDIO_BITS_BOUND_4 | */
+ BLACKBIRD_AUDIO_BITS_EMPHASIS_NONE |
+ BLACKBIRD_AUDIO_BITS_CRC_OFF |
+ BLACKBIRD_AUDIO_BITS_COPYRIGHT_OFF |
+ BLACKBIRD_AUDIO_BITS_COPY |
+ 0;
+ if( params->au_sample_rate < 32000 )
+ {
+ params->au_sample_rate = 32000;
+ au_params |= BLACKBIRD_AUDIO_BITS_32000HZ;
+ }
+ else if( params->au_sample_rate < 44100 )
+ {
+ params->au_sample_rate = 44100;
+ au_params |= BLACKBIRD_AUDIO_BITS_44100HZ;
+ }
+ else
+ {
+ params->au_sample_rate = 48000;
+ au_params |= BLACKBIRD_AUDIO_BITS_48000HZ;
+ }
+ if( params->au_type == V4L2_MPEG_AU_2_I )
+ {
+ au_params |= BLACKBIRD_AUDIO_BITS_LAYER_1;
+ }
+ else
+ {
+ /* TODO: try to handle the other formats more gracefully */
+ params->au_type = V4L2_MPEG_AU_2_II;
+ au_params |= BLACKBIRD_AUDIO_BITS_LAYER_2;
+ }
+ if( params->au_bitrate.mode )
+ {
+ int layer;
+
+ if( params->au_bitrate.mode == V4L2_BITRATE_CBR )
+ params->au_bitrate.max = params->vi_bitrate.target;
+ else
+ params->au_bitrate.target = params->vi_bitrate.max;
+
+ layer = params->au_type;
+ if( params->au_bitrate.target == 0 )
+ {
+ /* TODO: use the minimum possible bitrate instead of 0 ? */
+ au_params |= 0;
+ }
+ else if( params->au_bitrate.target >=
+ mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].rate )
+ {
+ /* clamp the bitrate to the max supported by the standard */
+ params->au_bitrate.target = mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].rate;
+ params->au_bitrate.max = params->au_bitrate.target;
+ au_params |= mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].bits;
+ }
+ else
+ {
+ /* round up to the nearest supported bitrate */
+ int i;
+ for(i = 1; i < BITRATES_SIZE; i++)
+ {
+ if( params->au_bitrate.target > mpeg_audio_bitrates[i-1].layer[layer].rate &&
+ params->au_bitrate.target <= mpeg_audio_bitrates[i].layer[layer].rate )
+ {
+ params->au_bitrate.target = mpeg_audio_bitrates[i].layer[layer].rate;
+ params->au_bitrate.max = params->au_bitrate.target;
+ au_params |= mpeg_audio_bitrates[i].layer[layer].bits;
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ /* TODO: ??? */
+ params->au_bitrate.target = params->au_bitrate.max = 0;
+ au_params |= 0;
+ }
+ if( CHECK_PARAM( au_type ) || CHECK_PARAM( au_sample_rate )
+ || CHECK_PARAM( au_bitrate.mode ) || CHECK_PARAM( au_bitrate.max )
+ || CHECK_PARAM( au_bitrate.target )
+ )
+ {
+ UPDATE_PARAM( au_type );
+ UPDATE_PARAM( au_sample_rate );
+ UPDATE_PARAM( au_bitrate );
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_AUDIO_PARAMS, 1, 0, au_params );
+ }
+
+ /* assign bitrates */
+ if( params->vi_bitrate.mode )
+ {
+ /* bitrate is set, let's figure out the cbr/vbr mess */
+ if( params->vi_bitrate.max < params->vi_bitrate.target )
+ {
+ if( params->vi_bitrate.mode == V4L2_BITRATE_CBR )
+ params->vi_bitrate.max = params->vi_bitrate.target;
+ else
+ params->vi_bitrate.target = params->vi_bitrate.max;
+ }
+ }
+ else
+ {
+ if( params->st_bitrate.max < params->st_bitrate.target )
+ {
+ if( params->st_bitrate.mode == V4L2_BITRATE_VBR )
+ params->st_bitrate.target = params->st_bitrate.max;
+ else
+ params->st_bitrate.max = params->st_bitrate.target;
+ }
+ /* calculate vi_bitrate = st_bitrate - au_bitrate */
+ params->vi_bitrate.max = params->st_bitrate.max - params->au_bitrate.max;
+ params->vi_bitrate.target = params->st_bitrate.target - params->au_bitrate.target;
+ }
+ UPDATE_PARAM( st_bitrate );
+ if( CHECK_PARAM( vi_bitrate.mode ) || CHECK_PARAM( vi_bitrate.max )
+ || CHECK_PARAM( vi_bitrate.target )
+ )
+ {
+ UPDATE_PARAM( vi_bitrate );
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_VIDEO_BITRATE, 4, 0,
+ mpeg_video_bitrates[params->vi_bitrate.mode],
+ params->vi_bitrate.target * 1000, /* kbps -> bps */
+ params->vi_bitrate.max * 1000 / BLACKBIRD_PEAK_RATE_DIVISOR, /* peak/400 */
+ BLACKBIRD_MUX_RATE_DEFAULT /*, 0x70*/); /* encoding buffer, ckennedy */
+ }
+ /* TODO: implement the stream ID stuff:
+ ts_pid_pmt, ts_pid_audio, ts_pid_video, ts_pid_pcr,
+ ps_size, au_pesid, vi_pesid
+ */
+ UPDATE_PARAM( ts_pid_pmt );
+ UPDATE_PARAM( ts_pid_audio );
+ UPDATE_PARAM( ts_pid_video );
+ UPDATE_PARAM( ts_pid_pcr );
+ UPDATE_PARAM( ps_size );
+ UPDATE_PARAM( au_pesid );
+ UPDATE_PARAM( vi_pesid );
+}
+static void blackbird_set_default_dnr_params(struct cx8802_dev *dev)
+{
/* assign dnr filter mode */
+ if( dev->dnr_params.mode > BLACKBIRD_DNR_BITS_AUTO )
+ dev->dnr_params.mode = BLACKBIRD_DNR_BITS_MANUAL;
+ if( dev->dnr_params.type > BLACKBIRD_MEDIAN_FILTER_DIAGONAL )
+ dev->dnr_params.type = BLACKBIRD_MEDIAN_FILTER_DISABLED;
blackbird_api_cmd(dev, BLACKBIRD_API_SET_DNR_MODE, 2, 0,
- BLACKBIRD_DNR_BITS_MANUAL,
- BLACKBIRD_MEDIAN_FILTER_DISABLED
- );
+ dev->dnr_params.mode,
+ dev->dnr_params.type
+ );
/* assign dnr filter props*/
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_MANUAL_DNR, 2, 0, 0, 0);
+ if( dev->dnr_params.spatial > 15 )
+ dev->dnr_params.spatial = 15;
+ if( dev->dnr_params.temporal > 31 )
+ dev->dnr_params.temporal = 31;
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_MANUAL_DNR, 2, 0,
+ dev->dnr_params.spatial,
+ dev->dnr_params.temporal
+ );
+}
+#define CHECK_DNR_PARAM( name ) ( dev->dnr_params.name != dnr_params->name )
+#define UPDATE_DNR_PARAM( name ) dev->dnr_params.name = dnr_params->name
+void blackbird_set_dnr_params(struct cx8802_dev *dev, struct blackbird_dnr* dnr_params)
+{
+ /* assign dnr filter mode */
+ /* clamp values */
+ if( dnr_params->mode > BLACKBIRD_DNR_BITS_AUTO )
+ dnr_params->mode = BLACKBIRD_DNR_BITS_MANUAL;
+ if( dnr_params->type > BLACKBIRD_MEDIAN_FILTER_DIAGONAL )
+ dnr_params->type = BLACKBIRD_MEDIAN_FILTER_DISABLED;
+ /* check if the params actually changed */
+ if( CHECK_DNR_PARAM( mode ) || CHECK_DNR_PARAM( type ) )
+ {
+ UPDATE_DNR_PARAM( mode );
+ UPDATE_DNR_PARAM( type );
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_DNR_MODE, 2, 0, dnr_params->mode, dnr_params->type);
+ }
+
+ /* assign dnr filter props*/
+ if( dnr_params->spatial > 15 )
+ dnr_params->spatial = 15;
+ if( dnr_params->temporal > 31 )
+ dnr_params->temporal = 31;
+ if( CHECK_DNR_PARAM( spatial ) || CHECK_DNR_PARAM( temporal ) )
+ {
+ UPDATE_DNR_PARAM( spatial );
+ UPDATE_DNR_PARAM( temporal );
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_MANUAL_DNR, 2, 0, dnr_params->spatial, dnr_params->temporal);
+ }
+}
+
+static void blackbird_codec_settings(struct cx8802_dev *dev)
+{
+
+ /* assign output port */
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_OUTPUT_PORT, 1, 0, BLACKBIRD_OUTPUT_PORT_STREAMING); /* Host */
+
+ /* assign frame size */
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_RESOLUTION, 2, 0,
+ dev->height, dev->width);
/* assign coring levels (luma_h, luma_l, chroma_h, chroma_l) */
blackbird_api_cmd(dev, BLACKBIRD_API_SET_DNR_MEDIAN, 4, 0, 0, 255, 0, 255);
/* assign spatial filter type: luma_t: horiz_only, chroma_t: horiz_only */
blackbird_api_cmd(dev, BLACKBIRD_API_SET_SPATIAL_FILTER, 2, 0,
- BLACKBIRD_SPATIAL_FILTER_LUMA_1D_HORIZ,
- BLACKBIRD_SPATIAL_FILTER_CHROMA_1D_HORIZ
- );
+ BLACKBIRD_SPATIAL_FILTER_LUMA_1D_HORIZ,
+ BLACKBIRD_SPATIAL_FILTER_CHROMA_1D_HORIZ
+ );
/* assign frame drop rate */
/* blackbird_api_cmd(dev, IVTV_API_ASSIGN_FRAME_DROP_RATE, 1, 0, 0); */
+
+ blackbird_set_default_params(dev);
+ blackbird_set_default_dnr_params(dev);
}
static int blackbird_initialize_codec(struct cx8802_dev *dev)
@@ -851,15 +1327,10 @@ static int bb_buf_setup(struct videobuf_queue *q,
struct cx8802_fh *fh = q->priv_data;
fh->dev->ts_packet_size = 188 * 4; /* was: 512 */
- fh->dev->ts_packet_count = 32; /* was: 100 */
+ fh->dev->ts_packet_count = mpegbufs; /* was: 100 */
*size = fh->dev->ts_packet_size * fh->dev->ts_packet_count;
- if (0 == *count)
- *count = mpegbufs;
- if (*count < 2)
- *count = 2;
- if (*count > 32)
- *count = 32;
+ *count = fh->dev->ts_packet_count;
return 0;
}
@@ -868,7 +1339,7 @@ bb_buf_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
enum v4l2_field field)
{
struct cx8802_fh *fh = q->priv_data;
- return cx8802_buf_prepare(fh->dev, (struct cx88_buffer*)vb);
+ return cx8802_buf_prepare(fh->dev, (struct cx88_buffer*)vb, field);
}
static void
@@ -920,8 +1391,6 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file,
V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING |
- V4L2_CAP_VBI_CAPTURE |
- V4L2_CAP_VIDEO_OVERLAY |
0;
if (UNSET != core->tuner_type)
cap->capabilities |= V4L2_CAP_TUNER;
@@ -941,27 +1410,52 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file,
memset(f,0,sizeof(*f));
f->index = index;
- strlcpy(f->description, "MPEG TS", sizeof(f->description));
+ strlcpy(f->description, "MPEG", sizeof(f->description));
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
f->pixelformat = V4L2_PIX_FMT_MPEG;
return 0;
}
case VIDIOC_G_FMT:
- case VIDIOC_S_FMT:
- case VIDIOC_TRY_FMT:
{
- /* FIXME -- quick'n'dirty for exactly one size ... */
struct v4l2_format *f = arg;
memset(f,0,sizeof(*f));
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */
+ f->fmt.pix.colorspace = 0;
f->fmt.pix.width = dev->width;
f->fmt.pix.height = dev->height;
+ f->fmt.pix.field = fh->mpegq.field;
+ dprintk(0,"VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
+ dev->width, dev->height, fh->mpegq.field );
+ return 0;
+ }
+ case VIDIOC_TRY_FMT:
+ {
+ struct v4l2_format *f = arg;
+
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */;
+ f->fmt.pix.colorspace = 0;
+ dprintk(0,"VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
+ dev->width, dev->height, fh->mpegq.field );
+ return 0;
+ }
+ case VIDIOC_S_FMT:
+ {
+ struct v4l2_format *f = arg;
+
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
- f->fmt.pix.field = V4L2_FIELD_NONE;
f->fmt.pix.bytesperline = 0;
- f->fmt.pix.sizeimage = 188 * 4 * 1024; /* 1024 * 512 */ /* FIXME: BUFFER_SIZE */;
+ f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */;
f->fmt.pix.colorspace = 0;
+ dprintk(0,"VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
+ f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field );
return 0;
}
@@ -985,6 +1479,22 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_STREAMOFF:
return videobuf_streamoff(&fh->mpegq);
+ /* --- mpeg compression -------------------------------------- */
+ case VIDIOC_G_MPEGCOMP:
+ {
+ struct v4l2_mpeg_compression *f = arg;
+
+ memcpy(f,&dev->params,sizeof(*f));
+ return 0;
+ }
+ case VIDIOC_S_MPEGCOMP:
+ {
+ struct v4l2_mpeg_compression *f = arg;
+
+ blackbird_set_params(dev, f);
+ return 0;
+ }
+
default:
return cx88_do_ioctl( inode, file, 0, dev->core, cmd, arg, cx88_ioctl_hook );
}
@@ -1034,16 +1544,17 @@ static int mpeg_open(struct inode *inode, struct file *file)
file->private_data = fh;
fh->dev = dev;
- /* FIXME: locking against other video device */
- cx88_set_scale(dev->core, dev->width, dev->height,
- V4L2_FIELD_INTERLACED);
-
videobuf_queue_init(&fh->mpegq, &blackbird_qops,
dev->pci, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_TOP,
+ V4L2_FIELD_INTERLACED,
sizeof(struct cx88_buffer),
fh);
+
+ /* FIXME: locking against other video device */
+ cx88_set_scale(dev->core, dev->width, dev->height,
+ fh->mpegq.field);
+
return 0;
}
@@ -1173,6 +1684,8 @@ static int __devinit blackbird_probe(struct pci_dev *pci_dev,
dev->core = core;
dev->width = 720;
dev->height = 576;
+ memcpy(&dev->params,&default_mpeg_params,sizeof(default_mpeg_params));
+ memcpy(&dev->dnr_params,&default_dnr_params,sizeof(default_dnr_params));
err = cx8802_init_common(dev);
if (0 != err)
@@ -1199,7 +1712,7 @@ static int __devinit blackbird_probe(struct pci_dev *pci_dev,
static void __devexit blackbird_remove(struct pci_dev *pci_dev)
{
- struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
+ struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
/* blackbird */
blackbird_unregister_video(dev);
@@ -1215,8 +1728,8 @@ static struct pci_device_id cx8802_pci_tbl[] = {
{
.vendor = 0x14f1,
.device = 0x8802,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
},{
/* --- end of list --- */
}
@@ -1224,10 +1737,10 @@ static struct pci_device_id cx8802_pci_tbl[] = {
MODULE_DEVICE_TABLE(pci, cx8802_pci_tbl);
static struct pci_driver blackbird_pci_driver = {
- .name = "cx88-blackbird",
- .id_table = cx8802_pci_tbl,
- .probe = blackbird_probe,
- .remove = __devexit_p(blackbird_remove),
+ .name = "cx88-blackbird",
+ .id_table = cx8802_pci_tbl,
+ .probe = blackbird_probe,
+ .remove = __devexit_p(blackbird_remove),
.suspend = cx8802_suspend_common,
.resume = cx8802_resume_common,
};
@@ -1257,6 +1770,8 @@ module_exit(blackbird_fini);
EXPORT_SYMBOL(cx88_ioctl_hook);
EXPORT_SYMBOL(cx88_ioctl_translator);
+EXPORT_SYMBOL(blackbird_set_params);
+EXPORT_SYMBOL(blackbird_set_dnr_params);
/* ----------------------------------------------------------- */
/*
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index 4da91d535a5..f2268631b7c 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -126,27 +126,27 @@ struct cx88_board cx88_boards[] = {
.input = {{
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
- .gpio0 = 0x03ff,
+ .gpio0 = 0x03ff,
},{
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
- .gpio0 = 0x03fe,
+ .gpio0 = 0x03fe,
},{
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
- .gpio0 = 0x03fe,
+ .gpio0 = 0x03fe,
}},
},
- [CX88_BOARD_WINFAST2000XP_EXPERT] = {
- .name = "Leadtek Winfast 2000XP Expert",
- .tuner_type = TUNER_PHILIPS_4IN1,
+ [CX88_BOARD_WINFAST2000XP_EXPERT] = {
+ .name = "Leadtek Winfast 2000XP Expert",
+ .tuner_type = TUNER_PHILIPS_4IN1,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .input = {{
- .type = CX88_VMUX_TELEVISION,
- .vmux = 0,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
.gpio0 = 0x00F5e700,
.gpio1 = 0x00003004,
.gpio2 = 0x00F5e700,
@@ -165,16 +165,16 @@ struct cx88_board cx88_boards[] = {
.gpio1 = 0x00003004,
.gpio2 = 0x00F5c700,
.gpio3 = 0x02000000,
- }},
- .radio = {
- .type = CX88_RADIO,
+ }},
+ .radio = {
+ .type = CX88_RADIO,
.gpio0 = 0x00F5d700,
.gpio1 = 0x00003004,
.gpio2 = 0x00F5d700,
.gpio3 = 0x02000000,
- },
- },
- [CX88_BOARD_AVERTV_303] = {
+ },
+ },
+ [CX88_BOARD_AVERTV_STUDIO_303] = {
.name = "AverTV Studio 303 (M126)",
.tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
.radio_type = UNSET,
@@ -206,7 +206,7 @@ struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .tda9887_conf = TDA9887_PRESENT,
+ .tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER_NTSC,
.input = {{
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
@@ -214,32 +214,32 @@ struct cx88_board cx88_boards[] = {
.gpio1 = 0x000080c0,
.gpio2 = 0x0000ff40,
},{
- .type = CX88_VMUX_COMPOSITE1,
- .vmux = 1,
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
.gpio0 = 0x000040bf,
.gpio1 = 0x000080c0,
.gpio2 = 0x0000ff40,
},{
- .type = CX88_VMUX_SVIDEO,
- .vmux = 2,
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
.gpio0 = 0x000040bf,
.gpio1 = 0x000080c0,
.gpio2 = 0x0000ff40,
- }},
- .radio = {
+ }},
+ .radio = {
.type = CX88_RADIO,
- },
+ },
},
[CX88_BOARD_WINFAST_DV2000] = {
- .name = "Leadtek Winfast DV2000",
- .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .name = "Leadtek Winfast DV2000",
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .input = {{
- .type = CX88_VMUX_TELEVISION,
- .vmux = 0,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
.gpio0 = 0x0035e700,
.gpio1 = 0x00003004,
.gpio2 = 0x0035e700,
@@ -260,14 +260,14 @@ struct cx88_board cx88_boards[] = {
.gpio2 = 0x02000000,
.gpio3 = 0x02000000,
}},
- .radio = {
+ .radio = {
.type = CX88_RADIO,
.gpio0 = 0x0035d700,
.gpio1 = 0x00007004,
.gpio2 = 0x0035d700,
.gpio3 = 0x02000000,
},
- },
+ },
[CX88_BOARD_LEADTEK_PVR2000] = {
// gpio values for PAL version from regspy by DScaler
.name = "Leadtek PVR 2000",
@@ -296,25 +296,25 @@ struct cx88_board cx88_boards[] = {
.blackbird = 1,
},
[CX88_BOARD_IODATA_GVVCP3PCI] = {
- .name = "IODATA GV-VCP3/PCI",
+ .name = "IODATA GV-VCP3/PCI",
.tuner_type = TUNER_ABSENT,
- .radio_type = UNSET,
+ .radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.input = {{
- .type = CX88_VMUX_COMPOSITE1,
- .vmux = 0,
- },{
- .type = CX88_VMUX_COMPOSITE2,
- .vmux = 1,
- },{
- .type = CX88_VMUX_SVIDEO,
- .vmux = 2,
- }},
- },
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 0,
+ },{
+ .type = CX88_VMUX_COMPOSITE2,
+ .vmux = 1,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ }},
+ },
[CX88_BOARD_PROLINK_PLAYTVPVR] = {
- .name = "Prolink PlayTV PVR",
- .tuner_type = TUNER_PHILIPS_FM1236_MK3,
+ .name = "Prolink PlayTV PVR",
+ .tuner_type = TUNER_PHILIPS_FM1236_MK3,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
@@ -348,15 +348,15 @@ struct cx88_board cx88_boards[] = {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x0000fde6,
- },{
+ },{
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x0000fde6, // 0x0000fda6 L,R RCA audio in?
}},
- .radio = {
- .type = CX88_RADIO,
+ .radio = {
+ .type = CX88_RADIO,
.gpio0 = 0x0000fde2,
- },
+ },
.blackbird = 1,
},
[CX88_BOARD_MSI_TVANYWHERE] = {
@@ -372,34 +372,34 @@ struct cx88_board cx88_boards[] = {
.gpio0 = 0x00000fbf,
.gpio2 = 0x0000fc08,
},{
- .type = CX88_VMUX_COMPOSITE1,
- .vmux = 1,
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
.gpio0 = 0x00000fbf,
.gpio2 = 0x0000fc68,
},{
- .type = CX88_VMUX_SVIDEO,
- .vmux = 2,
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
.gpio0 = 0x00000fbf,
.gpio2 = 0x0000fc68,
- }},
+ }},
},
- [CX88_BOARD_KWORLD_DVB_T] = {
- .name = "KWorld/VStream XPert DVB-T",
+ [CX88_BOARD_KWORLD_DVB_T] = {
+ .name = "KWorld/VStream XPert DVB-T",
.tuner_type = TUNER_ABSENT,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
- .type = CX88_VMUX_COMPOSITE1,
- .vmux = 1,
+ .input = {{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
.gpio0 = 0x0700,
.gpio2 = 0x0101,
- },{
- .type = CX88_VMUX_SVIDEO,
- .vmux = 2,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
.gpio0 = 0x0700,
.gpio2 = 0x0101,
- }},
+ }},
.dvb = 1,
},
[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1] = {
@@ -425,27 +425,27 @@ struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
- .type = CX88_VMUX_TELEVISION,
- .vmux = 0,
- .gpio0 = 0x07f8,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x07f8,
},{
.type = CX88_VMUX_DEBUG,
.vmux = 0,
.gpio0 = 0x07f9, // mono from tuner chip
- },{
- .type = CX88_VMUX_COMPOSITE1,
- .vmux = 1,
- .gpio0 = 0x000007fa,
- },{
- .type = CX88_VMUX_SVIDEO,
- .vmux = 2,
- .gpio0 = 0x000007fa,
- }},
- .radio = {
- .type = CX88_RADIO,
- .gpio0 = 0x000007f8,
- },
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x000007fa,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x000007fa,
+ }},
+ .radio = {
+ .type = CX88_RADIO,
+ .gpio0 = 0x000007f8,
+ },
},
[CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q] = {
.name = "DViCO FusionHDTV 3 Gold-Q",
@@ -489,28 +489,28 @@ struct cx88_board cx88_boards[] = {
}},
.dvb = 1,
},
- [CX88_BOARD_HAUPPAUGE_DVB_T1] = {
+ [CX88_BOARD_HAUPPAUGE_DVB_T1] = {
.name = "Hauppauge Nova-T DVB-T",
.tuner_type = TUNER_ABSENT,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.input = {{
- .type = CX88_VMUX_DVB,
- .vmux = 0,
- }},
+ .type = CX88_VMUX_DVB,
+ .vmux = 0,
+ }},
.dvb = 1,
},
- [CX88_BOARD_CONEXANT_DVB_T1] = {
+ [CX88_BOARD_CONEXANT_DVB_T1] = {
.name = "Conexant DVB-T reference design",
.tuner_type = TUNER_ABSENT,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
- .type = CX88_VMUX_DVB,
- .vmux = 0,
- }},
+ .input = {{
+ .type = CX88_VMUX_DVB,
+ .vmux = 0,
+ }},
.dvb = 1,
},
[CX88_BOARD_PROVIDEO_PV259] = {
@@ -543,12 +543,12 @@ struct cx88_board cx88_boards[] = {
.dvb = 1,
},
[CX88_BOARD_DNTV_LIVE_DVB_T] = {
- .name = "digitalnow DNTV Live! DVB-T",
+ .name = "digitalnow DNTV Live! DVB-T",
.tuner_type = TUNER_ABSENT,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = {{
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x00000700,
@@ -705,44 +705,44 @@ struct cx88_board cx88_boards[] = {
.gpio0 = 0xbf60,
},
},
- [CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T] = {
+ [CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T] = {
.name = "DViCO FusionHDTV 3 Gold-T",
.tuner_type = TUNER_THOMSON_DTT7611,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.input = {{
- .type = CX88_VMUX_TELEVISION,
- .vmux = 0,
- .gpio0 = 0x97ed,
- },{
- .type = CX88_VMUX_COMPOSITE1,
- .vmux = 1,
- .gpio0 = 0x97e9,
- },{
- .type = CX88_VMUX_SVIDEO,
- .vmux = 2,
- .gpio0 = 0x97e9,
- }},
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x97ed,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x97e9,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x97e9,
+ }},
.dvb = 1,
- },
- [CX88_BOARD_ADSTECH_DVB_T_PCI] = {
- .name = "ADS Tech Instant TV DVB-T PCI",
+ },
+ [CX88_BOARD_ADSTECH_DVB_T_PCI] = {
+ .name = "ADS Tech Instant TV DVB-T PCI",
.tuner_type = TUNER_ABSENT,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.input = {{
- .type = CX88_VMUX_COMPOSITE1,
- .vmux = 1,
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
.gpio0 = 0x0700,
.gpio2 = 0x0101,
- },{
- .type = CX88_VMUX_SVIDEO,
- .vmux = 2,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
.gpio0 = 0x0700,
.gpio2 = 0x0101,
- }},
+ }},
.dvb = 1,
},
[CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1] = {
@@ -762,20 +762,139 @@ struct cx88_board cx88_boards[] = {
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.input = {{
- .type = CX88_VMUX_TELEVISION,
- .vmux = 0,
- .gpio0 = 0x87fd,
- },{
- .type = CX88_VMUX_COMPOSITE1,
- .vmux = 1,
- .gpio0 = 0x87f9,
- },{
- .type = CX88_VMUX_SVIDEO,
- .vmux = 2,
- .gpio0 = 0x87f9,
- }},
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x87fd,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x87f9,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x87f9,
+ }},
+ .dvb = 1,
+ },
+ [CX88_BOARD_AVERMEDIA_ULTRATV_MC_550] = {
+ .name = "AverMedia UltraTV Media Center PCI 550",
+ .tuner_type = TUNER_PHILIPS_FM1236_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .blackbird = 1,
+ .input = {{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 0,
+ .gpio0 = 0x0000cd73,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 1,
+ .gpio0 = 0x0000cd73,
+ },{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 3,
+ .gpio0 = 0x0000cdb3,
+ }},
+ .radio = {
+ .type = CX88_RADIO,
+ .vmux = 2,
+ .gpio0 = 0x0000cdf3,
+ },
+ },
+ [CX88_BOARD_KWORLD_VSTREAM_EXPERT_DVD] = {
+ /* Alexander Wold <awold@bigfoot.com> */
+ .name = "Kworld V-Stream Xpert DVD",
+ .tuner_type = UNSET,
+ .input = {{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x03000000,
+ .gpio1 = 0x01000000,
+ .gpio2 = 0x02000000,
+ .gpio3 = 0x00100000,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x03000000,
+ .gpio1 = 0x01000000,
+ .gpio2 = 0x02000000,
+ .gpio3 = 0x00100000,
+ }},
+ },
+ [CX88_BOARD_ATI_HDTVWONDER] = {
+ .name = "ATI HDTV Wonder",
+ .tuner_type = TUNER_PHILIPS_TUV1236D,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x00000ff7,
+ .gpio1 = 0x000000ff,
+ .gpio2 = 0x00000001,
+ .gpio3 = 0x00000000,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x00000ffe,
+ .gpio1 = 0x000000ff,
+ .gpio2 = 0x00000001,
+ .gpio3 = 0x00000000,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x00000ffe,
+ .gpio1 = 0x000000ff,
+ .gpio2 = 0x00000001,
+ .gpio3 = 0x00000000,
+ }},
.dvb = 1,
},
+ [CX88_BOARD_WINFAST_DTV1000] = {
+ .name = "WinFast DTV1000-T",
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .input = {{
+ .type = CX88_VMUX_DVB,
+ .vmux = 0,
+ }},
+ .dvb = 1,
+ },
+ [CX88_BOARD_AVERTV_303] = {
+ .name = "AVerTV 303 (M126)",
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x00ff,
+ .gpio1 = 0xe09f,
+ .gpio2 = 0x0010,
+ .gpio3 = 0x0000,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x00ff,
+ .gpio1 = 0xe05f,
+ .gpio2 = 0x0010,
+ .gpio3 = 0x0000,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x00ff,
+ .gpio1 = 0xe05f,
+ .gpio2 = 0x0010,
+ .gpio3 = 0x0000,
+ }},
+ },
};
const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
@@ -804,41 +923,41 @@ struct cx88_subid cx88_subids[] = {
.subdevice = 0x00f8,
.card = CX88_BOARD_ATI_WONDER_PRO,
},{
- .subvendor = 0x107d,
- .subdevice = 0x6611,
- .card = CX88_BOARD_WINFAST2000XP_EXPERT,
+ .subvendor = 0x107d,
+ .subdevice = 0x6611,
+ .card = CX88_BOARD_WINFAST2000XP_EXPERT,
+ },{
+ .subvendor = 0x107d,
+ .subdevice = 0x6613, /* NTSC */
+ .card = CX88_BOARD_WINFAST2000XP_EXPERT,
},{
- .subvendor = 0x107d,
- .subdevice = 0x6613, /* NTSC */
- .card = CX88_BOARD_WINFAST2000XP_EXPERT,
+ .subvendor = 0x107d,
+ .subdevice = 0x6620,
+ .card = CX88_BOARD_WINFAST_DV2000,
+ },{
+ .subvendor = 0x107d,
+ .subdevice = 0x663b,
+ .card = CX88_BOARD_LEADTEK_PVR2000,
},{
.subvendor = 0x107d,
- .subdevice = 0x6620,
- .card = CX88_BOARD_WINFAST_DV2000,
- },{
- .subvendor = 0x107d,
- .subdevice = 0x663b,
- .card = CX88_BOARD_LEADTEK_PVR2000,
- },{
- .subvendor = 0x107d,
- .subdevice = 0x663C,
- .card = CX88_BOARD_LEADTEK_PVR2000,
- },{
+ .subdevice = 0x663C,
+ .card = CX88_BOARD_LEADTEK_PVR2000,
+ },{
.subvendor = 0x1461,
.subdevice = 0x000b,
- .card = CX88_BOARD_AVERTV_303,
+ .card = CX88_BOARD_AVERTV_STUDIO_303,
},{
.subvendor = 0x1462,
.subdevice = 0x8606,
.card = CX88_BOARD_MSI_TVANYWHERE_MASTER,
},{
- .subvendor = 0x10fc,
- .subdevice = 0xd003,
- .card = CX88_BOARD_IODATA_GVVCP3PCI,
+ .subvendor = 0x10fc,
+ .subdevice = 0xd003,
+ .card = CX88_BOARD_IODATA_GVVCP3PCI,
},{
- .subvendor = 0x1043,
- .subdevice = 0x4823, /* with mpeg encoder */
- .card = CX88_BOARD_ASUS_PVR_416,
+ .subvendor = 0x1043,
+ .subdevice = 0x4823, /* with mpeg encoder */
+ .card = CX88_BOARD_ASUS_PVR_416,
},{
.subvendor = 0x17de,
.subdevice = 0x08a6,
@@ -852,43 +971,43 @@ struct cx88_subid cx88_subids[] = {
.subdevice = 0xd820,
.card = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T,
},{
- .subvendor = 0x18AC,
- .subdevice = 0xDB00,
+ .subvendor = 0x18ac,
+ .subdevice = 0xdb00,
.card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1,
- },{
+ },{
.subvendor = 0x0070,
.subdevice = 0x9002,
.card = CX88_BOARD_HAUPPAUGE_DVB_T1,
- },{
+ },{
.subvendor = 0x14f1,
.subdevice = 0x0187,
.card = CX88_BOARD_CONEXANT_DVB_T1,
- },{
+ },{
.subvendor = 0x1540,
.subdevice = 0x2580,
.card = CX88_BOARD_PROVIDEO_PV259,
},{
- .subvendor = 0x18AC,
- .subdevice = 0xDB10,
+ .subvendor = 0x18ac,
+ .subdevice = 0xdb10,
.card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS,
},{
- .subvendor = 0x1554,
- .subdevice = 0x4811,
- .card = CX88_BOARD_PIXELVIEW,
+ .subvendor = 0x1554,
+ .subdevice = 0x4811,
+ .card = CX88_BOARD_PIXELVIEW,
},{
.subvendor = 0x7063,
.subdevice = 0x3000, /* HD-3000 card */
.card = CX88_BOARD_PCHDTV_HD3000,
},{
- .subvendor = 0x17DE,
- .subdevice = 0xA8A6,
+ .subvendor = 0x17de,
+ .subdevice = 0xa8a6,
.card = CX88_BOARD_DNTV_LIVE_DVB_T,
},{
.subvendor = 0x0070,
.subdevice = 0x2801,
.card = CX88_BOARD_HAUPPAUGE_ROSLYN,
},{
- .subvendor = 0x14F1,
+ .subvendor = 0x14f1,
.subdevice = 0x0342,
.card = CX88_BOARD_DIGITALLOGIC_MEC,
},{
@@ -899,14 +1018,30 @@ struct cx88_subid cx88_subids[] = {
.subvendor = 0x1421,
.subdevice = 0x0334,
.card = CX88_BOARD_ADSTECH_DVB_T_PCI,
- },{
+ },{
.subvendor = 0x153b,
.subdevice = 0x1166,
.card = CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1,
- },{
+ },{
.subvendor = 0x18ac,
.subdevice = 0xd500,
.card = CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD,
+ },{
+ .subvendor = 0x1461,
+ .subdevice = 0x8011,
+ .card = CX88_BOARD_AVERMEDIA_ULTRATV_MC_550,
+ },{
+ .subvendor = PCI_VENDOR_ID_ATI,
+ .subdevice = 0xa101,
+ .card = CX88_BOARD_ATI_HDTVWONDER,
+ },{
+ .subvendor = 0x107d,
+ .subdevice = 0x665f,
+ .card = CX88_BOARD_WINFAST_DTV1000,
+ },{
+ .subvendor = 0x1461,
+ .subdevice = 0x000a,
+ .card = CX88_BOARD_AVERTV_303,
},
};
const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
@@ -1108,6 +1243,19 @@ void cx88_card_setup(struct cx88_core *core)
cx_clear(MO_GP0_IO, 0x00000007);
cx_set(MO_GP2_IO, 0x00000101);
break;
+ case CX88_BOARD_ATI_HDTVWONDER:
+ if (0 == core->i2c_rc) {
+ /* enable tuner */
+ int i;
+ u8 buffer [] = { 0x10,0x12,0x13,0x04,0x16,0x00,0x14,0x04,0x017,0x00 };
+ core->i2c_client.addr = 0x0a;
+
+ for (i = 0; i < 5; i++)
+ if (2 != i2c_master_send(&core->i2c_client,&buffer[i*2],2))
+ printk(KERN_WARNING "%s: Unable to enable tuner(%i).\n",
+ core->name, i);
+ }
+ break;
}
if (cx88_boards[core->board].radio.type == CX88_RADIO)
core->has_radio = 1;
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
index dc5c5c1f346..eb806af1718 100644
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -31,7 +31,7 @@
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/delay.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
#include "cx88.h"
@@ -153,26 +153,26 @@ static u32* cx88_risc_field(u32 *rp, struct scatterlist *sglist,
}
if (bpl <= sg_dma_len(sg)-offset) {
/* fits into current chunk */
- *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl);
- *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
- offset+=bpl;
+ *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl);
+ *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
+ offset+=bpl;
} else {
/* scanline needs to be splitted */
- todo = bpl;
- *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|
+ todo = bpl;
+ *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|
(sg_dma_len(sg)-offset));
- *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
- todo -= (sg_dma_len(sg)-offset);
- offset = 0;
- sg++;
- while (todo > sg_dma_len(sg)) {
- *(rp++)=cpu_to_le32(RISC_WRITE|
+ *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
+ todo -= (sg_dma_len(sg)-offset);
+ offset = 0;
+ sg++;
+ while (todo > sg_dma_len(sg)) {
+ *(rp++)=cpu_to_le32(RISC_WRITE|
sg_dma_len(sg));
- *(rp++)=cpu_to_le32(sg_dma_address(sg));
+ *(rp++)=cpu_to_le32(sg_dma_address(sg));
todo -= sg_dma_len(sg);
sg++;
}
- *(rp++)=cpu_to_le32(RISC_WRITE|RISC_EOL|todo);
+ *(rp++)=cpu_to_le32(RISC_WRITE|RISC_EOL|todo);
*(rp++)=cpu_to_le32(sg_dma_address(sg));
offset += todo;
}
@@ -309,7 +309,7 @@ struct sram_channel cx88_sram_channels[] = {
.name = "video y / packed",
.cmds_start = 0x180040,
.ctrl_start = 0x180400,
- .cdt = 0x180400 + 64,
+ .cdt = 0x180400 + 64,
.fifo_start = 0x180c00,
.fifo_size = 0x002800,
.ptr1_reg = MO_DMA21_PTR1,
@@ -321,7 +321,7 @@ struct sram_channel cx88_sram_channels[] = {
.name = "video u",
.cmds_start = 0x180080,
.ctrl_start = 0x1804a0,
- .cdt = 0x1804a0 + 64,
+ .cdt = 0x1804a0 + 64,
.fifo_start = 0x183400,
.fifo_size = 0x000800,
.ptr1_reg = MO_DMA22_PTR1,
@@ -333,7 +333,7 @@ struct sram_channel cx88_sram_channels[] = {
.name = "video v",
.cmds_start = 0x1800c0,
.ctrl_start = 0x180540,
- .cdt = 0x180540 + 64,
+ .cdt = 0x180540 + 64,
.fifo_start = 0x183c00,
.fifo_size = 0x000800,
.ptr1_reg = MO_DMA23_PTR1,
@@ -345,7 +345,7 @@ struct sram_channel cx88_sram_channels[] = {
.name = "vbi",
.cmds_start = 0x180100,
.ctrl_start = 0x1805e0,
- .cdt = 0x1805e0 + 64,
+ .cdt = 0x1805e0 + 64,
.fifo_start = 0x184400,
.fifo_size = 0x001000,
.ptr1_reg = MO_DMA24_PTR1,
@@ -357,7 +357,7 @@ struct sram_channel cx88_sram_channels[] = {
.name = "audio from",
.cmds_start = 0x180140,
.ctrl_start = 0x180680,
- .cdt = 0x180680 + 64,
+ .cdt = 0x180680 + 64,
.fifo_start = 0x185400,
.fifo_size = 0x000200,
.ptr1_reg = MO_DMA25_PTR1,
@@ -369,7 +369,7 @@ struct sram_channel cx88_sram_channels[] = {
.name = "audio to",
.cmds_start = 0x180180,
.ctrl_start = 0x180720,
- .cdt = 0x180680 + 64, /* same as audio IN */
+ .cdt = 0x180680 + 64, /* same as audio IN */
.fifo_start = 0x185400, /* same as audio IN */
.fifo_size = 0x000200, /* same as audio IN */
.ptr1_reg = MO_DMA26_PTR1,
@@ -431,7 +431,7 @@ int cx88_sram_channel_setup(struct cx88_core *core,
/* ------------------------------------------------------------------ */
/* debug helper code */
-int cx88_risc_decode(u32 risc)
+static int cx88_risc_decode(u32 risc)
{
static char *instr[16] = {
[ RISC_SYNC >> 28 ] = "sync",
@@ -845,19 +845,19 @@ static int set_tvaudio(struct cx88_core *core)
return 0;
if (V4L2_STD_PAL_BG & norm->id) {
- core->tvaudio = nicam ? WW_NICAM_BGDKL : WW_A2_BG;
+ core->tvaudio = WW_BG;
} else if (V4L2_STD_PAL_DK & norm->id) {
- core->tvaudio = nicam ? WW_NICAM_BGDKL : WW_A2_DK;
+ core->tvaudio = WW_DK;
} else if (V4L2_STD_PAL_I & norm->id) {
- core->tvaudio = WW_NICAM_I;
+ core->tvaudio = WW_I;
} else if (V4L2_STD_SECAM_L & norm->id) {
- core->tvaudio = WW_SYSTEM_L_AM;
+ core->tvaudio = WW_L;
} else if (V4L2_STD_SECAM_DK & norm->id) {
- core->tvaudio = WW_A2_DK;
+ core->tvaudio = WW_DK;
} else if ((V4L2_STD_NTSC_M & norm->id) ||
(V4L2_STD_PAL_M & norm->id)) {
@@ -1137,7 +1137,7 @@ struct cx88_core* cx88_core_get(struct pci_dev *pci)
if (!core->radio_addr)
core->radio_addr = cx88_boards[core->board].radio_addr;
- printk(KERN_INFO "TV tuner %d at 0x%02x, Radio tuner %d at 0x%02x\n",
+ printk(KERN_INFO "TV tuner %d at 0x%02x, Radio tuner %d at 0x%02x\n",
core->tuner_type, core->tuner_addr<<1,
core->radio_type, core->radio_addr<<1);
@@ -1146,6 +1146,7 @@ struct cx88_core* cx88_core_get(struct pci_dev *pci)
/* init hardware */
cx88_reset(core);
cx88_i2c_init(core,pci);
+ cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL);
cx88_card_setup(core);
cx88_ir_init(core,pci);
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index 4334744652d..99ea955f598 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -29,7 +29,6 @@
#include <linux/file.h>
#include <linux/suspend.h>
-
#include "cx88.h"
#include "dvb-pll.h"
@@ -46,6 +45,9 @@
#ifdef HAVE_LGDT330X
# include "lgdt330x.h"
#endif
+#ifdef HAVE_NXT200X
+# include "nxt200x.h"
+#endif
MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
@@ -78,7 +80,7 @@ static int dvb_buf_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
enum v4l2_field field)
{
struct cx8802_dev *dev = q->priv_data;
- return cx8802_buf_prepare(dev, (struct cx88_buffer*)vb);
+ return cx8802_buf_prepare(dev, (struct cx88_buffer*)vb,field);
}
static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
@@ -129,7 +131,7 @@ static int dntv_live_dvbt_demod_init(struct dvb_frontend* fe)
static u8 reset [] = { 0x50, 0x80 };
static u8 adc_ctl_1_cfg [] = { 0x8E, 0x40 };
static u8 agc_cfg [] = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF,
- 0x00, 0xFF, 0x00, 0x40, 0x40 };
+ 0x00, 0xFF, 0x00, 0x40, 0x40 };
static u8 dntv_extra[] = { 0xB5, 0x7A };
static u8 capt_range_cfg[] = { 0x75, 0x32 };
@@ -285,6 +287,33 @@ static struct lgdt330x_config fusionhdtv_5_gold = {
};
#endif
+#ifdef HAVE_NXT200X
+static int nxt200x_set_ts_param(struct dvb_frontend* fe,
+ int is_punctured)
+{
+ struct cx8802_dev *dev= fe->dvb->priv;
+ dev->ts_gen_cntrl = is_punctured ? 0x04 : 0x00;
+ return 0;
+}
+
+static int nxt200x_set_pll_input(u8* buf, int input)
+{
+ if (input)
+ buf[3] |= 0x08;
+ else
+ buf[3] &= ~0x08;
+ return 0;
+}
+
+static struct nxt200x_config ati_hdtvwonder = {
+ .demod_address = 0x0a,
+ .pll_address = 0x61,
+ .pll_desc = &dvb_pll_tuv1236d,
+ .set_pll_input = nxt200x_set_pll_input,
+ .set_ts_params = nxt200x_set_ts_param,
+};
+#endif
+
static int dvb_register(struct cx8802_dev *dev)
{
/* init struct videobuf_dvb */
@@ -300,6 +329,7 @@ static int dvb_register(struct cx8802_dev *dev)
break;
case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
case CX88_BOARD_CONEXANT_DVB_T1:
+ case CX88_BOARD_WINFAST_DTV1000:
dev->dvb.frontend = cx22702_attach(&connexant_refboard_config,
&dev->core->i2c_adap);
break;
@@ -385,6 +415,12 @@ static int dvb_register(struct cx8802_dev *dev)
}
break;
#endif
+#ifdef HAVE_NXT200X
+ case CX88_BOARD_ATI_HDTVWONDER:
+ dev->dvb.frontend = nxt200x_attach(&ati_hdtvwonder,
+ &dev->core->i2c_adap);
+ break;
+#endif
default:
printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
dev->core->name);
@@ -461,7 +497,7 @@ static int __devinit dvb_probe(struct pci_dev *pci_dev,
static void __devexit dvb_remove(struct pci_dev *pci_dev)
{
- struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
+ struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
/* dvb */
videobuf_dvb_unregister(&dev->dvb);
@@ -476,8 +512,8 @@ static struct pci_device_id cx8802_pci_tbl[] = {
{
.vendor = 0x14f1,
.device = 0x8802,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
},{
/* --- end of list --- */
}
@@ -485,10 +521,10 @@ static struct pci_device_id cx8802_pci_tbl[] = {
MODULE_DEVICE_TABLE(pci, cx8802_pci_tbl);
static struct pci_driver dvb_pci_driver = {
- .name = "cx88-dvb",
- .id_table = cx8802_pci_tbl,
- .probe = dvb_probe,
- .remove = __devexit_p(dvb_remove),
+ .name = "cx88-dvb",
+ .id_table = cx8802_pci_tbl,
+ .probe = dvb_probe,
+ .remove = __devexit_p(dvb_remove),
.suspend = cx8802_suspend_common,
.resume = cx8802_resume_common,
};
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index 761cebd40db..9790d412f19 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -3,7 +3,7 @@
cx88-i2c.c -- all the i2c code is here
Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
- & Marcus Metzler (mocm@thp.uni-koeln.de)
+ & Marcus Metzler (mocm@thp.uni-koeln.de)
(c) 2002 Yurij Sysoev <yurij@naturesoft.net>
(c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
@@ -90,7 +90,7 @@ static int cx8800_bit_getsda(void *data)
static int attach_inform(struct i2c_client *client)
{
- struct tuner_setup tun_setup;
+ struct tuner_setup tun_setup;
struct cx88_core *core = i2c_get_adapdata(client->adapter);
dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
@@ -98,7 +98,7 @@ static int attach_inform(struct i2c_client *client)
if (!client->driver->command)
return 0;
- if (core->radio_type != UNSET) {
+ if (core->radio_type != UNSET) {
if ((core->radio_addr==ADDR_UNSET)||(core->radio_addr==client->addr)) {
tun_setup.mode_mask = T_RADIO;
tun_setup.type = core->radio_type;
@@ -106,8 +106,8 @@ static int attach_inform(struct i2c_client *client)
client->driver->command (client, TUNER_SET_TYPE_ADDR, &tun_setup);
}
- }
- if (core->tuner_type != UNSET) {
+ }
+ if (core->tuner_type != UNSET) {
if ((core->tuner_addr==ADDR_UNSET)||(core->tuner_addr==client->addr)) {
tun_setup.mode_mask = T_ANALOG_TV;
@@ -116,7 +116,7 @@ static int attach_inform(struct i2c_client *client)
client->driver->command (client,TUNER_SET_TYPE_ADDR, &tun_setup);
}
- }
+ }
if (core->tda9887_conf)
client->driver->command(client, TDA9887_SET_CONFIG, &core->tda9887_conf);
@@ -159,7 +159,7 @@ static struct i2c_adapter cx8800_i2c_adap_template = {
};
static struct i2c_client cx8800_i2c_client_template = {
- .name = "cx88xx internal",
+ .name = "cx88xx internal",
};
static char *i2c_devs[128] = {
@@ -202,10 +202,10 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
core->i2c_adap.dev.parent = &pci->dev;
strlcpy(core->i2c_adap.name,core->name,sizeof(core->i2c_adap.name));
- core->i2c_algo.data = core;
- i2c_set_adapdata(&core->i2c_adap,core);
- core->i2c_adap.algo_data = &core->i2c_algo;
- core->i2c_client.adapter = &core->i2c_adap;
+ core->i2c_algo.data = core;
+ i2c_set_adapdata(&core->i2c_adap,core);
+ core->i2c_adap.algo_data = &core->i2c_algo;
+ core->i2c_client.adapter = &core->i2c_adap;
cx8800_bit_setscl(core,1);
cx8800_bit_setsda(core,1);
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index c27fe4c36f6..38b12ebaa49 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -553,7 +553,7 @@ void cx88_ir_irq(struct cx88_core *core)
if ((ircode & 0xffff) != 0xeb04) { /* wrong address */
ir_dprintk("pulse distance decoded wrong address\n");
- break;
+ break;
}
if (((~ircode >> 24) & 0xff) != ((ircode >> 16) & 0xff)) { /* wrong checksum */
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index ee2300e1ae0..35e6d0c2b87 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -54,7 +54,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
{
struct cx88_core *core = dev->core;
- dprintk(0, "cx8802_start_dma %d\n", buf->vb.width);
+ dprintk(0, "cx8802_start_dma w: %d, h: %d, f: %d\n", dev->width, dev->height, buf->vb.field);
/* setup fifo + format */
cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28],
@@ -158,7 +158,8 @@ static int cx8802_restart_queue(struct cx8802_dev *dev,
/* ------------------------------------------------------------------ */
-int cx8802_buf_prepare(struct cx8802_dev *dev, struct cx88_buffer *buf)
+int cx8802_buf_prepare(struct cx8802_dev *dev, struct cx88_buffer *buf,
+ enum v4l2_field field)
{
int size = dev->ts_packet_size * dev->ts_packet_count;
int rc;
@@ -171,7 +172,7 @@ int cx8802_buf_prepare(struct cx8802_dev *dev, struct cx88_buffer *buf)
buf->vb.width = dev->ts_packet_size;
buf->vb.height = dev->ts_packet_count;
buf->vb.size = size;
- buf->vb.field = V4L2_FIELD_TOP;
+ buf->vb.field = field /*V4L2_FIELD_TOP*/;
if (0 != (rc = videobuf_iolock(dev->pci,&buf->vb,NULL)))
goto fail;
@@ -315,14 +316,14 @@ static void cx8802_mpeg_irq(struct cx8802_dev *dev)
spin_unlock(&dev->slock);
}
- /* other general errors */
- if (status & 0x1f0100) {
+ /* other general errors */
+ if (status & 0x1f0100) {
dprintk( 0, "general errors: 0x%08x\n", status & 0x1f0100 );
- spin_lock(&dev->slock);
+ spin_lock(&dev->slock);
cx8802_stop_dma(dev);
- cx8802_restart_queue(dev,&dev->mpegq);
- spin_unlock(&dev->slock);
- }
+ cx8802_restart_queue(dev,&dev->mpegq);
+ spin_unlock(&dev->slock);
+ }
}
#define MAX_IRQ_LOOP 10
@@ -378,8 +379,8 @@ int cx8802_init_common(struct cx8802_dev *dev)
}
pci_read_config_byte(dev->pci, PCI_CLASS_REVISION, &dev->pci_rev);
- pci_read_config_byte(dev->pci, PCI_LATENCY_TIMER, &dev->pci_lat);
- printk(KERN_INFO "%s/2: found at %s, rev: %d, irq: %d, "
+ pci_read_config_byte(dev->pci, PCI_LATENCY_TIMER, &dev->pci_lat);
+ printk(KERN_INFO "%s/2: found at %s, rev: %d, irq: %d, "
"latency: %d, mmio: 0x%lx\n", dev->core->name,
pci_name(dev->pci), dev->pci_rev, dev->pci->irq,
dev->pci_lat,pci_resource_start(dev->pci,0));
@@ -429,7 +430,7 @@ void cx8802_fini_common(struct cx8802_dev *dev)
int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state)
{
- struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
+ struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
struct cx88_core *core = dev->core;
/* stop mpeg dma */
diff --git a/drivers/media/video/cx88/cx88-reg.h b/drivers/media/video/cx88/cx88-reg.h
index 0a3a62fc9bb..d3bf5b17b1d 100644
--- a/drivers/media/video/cx88/cx88-reg.h
+++ b/drivers/media/video/cx88/cx88-reg.h
@@ -3,9 +3,9 @@
cx88x-hw.h - CX2388x register offsets
Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
- 2001 Michael Eskin
- 2002 Yurij Sysoev <yurij@naturesoft.net>
- 2003 Gerd Knorr <kraxel@bytesex.org>
+ 2001 Michael Eskin
+ 2002 Yurij Sysoev <yurij@naturesoft.net>
+ 2003 Gerd Knorr <kraxel@bytesex.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -728,13 +728,13 @@
#define ColorFormatGamma 0x1000
#define Interlaced 0x1
-#define NonInterlaced 0x0
+#define NonInterlaced 0x0
#define FieldEven 0x1
#define FieldOdd 0x0
-#define TGReadWriteMode 0x0
-#define TGEnableMode 0x1
+#define TGReadWriteMode 0x0
+#define TGEnableMode 0x1
#define DV_CbAlign 0x0
#define DV_Y0Align 0x1
diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c
index 2765acee028..6d9bec1c583 100644
--- a/drivers/media/video/cx88/cx88-tvaudio.c
+++ b/drivers/media/video/cx88/cx88-tvaudio.c
@@ -57,39 +57,38 @@
#include "cx88.h"
static unsigned int audio_debug = 0;
-module_param(audio_debug,int,0644);
-MODULE_PARM_DESC(audio_debug,"enable debug messages [audio]");
+module_param(audio_debug, int, 0644);
+MODULE_PARM_DESC(audio_debug, "enable debug messages [audio]");
#define dprintk(fmt, arg...) if (audio_debug) \
printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg)
/* ----------------------------------------------------------- */
-static char *aud_ctl_names[64] =
-{
- [ EN_BTSC_FORCE_MONO ] = "BTSC_FORCE_MONO",
- [ EN_BTSC_FORCE_STEREO ] = "BTSC_FORCE_STEREO",
- [ EN_BTSC_FORCE_SAP ] = "BTSC_FORCE_SAP",
- [ EN_BTSC_AUTO_STEREO ] = "BTSC_AUTO_STEREO",
- [ EN_BTSC_AUTO_SAP ] = "BTSC_AUTO_SAP",
- [ EN_A2_FORCE_MONO1 ] = "A2_FORCE_MONO1",
- [ EN_A2_FORCE_MONO2 ] = "A2_FORCE_MONO2",
- [ EN_A2_FORCE_STEREO ] = "A2_FORCE_STEREO",
- [ EN_A2_AUTO_MONO2 ] = "A2_AUTO_MONO2",
- [ EN_A2_AUTO_STEREO ] = "A2_AUTO_STEREO",
- [ EN_EIAJ_FORCE_MONO1 ] = "EIAJ_FORCE_MONO1",
- [ EN_EIAJ_FORCE_MONO2 ] = "EIAJ_FORCE_MONO2",
- [ EN_EIAJ_FORCE_STEREO ] = "EIAJ_FORCE_STEREO",
- [ EN_EIAJ_AUTO_MONO2 ] = "EIAJ_AUTO_MONO2",
- [ EN_EIAJ_AUTO_STEREO ] = "EIAJ_AUTO_STEREO",
- [ EN_NICAM_FORCE_MONO1 ] = "NICAM_FORCE_MONO1",
- [ EN_NICAM_FORCE_MONO2 ] = "NICAM_FORCE_MONO2",
- [ EN_NICAM_FORCE_STEREO ] = "NICAM_FORCE_STEREO",
- [ EN_NICAM_AUTO_MONO2 ] = "NICAM_AUTO_MONO2",
- [ EN_NICAM_AUTO_STEREO ] = "NICAM_AUTO_STEREO",
- [ EN_FMRADIO_FORCE_MONO ] = "FMRADIO_FORCE_MONO",
- [ EN_FMRADIO_FORCE_STEREO ] = "FMRADIO_FORCE_STEREO",
- [ EN_FMRADIO_AUTO_STEREO ] = "FMRADIO_AUTO_STEREO",
+static char *aud_ctl_names[64] = {
+ [EN_BTSC_FORCE_MONO] = "BTSC_FORCE_MONO",
+ [EN_BTSC_FORCE_STEREO] = "BTSC_FORCE_STEREO",
+ [EN_BTSC_FORCE_SAP] = "BTSC_FORCE_SAP",
+ [EN_BTSC_AUTO_STEREO] = "BTSC_AUTO_STEREO",
+ [EN_BTSC_AUTO_SAP] = "BTSC_AUTO_SAP",
+ [EN_A2_FORCE_MONO1] = "A2_FORCE_MONO1",
+ [EN_A2_FORCE_MONO2] = "A2_FORCE_MONO2",
+ [EN_A2_FORCE_STEREO] = "A2_FORCE_STEREO",
+ [EN_A2_AUTO_MONO2] = "A2_AUTO_MONO2",
+ [EN_A2_AUTO_STEREO] = "A2_AUTO_STEREO",
+ [EN_EIAJ_FORCE_MONO1] = "EIAJ_FORCE_MONO1",
+ [EN_EIAJ_FORCE_MONO2] = "EIAJ_FORCE_MONO2",
+ [EN_EIAJ_FORCE_STEREO] = "EIAJ_FORCE_STEREO",
+ [EN_EIAJ_AUTO_MONO2] = "EIAJ_AUTO_MONO2",
+ [EN_EIAJ_AUTO_STEREO] = "EIAJ_AUTO_STEREO",
+ [EN_NICAM_FORCE_MONO1] = "NICAM_FORCE_MONO1",
+ [EN_NICAM_FORCE_MONO2] = "NICAM_FORCE_MONO2",
+ [EN_NICAM_FORCE_STEREO] = "NICAM_FORCE_STEREO",
+ [EN_NICAM_AUTO_MONO2] = "NICAM_AUTO_MONO2",
+ [EN_NICAM_AUTO_STEREO] = "NICAM_AUTO_STEREO",
+ [EN_FMRADIO_FORCE_MONO] = "FMRADIO_FORCE_MONO",
+ [EN_FMRADIO_FORCE_STEREO] = "FMRADIO_FORCE_STEREO",
+ [EN_FMRADIO_AUTO_STEREO] = "FMRADIO_AUTO_STEREO",
};
struct rlist {
@@ -97,8 +96,7 @@ struct rlist {
u32 val;
};
-static void set_audio_registers(struct cx88_core *core,
- const struct rlist *l)
+static void set_audio_registers(struct cx88_core *core, const struct rlist *l)
{
int i;
@@ -119,17 +117,18 @@ static void set_audio_registers(struct cx88_core *core,
}
}
-static void set_audio_start(struct cx88_core *core,
- u32 mode)
+static void set_audio_start(struct cx88_core *core, u32 mode)
{
// mute
- cx_write(AUD_VOL_CTL, (1 << 6));
+ cx_write(AUD_VOL_CTL, (1 << 6));
// start programming
- cx_write(AUD_CTL, 0x0000);
- cx_write(AUD_INIT, mode);
- cx_write(AUD_INIT_LD, 0x0001);
- cx_write(AUD_SOFT_RESET, 0x0001);
+ cx_write(MO_AUD_DMACNTRL, 0x0000);
+ msleep(100);
+ //cx_write(AUD_CTL, 0x0000);
+ cx_write(AUD_INIT, mode);
+ cx_write(AUD_INIT_LD, 0x0001);
+ cx_write(AUD_SOFT_RESET, 0x0001);
}
static void set_audio_finish(struct cx88_core *core, u32 ctl)
@@ -148,12 +147,13 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl)
cx_write(AUD_I2SCNTL, 0);
//cx_write(AUD_APB_IN_RATE_ADJ, 0);
} else {
- ctl |= EN_DAC_ENABLE;
- cx_write(AUD_CTL, ctl);
+ ctl |= EN_DAC_ENABLE;
+ cx_write(AUD_CTL, ctl);
}
/* finish programming */
cx_write(AUD_SOFT_RESET, 0x0000);
+ cx_write(MO_AUD_DMACNTRL, 0x0003);
/* unmute */
volume = cx_sread(SHADOW_AUD_VOL_CTL);
@@ -162,486 +162,463 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl)
/* ----------------------------------------------------------- */
-static void set_audio_standard_BTSC(struct cx88_core *core, unsigned int sap, u32 mode)
+static void set_audio_standard_BTSC(struct cx88_core *core, unsigned int sap,
+ u32 mode)
{
static const struct rlist btsc[] = {
- { AUD_AFE_12DB_EN, 0x00000001 },
- { AUD_OUT1_SEL, 0x00000013 },
- { AUD_OUT1_SHIFT, 0x00000000 },
- { AUD_POLY0_DDS_CONSTANT, 0x0012010c },
- { AUD_DMD_RA_DDS, 0x00c3e7aa },
- { AUD_DBX_IN_GAIN, 0x00004734 },
- { AUD_DBX_WBE_GAIN, 0x00004640 },
- { AUD_DBX_SE_GAIN, 0x00008d31 },
- { AUD_DCOC_0_SRC, 0x0000001a },
- { AUD_IIR1_4_SEL, 0x00000021 },
- { AUD_DCOC_PASS_IN, 0x00000003 },
- { AUD_DCOC_0_SHIFT_IN0, 0x0000000a },
- { AUD_DCOC_0_SHIFT_IN1, 0x00000008 },
- { AUD_DCOC_1_SHIFT_IN0, 0x0000000a },
- { AUD_DCOC_1_SHIFT_IN1, 0x00000008 },
- { AUD_DN0_FREQ, 0x0000283b },
- { AUD_DN2_SRC_SEL, 0x00000008 },
- { AUD_DN2_FREQ, 0x00003000 },
- { AUD_DN2_AFC, 0x00000002 },
- { AUD_DN2_SHFT, 0x00000000 },
- { AUD_IIR2_2_SEL, 0x00000020 },
- { AUD_IIR2_2_SHIFT, 0x00000000 },
- { AUD_IIR2_3_SEL, 0x0000001f },
- { AUD_IIR2_3_SHIFT, 0x00000000 },
- { AUD_CRDC1_SRC_SEL, 0x000003ce },
- { AUD_CRDC1_SHIFT, 0x00000000 },
- { AUD_CORDIC_SHIFT_1, 0x00000007 },
- { AUD_DCOC_1_SRC, 0x0000001b },
- { AUD_DCOC1_SHIFT, 0x00000000 },
- { AUD_RDSI_SEL, 0x00000008 },
- { AUD_RDSQ_SEL, 0x00000008 },
- { AUD_RDSI_SHIFT, 0x00000000 },
- { AUD_RDSQ_SHIFT, 0x00000000 },
- { AUD_POLYPH80SCALEFAC, 0x00000003 },
+ {AUD_AFE_12DB_EN, 0x00000001},
+ {AUD_OUT1_SEL, 0x00000013},
+ {AUD_OUT1_SHIFT, 0x00000000},
+ {AUD_POLY0_DDS_CONSTANT, 0x0012010c},
+ {AUD_DMD_RA_DDS, 0x00c3e7aa},
+ {AUD_DBX_IN_GAIN, 0x00004734},
+ {AUD_DBX_WBE_GAIN, 0x00004640},
+ {AUD_DBX_SE_GAIN, 0x00008d31},
+ {AUD_DCOC_0_SRC, 0x0000001a},
+ {AUD_IIR1_4_SEL, 0x00000021},
+ {AUD_DCOC_PASS_IN, 0x00000003},
+ {AUD_DCOC_0_SHIFT_IN0, 0x0000000a},
+ {AUD_DCOC_0_SHIFT_IN1, 0x00000008},
+ {AUD_DCOC_1_SHIFT_IN0, 0x0000000a},
+ {AUD_DCOC_1_SHIFT_IN1, 0x00000008},
+ {AUD_DN0_FREQ, 0x0000283b},
+ {AUD_DN2_SRC_SEL, 0x00000008},
+ {AUD_DN2_FREQ, 0x00003000},
+ {AUD_DN2_AFC, 0x00000002},
+ {AUD_DN2_SHFT, 0x00000000},
+ {AUD_IIR2_2_SEL, 0x00000020},
+ {AUD_IIR2_2_SHIFT, 0x00000000},
+ {AUD_IIR2_3_SEL, 0x0000001f},
+ {AUD_IIR2_3_SHIFT, 0x00000000},
+ {AUD_CRDC1_SRC_SEL, 0x000003ce},
+ {AUD_CRDC1_SHIFT, 0x00000000},
+ {AUD_CORDIC_SHIFT_1, 0x00000007},
+ {AUD_DCOC_1_SRC, 0x0000001b},
+ {AUD_DCOC1_SHIFT, 0x00000000},
+ {AUD_RDSI_SEL, 0x00000008},
+ {AUD_RDSQ_SEL, 0x00000008},
+ {AUD_RDSI_SHIFT, 0x00000000},
+ {AUD_RDSQ_SHIFT, 0x00000000},
+ {AUD_POLYPH80SCALEFAC, 0x00000003},
{ /* end of list */ },
};
static const struct rlist btsc_sap[] = {
- { AUD_AFE_12DB_EN, 0x00000001 },
- { AUD_DBX_IN_GAIN, 0x00007200 },
- { AUD_DBX_WBE_GAIN, 0x00006200 },
- { AUD_DBX_SE_GAIN, 0x00006200 },
- { AUD_IIR1_1_SEL, 0x00000000 },
- { AUD_IIR1_3_SEL, 0x00000001 },
- { AUD_DN1_SRC_SEL, 0x00000007 },
- { AUD_IIR1_4_SHIFT, 0x00000006 },
- { AUD_IIR2_1_SHIFT, 0x00000000 },
- { AUD_IIR2_2_SHIFT, 0x00000000 },
- { AUD_IIR3_0_SHIFT, 0x00000000 },
- { AUD_IIR3_1_SHIFT, 0x00000000 },
- { AUD_IIR3_0_SEL, 0x0000000d },
- { AUD_IIR3_1_SEL, 0x0000000e },
- { AUD_DEEMPH1_SRC_SEL, 0x00000014 },
- { AUD_DEEMPH1_SHIFT, 0x00000000 },
- { AUD_DEEMPH1_G0, 0x00004000 },
- { AUD_DEEMPH1_A0, 0x00000000 },
- { AUD_DEEMPH1_B0, 0x00000000 },
- { AUD_DEEMPH1_A1, 0x00000000 },
- { AUD_DEEMPH1_B1, 0x00000000 },
- { AUD_OUT0_SEL, 0x0000003f },
- { AUD_OUT1_SEL, 0x0000003f },
- { AUD_DN1_AFC, 0x00000002 },
- { AUD_DCOC_0_SHIFT_IN0, 0x0000000a },
- { AUD_DCOC_0_SHIFT_IN1, 0x00000008 },
- { AUD_DCOC_1_SHIFT_IN0, 0x0000000a },
- { AUD_DCOC_1_SHIFT_IN1, 0x00000008 },
- { AUD_IIR1_0_SEL, 0x0000001d },
- { AUD_IIR1_2_SEL, 0x0000001e },
- { AUD_IIR2_1_SEL, 0x00000002 },
- { AUD_IIR2_2_SEL, 0x00000004 },
- { AUD_IIR3_2_SEL, 0x0000000f },
- { AUD_DCOC2_SHIFT, 0x00000001 },
- { AUD_IIR3_2_SHIFT, 0x00000001 },
- { AUD_DEEMPH0_SRC_SEL, 0x00000014 },
- { AUD_CORDIC_SHIFT_1, 0x00000006 },
- { AUD_POLY0_DDS_CONSTANT, 0x000e4db2 },
- { AUD_DMD_RA_DDS, 0x00f696e6 },
- { AUD_IIR2_3_SEL, 0x00000025 },
- { AUD_IIR1_4_SEL, 0x00000021 },
- { AUD_DN1_FREQ, 0x0000c965 },
- { AUD_DCOC_PASS_IN, 0x00000003 },
- { AUD_DCOC_0_SRC, 0x0000001a },
- { AUD_DCOC_1_SRC, 0x0000001b },
- { AUD_DCOC1_SHIFT, 0x00000000 },
- { AUD_RDSI_SEL, 0x00000009 },
- { AUD_RDSQ_SEL, 0x00000009 },
- { AUD_RDSI_SHIFT, 0x00000000 },
- { AUD_RDSQ_SHIFT, 0x00000000 },
- { AUD_POLYPH80SCALEFAC, 0x00000003 },
+ {AUD_AFE_12DB_EN, 0x00000001},
+ {AUD_DBX_IN_GAIN, 0x00007200},
+ {AUD_DBX_WBE_GAIN, 0x00006200},
+ {AUD_DBX_SE_GAIN, 0x00006200},
+ {AUD_IIR1_1_SEL, 0x00000000},
+ {AUD_IIR1_3_SEL, 0x00000001},
+ {AUD_DN1_SRC_SEL, 0x00000007},
+ {AUD_IIR1_4_SHIFT, 0x00000006},
+ {AUD_IIR2_1_SHIFT, 0x00000000},
+ {AUD_IIR2_2_SHIFT, 0x00000000},
+ {AUD_IIR3_0_SHIFT, 0x00000000},
+ {AUD_IIR3_1_SHIFT, 0x00000000},
+ {AUD_IIR3_0_SEL, 0x0000000d},
+ {AUD_IIR3_1_SEL, 0x0000000e},
+ {AUD_DEEMPH1_SRC_SEL, 0x00000014},
+ {AUD_DEEMPH1_SHIFT, 0x00000000},
+ {AUD_DEEMPH1_G0, 0x00004000},
+ {AUD_DEEMPH1_A0, 0x00000000},
+ {AUD_DEEMPH1_B0, 0x00000000},
+ {AUD_DEEMPH1_A1, 0x00000000},
+ {AUD_DEEMPH1_B1, 0x00000000},
+ {AUD_OUT0_SEL, 0x0000003f},
+ {AUD_OUT1_SEL, 0x0000003f},
+ {AUD_DN1_AFC, 0x00000002},
+ {AUD_DCOC_0_SHIFT_IN0, 0x0000000a},
+ {AUD_DCOC_0_SHIFT_IN1, 0x00000008},
+ {AUD_DCOC_1_SHIFT_IN0, 0x0000000a},
+ {AUD_DCOC_1_SHIFT_IN1, 0x00000008},
+ {AUD_IIR1_0_SEL, 0x0000001d},
+ {AUD_IIR1_2_SEL, 0x0000001e},
+ {AUD_IIR2_1_SEL, 0x00000002},
+ {AUD_IIR2_2_SEL, 0x00000004},
+ {AUD_IIR3_2_SEL, 0x0000000f},
+ {AUD_DCOC2_SHIFT, 0x00000001},
+ {AUD_IIR3_2_SHIFT, 0x00000001},
+ {AUD_DEEMPH0_SRC_SEL, 0x00000014},
+ {AUD_CORDIC_SHIFT_1, 0x00000006},
+ {AUD_POLY0_DDS_CONSTANT, 0x000e4db2},
+ {AUD_DMD_RA_DDS, 0x00f696e6},
+ {AUD_IIR2_3_SEL, 0x00000025},
+ {AUD_IIR1_4_SEL, 0x00000021},
+ {AUD_DN1_FREQ, 0x0000c965},
+ {AUD_DCOC_PASS_IN, 0x00000003},
+ {AUD_DCOC_0_SRC, 0x0000001a},
+ {AUD_DCOC_1_SRC, 0x0000001b},
+ {AUD_DCOC1_SHIFT, 0x00000000},
+ {AUD_RDSI_SEL, 0x00000009},
+ {AUD_RDSQ_SEL, 0x00000009},
+ {AUD_RDSI_SHIFT, 0x00000000},
+ {AUD_RDSQ_SHIFT, 0x00000000},
+ {AUD_POLYPH80SCALEFAC, 0x00000003},
{ /* end of list */ },
};
mode |= EN_FMRADIO_EN_RDS;
if (sap) {
- dprintk("%s SAP (status: unknown)\n",__FUNCTION__);
- set_audio_start(core, SEL_SAP);
+ dprintk("%s SAP (status: unknown)\n", __FUNCTION__);
+ set_audio_start(core, SEL_SAP);
set_audio_registers(core, btsc_sap);
set_audio_finish(core, mode);
} else {
- dprintk("%s (status: known-good)\n",__FUNCTION__);
- set_audio_start(core, SEL_BTSC);
+ dprintk("%s (status: known-good)\n", __FUNCTION__);
+ set_audio_start(core, SEL_BTSC);
set_audio_registers(core, btsc);
set_audio_finish(core, mode);
}
}
-
-static void set_audio_standard_NICAM_L(struct cx88_core *core, int stereo)
+static void set_audio_standard_NICAM(struct cx88_core *core, u32 mode)
{
- /* This is probably weird..
- * Let's operate and find out. */
-
- static const struct rlist nicam_l_mono[] = {
- { AUD_ERRLOGPERIOD_R, 0x00000064 },
- { AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF },
- { AUD_ERRINTRPTTHSHLD2_R, 0x0000001F },
- { AUD_ERRINTRPTTHSHLD3_R, 0x0000000F },
-
- { AUD_PDF_DDS_CNST_BYTE2, 0x48 },
- { AUD_PDF_DDS_CNST_BYTE1, 0x3D },
- { AUD_QAM_MODE, 0x00 },
- { AUD_PDF_DDS_CNST_BYTE0, 0xf5 },
- { AUD_PHACC_FREQ_8MSB, 0x3a },
- { AUD_PHACC_FREQ_8LSB, 0x4a },
-
- { AUD_DEEMPHGAIN_R, 0x6680 },
- { AUD_DEEMPHNUMER1_R, 0x353DE },
- { AUD_DEEMPHNUMER2_R, 0x1B1 },
- { AUD_DEEMPHDENOM1_R, 0x0F3D0 },
- { AUD_DEEMPHDENOM2_R, 0x0 },
- { AUD_FM_MODE_ENABLE, 0x7 },
- { AUD_POLYPH80SCALEFAC, 0x3 },
- { AUD_AFE_12DB_EN, 0x1 },
- { AAGC_GAIN, 0x0 },
- { AAGC_HYST, 0x18 },
- { AAGC_DEF, 0x20 },
- { AUD_DN0_FREQ, 0x0 },
- { AUD_POLY0_DDS_CONSTANT, 0x0E4DB2 },
- { AUD_DCOC_0_SRC, 0x21 },
- { AUD_IIR1_0_SEL, 0x0 },
- { AUD_IIR1_0_SHIFT, 0x7 },
- { AUD_IIR1_1_SEL, 0x2 },
- { AUD_IIR1_1_SHIFT, 0x0 },
- { AUD_DCOC_1_SRC, 0x3 },
- { AUD_DCOC1_SHIFT, 0x0 },
- { AUD_DCOC_PASS_IN, 0x0 },
- { AUD_IIR1_2_SEL, 0x23 },
- { AUD_IIR1_2_SHIFT, 0x0 },
- { AUD_IIR1_3_SEL, 0x4 },
- { AUD_IIR1_3_SHIFT, 0x7 },
- { AUD_IIR1_4_SEL, 0x5 },
- { AUD_IIR1_4_SHIFT, 0x7 },
- { AUD_IIR3_0_SEL, 0x7 },
- { AUD_IIR3_0_SHIFT, 0x0 },
- { AUD_DEEMPH0_SRC_SEL, 0x11 },
- { AUD_DEEMPH0_SHIFT, 0x0 },
- { AUD_DEEMPH0_G0, 0x7000 },
- { AUD_DEEMPH0_A0, 0x0 },
- { AUD_DEEMPH0_B0, 0x0 },
- { AUD_DEEMPH0_A1, 0x0 },
- { AUD_DEEMPH0_B1, 0x0 },
- { AUD_DEEMPH1_SRC_SEL, 0x11 },
- { AUD_DEEMPH1_SHIFT, 0x0 },
- { AUD_DEEMPH1_G0, 0x7000 },
- { AUD_DEEMPH1_A0, 0x0 },
- { AUD_DEEMPH1_B0, 0x0 },
- { AUD_DEEMPH1_A1, 0x0 },
- { AUD_DEEMPH1_B1, 0x0 },
- { AUD_OUT0_SEL, 0x3F },
- { AUD_OUT1_SEL, 0x3F },
- { AUD_DMD_RA_DDS, 0x0F5C285 },
- { AUD_PLL_INT, 0x1E },
- { AUD_PLL_DDS, 0x0 },
- { AUD_PLL_FRAC, 0x0E542 },
-
- // setup QAM registers
- { AUD_RATE_ADJ1, 0x00000100 },
- { AUD_RATE_ADJ2, 0x00000200 },
- { AUD_RATE_ADJ3, 0x00000300 },
- { AUD_RATE_ADJ4, 0x00000400 },
- { AUD_RATE_ADJ5, 0x00000500 },
- { AUD_RATE_THRES_DMD, 0x000000C0 },
+ static const struct rlist nicam_l[] = {
+ {AUD_AFE_12DB_EN, 0x00000001},
+ {AUD_RATE_ADJ1, 0x00000060},
+ {AUD_RATE_ADJ2, 0x000000F9},
+ {AUD_RATE_ADJ3, 0x000001CC},
+ {AUD_RATE_ADJ4, 0x000002B3},
+ {AUD_RATE_ADJ5, 0x00000726},
+ {AUD_DEEMPHDENOM1_R, 0x0000F3D0},
+ {AUD_DEEMPHDENOM2_R, 0x00000000},
+ {AUD_ERRLOGPERIOD_R, 0x00000064},
+ {AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF},
+ {AUD_ERRINTRPTTHSHLD2_R, 0x0000001F},
+ {AUD_ERRINTRPTTHSHLD3_R, 0x0000000F},
+ {AUD_POLYPH80SCALEFAC, 0x00000003},
+ {AUD_DMD_RA_DDS, 0x00C00000},
+ {AUD_PLL_INT, 0x0000001E},
+ {AUD_PLL_DDS, 0x00000000},
+ {AUD_PLL_FRAC, 0x0000E542},
+ {AUD_START_TIMER, 0x00000000},
+ {AUD_DEEMPHNUMER1_R, 0x000353DE},
+ {AUD_DEEMPHNUMER2_R, 0x000001B1},
+ {AUD_PDF_DDS_CNST_BYTE2, 0x06},
+ {AUD_PDF_DDS_CNST_BYTE1, 0x82},
+ {AUD_PDF_DDS_CNST_BYTE0, 0x12},
+ {AUD_QAM_MODE, 0x05},
+ {AUD_PHACC_FREQ_8MSB, 0x34},
+ {AUD_PHACC_FREQ_8LSB, 0x4C},
+ {AUD_DEEMPHGAIN_R, 0x00006680},
+ {AUD_RATE_THRES_DMD, 0x000000C0},
{ /* end of list */ },
};
- static const struct rlist nicam_l[] = {
- // setup QAM registers
- { AUD_RATE_ADJ1, 0x00000060 },
- { AUD_RATE_ADJ2, 0x000000F9 },
- { AUD_RATE_ADJ3, 0x000001CC },
- { AUD_RATE_ADJ4, 0x000002B3 },
- { AUD_RATE_ADJ5, 0x00000726 },
- { AUD_DEEMPHDENOM1_R, 0x0000F3D0 },
- { AUD_DEEMPHDENOM2_R, 0x00000000 },
- { AUD_ERRLOGPERIOD_R, 0x00000064 },
- { AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF },
- { AUD_ERRINTRPTTHSHLD2_R, 0x0000001F },
- { AUD_ERRINTRPTTHSHLD3_R, 0x0000000F },
- { AUD_POLYPH80SCALEFAC, 0x00000003 },
- { AUD_DMD_RA_DDS, 0x00C00000 },
- { AUD_PLL_INT, 0x0000001E },
- { AUD_PLL_DDS, 0x00000000 },
- { AUD_PLL_FRAC, 0x0000E542 },
- { AUD_START_TIMER, 0x00000000 },
- { AUD_DEEMPHNUMER1_R, 0x000353DE },
- { AUD_DEEMPHNUMER2_R, 0x000001B1 },
- { AUD_PDF_DDS_CNST_BYTE2, 0x06 },
- { AUD_PDF_DDS_CNST_BYTE1, 0x82 },
- { AUD_QAM_MODE, 0x05 },
- { AUD_PDF_DDS_CNST_BYTE0, 0x12 },
- { AUD_PHACC_FREQ_8MSB, 0x34 },
- { AUD_PHACC_FREQ_8LSB, 0x4C },
- { AUD_DEEMPHGAIN_R, 0x00006680 },
- { AUD_RATE_THRES_DMD, 0x000000C0 },
+ static const struct rlist nicam_bgdki_common[] = {
+ {AUD_AFE_12DB_EN, 0x00000001},
+ {AUD_RATE_ADJ1, 0x00000010},
+ {AUD_RATE_ADJ2, 0x00000040},
+ {AUD_RATE_ADJ3, 0x00000100},
+ {AUD_RATE_ADJ4, 0x00000400},
+ {AUD_RATE_ADJ5, 0x00001000},
+ //{ AUD_DMD_RA_DDS, 0x00c0d5ce },
+ {AUD_ERRLOGPERIOD_R, 0x00000fff},
+ {AUD_ERRINTRPTTHSHLD1_R, 0x000003ff},
+ {AUD_ERRINTRPTTHSHLD2_R, 0x000000ff},
+ {AUD_ERRINTRPTTHSHLD3_R, 0x0000003f},
+ {AUD_POLYPH80SCALEFAC, 0x00000003},
+ {AUD_DEEMPHGAIN_R, 0x000023c2},
+ {AUD_DEEMPHNUMER1_R, 0x0002a7bc},
+ {AUD_DEEMPHNUMER2_R, 0x0003023e},
+ {AUD_DEEMPHDENOM1_R, 0x0000f3d0},
+ {AUD_DEEMPHDENOM2_R, 0x00000000},
+ {AUD_PDF_DDS_CNST_BYTE2, 0x06},
+ {AUD_PDF_DDS_CNST_BYTE1, 0x82},
+ {AUD_QAM_MODE, 0x05},
{ /* end of list */ },
- } ;
- dprintk("%s (status: devel), stereo : %d\n",__FUNCTION__,stereo);
-
- if (!stereo) {
- /* AM Mono */
- set_audio_start(core, SEL_A2);
- set_audio_registers(core, nicam_l_mono);
- set_audio_finish(core, EN_A2_FORCE_MONO1);
- } else {
- /* Nicam Stereo */
- set_audio_start(core, SEL_NICAM);
- set_audio_registers(core, nicam_l);
- set_audio_finish(core, 0x1924); /* FIXME */
- }
-}
+ };
-static void set_audio_standard_PAL_I(struct cx88_core *core, int stereo)
-{
- static const struct rlist pal_i_fm_mono[] = {
- {AUD_ERRLOGPERIOD_R, 0x00000064},
- {AUD_ERRINTRPTTHSHLD1_R, 0x00000fff},
- {AUD_ERRINTRPTTHSHLD2_R, 0x0000001f},
- {AUD_ERRINTRPTTHSHLD3_R, 0x0000000f},
- {AUD_PDF_DDS_CNST_BYTE2, 0x06},
- {AUD_PDF_DDS_CNST_BYTE1, 0x82},
- {AUD_PDF_DDS_CNST_BYTE0, 0x12},
- {AUD_QAM_MODE, 0x05},
- {AUD_PHACC_FREQ_8MSB, 0x3a},
- {AUD_PHACC_FREQ_8LSB, 0x93},
- {AUD_DMD_RA_DDS, 0x002a4f2f},
- {AUD_PLL_INT, 0x0000001e},
- {AUD_PLL_DDS, 0x00000004},
- {AUD_PLL_FRAC, 0x0000e542},
- {AUD_RATE_ADJ1, 0x00000100},
- {AUD_RATE_ADJ2, 0x00000200},
- {AUD_RATE_ADJ3, 0x00000300},
- {AUD_RATE_ADJ4, 0x00000400},
- {AUD_RATE_ADJ5, 0x00000500},
- {AUD_THR_FR, 0x00000000},
- {AUD_PILOT_BQD_1_K0, 0x0000755b},
- {AUD_PILOT_BQD_1_K1, 0x00551340},
- {AUD_PILOT_BQD_1_K2, 0x006d30be},
- {AUD_PILOT_BQD_1_K3, 0xffd394af},
- {AUD_PILOT_BQD_1_K4, 0x00400000},
- {AUD_PILOT_BQD_2_K0, 0x00040000},
- {AUD_PILOT_BQD_2_K1, 0x002a4841},
- {AUD_PILOT_BQD_2_K2, 0x00400000},
- {AUD_PILOT_BQD_2_K3, 0x00000000},
- {AUD_PILOT_BQD_2_K4, 0x00000000},
- {AUD_MODE_CHG_TIMER, 0x00000060},
- {AUD_AFE_12DB_EN, 0x00000001},
- {AAGC_HYST, 0x0000000a},
- {AUD_CORDIC_SHIFT_0, 0x00000007},
- {AUD_CORDIC_SHIFT_1, 0x00000007},
- {AUD_C1_UP_THR, 0x00007000},
- {AUD_C1_LO_THR, 0x00005400},
- {AUD_C2_UP_THR, 0x00005400},
- {AUD_C2_LO_THR, 0x00003000},
- {AUD_DCOC_0_SRC, 0x0000001a},
- {AUD_DCOC0_SHIFT, 0x00000000},
- {AUD_DCOC_0_SHIFT_IN0, 0x0000000a},
- {AUD_DCOC_0_SHIFT_IN1, 0x00000008},
- {AUD_DCOC_PASS_IN, 0x00000003},
- {AUD_IIR3_0_SEL, 0x00000021},
- {AUD_DN2_AFC, 0x00000002},
- {AUD_DCOC_1_SRC, 0x0000001b},
- {AUD_DCOC1_SHIFT, 0x00000000},
- {AUD_DCOC_1_SHIFT_IN0, 0x0000000a},
- {AUD_DCOC_1_SHIFT_IN1, 0x00000008},
- {AUD_IIR3_1_SEL, 0x00000023},
- {AUD_DN0_FREQ, 0x000035a3},
- {AUD_DN2_FREQ, 0x000029c7},
- {AUD_CRDC0_SRC_SEL, 0x00000511},
- {AUD_IIR1_0_SEL, 0x00000001},
- {AUD_IIR1_1_SEL, 0x00000000},
- {AUD_IIR3_2_SEL, 0x00000003},
- {AUD_IIR3_2_SHIFT, 0x00000000},
- {AUD_IIR3_0_SEL, 0x00000002},
- {AUD_IIR2_0_SEL, 0x00000021},
- {AUD_IIR2_0_SHIFT, 0x00000002},
- {AUD_DEEMPH0_SRC_SEL, 0x0000000b},
- {AUD_DEEMPH1_SRC_SEL, 0x0000000b},
- {AUD_POLYPH80SCALEFAC, 0x00000001},
- {AUD_START_TIMER, 0x00000000},
- { /* end of list */ },
- };
-
- static const struct rlist pal_i_nicam[] = {
- { AUD_RATE_ADJ1, 0x00000010 },
- { AUD_RATE_ADJ2, 0x00000040 },
- { AUD_RATE_ADJ3, 0x00000100 },
- { AUD_RATE_ADJ4, 0x00000400 },
- { AUD_RATE_ADJ5, 0x00001000 },
- // { AUD_DMD_RA_DDS, 0x00c0d5ce },
- { AUD_DEEMPHGAIN_R, 0x000023c2 },
- { AUD_DEEMPHNUMER1_R, 0x0002a7bc },
- { AUD_DEEMPHNUMER2_R, 0x0003023e },
- { AUD_DEEMPHDENOM1_R, 0x0000f3d0 },
- { AUD_DEEMPHDENOM2_R, 0x00000000 },
- { AUD_DEEMPHDENOM2_R, 0x00000000 },
- { AUD_ERRLOGPERIOD_R, 0x00000fff },
- { AUD_ERRINTRPTTHSHLD1_R, 0x000003ff },
- { AUD_ERRINTRPTTHSHLD2_R, 0x000000ff },
- { AUD_ERRINTRPTTHSHLD3_R, 0x0000003f },
- { AUD_POLYPH80SCALEFAC, 0x00000003 },
- { AUD_PDF_DDS_CNST_BYTE2, 0x06 },
- { AUD_PDF_DDS_CNST_BYTE1, 0x82 },
- { AUD_PDF_DDS_CNST_BYTE0, 0x16 },
- { AUD_QAM_MODE, 0x05 },
- { AUD_PDF_DDS_CNST_BYTE0, 0x12 },
- { AUD_PHACC_FREQ_8MSB, 0x3a },
- { AUD_PHACC_FREQ_8LSB, 0x93 },
- { /* end of list */ },
+ static const struct rlist nicam_i[] = {
+ {AUD_PDF_DDS_CNST_BYTE0, 0x12},
+ {AUD_PHACC_FREQ_8MSB, 0x3a},
+ {AUD_PHACC_FREQ_8LSB, 0x93},
+ { /* end of list */ },
};
- dprintk("%s (status: devel), stereo : %d\n",__FUNCTION__,stereo);
+ static const struct rlist nicam_default[] = {
+ {AUD_PDF_DDS_CNST_BYTE0, 0x16},
+ {AUD_PHACC_FREQ_8MSB, 0x34},
+ {AUD_PHACC_FREQ_8LSB, 0x4c},
+ { /* end of list */ },
+ };
- if (!stereo) {
- /* FM Mono */
- set_audio_start(core, SEL_A2);
- set_audio_registers(core, pal_i_fm_mono);
- set_audio_finish(core, EN_DMTRX_SUMDIFF | EN_A2_FORCE_MONO1);
- } else {
- /* Nicam Stereo */
- set_audio_start(core, SEL_NICAM);
- set_audio_registers(core, pal_i_nicam);
- set_audio_finish(core, EN_DMTRX_LR | EN_DMTRX_BYPASS | EN_NICAM_AUTO_STEREO);
- }
+ set_audio_start(core,SEL_NICAM);
+ switch (core->tvaudio) {
+ case WW_L:
+ dprintk("%s SECAM-L NICAM (status: devel)\n", __FUNCTION__);
+ set_audio_registers(core, nicam_l);
+ break;
+ case WW_I:
+ dprintk("%s PAL-I NICAM (status: devel)\n", __FUNCTION__);
+ set_audio_registers(core, nicam_bgdki_common);
+ set_audio_registers(core, nicam_i);
+ break;
+ default:
+ dprintk("%s PAL-BGDK NICAM (status: unknown)\n", __FUNCTION__);
+ set_audio_registers(core, nicam_bgdki_common);
+ set_audio_registers(core, nicam_default);
+ break;
+ };
+
+ mode |= EN_DMTRX_LR | EN_DMTRX_BYPASS;
+ set_audio_finish(core, mode);
}
static void set_audio_standard_A2(struct cx88_core *core, u32 mode)
{
- static const struct rlist a2_common[] = {
- {AUD_ERRLOGPERIOD_R, 0x00000064},
- {AUD_ERRINTRPTTHSHLD1_R, 0x00000fff},
- {AUD_ERRINTRPTTHSHLD2_R, 0x0000001f},
- {AUD_ERRINTRPTTHSHLD3_R, 0x0000000f},
- {AUD_PDF_DDS_CNST_BYTE2, 0x06},
- {AUD_PDF_DDS_CNST_BYTE1, 0x82},
- {AUD_PDF_DDS_CNST_BYTE0, 0x12},
- {AUD_QAM_MODE, 0x05},
- {AUD_PHACC_FREQ_8MSB, 0x34},
- {AUD_PHACC_FREQ_8LSB, 0x4c},
- {AUD_RATE_ADJ1, 0x00000100},
- {AUD_RATE_ADJ2, 0x00000200},
- {AUD_RATE_ADJ3, 0x00000300},
- {AUD_RATE_ADJ4, 0x00000400},
- {AUD_RATE_ADJ5, 0x00000500},
- {AUD_THR_FR, 0x00000000},
- {AAGC_HYST, 0x0000001a},
- {AUD_PILOT_BQD_1_K0, 0x0000755b},
- {AUD_PILOT_BQD_1_K1, 0x00551340},
- {AUD_PILOT_BQD_1_K2, 0x006d30be},
- {AUD_PILOT_BQD_1_K3, 0xffd394af},
- {AUD_PILOT_BQD_1_K4, 0x00400000},
- {AUD_PILOT_BQD_2_K0, 0x00040000},
- {AUD_PILOT_BQD_2_K1, 0x002a4841},
- {AUD_PILOT_BQD_2_K2, 0x00400000},
- {AUD_PILOT_BQD_2_K3, 0x00000000},
- {AUD_PILOT_BQD_2_K4, 0x00000000},
- {AUD_MODE_CHG_TIMER, 0x00000040},
- {AUD_AFE_12DB_EN, 0x00000001},
- {AUD_CORDIC_SHIFT_0, 0x00000007},
- {AUD_CORDIC_SHIFT_1, 0x00000007},
- {AUD_DEEMPH0_G0, 0x00000380},
- {AUD_DEEMPH1_G0, 0x00000380},
- {AUD_DCOC_0_SRC, 0x0000001a},
- {AUD_DCOC0_SHIFT, 0x00000000},
- {AUD_DCOC_0_SHIFT_IN0, 0x0000000a},
- {AUD_DCOC_0_SHIFT_IN1, 0x00000008},
- {AUD_DCOC_PASS_IN, 0x00000003},
- {AUD_IIR3_0_SEL, 0x00000021},
- {AUD_DN2_AFC, 0x00000002},
- {AUD_DCOC_1_SRC, 0x0000001b},
- {AUD_DCOC1_SHIFT, 0x00000000},
- {AUD_DCOC_1_SHIFT_IN0, 0x0000000a},
- {AUD_DCOC_1_SHIFT_IN1, 0x00000008},
- {AUD_IIR3_1_SEL, 0x00000023},
- {AUD_RDSI_SEL, 0x00000017},
- {AUD_RDSI_SHIFT, 0x00000000},
- {AUD_RDSQ_SEL, 0x00000017},
- {AUD_RDSQ_SHIFT, 0x00000000},
- {AUD_PLL_INT, 0x0000001e},
- {AUD_PLL_DDS, 0x00000000},
- {AUD_PLL_FRAC, 0x0000e542},
- {AUD_POLYPH80SCALEFAC, 0x00000001},
- {AUD_START_TIMER, 0x00000000},
- { /* end of list */ },
+ static const struct rlist a2_bgdk_common[] = {
+ {AUD_ERRLOGPERIOD_R, 0x00000064},
+ {AUD_ERRINTRPTTHSHLD1_R, 0x00000fff},
+ {AUD_ERRINTRPTTHSHLD2_R, 0x0000001f},
+ {AUD_ERRINTRPTTHSHLD3_R, 0x0000000f},
+ {AUD_PDF_DDS_CNST_BYTE2, 0x06},
+ {AUD_PDF_DDS_CNST_BYTE1, 0x82},
+ {AUD_PDF_DDS_CNST_BYTE0, 0x12},
+ {AUD_QAM_MODE, 0x05},
+ {AUD_PHACC_FREQ_8MSB, 0x34},
+ {AUD_PHACC_FREQ_8LSB, 0x4c},
+ {AUD_RATE_ADJ1, 0x00000100},
+ {AUD_RATE_ADJ2, 0x00000200},
+ {AUD_RATE_ADJ3, 0x00000300},
+ {AUD_RATE_ADJ4, 0x00000400},
+ {AUD_RATE_ADJ5, 0x00000500},
+ {AUD_THR_FR, 0x00000000},
+ {AAGC_HYST, 0x0000001a},
+ {AUD_PILOT_BQD_1_K0, 0x0000755b},
+ {AUD_PILOT_BQD_1_K1, 0x00551340},
+ {AUD_PILOT_BQD_1_K2, 0x006d30be},
+ {AUD_PILOT_BQD_1_K3, 0xffd394af},
+ {AUD_PILOT_BQD_1_K4, 0x00400000},
+ {AUD_PILOT_BQD_2_K0, 0x00040000},
+ {AUD_PILOT_BQD_2_K1, 0x002a4841},
+ {AUD_PILOT_BQD_2_K2, 0x00400000},
+ {AUD_PILOT_BQD_2_K3, 0x00000000},
+ {AUD_PILOT_BQD_2_K4, 0x00000000},
+ {AUD_MODE_CHG_TIMER, 0x00000040},
+ {AUD_AFE_12DB_EN, 0x00000001},
+ {AUD_CORDIC_SHIFT_0, 0x00000007},
+ {AUD_CORDIC_SHIFT_1, 0x00000007},
+ {AUD_DEEMPH0_G0, 0x00000380},
+ {AUD_DEEMPH1_G0, 0x00000380},
+ {AUD_DCOC_0_SRC, 0x0000001a},
+ {AUD_DCOC0_SHIFT, 0x00000000},
+ {AUD_DCOC_0_SHIFT_IN0, 0x0000000a},
+ {AUD_DCOC_0_SHIFT_IN1, 0x00000008},
+ {AUD_DCOC_PASS_IN, 0x00000003},
+ {AUD_IIR3_0_SEL, 0x00000021},
+ {AUD_DN2_AFC, 0x00000002},
+ {AUD_DCOC_1_SRC, 0x0000001b},
+ {AUD_DCOC1_SHIFT, 0x00000000},
+ {AUD_DCOC_1_SHIFT_IN0, 0x0000000a},
+ {AUD_DCOC_1_SHIFT_IN1, 0x00000008},
+ {AUD_IIR3_1_SEL, 0x00000023},
+ {AUD_RDSI_SEL, 0x00000017},
+ {AUD_RDSI_SHIFT, 0x00000000},
+ {AUD_RDSQ_SEL, 0x00000017},
+ {AUD_RDSQ_SHIFT, 0x00000000},
+ {AUD_PLL_INT, 0x0000001e},
+ {AUD_PLL_DDS, 0x00000000},
+ {AUD_PLL_FRAC, 0x0000e542},
+ {AUD_POLYPH80SCALEFAC, 0x00000001},
+ {AUD_START_TIMER, 0x00000000},
+ { /* end of list */ },
};
static const struct rlist a2_bg[] = {
- {AUD_DMD_RA_DDS, 0x002a4f2f},
- {AUD_C1_UP_THR, 0x00007000},
- {AUD_C1_LO_THR, 0x00005400},
- {AUD_C2_UP_THR, 0x00005400},
- {AUD_C2_LO_THR, 0x00003000},
+ {AUD_DMD_RA_DDS, 0x002a4f2f},
+ {AUD_C1_UP_THR, 0x00007000},
+ {AUD_C1_LO_THR, 0x00005400},
+ {AUD_C2_UP_THR, 0x00005400},
+ {AUD_C2_LO_THR, 0x00003000},
{ /* end of list */ },
};
static const struct rlist a2_dk[] = {
- {AUD_DMD_RA_DDS, 0x002a4f2f},
- {AUD_C1_UP_THR, 0x00007000},
- {AUD_C1_LO_THR, 0x00005400},
- {AUD_C2_UP_THR, 0x00005400},
- {AUD_C2_LO_THR, 0x00003000},
- {AUD_DN0_FREQ, 0x00003a1c},
- {AUD_DN2_FREQ, 0x0000d2e0},
+ {AUD_DMD_RA_DDS, 0x002a4f2f},
+ {AUD_C1_UP_THR, 0x00007000},
+ {AUD_C1_LO_THR, 0x00005400},
+ {AUD_C2_UP_THR, 0x00005400},
+ {AUD_C2_LO_THR, 0x00003000},
+ {AUD_DN0_FREQ, 0x00003a1c},
+ {AUD_DN2_FREQ, 0x0000d2e0},
{ /* end of list */ },
};
-/* unknown, probably NTSC-M */
- static const struct rlist a2_m[] = {
- {AUD_DMD_RA_DDS, 0x002a0425},
- {AUD_C1_UP_THR, 0x00003c00},
- {AUD_C1_LO_THR, 0x00003000},
- {AUD_C2_UP_THR, 0x00006000},
- {AUD_C2_LO_THR, 0x00003c00},
- {AUD_DEEMPH0_A0, 0x00007a80},
- {AUD_DEEMPH1_A0, 0x00007a80},
- {AUD_DEEMPH0_G0, 0x00001200},
- {AUD_DEEMPH1_G0, 0x00001200},
- {AUD_DN0_FREQ, 0x0000283b},
- {AUD_DN1_FREQ, 0x00003418},
- {AUD_DN2_FREQ, 0x000029c7},
- {AUD_POLY0_DDS_CONSTANT, 0x000a7540},
+
+ static const struct rlist a1_i[] = {
+ {AUD_ERRLOGPERIOD_R, 0x00000064},
+ {AUD_ERRINTRPTTHSHLD1_R, 0x00000fff},
+ {AUD_ERRINTRPTTHSHLD2_R, 0x0000001f},
+ {AUD_ERRINTRPTTHSHLD3_R, 0x0000000f},
+ {AUD_PDF_DDS_CNST_BYTE2, 0x06},
+ {AUD_PDF_DDS_CNST_BYTE1, 0x82},
+ {AUD_PDF_DDS_CNST_BYTE0, 0x12},
+ {AUD_QAM_MODE, 0x05},
+ {AUD_PHACC_FREQ_8MSB, 0x3a},
+ {AUD_PHACC_FREQ_8LSB, 0x93},
+ {AUD_DMD_RA_DDS, 0x002a4f2f},
+ {AUD_PLL_INT, 0x0000001e},
+ {AUD_PLL_DDS, 0x00000004},
+ {AUD_PLL_FRAC, 0x0000e542},
+ {AUD_RATE_ADJ1, 0x00000100},
+ {AUD_RATE_ADJ2, 0x00000200},
+ {AUD_RATE_ADJ3, 0x00000300},
+ {AUD_RATE_ADJ4, 0x00000400},
+ {AUD_RATE_ADJ5, 0x00000500},
+ {AUD_THR_FR, 0x00000000},
+ {AUD_PILOT_BQD_1_K0, 0x0000755b},
+ {AUD_PILOT_BQD_1_K1, 0x00551340},
+ {AUD_PILOT_BQD_1_K2, 0x006d30be},
+ {AUD_PILOT_BQD_1_K3, 0xffd394af},
+ {AUD_PILOT_BQD_1_K4, 0x00400000},
+ {AUD_PILOT_BQD_2_K0, 0x00040000},
+ {AUD_PILOT_BQD_2_K1, 0x002a4841},
+ {AUD_PILOT_BQD_2_K2, 0x00400000},
+ {AUD_PILOT_BQD_2_K3, 0x00000000},
+ {AUD_PILOT_BQD_2_K4, 0x00000000},
+ {AUD_MODE_CHG_TIMER, 0x00000060},
+ {AUD_AFE_12DB_EN, 0x00000001},
+ {AAGC_HYST, 0x0000000a},
+ {AUD_CORDIC_SHIFT_0, 0x00000007},
+ {AUD_CORDIC_SHIFT_1, 0x00000007},
+ {AUD_C1_UP_THR, 0x00007000},
+ {AUD_C1_LO_THR, 0x00005400},
+ {AUD_C2_UP_THR, 0x00005400},
+ {AUD_C2_LO_THR, 0x00003000},
+ {AUD_DCOC_0_SRC, 0x0000001a},
+ {AUD_DCOC0_SHIFT, 0x00000000},
+ {AUD_DCOC_0_SHIFT_IN0, 0x0000000a},
+ {AUD_DCOC_0_SHIFT_IN1, 0x00000008},
+ {AUD_DCOC_PASS_IN, 0x00000003},
+ {AUD_IIR3_0_SEL, 0x00000021},
+ {AUD_DN2_AFC, 0x00000002},
+ {AUD_DCOC_1_SRC, 0x0000001b},
+ {AUD_DCOC1_SHIFT, 0x00000000},
+ {AUD_DCOC_1_SHIFT_IN0, 0x0000000a},
+ {AUD_DCOC_1_SHIFT_IN1, 0x00000008},
+ {AUD_IIR3_1_SEL, 0x00000023},
+ {AUD_DN0_FREQ, 0x000035a3},
+ {AUD_DN2_FREQ, 0x000029c7},
+ {AUD_CRDC0_SRC_SEL, 0x00000511},
+ {AUD_IIR1_0_SEL, 0x00000001},
+ {AUD_IIR1_1_SEL, 0x00000000},
+ {AUD_IIR3_2_SEL, 0x00000003},
+ {AUD_IIR3_2_SHIFT, 0x00000000},
+ {AUD_IIR3_0_SEL, 0x00000002},
+ {AUD_IIR2_0_SEL, 0x00000021},
+ {AUD_IIR2_0_SHIFT, 0x00000002},
+ {AUD_DEEMPH0_SRC_SEL, 0x0000000b},
+ {AUD_DEEMPH1_SRC_SEL, 0x0000000b},
+ {AUD_POLYPH80SCALEFAC, 0x00000001},
+ {AUD_START_TIMER, 0x00000000},
{ /* end of list */ },
};
- static const struct rlist a2_deemph50[] = {
- {AUD_DEEMPH0_G0, 0x00000380},
- {AUD_DEEMPH1_G0, 0x00000380},
- {AUD_DEEMPHGAIN_R, 0x000011e1},
- {AUD_DEEMPHNUMER1_R, 0x0002a7bc},
- {AUD_DEEMPHNUMER2_R, 0x0003023c},
- { /* end of list */ },
+ static const struct rlist am_l[] = {
+ {AUD_ERRLOGPERIOD_R, 0x00000064},
+ {AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF},
+ {AUD_ERRINTRPTTHSHLD2_R, 0x0000001F},
+ {AUD_ERRINTRPTTHSHLD3_R, 0x0000000F},
+ {AUD_PDF_DDS_CNST_BYTE2, 0x48},
+ {AUD_PDF_DDS_CNST_BYTE1, 0x3D},
+ {AUD_QAM_MODE, 0x00},
+ {AUD_PDF_DDS_CNST_BYTE0, 0xf5},
+ {AUD_PHACC_FREQ_8MSB, 0x3a},
+ {AUD_PHACC_FREQ_8LSB, 0x4a},
+ {AUD_DEEMPHGAIN_R, 0x00006680},
+ {AUD_DEEMPHNUMER1_R, 0x000353DE},
+ {AUD_DEEMPHNUMER2_R, 0x000001B1},
+ {AUD_DEEMPHDENOM1_R, 0x0000F3D0},
+ {AUD_DEEMPHDENOM2_R, 0x00000000},
+ {AUD_FM_MODE_ENABLE, 0x00000007},
+ {AUD_POLYPH80SCALEFAC, 0x00000003},
+ {AUD_AFE_12DB_EN, 0x00000001},
+ {AAGC_GAIN, 0x00000000},
+ {AAGC_HYST, 0x00000018},
+ {AAGC_DEF, 0x00000020},
+ {AUD_DN0_FREQ, 0x00000000},
+ {AUD_POLY0_DDS_CONSTANT, 0x000E4DB2},
+ {AUD_DCOC_0_SRC, 0x00000021},
+ {AUD_IIR1_0_SEL, 0x00000000},
+ {AUD_IIR1_0_SHIFT, 0x00000007},
+ {AUD_IIR1_1_SEL, 0x00000002},
+ {AUD_IIR1_1_SHIFT, 0x00000000},
+ {AUD_DCOC_1_SRC, 0x00000003},
+ {AUD_DCOC1_SHIFT, 0x00000000},
+ {AUD_DCOC_PASS_IN, 0x00000000},
+ {AUD_IIR1_2_SEL, 0x00000023},
+ {AUD_IIR1_2_SHIFT, 0x00000000},
+ {AUD_IIR1_3_SEL, 0x00000004},
+ {AUD_IIR1_3_SHIFT, 0x00000007},
+ {AUD_IIR1_4_SEL, 0x00000005},
+ {AUD_IIR1_4_SHIFT, 0x00000007},
+ {AUD_IIR3_0_SEL, 0x00000007},
+ {AUD_IIR3_0_SHIFT, 0x00000000},
+ {AUD_DEEMPH0_SRC_SEL, 0x00000011},
+ {AUD_DEEMPH0_SHIFT, 0x00000000},
+ {AUD_DEEMPH0_G0, 0x00007000},
+ {AUD_DEEMPH0_A0, 0x00000000},
+ {AUD_DEEMPH0_B0, 0x00000000},
+ {AUD_DEEMPH0_A1, 0x00000000},
+ {AUD_DEEMPH0_B1, 0x00000000},
+ {AUD_DEEMPH1_SRC_SEL, 0x00000011},
+ {AUD_DEEMPH1_SHIFT, 0x00000000},
+ {AUD_DEEMPH1_G0, 0x00007000},
+ {AUD_DEEMPH1_A0, 0x00000000},
+ {AUD_DEEMPH1_B0, 0x00000000},
+ {AUD_DEEMPH1_A1, 0x00000000},
+ {AUD_DEEMPH1_B1, 0x00000000},
+ {AUD_OUT0_SEL, 0x0000003F},
+ {AUD_OUT1_SEL, 0x0000003F},
+ {AUD_DMD_RA_DDS, 0x00F5C285},
+ {AUD_PLL_INT, 0x0000001E},
+ {AUD_PLL_DDS, 0x00000000},
+ {AUD_PLL_FRAC, 0x0000E542},
+ {AUD_RATE_ADJ1, 0x00000100},
+ {AUD_RATE_ADJ2, 0x00000200},
+ {AUD_RATE_ADJ3, 0x00000300},
+ {AUD_RATE_ADJ4, 0x00000400},
+ {AUD_RATE_ADJ5, 0x00000500},
+ {AUD_RATE_THRES_DMD, 0x000000C0},
+ { /* end of list */ },
};
- static const struct rlist a2_deemph75[] = {
- {AUD_DEEMPH0_G0, 0x00000480},
- {AUD_DEEMPH1_G0, 0x00000480},
- {AUD_DEEMPHGAIN_R, 0x00009000},
- {AUD_DEEMPHNUMER1_R, 0x000353de},
- {AUD_DEEMPHNUMER2_R, 0x000001b1},
+ static const struct rlist a2_deemph50[] = {
+ {AUD_DEEMPH0_G0, 0x00000380},
+ {AUD_DEEMPH1_G0, 0x00000380},
+ {AUD_DEEMPHGAIN_R, 0x000011e1},
+ {AUD_DEEMPHNUMER1_R, 0x0002a7bc},
+ {AUD_DEEMPHNUMER2_R, 0x0003023c},
{ /* end of list */ },
};
set_audio_start(core, SEL_A2);
- set_audio_registers(core, a2_common);
switch (core->tvaudio) {
- case WW_A2_BG:
- dprintk("%s PAL-BG A2 (status: known-good)\n",__FUNCTION__);
- set_audio_registers(core, a2_bg);
- set_audio_registers(core, a2_deemph50);
+ case WW_BG:
+ dprintk("%s PAL-BG A1/2 (status: known-good)\n", __FUNCTION__);
+ set_audio_registers(core, a2_bgdk_common);
+ set_audio_registers(core, a2_bg);
+ set_audio_registers(core, a2_deemph50);
break;
- case WW_A2_DK:
- dprintk("%s PAL-DK A2 (status: known-good)\n",__FUNCTION__);
- set_audio_registers(core, a2_dk);
- set_audio_registers(core, a2_deemph50);
+ case WW_DK:
+ dprintk("%s PAL-DK A1/2 (status: known-good)\n", __FUNCTION__);
+ set_audio_registers(core, a2_bgdk_common);
+ set_audio_registers(core, a2_dk);
+ set_audio_registers(core, a2_deemph50);
break;
- case WW_A2_M:
- dprintk("%s NTSC-M A2 (status: unknown)\n",__FUNCTION__);
- set_audio_registers(core, a2_m);
- set_audio_registers(core, a2_deemph75);
+ case WW_I:
+ dprintk("%s PAL-I A1 (status: known-good)\n", __FUNCTION__);
+ set_audio_registers(core, a1_i);
+ set_audio_registers(core, a2_deemph50);
+ break;
+ case WW_L:
+ dprintk("%s AM-L (status: devel)\n", __FUNCTION__);
+ set_audio_registers(core, am_l);
+ break;
+ default:
+ dprintk("%s Warning: wrong value\n", __FUNCTION__);
+ return;
break;
};
@@ -656,71 +633,71 @@ static void set_audio_standard_EIAJ(struct cx88_core *core)
{ /* end of list */ },
};
- dprintk("%s (status: unknown)\n",__FUNCTION__);
+ dprintk("%s (status: unknown)\n", __FUNCTION__);
set_audio_start(core, SEL_EIAJ);
set_audio_registers(core, eiaj);
set_audio_finish(core, EN_EIAJ_AUTO_STEREO);
}
-static void set_audio_standard_FM(struct cx88_core *core, enum cx88_deemph_type deemph)
+static void set_audio_standard_FM(struct cx88_core *core,
+ enum cx88_deemph_type deemph)
{
static const struct rlist fm_deemph_50[] = {
- { AUD_DEEMPH0_G0, 0x0C45 },
- { AUD_DEEMPH0_A0, 0x6262 },
- { AUD_DEEMPH0_B0, 0x1C29 },
- { AUD_DEEMPH0_A1, 0x3FC66},
- { AUD_DEEMPH0_B1, 0x399A },
-
- { AUD_DEEMPH1_G0, 0x0D80 },
- { AUD_DEEMPH1_A0, 0x6262 },
- { AUD_DEEMPH1_B0, 0x1C29 },
- { AUD_DEEMPH1_A1, 0x3FC66},
- { AUD_DEEMPH1_B1, 0x399A},
-
- { AUD_POLYPH80SCALEFAC, 0x0003},
+ {AUD_DEEMPH0_G0, 0x0C45},
+ {AUD_DEEMPH0_A0, 0x6262},
+ {AUD_DEEMPH0_B0, 0x1C29},
+ {AUD_DEEMPH0_A1, 0x3FC66},
+ {AUD_DEEMPH0_B1, 0x399A},
+
+ {AUD_DEEMPH1_G0, 0x0D80},
+ {AUD_DEEMPH1_A0, 0x6262},
+ {AUD_DEEMPH1_B0, 0x1C29},
+ {AUD_DEEMPH1_A1, 0x3FC66},
+ {AUD_DEEMPH1_B1, 0x399A},
+
+ {AUD_POLYPH80SCALEFAC, 0x0003},
{ /* end of list */ },
};
static const struct rlist fm_deemph_75[] = {
- { AUD_DEEMPH0_G0, 0x091B },
- { AUD_DEEMPH0_A0, 0x6B68 },
- { AUD_DEEMPH0_B0, 0x11EC },
- { AUD_DEEMPH0_A1, 0x3FC66},
- { AUD_DEEMPH0_B1, 0x399A },
-
- { AUD_DEEMPH1_G0, 0x0AA0 },
- { AUD_DEEMPH1_A0, 0x6B68 },
- { AUD_DEEMPH1_B0, 0x11EC },
- { AUD_DEEMPH1_A1, 0x3FC66},
- { AUD_DEEMPH1_B1, 0x399A},
-
- { AUD_POLYPH80SCALEFAC, 0x0003},
+ {AUD_DEEMPH0_G0, 0x091B},
+ {AUD_DEEMPH0_A0, 0x6B68},
+ {AUD_DEEMPH0_B0, 0x11EC},
+ {AUD_DEEMPH0_A1, 0x3FC66},
+ {AUD_DEEMPH0_B1, 0x399A},
+
+ {AUD_DEEMPH1_G0, 0x0AA0},
+ {AUD_DEEMPH1_A0, 0x6B68},
+ {AUD_DEEMPH1_B0, 0x11EC},
+ {AUD_DEEMPH1_A1, 0x3FC66},
+ {AUD_DEEMPH1_B1, 0x399A},
+
+ {AUD_POLYPH80SCALEFAC, 0x0003},
{ /* end of list */ },
};
/* It is enough to leave default values? */
static const struct rlist fm_no_deemph[] = {
- { AUD_POLYPH80SCALEFAC, 0x0003},
+ {AUD_POLYPH80SCALEFAC, 0x0003},
{ /* end of list */ },
};
- dprintk("%s (status: unknown)\n",__FUNCTION__);
+ dprintk("%s (status: unknown)\n", __FUNCTION__);
set_audio_start(core, SEL_FMRADIO);
- switch (deemph)
- {
- case FM_NO_DEEMPH:
- set_audio_registers(core, fm_no_deemph);
- break;
+ switch (deemph) {
+ case FM_NO_DEEMPH:
+ set_audio_registers(core, fm_no_deemph);
+ break;
- case FM_DEEMPH_50:
- set_audio_registers(core, fm_deemph_50);
- break;
+ case FM_DEEMPH_50:
+ set_audio_registers(core, fm_deemph_50);
+ break;
- case FM_DEEMPH_75:
- set_audio_registers(core, fm_deemph_75);
- break;
+ case FM_DEEMPH_75:
+ set_audio_registers(core, fm_deemph_75);
+ break;
}
set_audio_finish(core, EN_FMRADIO_AUTO_STEREO);
@@ -728,36 +705,64 @@ static void set_audio_standard_FM(struct cx88_core *core, enum cx88_deemph_type
/* ----------------------------------------------------------- */
+int cx88_detect_nicam(struct cx88_core *core)
+{
+ int i, j = 0;
+
+ dprintk("start nicam autodetect.\n");
+
+ for (i = 0; i < 6; i++) {
+ /* if bit1=1 then nicam is detected */
+ j += ((cx_read(AUD_NICAM_STATUS2) & 0x02) >> 1);
+
+ /* 3x detected: absolutly sure now */
+ if (j == 3) {
+ dprintk("nicam is detected.\n");
+ return 1;
+ }
+
+ /* wait a little bit for next reading status */
+ msleep(10);
+ }
+
+ dprintk("nicam is not detected.\n");
+ return 0;
+}
+
void cx88_set_tvaudio(struct cx88_core *core)
{
switch (core->tvaudio) {
case WW_BTSC:
set_audio_standard_BTSC(core, 0, EN_BTSC_AUTO_STEREO);
break;
- case WW_NICAM_BGDKL:
- set_audio_standard_NICAM_L(core,0);
- break;
- case WW_NICAM_I:
- set_audio_standard_PAL_I(core,0);
- break;
- case WW_A2_BG:
- case WW_A2_DK:
- case WW_A2_M:
- set_audio_standard_A2(core, EN_A2_FORCE_MONO1);
+ case WW_BG:
+ case WW_DK:
+ case WW_I:
+ case WW_L:
+ /* prepare all dsp registers */
+ set_audio_standard_A2(core, EN_A2_FORCE_MONO1);
+
+ /* set nicam mode - otherwise
+ AUD_NICAM_STATUS2 contains wrong values */
+ set_audio_standard_NICAM(core, EN_NICAM_AUTO_STEREO);
+ if (0 == cx88_detect_nicam(core)) {
+ /* fall back to fm / am mono */
+ set_audio_standard_A2(core, EN_A2_FORCE_MONO1);
+ core->use_nicam = 0;
+ } else {
+ core->use_nicam = 1;
+ }
break;
case WW_EIAJ:
set_audio_standard_EIAJ(core);
break;
case WW_FM:
- set_audio_standard_FM(core,FM_NO_DEEMPH);
- break;
- case WW_SYSTEM_L_AM:
- set_audio_standard_NICAM_L(core, 1);
+ set_audio_standard_FM(core, FM_NO_DEEMPH);
break;
case WW_NONE:
default:
printk("%s/0: unknown tv audio mode [%d]\n",
- core->name, core->tvaudio);
+ core->name, core->tvaudio);
break;
}
return;
@@ -766,24 +771,16 @@ void cx88_set_tvaudio(struct cx88_core *core)
void cx88_newstation(struct cx88_core *core)
{
core->audiomode_manual = UNSET;
-
- switch (core->tvaudio) {
- case WW_SYSTEM_L_AM:
- /* try nicam ... */
- core->audiomode_current = V4L2_TUNER_MODE_STEREO;
- set_audio_standard_NICAM_L(core, 1);
- break;
- }
}
void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
{
- static char *m[] = {"stereo", "dual mono", "mono", "sap"};
- static char *p[] = {"no pilot", "pilot c1", "pilot c2", "?"};
- u32 reg,mode,pilot;
+ static char *m[] = { "stereo", "dual mono", "mono", "sap" };
+ static char *p[] = { "no pilot", "pilot c1", "pilot c2", "?" };
+ u32 reg, mode, pilot;
- reg = cx_read(AUD_STATUS);
- mode = reg & 0x03;
+ reg = cx_read(AUD_STATUS);
+ mode = reg & 0x03;
pilot = (reg >> 2) & 0x03;
if (core->astat != reg)
@@ -800,14 +797,13 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
# if 0
t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP |
- V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
+ V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
t->rxsubchans = V4L2_TUNER_SUB_MONO;
- t->audmode = V4L2_TUNER_MODE_MONO;
+ t->audmode = V4L2_TUNER_MODE_MONO;
switch (core->tvaudio) {
case WW_BTSC:
- t->capability = V4L2_TUNER_CAP_STEREO |
- V4L2_TUNER_CAP_SAP;
+ t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP;
t->rxsubchans = V4L2_TUNER_SUB_STEREO;
if (1 == pilot) {
/* SAP */
@@ -819,13 +815,15 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
case WW_A2_M:
if (1 == pilot) {
/* stereo */
- t->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+ t->rxsubchans =
+ V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
if (0 == mode)
t->audmode = V4L2_TUNER_MODE_STEREO;
}
if (2 == pilot) {
/* dual language -- FIXME */
- t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+ t->rxsubchans =
+ V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
t->audmode = V4L2_TUNER_MODE_LANG1;
}
break;
@@ -840,7 +838,7 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
t->audmode = V4L2_TUNER_MODE_STEREO;
t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
}
- break ;
+ break;
default:
/* nothing */
break;
@@ -851,7 +849,7 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual)
{
- u32 ctl = UNSET;
+ u32 ctl = UNSET;
u32 mask = UNSET;
if (manual) {
@@ -879,68 +877,58 @@ void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual)
break;
}
break;
- case WW_A2_BG:
- case WW_A2_DK:
- case WW_A2_M:
- switch (mode) {
- case V4L2_TUNER_MODE_MONO:
- case V4L2_TUNER_MODE_LANG1:
- set_audio_standard_A2(core, EN_A2_FORCE_MONO1);
- break;
- case V4L2_TUNER_MODE_LANG2:
- set_audio_standard_A2(core, EN_A2_FORCE_MONO2);
- break;
- case V4L2_TUNER_MODE_STEREO:
- set_audio_standard_A2(core, EN_A2_FORCE_STEREO);
- break;
- }
- break;
- case WW_NICAM_BGDKL:
- switch (mode) {
- case V4L2_TUNER_MODE_MONO:
- ctl = EN_NICAM_FORCE_MONO1;
- mask = 0x3f;
- break;
- case V4L2_TUNER_MODE_LANG1:
- ctl = EN_NICAM_AUTO_MONO2;
- mask = 0x3f;
- break;
- case V4L2_TUNER_MODE_STEREO:
- ctl = EN_NICAM_FORCE_STEREO | EN_DMTRX_LR;
- mask = 0x93f;
- break;
- }
- break;
- case WW_SYSTEM_L_AM:
- switch (mode) {
- case V4L2_TUNER_MODE_MONO:
- case V4L2_TUNER_MODE_LANG1: /* FIXME */
- set_audio_standard_NICAM_L(core, 0);
- break;
- case V4L2_TUNER_MODE_STEREO:
- set_audio_standard_NICAM_L(core, 1);
- break;
- }
- break;
- case WW_NICAM_I:
- switch (mode) {
- case V4L2_TUNER_MODE_MONO:
- case V4L2_TUNER_MODE_LANG1:
- set_audio_standard_PAL_I(core, 0);
- break;
- case V4L2_TUNER_MODE_STEREO:
- set_audio_standard_PAL_I(core, 1);
- break;
+ case WW_BG:
+ case WW_DK:
+ case WW_I:
+ case WW_L:
+ if (1 == core->use_nicam) {
+ switch (mode) {
+ case V4L2_TUNER_MODE_MONO:
+ case V4L2_TUNER_MODE_LANG1:
+ set_audio_standard_NICAM(core,
+ EN_NICAM_FORCE_MONO1);
+ break;
+ case V4L2_TUNER_MODE_LANG2:
+ set_audio_standard_NICAM(core,
+ EN_NICAM_FORCE_MONO2);
+ break;
+ case V4L2_TUNER_MODE_STEREO:
+ set_audio_standard_NICAM(core,
+ EN_NICAM_FORCE_STEREO);
+ break;
+ }
+ } else {
+ if ((core->tvaudio == WW_I) || (core->tvaudio == WW_L)) {
+ /* fall back to fm / am mono */
+ set_audio_standard_A2(core, EN_A2_FORCE_MONO1);
+ } else {
+ /* TODO: Add A2 autodection */
+ switch (mode) {
+ case V4L2_TUNER_MODE_MONO:
+ case V4L2_TUNER_MODE_LANG1:
+ set_audio_standard_A2(core,
+ EN_A2_FORCE_MONO1);
+ break;
+ case V4L2_TUNER_MODE_LANG2:
+ set_audio_standard_A2(core,
+ EN_A2_FORCE_MONO2);
+ break;
+ case V4L2_TUNER_MODE_STEREO:
+ set_audio_standard_A2(core,
+ EN_A2_FORCE_STEREO);
+ break;
+ }
+ }
}
break;
case WW_FM:
switch (mode) {
case V4L2_TUNER_MODE_MONO:
- ctl = EN_FMRADIO_FORCE_MONO;
+ ctl = EN_FMRADIO_FORCE_MONO;
mask = 0x3f;
break;
case V4L2_TUNER_MODE_STEREO:
- ctl = EN_FMRADIO_AUTO_STEREO;
+ ctl = EN_FMRADIO_AUTO_STEREO;
mask = 0x3f;
break;
}
@@ -970,8 +958,8 @@ int cx88_audio_thread(void *data)
break;
/* just monitor the audio status for now ... */
- memset(&t,0,sizeof(t));
- cx88_get_stereo(core,&t);
+ memset(&t, 0, sizeof(t));
+ cx88_get_stereo(core, &t);
if (UNSET != core->audiomode_manual)
/* manually set, don't do anything. */
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index 3dbc074fb51..24a48f8a48c 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -34,6 +34,9 @@
#include "cx88.h"
+/* Include V4L1 specific functions. Should be removed soon */
+#include <linux/videodev.h>
+
MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
MODULE_LICENSE("GPL");
@@ -100,7 +103,7 @@ static struct cx88_tvnorm tvnorms[] = {
.id = V4L2_STD_PAL_I,
.cxiformat = VideoFormatPAL,
.cxoformat = 0x181f0008,
- },{
+ },{
.name = "PAL-M",
.id = V4L2_STD_PAL_M,
.cxiformat = VideoFormatPALM,
@@ -470,7 +473,7 @@ static int restart_video_queue(struct cx8800_dev *dev,
struct list_head *item;
if (!list_empty(&q->active)) {
- buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
+ buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
dprintk(2,"restart_queue [%p/%d]: restart dma\n",
buf, buf->vb.i);
start_video_dma(dev, q, buf);
@@ -486,7 +489,7 @@ static int restart_video_queue(struct cx8800_dev *dev,
for (;;) {
if (list_empty(&q->queued))
return 0;
- buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue);
+ buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue);
if (NULL == prev) {
list_del(&buf->vb.queue);
list_add_tail(&buf->vb.queue,&q->active);
@@ -783,11 +786,11 @@ static int video_open(struct inode *inode, struct file *file)
cx88_call_i2c_clients(core,AUDC_SET_RADIO,NULL);
}
- return 0;
+ return 0;
}
static ssize_t
-video_read(struct file *file, char *data, size_t count, loff_t *ppos)
+video_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
{
struct cx8800_fh *fh = file->private_data;
@@ -922,7 +925,7 @@ static int set_control(struct cx88_core *core, struct v4l2_control *ctl)
{
/* struct cx88_core *core = dev->core; */
struct cx88_ctrl *c = NULL;
- u32 v_sat_value;
+ u32 v_sat_value;
u32 value;
int i;
@@ -1187,7 +1190,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
struct v4l2_format *f = arg;
return cx8800_try_fmt(dev,fh,f);
}
-
+#ifdef HAVE_V4L1
/* --- streaming capture ------------------------------------- */
case VIDIOCGMBUF:
{
@@ -1213,6 +1216,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
}
return 0;
}
+#endif
case VIDIOC_REQBUFS:
return videobuf_reqbufs(get_queue(fh), arg);
@@ -1244,7 +1248,6 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
res_free(dev,fh,res);
return 0;
}
-
default:
return cx88_do_ioctl( inode, file, fh->radio, core, cmd, arg, video_do_ioctl );
}
@@ -1252,15 +1255,13 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
}
int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
- struct cx88_core *core, unsigned int cmd, void *arg, v4l2_kioctl driver_ioctl)
+ struct cx88_core *core, unsigned int cmd, void *arg, v4l2_kioctl driver_ioctl)
{
int err;
+ dprintk( 1, "CORE IOCTL: 0x%x\n", cmd );
if (video_debug > 1)
cx88_print_ioctl(core->name,cmd);
- printk( KERN_INFO "CORE IOCTL: 0x%x\n", cmd );
- cx88_print_ioctl(core->name,cmd);
- dprintk( 1, "CORE IOCTL: 0x%x\n", cmd );
switch (cmd) {
/* ---------- tv norms ---------- */
@@ -1401,7 +1402,7 @@ int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
cx88_get_stereo(core ,t);
reg = cx_read(MO_DEVICE_STATUS);
- t->signal = (reg & (1<<5)) ? 0xffff : 0x0000;
+ t->signal = (reg & (1<<5)) ? 0xffff : 0x0000;
return 0;
}
case VIDIOC_S_TUNER:
@@ -1488,7 +1489,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
struct v4l2_capability *cap = arg;
memset(cap,0,sizeof(*cap));
- strcpy(cap->driver, "cx8800");
+ strcpy(cap->driver, "cx8800");
strlcpy(cap->card, cx88_boards[core->board].name,
sizeof(cap->card));
sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci));
@@ -1505,6 +1506,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
memset(t,0,sizeof(*t));
strcpy(t->name, "Radio");
+ t->type = V4L2_TUNER_RADIO;
cx88_call_i2c_clients(core,VIDIOC_G_TUNER,t);
return 0;
@@ -1539,6 +1541,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
*id = 0;
return 0;
}
+#ifdef HAVE_V4L1
case VIDIOCSTUNER:
{
struct video_tuner *v = arg;
@@ -1549,6 +1552,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
cx88_call_i2c_clients(core,VIDIOCSTUNER,v);
return 0;
}
+#endif
case VIDIOC_S_TUNER:
{
struct v4l2_tuner *t = arg;
@@ -1829,8 +1833,8 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
/* print pci info */
pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
- pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat);
- printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, "
+ pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat);
+ printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, "
"latency: %d, mmio: 0x%lx\n", core->name,
pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
dev->pci_lat,pci_resource_start(pci_dev,0));
@@ -1946,7 +1950,7 @@ fail_free:
static void __devexit cx8800_finidev(struct pci_dev *pci_dev)
{
- struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
+ struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
struct cx88_core *core = dev->core;
/* stop thread */
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index f48dd435356..b19d3a9e229 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -22,7 +22,7 @@
#include <linux/pci.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
#include <linux/kdev_t.h>
#include <media/tuner.h>
@@ -148,7 +148,7 @@ extern struct sram_channel cx88_sram_channels[];
#define CX88_BOARD_PIXELVIEW 3
#define CX88_BOARD_ATI_WONDER_PRO 4
#define CX88_BOARD_WINFAST2000XP_EXPERT 5
-#define CX88_BOARD_AVERTV_303 6
+#define CX88_BOARD_AVERTV_STUDIO_303 6
#define CX88_BOARD_MSI_TVANYWHERE_MASTER 7
#define CX88_BOARD_WINFAST_DV2000 8
#define CX88_BOARD_LEADTEK_PVR2000 9
@@ -174,6 +174,11 @@ extern struct sram_channel cx88_sram_channels[];
#define CX88_BOARD_ADSTECH_DVB_T_PCI 29
#define CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1 30
#define CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD 31
+#define CX88_BOARD_AVERMEDIA_ULTRATV_MC_550 32
+#define CX88_BOARD_KWORLD_VSTREAM_EXPERT_DVD 33
+#define CX88_BOARD_ATI_HDTVWONDER 34
+#define CX88_BOARD_WINFAST_DTV1000 35
+#define CX88_BOARD_AVERTV_303 36
enum cx88_itype {
CX88_VMUX_COMPOSITE1 = 1,
@@ -203,8 +208,8 @@ struct cx88_board {
int tda9887_conf;
struct cx88_input input[MAX_CX88_INPUT];
struct cx88_input radio;
- int blackbird:1;
- int dvb:1;
+ unsigned int blackbird:1;
+ unsigned int dvb:1;
};
struct cx88_subid {
@@ -255,8 +260,8 @@ struct cx88_core {
/* pci stuff */
int pci_bus;
int pci_slot;
- u32 __iomem *lmmio;
- u8 __iomem *bmmio;
+ u32 __iomem *lmmio;
+ u8 __iomem *bmmio;
u32 shadow[SHADOW_MAX];
int pci_irqmask;
@@ -287,6 +292,7 @@ struct cx88_core {
u32 audiomode_current;
u32 input;
u32 astat;
+ u32 use_nicam;
/* IR remote control state */
struct cx88_IR *ir;
@@ -370,6 +376,14 @@ struct cx8802_suspend_state {
int disabled;
};
+/* TODO: move this to struct v4l2_mpeg_compression ? */
+struct blackbird_dnr {
+ u32 mode;
+ u32 type;
+ u32 spatial;
+ u32 temporal;
+};
+
struct cx8802_dev {
struct cx88_core *core;
spinlock_t slock;
@@ -400,6 +414,10 @@ struct cx8802_dev {
/* for switching modulation types */
unsigned char ts_gen_cntrl;
+
+ /* mpeg params */
+ struct v4l2_mpeg_compression params;
+ struct blackbird_dnr dnr_params;
};
/* ----------------------------------------------------------- */
@@ -514,22 +532,20 @@ extern void cx88_card_setup(struct cx88_core *core);
#define WW_NONE 1
#define WW_BTSC 2
-#define WW_NICAM_I 3
-#define WW_NICAM_BGDKL 4
-#define WW_A1 5
-#define WW_A2_BG 6
-#define WW_A2_DK 7
-#define WW_A2_M 8
-#define WW_EIAJ 9
-#define WW_SYSTEM_L_AM 10
-#define WW_I2SPT 11
-#define WW_FM 12
+#define WW_BG 3
+#define WW_DK 4
+#define WW_I 5
+#define WW_L 6
+#define WW_EIAJ 7
+#define WW_I2SPT 8
+#define WW_FM 9
void cx88_set_tvaudio(struct cx88_core *core);
void cx88_newstation(struct cx88_core *core);
void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t);
void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual);
int cx88_audio_thread(void *data);
+int cx88_detect_nicam(struct cx88_core *core);
/* ----------------------------------------------------------- */
/* cx88-input.c */
@@ -541,7 +557,8 @@ void cx88_ir_irq(struct cx88_core *core);
/* ----------------------------------------------------------- */
/* cx88-mpeg.c */
-int cx8802_buf_prepare(struct cx8802_dev *dev, struct cx88_buffer *buf);
+int cx8802_buf_prepare(struct cx8802_dev *dev, struct cx88_buffer *buf,
+ enum v4l2_field field);
void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf);
void cx8802_cancel_buffers(struct cx8802_dev *dev);
@@ -562,6 +579,10 @@ extern int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
extern int (*cx88_ioctl_hook)(struct inode *inode, struct file *file,
unsigned int cmd, void *arg);
extern unsigned int (*cx88_ioctl_translator)(unsigned int cmd);
+void blackbird_set_params(struct cx8802_dev *dev,
+ struct v4l2_mpeg_compression *params);
+void blackbird_set_dnr_params(struct cx8802_dev *dev,
+ struct blackbird_dnr* dnr_params);
/*
* Local variables:
diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig
new file mode 100644
index 00000000000..885fd017008
--- /dev/null
+++ b/drivers/media/video/em28xx/Kconfig
@@ -0,0 +1,12 @@
+config VIDEO_EM28XX
+ tristate "Empia EM2800/2820/2840 USB video capture support"
+ depends on VIDEO_DEV && USB && I2C
+ select VIDEO_BUF
+ select VIDEO_TUNER
+ select VIDEO_TVEEPROM
+ select VIDEO_IR
+ ---help---
+ This is a video4linux driver for Empia 28xx based TV cards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called em28xx
diff --git a/drivers/media/video/em28xx/Makefile b/drivers/media/video/em28xx/Makefile
new file mode 100644
index 00000000000..da457a05b0d
--- /dev/null
+++ b/drivers/media/video/em28xx/Makefile
@@ -0,0 +1,6 @@
+em28xx-objs := em28xx-video.o em28xx-i2c.o em28xx-cards.o em28xx-core.o \
+ em28xx-input.o
+
+obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o
+
+EXTRA_CFLAGS += -I$(src)/..
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
new file mode 100644
index 00000000000..57779e63f35
--- /dev/null
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -0,0 +1,292 @@
+/*
+ em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+
+ Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+ Markus Rechberger <mrechberger@gmail.com>
+ Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ Sascha Sommer <saschasommer@freenet.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/usb.h>
+#include <media/tuner.h>
+#include <media/audiochip.h>
+#include <media/tveeprom.h>
+#include "msp3400.h"
+
+#include "em28xx.h"
+
+struct em28xx_board em28xx_boards[] = {
+ [EM2800_BOARD_UNKNOWN] = {
+ .name = "Unknown EM2800 video grabber",
+ .is_em2800 = 1,
+ .vchannels = 2,
+ .norm = VIDEO_MODE_PAL,
+ .tda9887_conf = TDA9887_PRESENT,
+ .has_tuner = 1,
+ .decoder = EM28XX_SAA7113,
+ .input = {{
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = 0,
+ .amux = 1,
+ },{
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = 9,
+ .amux = 1,
+ }},
+ },
+ [EM2820_BOARD_UNKNOWN] = {
+ .name = "Unknown EM2820/2840 video grabber",
+ .is_em2800 = 0,
+ .vchannels = 2,
+ .norm = VIDEO_MODE_PAL,
+ .tda9887_conf = TDA9887_PRESENT,
+ .has_tuner = 1,
+ .decoder = EM28XX_SAA7113,
+ .input = {{
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = 0,
+ .amux = 1,
+ },{
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = 9,
+ .amux = 1,
+ }},
+ },
+ [EM2820_BOARD_TERRATEC_CINERGY_250] = {
+ .name = "Terratec Cinergy 250 USB",
+ .vchannels = 3,
+ .norm = VIDEO_MODE_PAL,
+ .tuner_type = TUNER_LG_PAL_NEW_TAPC,
+ .tda9887_conf = TDA9887_PRESENT,
+ .has_tuner = 1,
+ .decoder = EM28XX_SAA7113,
+ .input = {{
+ .type = EM28XX_VMUX_TELEVISION,
+ .vmux = 2,
+ .amux = 0,
+ },{
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = 0,
+ .amux = 1,
+ },{
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = 9,
+ .amux = 1,
+ }},
+ },
+ [EM2820_BOARD_PINNACLE_USB_2] = {
+ .name = "Pinnacle PCTV USB 2",
+ .vchannels = 3,
+ .norm = VIDEO_MODE_PAL,
+ .tuner_type = TUNER_LG_PAL_NEW_TAPC,
+ .tda9887_conf = TDA9887_PRESENT,
+ .has_tuner = 1,
+ .decoder = EM28XX_SAA7113,
+ .input = {{
+ .type = EM28XX_VMUX_TELEVISION,
+ .vmux = 2,
+ .amux = 0,
+ },{
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = 0,
+ .amux = 1,
+ },{
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = 9,
+ .amux = 1,
+ }},
+ },
+ [EM2820_BOARD_HAUPPAUGE_WINTV_USB_2] = {
+ .name = "Hauppauge WinTV USB 2",
+ .vchannels = 3,
+ .norm = VIDEO_MODE_NTSC,
+ .tuner_type = TUNER_PHILIPS_FM1236_MK3,
+ .tda9887_conf = TDA9887_PRESENT|TDA9887_PORT1_ACTIVE|TDA9887_PORT2_ACTIVE,
+ .has_tuner = 1,
+ .decoder = EM28XX_TVP5150,
+ .has_msp34xx = 1,
+ /*FIXME: S-Video not tested */
+ .input = {{
+ .type = EM28XX_VMUX_TELEVISION,
+ .vmux = 0,
+ .amux = 6,
+ },{
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = 2,
+ .amux = 1,
+ }},
+ },
+ [EM2820_BOARD_MSI_VOX_USB_2] = {
+ .name = "MSI VOX USB 2.0",
+ .vchannels = 3,
+ .norm = VIDEO_MODE_PAL,
+ .tuner_type = TUNER_LG_PAL_NEW_TAPC,
+ .tda9887_conf = TDA9887_PRESENT|TDA9887_PORT1_ACTIVE|TDA9887_PORT2_ACTIVE,
+ .has_tuner = 1,
+ .decoder = EM28XX_SAA7114,
+ .input = {{
+ .type = EM28XX_VMUX_TELEVISION,
+ .vmux = 4,
+ .amux = 0,
+ },{
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = 0,
+ .amux = 1,
+ },{
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = 9,
+ .amux = 1,
+ }},
+ },
+ [EM2800_BOARD_TERRATEC_CINERGY_200] = {
+ .name = "Terratec Cinergy 200 USB",
+ .is_em2800 = 1,
+ .vchannels = 3,
+ .norm = VIDEO_MODE_PAL,
+ .tuner_type = TUNER_LG_PAL_NEW_TAPC,
+ .tda9887_conf = TDA9887_PRESENT,
+ .has_tuner = 1,
+ .decoder = EM28XX_SAA7113,
+ .input = {{
+ .type = EM28XX_VMUX_TELEVISION,
+ .vmux = 2,
+ .amux = 0,
+ },{
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = 0,
+ .amux = 1,
+ },{
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = 9,
+ .amux = 1,
+ }},
+ },
+ [EM2800_BOARD_LEADTEK_WINFAST_USBII] = {
+ .name = "Leadtek Winfast USB II",
+ .is_em2800 = 1,
+ .vchannels = 3,
+ .norm = VIDEO_MODE_PAL,
+ .tuner_type = TUNER_LG_PAL_NEW_TAPC,
+ .tda9887_conf = TDA9887_PRESENT,
+ .has_tuner = 1,
+ .decoder = EM28XX_SAA7113,
+ .input = {{
+ .type = EM28XX_VMUX_TELEVISION,
+ .vmux = 2,
+ .amux = 0,
+ },{
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = 0,
+ .amux = 1,
+ },{
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = 9,
+ .amux = 1,
+ }},
+ },
+ [EM2800_BOARD_KWORLD_USB2800] = {
+ .name = "Kworld USB2800",
+ .is_em2800 = 1,
+ .vchannels = 3,
+ .norm = VIDEO_MODE_PAL,
+ .tuner_type = TUNER_PHILIPS_ATSC,
+ .tda9887_conf = TDA9887_PRESENT,
+ .has_tuner = 1,
+ .decoder = EM28XX_SAA7113,
+ .input = {{
+ .type = EM28XX_VMUX_TELEVISION,
+ .vmux = 2,
+ .amux = 0,
+ },{
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = 0,
+ .amux = 1,
+ },{
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = 9,
+ .amux = 1,
+ }},
+ },
+ [EM2820_BOARD_PINNACLE_DVC_90] = {
+ .name = "Pinnacle Dazzle DVC 90",
+ .vchannels = 3,
+ .norm = VIDEO_MODE_PAL,
+ .has_tuner = 0,
+ .decoder = EM28XX_SAA7113,
+ .input = {{
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = 0,
+ .amux = 1,
+ },{
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = 9,
+ .amux = 1,
+ }},
+ },
+};
+const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
+
+/* table of devices that work with this driver */
+struct usb_device_id em28xx_id_table [] = {
+ { USB_DEVICE(0xeb1a, 0x2800), .driver_info = EM2800_BOARD_UNKNOWN },
+ { USB_DEVICE(0xeb1a, 0x2820), .driver_info = EM2820_BOARD_MSI_VOX_USB_2 },
+ { USB_DEVICE(0x0ccd, 0x0036), .driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 },
+ { USB_DEVICE(0x2304, 0x0208), .driver_info = EM2820_BOARD_PINNACLE_USB_2 },
+ { USB_DEVICE(0x2040, 0x4200), .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 },
+ { USB_DEVICE(0x2304, 0x0207), .driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
+ { },
+};
+
+void em28xx_card_setup(struct em28xx *dev)
+{
+ /* request some modules */
+ if (dev->model == EM2820_BOARD_HAUPPAUGE_WINTV_USB_2) {
+ struct tveeprom tv;
+ struct v4l2_audioout ao;
+#ifdef CONFIG_MODULES
+ request_module("tveeprom");
+ request_module("ir-kbd-i2c");
+ request_module("msp3400");
+#endif
+ /* Call first TVeeprom */
+
+ dev->i2c_client.addr = 0xa0 >> 1;
+ tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata);
+
+ dev->tuner_type= tv.tuner_type;
+ if (tv.audio_processor == AUDIO_CHIP_MSP34XX) {
+ dev->has_msp34xx=1;
+ memset (&ao,0,sizeof(ao));
+
+ ao.index=2;
+ ao.mode=V4L2_AUDMODE_32BITS;
+ em28xx_i2c_call_clients(dev, VIDIOC_S_AUDOUT, &ao);
+ } else
+ dev->has_msp34xx=0;
+ }
+}
+
+EXPORT_SYMBOL(em28xx_boards);
+EXPORT_SYMBOL(em28xx_bcount);
+EXPORT_SYMBOL(em28xx_id_table);
+
+MODULE_DEVICE_TABLE (usb, em28xx_id_table);
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
new file mode 100644
index 00000000000..d54bc012748
--- /dev/null
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -0,0 +1,817 @@
+/*
+ em28xx-core.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+
+ Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+ Markus Rechberger <mrechberger@gmail.com>
+ Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ Sascha Sommer <saschasommer@freenet.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/usb.h>
+#include <linux/vmalloc.h>
+
+#include "em28xx.h"
+
+/* #define ENABLE_DEBUG_ISOC_FRAMES */
+
+unsigned int core_debug;
+module_param(core_debug,int,0644);
+MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
+
+#define em28xx_coredbg(fmt, arg...) do {\
+ if (core_debug) \
+ printk(KERN_INFO "%s %s :"fmt, \
+ dev->name, __FUNCTION__ , ##arg); } while (0)
+
+unsigned int reg_debug;
+module_param(reg_debug,int,0644);
+MODULE_PARM_DESC(reg_debug,"enable debug messages [URB reg]");
+
+#define em28xx_regdbg(fmt, arg...) do {\
+ if (reg_debug) \
+ printk(KERN_INFO "%s %s :"fmt, \
+ dev->name, __FUNCTION__ , ##arg); } while (0)
+
+unsigned int isoc_debug;
+module_param(isoc_debug,int,0644);
+MODULE_PARM_DESC(isoc_debug,"enable debug messages [isoc transfers]");
+
+#define em28xx_isocdbg(fmt, arg...) do {\
+ if (isoc_debug) \
+ printk(KERN_INFO "%s %s :"fmt, \
+ dev->name, __FUNCTION__ , ##arg); } while (0)
+
+static int alt = EM28XX_PINOUT;
+module_param(alt, int, 0644);
+MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
+
+/* ------------------------------------------------------------------ */
+/* debug help functions */
+
+static const char *v4l1_ioctls[] = {
+ "0", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT",
+ "CCAPTURE", "GWIN", "SWIN", "GFBUF", "SFBUF", "KEY", "GFREQ",
+ "SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT",
+ "GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO",
+ "SMICROCODE", "GVBIFMT", "SVBIFMT" };
+#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls)
+
+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 ARRAY_SIZE(v4l2_ioctls)
+
+void em28xx_print_ioctl(char *name, unsigned int cmd)
+{
+ char *dir;
+
+ switch (_IOC_DIR(cmd)) {
+ case _IOC_NONE: dir = "--"; break;
+ case _IOC_READ: dir = "r-"; break;
+ case _IOC_WRITE: dir = "-w"; break;
+ case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
+ default: dir = "??"; break;
+ }
+ switch (_IOC_TYPE(cmd)) {
+ case 'v':
+ printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l1, %s, VIDIOC%s)\n",
+ name, cmd, dir, (_IOC_NR(cmd) < V4L1_IOCTLS) ?
+ v4l1_ioctls[_IOC_NR(cmd)] : "???");
+ break;
+ case 'V':
+ printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l2, %s, VIDIOC_%s)\n",
+ name, cmd, dir, (_IOC_NR(cmd) < V4L2_IOCTLS) ?
+ v4l2_ioctls[_IOC_NR(cmd)] : "???");
+ break;
+ default:
+ printk(KERN_DEBUG "%s: ioctl 0x%08x (???, %s, #%d)\n",
+ name, cmd, dir, _IOC_NR(cmd));
+ }
+}
+
+static void *rvmalloc(size_t size)
+{
+ void *mem;
+ unsigned long adr;
+
+ size = PAGE_ALIGN(size);
+
+ mem = vmalloc_32((unsigned long)size);
+ if (!mem)
+ return NULL;
+
+ memset(mem, 0, size);
+
+ adr = (unsigned long)mem;
+ while (size > 0) {
+ SetPageReserved(vmalloc_to_page((void *)adr));
+ adr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+
+ return mem;
+}
+
+static void rvfree(void *mem, size_t size)
+{
+ unsigned long adr;
+
+ if (!mem)
+ return;
+
+ size = PAGE_ALIGN(size);
+
+ adr = (unsigned long)mem;
+ while (size > 0) {
+ ClearPageReserved(vmalloc_to_page((void *)adr));
+ adr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+
+ vfree(mem);
+}
+
+/*
+ * em28xx_request_buffers()
+ * allocate a number of buffers
+ */
+u32 em28xx_request_buffers(struct em28xx *dev, u32 count)
+{
+ const size_t imagesize = PAGE_ALIGN(dev->frame_size); /*needs to be page aligned cause the buffers can be mapped individually! */
+ void *buff = NULL;
+ u32 i;
+ em28xx_coredbg("requested %i buffers with size %i", count, imagesize);
+ if (count > EM28XX_NUM_FRAMES)
+ count = EM28XX_NUM_FRAMES;
+
+ dev->num_frames = count;
+ while (dev->num_frames > 0) {
+ if ((buff = rvmalloc(dev->num_frames * imagesize)))
+ break;
+ dev->num_frames--;
+ }
+
+ for (i = 0; i < dev->num_frames; i++) {
+ dev->frame[i].bufmem = buff + i * imagesize;
+ dev->frame[i].buf.index = i;
+ dev->frame[i].buf.m.offset = i * imagesize;
+ dev->frame[i].buf.length = dev->frame_size;
+ dev->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ dev->frame[i].buf.sequence = 0;
+ dev->frame[i].buf.field = V4L2_FIELD_NONE;
+ dev->frame[i].buf.memory = V4L2_MEMORY_MMAP;
+ dev->frame[i].buf.flags = 0;
+ }
+ return dev->num_frames;
+}
+
+/*
+ * em28xx_queue_unusedframes()
+ * add all frames that are not currently in use to the inbuffer queue
+ */
+void em28xx_queue_unusedframes(struct em28xx *dev)
+{
+ unsigned long lock_flags;
+ u32 i;
+
+ for (i = 0; i < dev->num_frames; i++)
+ if (dev->frame[i].state == F_UNUSED) {
+ dev->frame[i].state = F_QUEUED;
+ spin_lock_irqsave(&dev->queue_lock, lock_flags);
+ list_add_tail(&dev->frame[i].frame, &dev->inqueue);
+ spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
+ }
+}
+
+/*
+ * em28xx_release_buffers()
+ * free frame buffers
+ */
+void em28xx_release_buffers(struct em28xx *dev)
+{
+ if (dev->num_frames) {
+ rvfree(dev->frame[0].bufmem,
+ dev->num_frames * PAGE_ALIGN(dev->frame[0].buf.length));
+ dev->num_frames = 0;
+ }
+}
+
+/*
+ * em28xx_read_reg_req()
+ * reads data from the usb device specifying bRequest
+ */
+int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
+ char *buf, int len)
+{
+ int ret, byte;
+
+ em28xx_regdbg("req=%02x, reg=%02x ", req, reg);
+
+ ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), req,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0x0000, reg, buf, len, HZ);
+
+ if (reg_debug){
+ printk(ret < 0 ? " failed!\n" : "%02x values: ", ret);
+ for (byte = 0; byte < len; byte++) {
+ printk(" %02x", buf[byte]);
+ }
+ printk("\n");
+ }
+
+ return ret;
+}
+
+/*
+ * em28xx_read_reg_req()
+ * reads data from the usb device specifying bRequest
+ */
+int em28xx_read_reg_req(struct em28xx *dev, u8 req, u16 reg)
+{
+ u8 val;
+ int ret;
+
+ em28xx_regdbg("req=%02x, reg=%02x:", req, reg);
+
+ ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), req,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0x0000, reg, &val, 1, HZ);
+
+ if (reg_debug)
+ printk(ret < 0 ? " failed!\n" : "%02x\n", val);
+
+ if (ret < 0)
+ return ret;
+
+ return val;
+}
+
+int em28xx_read_reg(struct em28xx *dev, u16 reg)
+{
+ return em28xx_read_reg_req(dev, USB_REQ_GET_STATUS, reg);
+}
+
+/*
+ * em28xx_write_regs_req()
+ * sends data to the usb device, specifying bRequest
+ */
+int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
+ int len)
+{
+ int ret;
+
+ /*usb_control_msg seems to expect a kmalloced buffer */
+ unsigned char *bufs = kmalloc(len, GFP_KERNEL);
+
+ em28xx_regdbg("req=%02x reg=%02x:", req, reg);
+
+ if (reg_debug) {
+ int i;
+ for (i = 0; i < len; ++i)
+ printk (" %02x", (unsigned char)buf[i]);
+ printk ("\n");
+ }
+
+ if (!bufs)
+ return -ENOMEM;
+ memcpy(bufs, buf, len);
+ ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), req,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0x0000, reg, bufs, len, HZ);
+ mdelay(5); /* FIXME: magic number */
+ kfree(bufs);
+ return ret;
+}
+
+int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len)
+{
+ return em28xx_write_regs_req(dev, USB_REQ_GET_STATUS, reg, buf, len);
+}
+
+/*
+ * em28xx_write_reg_bits()
+ * sets only some bits (specified by bitmask) of a register, by first reading
+ * the actual value
+ */
+int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
+ u8 bitmask)
+{
+ int oldval;
+ u8 newval;
+ if ((oldval = em28xx_read_reg(dev, reg)) < 0)
+ return oldval;
+ newval = (((u8) oldval) & ~bitmask) | (val & bitmask);
+ return em28xx_write_regs(dev, reg, &newval, 1);
+}
+
+/*
+ * em28xx_write_ac97()
+ * write a 16 bit value to the specified AC97 address (LSB first!)
+ */
+int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 * val)
+{
+ int ret;
+ u8 addr = reg & 0x7f;
+ if ((ret = em28xx_write_regs(dev, AC97LSB_REG, val, 2)) < 0)
+ return ret;
+ if ((ret = em28xx_write_regs(dev, AC97ADDR_REG, &addr, 1)) < 0)
+ return ret;
+ if ((ret = em28xx_read_reg(dev, AC97BUSY_REG)) < 0)
+ return ret;
+ else if (((u8) ret) & 0x01) {
+ em28xx_warn ("AC97 command still being exectuted: not handled properly!\n");
+ }
+ return 0;
+}
+
+int em28xx_audio_analog_set(struct em28xx *dev)
+{
+ char s[2] = { 0x00, 0x00 };
+ s[0] |= 0x1f - dev->volume;
+ s[1] |= 0x1f - dev->volume;
+ if (dev->mute)
+ s[1] |= 0x80;
+ return em28xx_write_ac97(dev, MASTER_AC97, s);
+}
+
+
+int em28xx_colorlevels_set_default(struct em28xx *dev)
+{
+ em28xx_write_regs(dev, YGAIN_REG, "\x10", 1); /* contrast */
+ em28xx_write_regs(dev, YOFFSET_REG, "\x00", 1); /* brightness */
+ em28xx_write_regs(dev, UVGAIN_REG, "\x10", 1); /* saturation */
+ em28xx_write_regs(dev, UOFFSET_REG, "\x00", 1);
+ em28xx_write_regs(dev, VOFFSET_REG, "\x00", 1);
+ em28xx_write_regs(dev, SHARPNESS_REG, "\x00", 1);
+
+ em28xx_write_regs(dev, GAMMA_REG, "\x20", 1);
+ em28xx_write_regs(dev, RGAIN_REG, "\x20", 1);
+ em28xx_write_regs(dev, GGAIN_REG, "\x20", 1);
+ em28xx_write_regs(dev, BGAIN_REG, "\x20", 1);
+ em28xx_write_regs(dev, ROFFSET_REG, "\x00", 1);
+ em28xx_write_regs(dev, GOFFSET_REG, "\x00", 1);
+ return em28xx_write_regs(dev, BOFFSET_REG, "\x00", 1);
+}
+
+int em28xx_capture_start(struct em28xx *dev, int start)
+{
+ int ret;
+ /* FIXME: which is the best order? */
+ /* video registers are sampled by VREF */
+ if ((ret = em28xx_write_reg_bits(dev, USBSUSP_REG, start ? 0x10 : 0x00,
+ 0x10)) < 0)
+ return ret;
+ /* enable video capture */
+ return em28xx_write_regs(dev, VINENABLE_REG, start ? "\x67" : "\x27", 1);
+}
+
+int em28xx_outfmt_set_yuv422(struct em28xx *dev)
+{
+ em28xx_write_regs(dev, OUTFMT_REG, "\x34", 1);
+ em28xx_write_regs(dev, VINMODE_REG, "\x10", 1);
+ return em28xx_write_regs(dev, VINCTRL_REG, "\x11", 1);
+}
+
+int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, u8 ymin,
+ u8 ymax)
+{
+ em28xx_coredbg("em28xx Scale: (%d,%d)-(%d,%d)\n", xmin, ymin, xmax, ymax);
+
+ em28xx_write_regs(dev, XMIN_REG, &xmin, 1);
+ em28xx_write_regs(dev, XMAX_REG, &xmax, 1);
+ em28xx_write_regs(dev, YMIN_REG, &ymin, 1);
+ return em28xx_write_regs(dev, YMAX_REG, &ymax, 1);
+}
+
+int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
+ u16 width, u16 height)
+{
+ u8 cwidth = width;
+ u8 cheight = height;
+ u8 overflow = (height >> 7 & 0x02) | (width >> 8 & 0x01);
+
+ em28xx_coredbg("em28xx Area Set: (%d,%d)\n", (width | (overflow & 2) << 7),
+ (height | (overflow & 1) << 8));
+
+ em28xx_write_regs(dev, HSTART_REG, &hstart, 1);
+ em28xx_write_regs(dev, VSTART_REG, &vstart, 1);
+ em28xx_write_regs(dev, CWIDTH_REG, &cwidth, 1);
+ em28xx_write_regs(dev, CHEIGHT_REG, &cheight, 1);
+ return em28xx_write_regs(dev, OFLOW_REG, &overflow, 1);
+}
+
+int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
+{
+ u8 mode;
+ /* the em2800 scaler only supports scaling down to 50% */
+ if(dev->is_em2800)
+ mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00);
+ else {
+ u8 buf[2];
+ buf[0] = h;
+ buf[1] = h >> 8;
+ em28xx_write_regs(dev, HSCALELOW_REG, (char *)buf, 2);
+ buf[0] = v;
+ buf[1] = v >> 8;
+ em28xx_write_regs(dev, VSCALELOW_REG, (char *)buf, 2);
+ /* it seems that both H and V scalers must be active to work correctly */
+ mode = (h || v)? 0x30: 0x00;
+ }
+ return em28xx_write_reg_bits(dev, COMPR_REG, mode, 0x30);
+}
+
+/* FIXME: this only function read values from dev */
+int em28xx_resolution_set(struct em28xx *dev)
+{
+ int width, height;
+ width = norm_maxw(dev);
+ height = norm_maxh(dev) >> 1;
+
+ em28xx_outfmt_set_yuv422(dev);
+ em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2);
+ em28xx_capture_area_set(dev, 0, 0, width >> 2, height >> 2);
+ return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
+}
+
+
+/******************* isoc transfer handling ****************************/
+
+#ifdef ENABLE_DEBUG_ISOC_FRAMES
+static void em28xx_isoc_dump(struct urb *urb, struct pt_regs *regs)
+{
+ int len = 0;
+ int ntrans = 0;
+ int i;
+
+ printk(KERN_DEBUG "isocIrq: sf=%d np=%d ec=%x\n",
+ urb->start_frame, urb->number_of_packets,
+ urb->error_count);
+ for (i = 0; i < urb->number_of_packets; i++) {
+ unsigned char *buf =
+ urb->transfer_buffer +
+ urb->iso_frame_desc[i].offset;
+ int alen = urb->iso_frame_desc[i].actual_length;
+ if (alen > 0) {
+ if (buf[0] == 0x88) {
+ ntrans++;
+ len += alen;
+ } else if (buf[0] == 0x22) {
+ printk(KERN_DEBUG
+ "= l=%d nt=%d bpp=%d\n",
+ len - 4 * ntrans, ntrans,
+ ntrans == 0 ? 0 : len / ntrans);
+ ntrans = 1;
+ len = alen;
+ } else
+ printk(KERN_DEBUG "!\n");
+ }
+ printk(KERN_DEBUG " n=%d s=%d al=%d %x\n", i,
+ urb->iso_frame_desc[i].status,
+ urb->iso_frame_desc[i].actual_length,
+ (unsigned int)
+ *((unsigned char *)(urb->transfer_buffer +
+ urb->iso_frame_desc[i].
+ offset)));
+ }
+}
+#endif
+
+static inline int em28xx_isoc_video(struct em28xx *dev,struct em28xx_frame_t **f,
+ unsigned long *lock_flags, unsigned char buf)
+{
+ if (!(buf & 0x01)) {
+ if ((*f)->state == F_GRABBING) {
+ /*previous frame is incomplete */
+ if ((*f)->fieldbytesused < dev->field_size) {
+ (*f)->state = F_ERROR;
+ em28xx_isocdbg ("dropping incomplete bottom field (%i missing bytes)",
+ dev->field_size-(*f)->fieldbytesused);
+ } else {
+ (*f)->state = F_DONE;
+ (*f)->buf.bytesused = dev->frame_size;
+ }
+ }
+ if ((*f)->state == F_DONE || (*f)->state == F_ERROR) {
+ /* move current frame to outqueue and get next free buffer from inqueue */
+ spin_lock_irqsave(&dev-> queue_lock, *lock_flags);
+ list_move_tail(&(*f)->frame, &dev->outqueue);
+ if (!list_empty(&dev->inqueue))
+ (*f) = list_entry(dev-> inqueue.next,
+ struct em28xx_frame_t,frame);
+ else
+ (*f) = NULL;
+ spin_unlock_irqrestore(&dev->queue_lock,*lock_flags);
+ }
+ if (!(*f)) {
+ em28xx_isocdbg ("new frame but no buffer is free");
+ return -1;
+ }
+ do_gettimeofday(&(*f)->buf.timestamp);
+ (*f)->buf.sequence = ++dev->frame_count;
+ (*f)->buf.field = V4L2_FIELD_INTERLACED;
+ (*f)->state = F_GRABBING;
+ (*f)->buf.bytesused = 0;
+ (*f)->top_field = 1;
+ (*f)->fieldbytesused = 0;
+ } else {
+ /* acquiring bottom field */
+ if ((*f)->state == F_GRABBING) {
+ if (!(*f)->top_field) {
+ (*f)->state = F_ERROR;
+ em28xx_isocdbg ("unexpected begin of bottom field; discarding it");
+ } else if ((*f)-> fieldbytesused < dev->field_size - 172) {
+ (*f)->state = F_ERROR;
+ em28xx_isocdbg ("dropping incomplete top field (%i missing bytes)",
+ dev->field_size-(*f)->fieldbytesused);
+ } else {
+ (*f)->top_field = 0;
+ (*f)->fieldbytesused = 0;
+ }
+ }
+ }
+ return (0);
+}
+
+static inline void em28xx_isoc_video_copy(struct em28xx *dev,
+ struct em28xx_frame_t **f, unsigned char *buf, int len)
+{
+ void *fieldstart, *startwrite, *startread;
+ int linesdone, currlinedone, offset, lencopy,remain;
+
+ if(dev->frame_size != (*f)->buf.length){
+ em28xx_err("frame_size %i and buf.length %i are different!!!\n",dev->frame_size,(*f)->buf.length);
+ return;
+ }
+
+ if ((*f)->fieldbytesused + len > dev->field_size)
+ len =dev->field_size - (*f)->fieldbytesused;
+
+ if (buf[0] != 0x88 && buf[0] != 0x22) {
+ em28xx_isocdbg("frame is not complete\n");
+ startread = buf;
+ len+=4;
+ } else
+ startread = buf + 4;
+
+ remain = len;
+
+ if ((*f)->top_field)
+ fieldstart = (*f)->bufmem;
+ else
+ fieldstart = (*f)->bufmem + dev->bytesperline;
+
+ linesdone = (*f)->fieldbytesused / dev->bytesperline;
+ currlinedone = (*f)->fieldbytesused % dev->bytesperline;
+ offset = linesdone * dev->bytesperline * 2 + currlinedone;
+ startwrite = fieldstart + offset;
+ lencopy = dev->bytesperline - currlinedone;
+ lencopy = lencopy > remain ? remain : lencopy;
+
+ memcpy(startwrite, startread, lencopy);
+ remain -= lencopy;
+
+ while (remain > 0) {
+ startwrite += lencopy + dev->bytesperline;
+ startread += lencopy;
+ if (dev->bytesperline > remain)
+ lencopy = remain;
+ else
+ lencopy = dev->bytesperline;
+
+ memcpy(startwrite, startread, lencopy);
+ remain -= lencopy;
+ }
+
+ (*f)->fieldbytesused += len;
+}
+
+/*
+ * em28xx_isoIrq()
+ * handles the incoming isoc urbs and fills the frames from our inqueue
+ */
+void em28xx_isocIrq(struct urb *urb, struct pt_regs *regs)
+{
+ struct em28xx *dev = urb->context;
+ int i, status;
+ struct em28xx_frame_t **f;
+ unsigned long lock_flags;
+
+ if (!dev)
+ return;
+#ifdef ENABLE_DEBUG_ISOC_FRAMES
+ if (isoc_debug>1)
+ em28xx_isoc_dump(urb, regs);
+#endif
+
+ if (urb->status == -ENOENT)
+ return;
+
+ f = &dev->frame_current;
+
+ if (dev->stream == STREAM_INTERRUPT) {
+ dev->stream = STREAM_OFF;
+ if ((*f))
+ (*f)->state = F_QUEUED;
+ em28xx_isocdbg("stream interrupted");
+ wake_up_interruptible(&dev->wait_stream);
+ }
+
+ if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+ return;
+
+ if (dev->stream == STREAM_ON && !list_empty(&dev->inqueue)) {
+ if (!(*f))
+ (*f) = list_entry(dev->inqueue.next,
+ struct em28xx_frame_t, frame);
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ unsigned char *buf = urb->transfer_buffer +
+ urb->iso_frame_desc[i].offset;
+ int len = urb->iso_frame_desc[i].actual_length - 4;
+
+ if (urb->iso_frame_desc[i].status) {
+ em28xx_isocdbg("data error: [%d] len=%d, status=%d", i,
+ urb->iso_frame_desc[i].actual_length,
+ urb->iso_frame_desc[i].status);
+ if (urb->iso_frame_desc[i].status != -EPROTO)
+ continue;
+ }
+ if (urb->iso_frame_desc[i].actual_length <= 0) {
+ em28xx_isocdbg("packet %d is empty",i);
+ continue;
+ }
+ if (urb->iso_frame_desc[i].actual_length >
+ dev->max_pkt_size) {
+ em28xx_isocdbg("packet bigger than packet size");
+ continue;
+ }
+ /*new frame */
+ if (buf[0] == 0x22 && buf[1] == 0x5a) {
+ em28xx_isocdbg("Video frame, length=%i!",len);
+
+ if (em28xx_isoc_video(dev,f,&lock_flags,buf[2]))
+ break;
+ } else if (buf[0]==0x33 && buf[1]==0x95 && buf[2]==0x00) {
+ em28xx_isocdbg("VBI HEADER!!!");
+ }
+
+ /* actual copying */
+ if ((*f)->state == F_GRABBING) {
+ em28xx_isoc_video_copy(dev,f,buf, len);
+ }
+ }
+ }
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ urb->iso_frame_desc[i].status = 0;
+ urb->iso_frame_desc[i].actual_length = 0;
+ }
+
+ urb->status = 0;
+ if ((status = usb_submit_urb(urb, GFP_ATOMIC))) {
+ em28xx_errdev("resubmit of urb failed (error=%i)\n", status);
+ dev->state |= DEV_MISCONFIGURED;
+ }
+ wake_up_interruptible(&dev->wait_frame);
+ return;
+}
+
+/*
+ * em28xx_uninit_isoc()
+ * deallocates the buffers and urbs allocated during em28xx_init_iosc()
+ */
+void em28xx_uninit_isoc(struct em28xx *dev)
+{
+ int i;
+
+ for (i = 0; i < EM28XX_NUM_BUFS; i++) {
+ if (dev->urb[i]) {
+ usb_kill_urb(dev->urb[i]);
+ if (dev->transfer_buffer[i]){
+ usb_buffer_free(dev->udev,(EM28XX_NUM_PACKETS*dev->max_pkt_size),dev->transfer_buffer[i],dev->urb[i]->transfer_dma);
+ }
+ usb_free_urb(dev->urb[i]);
+ }
+ dev->urb[i] = NULL;
+ dev->transfer_buffer[i] = NULL;
+ }
+ em28xx_capture_start(dev, 0);
+}
+
+/*
+ * em28xx_init_isoc()
+ * allocates transfer buffers and submits the urbs for isoc transfer
+ */
+int em28xx_init_isoc(struct em28xx *dev)
+{
+ /* change interface to 3 which allowes the biggest packet sizes */
+ int i, errCode;
+ const int sb_size = EM28XX_NUM_PACKETS * dev->max_pkt_size;
+
+ /* reset streaming vars */
+ dev->frame_current = NULL;
+ dev->frame_count = 0;
+
+ /* allocate urbs */
+ for (i = 0; i < EM28XX_NUM_BUFS; i++) {
+ struct urb *urb;
+ int j, k;
+ /* allocate transfer buffer */
+ urb = usb_alloc_urb(EM28XX_NUM_PACKETS, GFP_KERNEL);
+ if (!urb){
+ em28xx_errdev("cannot alloc urb %i\n", i);
+ em28xx_uninit_isoc(dev);
+ return -ENOMEM;
+ }
+ dev->transfer_buffer[i] = usb_buffer_alloc(dev->udev, sb_size, GFP_KERNEL,&urb->transfer_dma);
+ if (!dev->transfer_buffer[i]) {
+ em28xx_errdev
+ ("unable to allocate %i bytes for transfer buffer %i\n",
+ sb_size, i);
+ em28xx_uninit_isoc(dev);
+ return -ENOMEM;
+ }
+ memset(dev->transfer_buffer[i], 0, sb_size);
+ urb->dev = dev->udev;
+ urb->context = dev;
+ urb->pipe = usb_rcvisocpipe(dev->udev, 0x82);
+ urb->transfer_flags = URB_ISO_ASAP;
+ urb->interval = 1;
+ urb->transfer_buffer = dev->transfer_buffer[i];
+ urb->complete = em28xx_isocIrq;
+ urb->number_of_packets = EM28XX_NUM_PACKETS;
+ urb->transfer_buffer_length = sb_size;
+ for (j = k = 0; j < EM28XX_NUM_PACKETS;
+ j++, k += dev->max_pkt_size) {
+ urb->iso_frame_desc[j].offset = k;
+ urb->iso_frame_desc[j].length =
+ dev->max_pkt_size;
+ }
+ dev->urb[i] = urb;
+ }
+
+ /* submit urbs */
+ for (i = 0; i < EM28XX_NUM_BUFS; i++) {
+ errCode = usb_submit_urb(dev->urb[i], GFP_KERNEL);
+ if (errCode) {
+ em28xx_errdev("submit of urb %i failed (error=%i)\n", i,
+ errCode);
+ em28xx_uninit_isoc(dev);
+ return errCode;
+ }
+ }
+
+ return 0;
+}
+
+int em28xx_set_alternate(struct em28xx *dev)
+{
+ int errCode, prev_alt = dev->alt;
+ dev->alt = alt;
+ if (dev->alt == 0) {
+ int i;
+ for(i=0;i< dev->num_alt; i++)
+ if(dev->alt_max_pkt_size[i]>dev->alt_max_pkt_size[dev->alt])
+ dev->alt=i;
+ }
+
+ if (dev->alt != prev_alt) {
+ dev->max_pkt_size = dev->alt_max_pkt_size[dev->alt];
+ em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n", dev->alt,
+ dev->max_pkt_size);
+ errCode = usb_set_interface(dev->udev, 0, dev->alt);
+ if (errCode < 0) {
+ em28xx_errdev ("cannot change alternate number to %d (error=%i)\n",
+ dev->alt, errCode);
+ return errCode;
+ }
+ }
+ return 0;
+}
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
new file mode 100644
index 00000000000..b32d9852f34
--- /dev/null
+++ b/drivers/media/video/em28xx/em28xx-i2c.c
@@ -0,0 +1,586 @@
+/*
+ em28xx-i2c.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+
+ Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+ Markus Rechberger <mrechberger@gmail.com>
+ Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ Sascha Sommer <saschasommer@freenet.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <linux/video_decoder.h>
+
+#include "em28xx.h"
+#include <media/tuner.h>
+
+/* ----------------------------------------------------------- */
+
+static unsigned int i2c_scan = 0;
+module_param(i2c_scan, int, 0444);
+MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
+
+static unsigned int i2c_debug = 0;
+module_param(i2c_debug, int, 0644);
+MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
+
+#define dprintk1(lvl,fmt, args...) if (i2c_debug>=lvl) do {\
+ printk(fmt , ##args); } while (0)
+#define dprintk2(lvl,fmt, args...) if (i2c_debug>=lvl) do{ \
+ printk(KERN_DEBUG "%s at %s: " fmt, \
+ dev->name, __FUNCTION__ , ##args); } while (0)
+
+/*
+ * em2800_i2c_send_max4()
+ * send up to 4 bytes to the i2c device
+ */
+static int em2800_i2c_send_max4(struct em28xx *dev, unsigned char addr,
+ char *buf, int len)
+{
+ int ret;
+ int write_timeout;
+ unsigned char b2[6];
+ BUG_ON(len < 1 || len > 4);
+ b2[5] = 0x80 + len - 1;
+ b2[4] = addr;
+ b2[3] = buf[0];
+ if (len > 1)
+ b2[2] = buf[1];
+ if (len > 2)
+ b2[1] = buf[2];
+ if (len > 3)
+ b2[0] = buf[3];
+
+ ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len);
+ if (ret != 2 + len) {
+ em28xx_warn("writting to i2c device failed (error=%i)\n", ret);
+ return -EIO;
+ }
+ for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
+ write_timeout -= 5) {
+ ret = dev->em28xx_read_reg(dev, 0x05);
+ if (ret == 0x80 + len - 1)
+ return len;
+ mdelay(5);
+ }
+ em28xx_warn("i2c write timed out\n");
+ return -EIO;
+}
+
+/*
+ * em2800_i2c_send_bytes()
+ */
+static int em2800_i2c_send_bytes(void *data, unsigned char addr, char *buf,
+ short len)
+{
+ char *bufPtr = buf;
+ int ret;
+ int wrcount = 0;
+ int count;
+ int maxLen = 4;
+ struct em28xx *dev = (struct em28xx *)data;
+ while (len > 0) {
+ count = (len > maxLen) ? maxLen : len;
+ ret = em2800_i2c_send_max4(dev, addr, bufPtr, count);
+ if (ret > 0) {
+ len -= count;
+ bufPtr += count;
+ wrcount += count;
+ } else
+ return (ret < 0) ? ret : -EFAULT;
+ }
+ return wrcount;
+}
+
+/*
+ * em2800_i2c_check_for_device()
+ * check if there is a i2c_device at the supplied address
+ */
+static int em2800_i2c_check_for_device(struct em28xx *dev, unsigned char addr)
+{
+ char msg;
+ int ret;
+ int write_timeout;
+ msg = addr;
+ ret = dev->em28xx_write_regs(dev, 0x04, &msg, 1);
+ if (ret < 0) {
+ em28xx_warn("setting i2c device address failed (error=%i)\n",
+ ret);
+ return ret;
+ }
+ msg = 0x84;
+ ret = dev->em28xx_write_regs(dev, 0x05, &msg, 1);
+ if (ret < 0) {
+ em28xx_warn("preparing i2c read failed (error=%i)\n", ret);
+ return ret;
+ }
+ for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
+ write_timeout -= 5) {
+ unsigned msg = dev->em28xx_read_reg(dev, 0x5);
+ if (msg == 0x94)
+ return -ENODEV;
+ else if (msg == 0x84)
+ return 0;
+ mdelay(5);
+ }
+ return -ENODEV;
+}
+
+/*
+ * em2800_i2c_recv_bytes()
+ * read from the i2c device
+ */
+static int em2800_i2c_recv_bytes(struct em28xx *dev, unsigned char addr,
+ char *buf, int len)
+{
+ int ret;
+ /* check for the device and set i2c read address */
+ ret = em2800_i2c_check_for_device(dev, addr);
+ if (ret) {
+ em28xx_warn
+ ("preparing read at i2c address 0x%x failed (error=%i)\n",
+ addr, ret);
+ return ret;
+ }
+ ret = dev->em28xx_read_reg_req_len(dev, 0x0, 0x3, buf, len);
+ if (ret < 0) {
+ em28xx_warn("reading from i2c device at 0x%x failed (error=%i)",
+ addr, ret);
+ return ret;
+ }
+ return ret;
+}
+
+/*
+ * em28xx_i2c_send_bytes()
+ * untested for more than 4 bytes
+ */
+static int em28xx_i2c_send_bytes(void *data, unsigned char addr, char *buf,
+ short len, int stop)
+{
+ int wrcount = 0;
+ struct em28xx *dev = (struct em28xx *)data;
+
+ wrcount = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len);
+
+ return wrcount;
+}
+
+/*
+ * em28xx_i2c_recv_bytes()
+ * read a byte from the i2c device
+ */
+static int em28xx_i2c_recv_bytes(struct em28xx *dev, unsigned char addr,
+ char *buf, int len)
+{
+ int ret;
+ ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len);
+ if (ret < 0) {
+ em28xx_warn("reading i2c device failed (error=%i)\n", ret);
+ return ret;
+ }
+ if (dev->em28xx_read_reg(dev, 0x5) != 0)
+ return -ENODEV;
+ return ret;
+}
+
+/*
+ * em28xx_i2c_check_for_device()
+ * check if there is a i2c_device at the supplied address
+ */
+static int em28xx_i2c_check_for_device(struct em28xx *dev, unsigned char addr)
+{
+ char msg;
+ int ret;
+ msg = addr;
+
+ ret = dev->em28xx_read_reg_req(dev, 2, addr);
+ if (ret < 0) {
+ em28xx_warn("reading from i2c device failed (error=%i)\n", ret);
+ return ret;
+ }
+ if (dev->em28xx_read_reg(dev, 0x5) != 0)
+ return -ENODEV;
+ return 0;
+}
+
+/*
+ * em28xx_i2c_xfer()
+ * the main i2c transfer function
+ */
+static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg msgs[], int num)
+{
+ struct em28xx *dev = i2c_adap->algo_data;
+ int addr, rc, i, byte;
+
+ if (num <= 0)
+ return 0;
+ for (i = 0; i < num; i++) {
+ addr = msgs[i].addr << 1;
+ dprintk2(2,"%s %s addr=%x len=%d:",
+ (msgs[i].flags & I2C_M_RD) ? "read" : "write",
+ i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
+ if (!msgs[i].len) { /* no len: check only for device presence */
+ if (dev->is_em2800)
+ rc = em2800_i2c_check_for_device(dev, addr);
+ else
+ rc = em28xx_i2c_check_for_device(dev, addr);
+ if (rc < 0) {
+ dprintk2(2," no device\n");
+ return rc;
+ }
+
+ } else if (msgs[i].flags & I2C_M_RD) {
+ /* read bytes */
+ if (dev->is_em2800)
+ rc = em2800_i2c_recv_bytes(dev, addr,
+ msgs[i].buf,
+ msgs[i].len);
+ else
+ rc = em28xx_i2c_recv_bytes(dev, addr,
+ msgs[i].buf,
+ msgs[i].len);
+ if (i2c_debug>=2) {
+ for (byte = 0; byte < msgs[i].len; byte++) {
+ printk(" %02x", msgs[i].buf[byte]);
+ }
+ }
+ } else {
+ /* write bytes */
+ if (i2c_debug>=2) {
+ for (byte = 0; byte < msgs[i].len; byte++)
+ printk(" %02x", msgs[i].buf[byte]);
+ }
+ if (dev->is_em2800)
+ rc = em2800_i2c_send_bytes(dev, addr,
+ msgs[i].buf,
+ msgs[i].len);
+ else
+ rc = em28xx_i2c_send_bytes(dev, addr,
+ msgs[i].buf,
+ msgs[i].len,
+ i == num - 1);
+ if (rc < 0)
+ goto err;
+ }
+ if (i2c_debug>=2)
+ printk("\n");
+ }
+
+ return num;
+ err:
+ dprintk2(2," ERROR: %i\n", rc);
+ return rc;
+}
+
+static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
+{
+ unsigned char buf, *p = eedata;
+ struct em28xx_eeprom *em_eeprom = (void *)eedata;
+ int i, err, size = len, block;
+
+ dev->i2c_client.addr = 0xa0 >> 1;
+
+ /* Check if board has eeprom */
+ err = i2c_master_recv(&dev->i2c_client, &buf, 0);
+ if (err < 0)
+ return -1;
+
+ buf = 0;
+ if (1 != (err = i2c_master_send(&dev->i2c_client, &buf, 1))) {
+ printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
+ dev->name, err);
+ return -1;
+ }
+ while (size > 0) {
+ if (size > 16)
+ block = 16;
+ else
+ block = size;
+
+ if (block !=
+ (err = i2c_master_recv(&dev->i2c_client, p, block))) {
+ printk(KERN_WARNING
+ "%s: i2c eeprom read error (err=%d)\n",
+ dev->name, err);
+ return -1;
+ }
+ size -= block;
+ p += block;
+ }
+ for (i = 0; i < len; i++) {
+ if (0 == (i % 16))
+ printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i);
+ printk(" %02x", eedata[i]);
+ if (15 == (i % 16))
+ printk("\n");
+ }
+
+ printk(KERN_INFO "EEPROM ID= 0x%08x\n", em_eeprom->id);
+ printk(KERN_INFO "Vendor/Product ID= %04x:%04x\n", em_eeprom->vendor_ID,
+ em_eeprom->product_ID);
+
+ switch (em_eeprom->chip_conf >> 4 & 0x3) {
+ case 0:
+ printk(KERN_INFO "No audio on board.\n");
+ break;
+ case 1:
+ printk(KERN_INFO "AC97 audio (5 sample rates)\n");
+ break;
+ case 2:
+ printk(KERN_INFO "I2S audio, sample rate=32k\n");
+ break;
+ case 3:
+ printk(KERN_INFO "I2S audio, 3 sample rates\n");
+ break;
+ }
+
+ if (em_eeprom->chip_conf & 1 << 3)
+ printk(KERN_INFO "USB Remote wakeup capable\n");
+
+ if (em_eeprom->chip_conf & 1 << 2)
+ printk(KERN_INFO "USB Self power capable\n");
+
+ switch (em_eeprom->chip_conf & 0x3) {
+ case 0:
+ printk(KERN_INFO "500mA max power\n");
+ break;
+ case 1:
+ printk(KERN_INFO "400mA max power\n");
+ break;
+ case 2:
+ printk(KERN_INFO "300mA max power\n");
+ break;
+ case 3:
+ printk(KERN_INFO "200mA max power\n");
+ break;
+ }
+ printk(KERN_INFO "Table at 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n",
+ em_eeprom->string_idx_table,em_eeprom->string1,
+ em_eeprom->string2,em_eeprom->string3);
+
+ return 0;
+}
+
+/* ----------------------------------------------------------- */
+
+/*
+ * algo_control()
+ */
+static int algo_control(struct i2c_adapter *adapter,
+ unsigned int cmd, unsigned long arg)
+{
+ return 0;
+}
+
+/*
+ * functionality()
+ */
+static u32 functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_SMBUS_EMUL;
+}
+
+#ifndef I2C_PEC
+static void inc_use(struct i2c_adapter *adap)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void dec_use(struct i2c_adapter *adap)
+{
+ MOD_DEC_USE_COUNT;
+}
+#endif
+
+static int em28xx_set_tuner(int check_eeprom, struct i2c_client *client)
+{
+ struct em28xx *dev = client->adapter->algo_data;
+ struct tuner_setup tun_setup;
+
+ if (dev->has_tuner) {
+ tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
+ tun_setup.type = dev->tuner_type;
+ tun_setup.addr = dev->tuner_addr;
+
+ em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
+ }
+
+ return (0);
+}
+
+/*
+ * attach_inform()
+ * gets called when a device attaches to the i2c bus
+ * does some basic configuration
+ */
+static int attach_inform(struct i2c_client *client)
+{
+ struct em28xx *dev = client->adapter->algo_data;
+
+ switch (client->addr << 1) {
+ case 0x86:
+ em28xx_i2c_call_clients(dev, TDA9887_SET_CONFIG, &dev->tda9887_conf);
+ break;
+ case 0x42:
+ dprintk1(1,"attach_inform: saa7114 detected.\n");
+ break;
+ case 0x4a:
+ dprintk1(1,"attach_inform: saa7113 detected.\n");
+ break;
+ case 0xa0:
+ dprintk1(1,"attach_inform: eeprom detected.\n");
+ break;
+ case 0x60:
+ case 0x8e:
+ {
+ struct IR_i2c *ir = i2c_get_clientdata(client);
+ dprintk1(1,"attach_inform: IR detected (%s).\n",ir->phys);
+ em28xx_set_ir(dev,ir);
+ break;
+ }
+ case 0x80:
+ case 0x88:
+ dprintk1(1,"attach_inform: msp34xx detected.\n");
+ break;
+ case 0xb8:
+ case 0xba:
+ dprintk1(1,"attach_inform: tvp5150 detected.\n");
+ break;
+ default:
+ dprintk1(1,"attach inform: detected I2C address %x\n", client->addr << 1);
+ dev->tuner_addr = client->addr;
+ em28xx_set_tuner(-1, client);
+ }
+
+ return 0;
+}
+
+static struct i2c_algorithm em28xx_algo = {
+ .master_xfer = em28xx_i2c_xfer,
+ .algo_control = algo_control,
+ .functionality = functionality,
+};
+
+static struct i2c_adapter em28xx_adap_template = {
+#ifdef I2C_PEC
+ .owner = THIS_MODULE,
+#else
+ .inc_use = inc_use,
+ .dec_use = dec_use,
+#endif
+#ifdef I2C_CLASS_TV_ANALOG
+ .class = I2C_CLASS_TV_ANALOG,
+#endif
+ .name = "em28xx",
+ .id = I2C_HW_B_EM28XX,
+ .algo = &em28xx_algo,
+ .client_register = attach_inform,
+};
+
+static struct i2c_client em28xx_client_template = {
+ .name = "em28xx internal",
+ .flags = I2C_CLIENT_ALLOW_USE,
+};
+
+/* ----------------------------------------------------------- */
+
+/*
+ * i2c_devs
+ * incomplete list of known devices
+ */
+static char *i2c_devs[128] = {
+ [0x4a >> 1] = "saa7113h",
+ [0x60 >> 1] = "remote IR sensor",
+ [0x8e >> 1] = "remote IR sensor",
+ [0x86 >> 1] = "tda9887",
+ [0x80 >> 1] = "msp34xx",
+ [0x88 >> 1] = "msp34xx",
+ [0xa0 >> 1] = "eeprom",
+ [0xb8 >> 1] = "tvp5150a",
+ [0xba >> 1] = "tvp5150a",
+ [0xc0 >> 1] = "tuner (analog)",
+ [0xc2 >> 1] = "tuner (analog)",
+ [0xc4 >> 1] = "tuner (analog)",
+ [0xc6 >> 1] = "tuner (analog)",
+};
+
+/*
+ * do_i2c_scan()
+ * check i2c address range for devices
+ */
+static void do_i2c_scan(char *name, struct i2c_client *c)
+{
+ unsigned char buf;
+ int i, rc;
+
+ for (i = 0; i < 128; i++) {
+ c->addr = i;
+ rc = i2c_master_recv(c, &buf, 0);
+ if (rc < 0)
+ continue;
+ printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n", name,
+ i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
+ }
+}
+
+/*
+ * em28xx_i2c_call_clients()
+ * send commands to all attached i2c devices
+ */
+void em28xx_i2c_call_clients(struct em28xx *dev, unsigned int cmd, void *arg)
+{
+ BUG_ON(NULL == dev->i2c_adap.algo_data);
+ i2c_clients_command(&dev->i2c_adap, cmd, arg);
+}
+
+/*
+ * em28xx_i2c_register()
+ * register i2c bus
+ */
+int em28xx_i2c_register(struct em28xx *dev)
+{
+ BUG_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg);
+ BUG_ON(!dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req);
+ dev->i2c_adap = em28xx_adap_template;
+ dev->i2c_adap.dev.parent = &dev->udev->dev;
+ strcpy(dev->i2c_adap.name, dev->name);
+ dev->i2c_adap.algo_data = dev;
+ i2c_add_adapter(&dev->i2c_adap);
+
+ dev->i2c_client = em28xx_client_template;
+ dev->i2c_client.adapter = &dev->i2c_adap;
+
+ em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata));
+
+ if (i2c_scan)
+ do_i2c_scan(dev->name, &dev->i2c_client);
+ return 0;
+}
+
+/*
+ * em28xx_i2c_unregister()
+ * unregister i2c_bus
+ */
+int em28xx_i2c_unregister(struct em28xx *dev)
+{
+ i2c_del_adapter(&dev->i2c_adap);
+ return 0;
+}
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
new file mode 100644
index 00000000000..9b94f77d6fd
--- /dev/null
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -0,0 +1,181 @@
+/*
+ handle em28xx IR remotes via linux kernel input layer.
+
+ Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+ Markus Rechberger <mrechberger@gmail.com>
+ Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ Sascha Sommer <saschasommer@freenet.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+
+#include "em28xx.h"
+
+static unsigned int disable_ir = 0;
+module_param(disable_ir, int, 0444);
+MODULE_PARM_DESC(disable_ir,"disable infrared remote support");
+
+static unsigned int ir_debug = 0;
+module_param(ir_debug, int, 0644);
+MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
+
+#define dprintk(fmt, arg...) if (ir_debug) \
+ printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg)
+
+/* ---------------------------------------------------------------------- */
+
+static IR_KEYTAB_TYPE ir_codes_em_terratec[IR_KEYTAB_SIZE] = {
+ [ 0x01 ] = KEY_CHANNEL,
+ [ 0x02 ] = KEY_SELECT,
+ [ 0x03 ] = KEY_MUTE,
+ [ 0x04 ] = KEY_POWER,
+ [ 0x05 ] = KEY_KP1,
+ [ 0x06 ] = KEY_KP2,
+ [ 0x07 ] = KEY_KP3,
+ [ 0x08 ] = KEY_CHANNELUP,
+ [ 0x09 ] = KEY_KP4,
+ [ 0x0a ] = KEY_KP5,
+ [ 0x0b ] = KEY_KP6,
+ [ 0x0c ] = KEY_CHANNELDOWN,
+ [ 0x0d ] = KEY_KP7,
+ [ 0x0e ] = KEY_KP8,
+ [ 0x0f ] = KEY_KP9,
+ [ 0x10 ] = KEY_VOLUMEUP,
+ [ 0x11 ] = KEY_KP0,
+ [ 0x12 ] = KEY_MENU,
+ [ 0x13 ] = KEY_PRINT,
+ [ 0x14 ] = KEY_VOLUMEDOWN,
+ [ 0x16 ] = KEY_PAUSE,
+ [ 0x18 ] = KEY_RECORD,
+ [ 0x19 ] = KEY_REWIND,
+ [ 0x1a ] = KEY_PLAY,
+ [ 0x1b ] = KEY_FORWARD,
+ [ 0x1c ] = KEY_BACKSPACE,
+ [ 0x1e ] = KEY_STOP,
+ [ 0x40 ] = KEY_ZOOM,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static int get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+ unsigned char b;
+
+ /* poll IR chip */
+ if (1 != i2c_master_recv(&ir->c,&b,1)) {
+ dprintk("read error\n");
+ return -EIO;
+ }
+
+ /* it seems that 0xFE indicates that a button is still hold
+ down, while 0xff indicates that no button is hold
+ down. 0xfe sequences are sometimes interrupted by 0xFF */
+
+ dprintk("key %02x\n", b);
+
+ if (b == 0xff)
+ return 0;
+
+ if (b == 0xfe)
+ /* keep old data */
+ return 1;
+
+ *ir_key = b;
+ *ir_raw = b;
+ return 1;
+}
+
+
+static int get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+ unsigned char buf[2];
+ unsigned char code;
+
+ /* poll IR chip */
+ if (2 != i2c_master_recv(&ir->c,buf,2))
+ return -EIO;
+
+ /* Does eliminate repeated parity code */
+ if (buf[1]==0xff)
+ return 0;
+
+ ir->old=buf[1];
+
+ /* Rearranges bits to the right order */
+ code= ((buf[0]&0x01)<<5) | /* 0010 0000 */
+ ((buf[0]&0x02)<<3) | /* 0001 0000 */
+ ((buf[0]&0x04)<<1) | /* 0000 1000 */
+ ((buf[0]&0x08)>>1) | /* 0000 0100 */
+ ((buf[0]&0x10)>>3) | /* 0000 0010 */
+ ((buf[0]&0x20)>>5); /* 0000 0001 */
+
+ dprintk("ir hauppauge (em2840): code=0x%02x (rcv=0x%02x)\n",code,buf[0]);
+
+ /* return key */
+ *ir_key = code;
+ *ir_raw = code;
+ return 1;
+}
+
+/* ----------------------------------------------------------------------- */
+void em28xx_set_ir(struct em28xx * dev,struct IR_i2c *ir)
+{
+ if (disable_ir) {
+ ir->get_key=NULL;
+ return ;
+ }
+
+ /* detect & configure */
+ switch (dev->model) {
+ case (EM2800_BOARD_UNKNOWN):
+ break;
+ case (EM2820_BOARD_UNKNOWN):
+ break;
+ case (EM2800_BOARD_TERRATEC_CINERGY_200):
+ case (EM2820_BOARD_TERRATEC_CINERGY_250):
+ ir->ir_codes = ir_codes_em_terratec;
+ ir->get_key = get_key_terratec;
+ snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM28XX Terratec)");
+ break;
+ case (EM2820_BOARD_PINNACLE_USB_2):
+ break;
+ case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2):
+ ir->ir_codes = ir_codes_hauppauge_new;
+ ir->get_key = get_key_em_haup;
+ snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM2840 Hauppauge)");
+ break;
+ case (EM2820_BOARD_MSI_VOX_USB_2):
+ break;
+ case (EM2800_BOARD_LEADTEK_WINFAST_USBII):
+ break;
+ case (EM2800_BOARD_KWORLD_USB2800):
+ break;
+ }
+}
+
+/* ----------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
new file mode 100644
index 00000000000..57c1826b928
--- /dev/null
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -0,0 +1,1933 @@
+/*
+ em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+
+ Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+ Markus Rechberger <mrechberger@gmail.com>
+ Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ Sascha Sommer <saschasommer@freenet.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <linux/version.h>
+#include <linux/video_decoder.h>
+
+#include "em28xx.h"
+#include <media/tuner.h>
+
+#define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
+ "Markus Rechberger <mrechberger@gmail.com>, " \
+ "Mauro Carvalho Chehab <mchehab@brturbo.com.br>, " \
+ "Sascha Sommer <saschasommer@freenet.de>"
+
+#define DRIVER_NAME "em28xx"
+#define DRIVER_DESC "Empia em28xx based USB video device driver"
+#define EM28XX_VERSION_CODE KERNEL_VERSION(0, 0, 1)
+
+#define em28xx_videodbg(fmt, arg...) do {\
+ if (video_debug) \
+ printk(KERN_INFO "%s %s :"fmt, \
+ dev->name, __FUNCTION__ , ##arg); } while (0)
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+static LIST_HEAD(em28xx_devlist);
+
+static unsigned int card[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
+module_param_array(card, int, NULL, 0444);
+MODULE_PARM_DESC(card,"card type");
+
+static int tuner = -1;
+module_param(tuner, int, 0444);
+MODULE_PARM_DESC(tuner, "tuner type");
+
+static unsigned int video_debug = 0;
+module_param(video_debug,int,0644);
+MODULE_PARM_DESC(video_debug,"enable debug messages [video]");
+
+/* supported tv norms */
+static struct em28xx_tvnorm tvnorms[] = {
+ {
+ .name = "PAL",
+ .id = V4L2_STD_PAL,
+ .mode = VIDEO_MODE_PAL,
+ }, {
+ .name = "NTSC",
+ .id = V4L2_STD_NTSC,
+ .mode = VIDEO_MODE_NTSC,
+ }, {
+ .name = "SECAM",
+ .id = V4L2_STD_SECAM,
+ .mode = VIDEO_MODE_SECAM,
+ }, {
+ .name = "PAL-M",
+ .id = V4L2_STD_PAL_M,
+ .mode = VIDEO_MODE_PAL,
+ }
+};
+
+static const unsigned char saa7114_i2c_init[] = {
+ 0x00,0x00,0x01,0x08,0x02,0xc4,0x03,0x30,0x04,0x90,0x05,0x90,0x06,0xeb,0x07,0xe0,
+ 0x08,0x88,0x09,0x40,0x0a,0x80,0x0b,0x44,0x0c,0x40,0x0d,0x00,0x0e,0x81,0x0f,0x2a,
+ 0x10,0x06,0x11,0x00,0x12,0xc8,0x13,0x80,0x14,0x00,0x15,0x11,0x16,0x01,0x17,0x42,
+ 0x18,0x40,0x19,0x80,0x40,0x00,0x41,0xff,0x42,0xff,0x43,0xff,0x44,0xff,0x45,0xff,
+ 0x46,0xff,0x47,0xff,0x48,0xff,0x49,0xff,0x4a,0xff,0x4b,0xff,0x4c,0xff,0x4d,0xff,
+ 0x4e,0xff,0x4f,0xff,0x50,0xff,0x51,0xff,0x52,0xff,0x53,0xff,0x54,0x5f,0x55,0xff,
+ 0x56,0xff,0x57,0xff,0x58,0x00,0x59,0x47,0x5a,0x03,0x5b,0x03,0x5d,0x3e,0x5e,0x00,
+ 0x80,0x1c,0x83,0x01,0x84,0xa5,0x85,0x10,0x86,0x45,0x87,0x41,0x88,0xf0,0x88,0x00,
+ 0x88,0xf0,0x90,0x00,0x91,0x08,0x92,0x00,0x93,0x80,0x94,0x08,0x95,0x00,0x96,0xc0,
+ 0x97,0x02,0x98,0x13,0x99,0x00,0x9a,0x38,0x9b,0x01,0x9c,0x80,0x9d,0x02,0x9e,0x06,
+ 0x9f,0x01,0xa0,0x01,0xa1,0x00,0xa2,0x00,0xa4,0x80,0xa5,0x36,0xa6,0x36,0xa8,0x67,
+ 0xa9,0x04,0xaa,0x00,0xac,0x33,0xad,0x02,0xae,0x00,0xb0,0xcd,0xb1,0x04,0xb2,0xcd,
+ 0xb3,0x04,0xb4,0x01,0xb8,0x00,0xb9,0x00,0xba,0x00,0xbb,0x00,0xbc,0x00,0xbd,0x00,
+ 0xbe,0x00,0xbf,0x00
+};
+
+#define TVNORMS ARRAY_SIZE(tvnorms)
+
+/* supported controls */
+static struct v4l2_queryctrl em28xx_qctrl[] = {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = -128,
+ .maximum = 127,
+ .step = 1,
+ .default_value = 0,
+ .flags = 0,
+ },{
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0x0,
+ .maximum = 0x1f,
+ .step = 0x1,
+ .default_value = 0x10,
+ .flags = 0,
+ },{
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = 0x0,
+ .maximum = 0x1f,
+ .step = 0x1,
+ .default_value = 0x10,
+ .flags = 0,
+ },{
+ .id = V4L2_CID_AUDIO_VOLUME,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Volume",
+ .minimum = 0x0,
+ .maximum = 0x1f,
+ .step = 0x1,
+ .default_value = 0x1f,
+ .flags = 0,
+ },{
+ .id = V4L2_CID_AUDIO_MUTE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Mute",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ .flags = 0,
+ },{
+ .id = V4L2_CID_RED_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Red chroma balance",
+ .minimum = -128,
+ .maximum = 127,
+ .step = 1,
+ .default_value = 0,
+ .flags = 0,
+ },{
+ .id = V4L2_CID_BLUE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Blue chroma balance",
+ .minimum = -128,
+ .maximum = 127,
+ .step = 1,
+ .default_value = 0,
+ .flags = 0,
+ },{
+ .id = V4L2_CID_GAMMA,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gamma",
+ .minimum = 0x0,
+ .maximum = 0x3f,
+ .step = 0x1,
+ .default_value = 0x20,
+ .flags = 0,
+ }
+};
+
+static struct usb_driver em28xx_usb_driver;
+
+static DECLARE_MUTEX(em28xx_sysfs_lock);
+static DECLARE_RWSEM(em28xx_disconnect);
+
+/********************* v4l2 interface ******************************************/
+
+static inline unsigned long kvirt_to_pa(unsigned long adr)
+{
+ unsigned long kva, ret;
+
+ kva = (unsigned long)page_address(vmalloc_to_page((void *)adr));
+ kva |= adr & (PAGE_SIZE - 1);
+ ret = __pa(kva);
+ return ret;
+}
+
+/*
+ * em28xx_config()
+ * inits registers with sane defaults
+ */
+static int em28xx_config(struct em28xx *dev)
+{
+
+ /* Sets I2C speed to 100 KHz */
+ em28xx_write_regs_req(dev, 0x00, 0x06, "\x40", 1);
+
+ /* enable vbi capturing */
+ em28xx_audio_usb_mute(dev, 1);
+ dev->mute = 1; /* maybe not the right place... */
+ dev->volume = 0x1f;
+ em28xx_audio_analog_set(dev);
+ em28xx_audio_analog_setup(dev);
+ em28xx_outfmt_set_yuv422(dev);
+ em28xx_colorlevels_set_default(dev);
+ em28xx_compression_disable(dev);
+
+ return 0;
+}
+
+/*
+ * em28xx_config_i2c()
+ * configure i2c attached devices
+ */
+void em28xx_config_i2c(struct em28xx *dev)
+{
+ struct v4l2_frequency f;
+ struct video_decoder_init em28xx_vdi = {.data = NULL };
+
+
+ /* configure decoder */
+ if(dev->model == EM2820_BOARD_MSI_VOX_USB_2){
+ em28xx_vdi.data=saa7114_i2c_init;
+ em28xx_vdi.len=sizeof(saa7114_i2c_init);
+ }
+
+
+ em28xx_i2c_call_clients(dev, DECODER_INIT, &em28xx_vdi);
+ em28xx_i2c_call_clients(dev, DECODER_SET_INPUT, &dev->ctl_input);
+/* em28xx_i2c_call_clients(dev,DECODER_SET_PICTURE, &dev->vpic); */
+/* em28xx_i2c_call_clients(dev,DECODER_SET_NORM,&dev->tvnorm->id); */
+/* em28xx_i2c_call_clients(dev,DECODER_ENABLE_OUTPUT,&output); */
+/* em28xx_i2c_call_clients(dev,DECODER_DUMP, NULL); */
+
+ /* configure tuner */
+ f.tuner = 0;
+ f.type = V4L2_TUNER_ANALOG_TV;
+ f.frequency = 9076; /* FIXME:remove magic number */
+ dev->ctl_freq = f.frequency;
+ em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f);
+
+ /* configure tda9887 */
+
+
+/* em28xx_i2c_call_clients(dev,VIDIOC_S_STD,&dev->tvnorm->id); */
+}
+
+/*
+ * em28xx_empty_framequeues()
+ * prepare queues for incoming and outgoing frames
+ */
+static void em28xx_empty_framequeues(struct em28xx *dev)
+{
+ u32 i;
+
+ INIT_LIST_HEAD(&dev->inqueue);
+ INIT_LIST_HEAD(&dev->outqueue);
+
+ for (i = 0; i < EM28XX_NUM_FRAMES; i++) {
+ dev->frame[i].state = F_UNUSED;
+ dev->frame[i].buf.bytesused = 0;
+ }
+}
+
+static void video_mux(struct em28xx *dev, int index)
+{
+ int input, ainput;
+
+ input = INPUT(index)->vmux;
+ dev->ctl_input = index;
+ dev->ctl_ainput = INPUT(index)->amux;
+
+ em28xx_i2c_call_clients(dev, DECODER_SET_INPUT, &input);
+
+
+ em28xx_videodbg("Setting input index=%d, vmux=%d, amux=%d\n",index,input,dev->ctl_ainput);
+
+ if (dev->has_msp34xx) {
+ em28xx_i2c_call_clients(dev, VIDIOC_S_AUDIO, &dev->ctl_ainput);
+ ainput = EM28XX_AUDIO_SRC_TUNER;
+ em28xx_audio_source(dev, ainput);
+ } else {
+ switch (dev->ctl_ainput) {
+ case 0:
+ ainput = EM28XX_AUDIO_SRC_TUNER;
+ break;
+ default:
+ ainput = EM28XX_AUDIO_SRC_LINE;
+ }
+ em28xx_audio_source(dev, ainput);
+ }
+}
+
+/*
+ * em28xx_v4l2_open()
+ * inits the device and starts isoc transfer
+ */
+static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
+{
+ int minor = iminor(inode);
+ int errCode = 0;
+ struct em28xx *h,*dev = NULL;
+ struct list_head *list;
+
+ list_for_each(list,&em28xx_devlist) {
+ h = list_entry(list, struct em28xx, devlist);
+ if (h->vdev->minor == minor) {
+ dev = h;
+ }
+ }
+
+ filp->private_data=dev;
+
+
+ em28xx_videodbg("users=%d\n", dev->users);
+
+ if (!down_read_trylock(&em28xx_disconnect))
+ return -ERESTARTSYS;
+
+ if (dev->users) {
+ em28xx_warn("this driver can be opened only once\n");
+ up_read(&em28xx_disconnect);
+ return -EBUSY;
+ }
+
+/* if(dev->vbi_dev->minor == minor){
+ dev->type=V4L2_BUF_TYPE_VBI_CAPTURE;
+ }*/
+ if (dev->vdev->minor == minor) {
+ dev->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ }
+
+ init_MUTEX(&dev->fileop_lock); /* to 1 == available */
+ spin_lock_init(&dev->queue_lock);
+ init_waitqueue_head(&dev->wait_frame);
+ init_waitqueue_head(&dev->wait_stream);
+
+ down(&dev->lock);
+
+ em28xx_set_alternate(dev);
+
+ dev->width = norm_maxw(dev);
+ dev->height = norm_maxh(dev);
+ dev->frame_size = dev->width * dev->height * 2;
+ dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */
+ dev->bytesperline = dev->width * 2;
+ dev->hscale = 0;
+ dev->vscale = 0;
+
+ em28xx_capture_start(dev, 1);
+ em28xx_resolution_set(dev);
+
+ /* start the transfer */
+ errCode = em28xx_init_isoc(dev);
+ if (errCode)
+ goto err;
+
+ dev->users++;
+ filp->private_data = dev;
+ dev->io = IO_NONE;
+ dev->stream = STREAM_OFF;
+ dev->num_frames = 0;
+
+ /* prepare queues */
+ em28xx_empty_framequeues(dev);
+
+ dev->state |= DEV_INITIALIZED;
+
+ video_mux(dev, 0);
+
+ err:
+ up(&dev->lock);
+ up_read(&em28xx_disconnect);
+ return errCode;
+}
+
+/*
+ * em28xx_realease_resources()
+ * unregisters the v4l2,i2c and usb devices
+ * called when the device gets disconected or at module unload
+*/
+static void em28xx_release_resources(struct em28xx *dev)
+{
+ down(&em28xx_sysfs_lock);
+
+ em28xx_info("V4L2 device /dev/video%d deregistered\n",
+ dev->vdev->minor);
+ list_del(&dev->devlist);
+ video_unregister_device(dev->vdev);
+/* video_unregister_device(dev->vbi_dev); */
+ em28xx_i2c_unregister(dev);
+ usb_put_dev(dev->udev);
+ up(&em28xx_sysfs_lock);
+}
+
+/*
+ * em28xx_v4l2_close()
+ * stops streaming and deallocates all resources allocated by the v4l2 calls and ioctls
+ */
+static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
+{
+ int errCode;
+ struct em28xx *dev=filp->private_data;
+
+ em28xx_videodbg("users=%d\n", dev->users);
+
+ down(&dev->lock);
+
+ em28xx_uninit_isoc(dev);
+
+ em28xx_release_buffers(dev);
+
+ /* the device is already disconnect, free the remaining resources */
+ if (dev->state & DEV_DISCONNECTED) {
+ em28xx_release_resources(dev);
+ up(&dev->lock);
+ kfree(dev);
+ return 0;
+ }
+
+ /* set alternate 0 */
+ dev->alt = 0;
+ em28xx_videodbg("setting alternate 0\n");
+ errCode = usb_set_interface(dev->udev, 0, 0);
+ if (errCode < 0) {
+ em28xx_errdev ("cannot change alternate number to 0 (error=%i)\n",
+ errCode);
+ }
+
+ dev->users--;
+ wake_up_interruptible_nr(&dev->open, 1);
+ up(&dev->lock);
+ return 0;
+}
+
+/*
+ * em28xx_v4l2_read()
+ * will allocate buffers when called for the first time
+ */
+static ssize_t
+em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
+ loff_t * f_pos)
+{
+ struct em28xx_frame_t *f, *i;
+ unsigned long lock_flags;
+ int ret = 0;
+ struct em28xx *dev = filp->private_data;
+
+ if (down_interruptible(&dev->fileop_lock))
+ return -ERESTARTSYS;
+
+ if (dev->state & DEV_DISCONNECTED) {
+ em28xx_videodbg("device not present\n");
+ up(&dev->fileop_lock);
+ return -ENODEV;
+ }
+
+ if (dev->state & DEV_MISCONFIGURED) {
+ em28xx_videodbg("device misconfigured; close and open it again\n");
+ up(&dev->fileop_lock);
+ return -EIO;
+ }
+
+ if (dev->io == IO_MMAP) {
+ em28xx_videodbg ("IO method is set to mmap; close and open"
+ " the device again to choose the read method\n");
+ up(&dev->fileop_lock);
+ return -EINVAL;
+ }
+
+ if (dev->io == IO_NONE) {
+ if (!em28xx_request_buffers(dev, EM28XX_NUM_READ_FRAMES)) {
+ em28xx_errdev("read failed, not enough memory\n");
+ up(&dev->fileop_lock);
+ return -ENOMEM;
+ }
+ dev->io = IO_READ;
+ dev->stream = STREAM_ON;
+ em28xx_queue_unusedframes(dev);
+ }
+
+ if (!count) {
+ up(&dev->fileop_lock);
+ return 0;
+ }
+
+ if (list_empty(&dev->outqueue)) {
+ if (filp->f_flags & O_NONBLOCK) {
+ up(&dev->fileop_lock);
+ return -EAGAIN;
+ }
+ ret = wait_event_interruptible
+ (dev->wait_frame,
+ (!list_empty(&dev->outqueue)) ||
+ (dev->state & DEV_DISCONNECTED));
+ if (ret) {
+ up(&dev->fileop_lock);
+ return ret;
+ }
+ if (dev->state & DEV_DISCONNECTED) {
+ up(&dev->fileop_lock);
+ return -ENODEV;
+ }
+ }
+
+ f = list_entry(dev->outqueue.prev, struct em28xx_frame_t, frame);
+
+ spin_lock_irqsave(&dev->queue_lock, lock_flags);
+ list_for_each_entry(i, &dev->outqueue, frame)
+ i->state = F_UNUSED;
+ INIT_LIST_HEAD(&dev->outqueue);
+ spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
+
+ em28xx_queue_unusedframes(dev);
+
+ if (count > f->buf.length)
+ count = f->buf.length;
+
+ if (copy_to_user(buf, f->bufmem, count)) {
+ up(&dev->fileop_lock);
+ return -EFAULT;
+ }
+ *f_pos += count;
+
+ up(&dev->fileop_lock);
+
+ return count;
+}
+
+/*
+ * em28xx_v4l2_poll()
+ * will allocate buffers when called for the first time
+ */
+static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait)
+{
+ unsigned int mask = 0;
+ struct em28xx *dev = filp->private_data;
+
+ if (down_interruptible(&dev->fileop_lock))
+ return POLLERR;
+
+ if (dev->state & DEV_DISCONNECTED) {
+ em28xx_videodbg("device not present\n");
+ } else if (dev->state & DEV_MISCONFIGURED) {
+ em28xx_videodbg("device is misconfigured; close and open it again\n");
+ } else {
+ if (dev->io == IO_NONE) {
+ if (!em28xx_request_buffers
+ (dev, EM28XX_NUM_READ_FRAMES)) {
+ em28xx_warn
+ ("poll() failed, not enough memory\n");
+ } else {
+ dev->io = IO_READ;
+ dev->stream = STREAM_ON;
+ }
+ }
+
+ if (dev->io == IO_READ) {
+ em28xx_queue_unusedframes(dev);
+ poll_wait(filp, &dev->wait_frame, wait);
+
+ if (!list_empty(&dev->outqueue))
+ mask |= POLLIN | POLLRDNORM;
+
+ up(&dev->fileop_lock);
+
+ return mask;
+ }
+ }
+
+ up(&dev->fileop_lock);
+ return POLLERR;
+}
+
+/*
+ * em28xx_vm_open()
+ */
+static void em28xx_vm_open(struct vm_area_struct *vma)
+{
+ struct em28xx_frame_t *f = vma->vm_private_data;
+ f->vma_use_count++;
+}
+
+/*
+ * em28xx_vm_close()
+ */
+static void em28xx_vm_close(struct vm_area_struct *vma)
+{
+ /* NOTE: buffers are not freed here */
+ struct em28xx_frame_t *f = vma->vm_private_data;
+ f->vma_use_count--;
+}
+
+static struct vm_operations_struct em28xx_vm_ops = {
+ .open = em28xx_vm_open,
+ .close = em28xx_vm_close,
+};
+
+/*
+ * em28xx_v4l2_mmap()
+ */
+static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ unsigned long size = vma->vm_end - vma->vm_start,
+ start = vma->vm_start, pos, page;
+ u32 i;
+
+ struct em28xx *dev = filp->private_data;
+
+ if (down_interruptible(&dev->fileop_lock))
+ return -ERESTARTSYS;
+
+ if (dev->state & DEV_DISCONNECTED) {
+ em28xx_videodbg("mmap: device not present\n");
+ up(&dev->fileop_lock);
+ return -ENODEV;
+ }
+
+ if (dev->state & DEV_MISCONFIGURED) {
+ em28xx_videodbg ("mmap: Device is misconfigured; close and "
+ "open it again\n");
+ up(&dev->fileop_lock);
+ return -EIO;
+ }
+
+ if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
+ size != PAGE_ALIGN(dev->frame[0].buf.length)) {
+ up(&dev->fileop_lock);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < dev->num_frames; i++) {
+ if ((dev->frame[i].buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
+ break;
+ }
+ if (i == dev->num_frames) {
+ em28xx_videodbg("mmap: user supplied mapping address is out of range\n");
+ up(&dev->fileop_lock);
+ return -EINVAL;
+ }
+
+ /* VM_IO is eventually going to replace PageReserved altogether */
+ vma->vm_flags |= VM_IO;
+ vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */
+
+ pos = (unsigned long)dev->frame[i].bufmem;
+ while (size > 0) { /* size is page-aligned */
+ page = vmalloc_to_pfn((void *)pos);
+ if (remap_pfn_range(vma, start, page, PAGE_SIZE,
+ vma->vm_page_prot)) {
+ em28xx_videodbg("mmap: rename page map failed\n");
+ up(&dev->fileop_lock);
+ return -EAGAIN;
+ }
+ start += PAGE_SIZE;
+ pos += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+
+ vma->vm_ops = &em28xx_vm_ops;
+ vma->vm_private_data = &dev->frame[i];
+
+ em28xx_vm_open(vma);
+ up(&dev->fileop_lock);
+ return 0;
+}
+
+/*
+ * em28xx_get_ctrl()
+ * return the current saturation, brightness or contrast, mute state
+ */
+static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
+{
+ s32 tmp;
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ ctrl->value = dev->mute;
+ return 0;
+ case V4L2_CID_AUDIO_VOLUME:
+ ctrl->value = dev->volume;
+ return 0;
+ case V4L2_CID_BRIGHTNESS:
+ if ((tmp = em28xx_brightness_get(dev)) < 0)
+ return -EIO;
+ ctrl->value = (s32) ((s8) tmp); /* FIXME: clenaer way to extend sign? */
+ return 0;
+ case V4L2_CID_CONTRAST:
+ if ((ctrl->value = em28xx_contrast_get(dev)) < 0)
+ return -EIO;
+ return 0;
+ case V4L2_CID_SATURATION:
+ if ((ctrl->value = em28xx_saturation_get(dev)) < 0)
+ return -EIO;
+ return 0;
+ case V4L2_CID_RED_BALANCE:
+ if ((tmp = em28xx_v_balance_get(dev)) < 0)
+ return -EIO;
+ ctrl->value = (s32) ((s8) tmp); /* FIXME: clenaer way to extend sign? */
+ return 0;
+ case V4L2_CID_BLUE_BALANCE:
+ if ((tmp = em28xx_u_balance_get(dev)) < 0)
+ return -EIO;
+ ctrl->value = (s32) ((s8) tmp); /* FIXME: clenaer way to extend sign? */
+ return 0;
+ case V4L2_CID_GAMMA:
+ if ((ctrl->value = em28xx_gamma_get(dev)) < 0)
+ return -EIO;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+/*
+ * em28xx_set_ctrl()
+ * mute or set new saturation, brightness or contrast
+ */
+static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
+{
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ if (ctrl->value != dev->mute) {
+ dev->mute = ctrl->value;
+ em28xx_audio_usb_mute(dev, ctrl->value);
+ return em28xx_audio_analog_set(dev);
+ }
+ return 0;
+ case V4L2_CID_AUDIO_VOLUME:
+ dev->volume = ctrl->value;
+ return em28xx_audio_analog_set(dev);
+ case V4L2_CID_BRIGHTNESS:
+ return em28xx_brightness_set(dev, ctrl->value);
+ case V4L2_CID_CONTRAST:
+ return em28xx_contrast_set(dev, ctrl->value);
+ case V4L2_CID_SATURATION:
+ return em28xx_saturation_set(dev, ctrl->value);
+ case V4L2_CID_RED_BALANCE:
+ return em28xx_v_balance_set(dev, ctrl->value);
+ case V4L2_CID_BLUE_BALANCE:
+ return em28xx_u_balance_set(dev, ctrl->value);
+ case V4L2_CID_GAMMA:
+ return em28xx_gamma_set(dev, ctrl->value);
+ default:
+ return -EINVAL;
+ }
+}
+
+/*
+ * em28xx_stream_interrupt()
+ * stops streaming
+ */
+static int em28xx_stream_interrupt(struct em28xx *dev)
+{
+ int ret = 0;
+
+ /* stop reading from the device */
+
+ dev->stream = STREAM_INTERRUPT;
+ ret = wait_event_timeout(dev->wait_stream,
+ (dev->stream == STREAM_OFF) ||
+ (dev->state & DEV_DISCONNECTED),
+ EM28XX_URB_TIMEOUT);
+ if (dev->state & DEV_DISCONNECTED)
+ return -ENODEV;
+ else if (ret) {
+ dev->state |= DEV_MISCONFIGURED;
+ em28xx_videodbg("device is misconfigured; close and "
+ "open /dev/video%d again\n", dev->vdev->minor);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int em28xx_set_norm(struct em28xx *dev, int width, int height)
+{
+ unsigned int hscale, vscale;
+ unsigned int maxh, maxw;
+
+ maxw = norm_maxw(dev);
+ maxh = norm_maxh(dev);
+
+ /* width must even because of the YUYV format */
+ /* height must be even because of interlacing */
+ height &= 0xfffe;
+ width &= 0xfffe;
+
+ if (height < 32)
+ height = 32;
+ if (height > maxh)
+ height = maxh;
+ if (width < 48)
+ width = 48;
+ if (width > maxw)
+ width = maxw;
+
+ if ((hscale = (((unsigned long)maxw) << 12) / width - 4096L) >= 0x4000)
+ hscale = 0x3fff;
+ width = (((unsigned long)maxw) << 12) / (hscale + 4096L);
+
+ if ((vscale = (((unsigned long)maxh) << 12) / height - 4096L) >= 0x4000)
+ vscale = 0x3fff;
+ height = (((unsigned long)maxh) << 12) / (vscale + 4096L);
+
+ /* set new image size */
+ dev->width = width;
+ dev->height = height;
+ dev->frame_size = dev->width * dev->height * 2;
+ dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */
+ dev->bytesperline = dev->width * 2;
+ dev->hscale = hscale;
+ dev->vscale = vscale;
+
+ em28xx_resolution_set(dev);
+
+ return 0;
+}
+
+/*
+ * em28xx_v4l2_do_ioctl()
+ * This function is _not_ called directly, but from
+ * em28xx_v4l2_ioctl. Userspace
+ * copying is done already, arg is a kernel pointer.
+ */
+static int em28xx_do_ioctl(struct inode *inode, struct file *filp,
+ struct em28xx *dev, unsigned int cmd, void *arg,
+ v4l2_kioctl driver_ioctl)
+{
+ int ret;
+
+ switch (cmd) {
+ /* ---------- tv norms ---------- */
+ case VIDIOC_ENUMSTD:
+ {
+ struct v4l2_standard *e = arg;
+ unsigned int i;
+
+ i = e->index;
+ if (i >= TVNORMS)
+ return -EINVAL;
+ ret = v4l2_video_std_construct(e, tvnorms[e->index].id,
+ tvnorms[e->index].name);
+ e->index = i;
+ if (ret < 0)
+ return ret;
+ return 0;
+ }
+ case VIDIOC_G_STD:
+ {
+ v4l2_std_id *id = arg;
+
+ *id = dev->tvnorm->id;
+ return 0;
+ }
+ case VIDIOC_S_STD:
+ {
+ v4l2_std_id *id = arg;
+ unsigned int i;
+
+ for (i = 0; i < TVNORMS; i++)
+ if (*id == tvnorms[i].id)
+ break;
+ if (i == TVNORMS)
+ for (i = 0; i < TVNORMS; i++)
+ if (*id & tvnorms[i].id)
+ break;
+ if (i == TVNORMS)
+ return -EINVAL;
+
+ down(&dev->lock);
+ dev->tvnorm = &tvnorms[i];
+
+ em28xx_set_norm(dev, dev->width, dev->height);
+
+/*
+ dev->width=norm_maxw(dev);
+ dev->height=norm_maxh(dev);
+ dev->frame_size=dev->width*dev->height*2;
+ dev->field_size=dev->frame_size>>1;
+ dev->bytesperline=dev->width*2;
+ dev->hscale=0;
+ dev->vscale=0;
+
+ em28xx_resolution_set(dev);
+*/
+/*
+ em28xx_uninit_isoc(dev);
+ em28xx_set_alternate(dev);
+ em28xx_capture_start(dev, 1);
+ em28xx_resolution_set(dev);
+ em28xx_init_isoc(dev);
+*/
+ em28xx_i2c_call_clients(dev, DECODER_SET_NORM,
+ &tvnorms[i].mode);
+ em28xx_i2c_call_clients(dev, VIDIOC_S_STD,
+ &dev->tvnorm->id);
+
+ up(&dev->lock);
+
+ return 0;
+ }
+
+ /* ------ input switching ---------- */
+ case VIDIOC_ENUMINPUT:
+ {
+ struct v4l2_input *i = arg;
+ unsigned int n;
+ static const char *iname[] = {
+ [EM28XX_VMUX_COMPOSITE1] = "Composite1",
+ [EM28XX_VMUX_COMPOSITE2] = "Composite2",
+ [EM28XX_VMUX_COMPOSITE3] = "Composite3",
+ [EM28XX_VMUX_COMPOSITE4] = "Composite4",
+ [EM28XX_VMUX_SVIDEO] = "S-Video",
+ [EM28XX_VMUX_TELEVISION] = "Television",
+ [EM28XX_VMUX_CABLE] = "Cable TV",
+ [EM28XX_VMUX_DVB] = "DVB",
+ [EM28XX_VMUX_DEBUG] = "for debug only",
+ };
+
+ n = i->index;
+ if (n >= MAX_EM28XX_INPUT)
+ return -EINVAL;
+ if (0 == INPUT(n)->type)
+ return -EINVAL;
+ memset(i, 0, sizeof(*i));
+ i->index = n;
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+ strcpy(i->name, iname[INPUT(n)->type]);
+ if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) ||
+ (EM28XX_VMUX_CABLE == INPUT(n)->type))
+ i->type = V4L2_INPUT_TYPE_TUNER;
+ for (n = 0; n < ARRAY_SIZE(tvnorms); n++)
+ i->std |= tvnorms[n].id;
+ return 0;
+ }
+
+ case VIDIOC_G_INPUT:
+ {
+ int *i = arg;
+ *i = dev->ctl_input;
+
+ return 0;
+ }
+
+ case VIDIOC_S_INPUT:
+ {
+ int *index = arg;
+
+ if (*index >= MAX_EM28XX_INPUT)
+ return -EINVAL;
+ if (0 == INPUT(*index)->type)
+ return -EINVAL;
+
+ down(&dev->lock);
+ video_mux(dev, *index);
+ up(&dev->lock);
+
+ return 0;
+ }
+
+ case VIDIOC_G_AUDIO:
+ {
+ struct v4l2_audio *a = arg;
+ unsigned int index = a->index;
+
+ if (a->index > 1)
+ return -EINVAL;
+ memset(a, 0, sizeof(*a));
+ index = dev->ctl_ainput;
+
+ if (index == 0) {
+ strcpy(a->name, "Television");
+ } else {
+ strcpy(a->name, "Line In");
+ }
+ a->capability = V4L2_AUDCAP_STEREO;
+ a->index = index;
+ return 0;
+ }
+
+ case VIDIOC_S_AUDIO:
+ {
+ struct v4l2_audio *a = arg;
+ if (a->index != dev->ctl_ainput)
+ return -EINVAL;
+
+ return 0;
+ }
+
+ /* --- controls ---------------------------------------------- */
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *qc = arg;
+ u8 i, n;
+ n = sizeof(em28xx_qctrl) / sizeof(em28xx_qctrl[0]);
+ for (i = 0; i < n; i++)
+ if (qc->id && qc->id == em28xx_qctrl[i].id) {
+ memcpy(qc, &(em28xx_qctrl[i]),
+ sizeof(*qc));
+ return 0;
+ }
+
+ return -EINVAL;
+ }
+
+ case VIDIOC_G_CTRL:
+ {
+ struct v4l2_control *ctrl = arg;
+
+
+ return em28xx_get_ctrl(dev, ctrl);
+ }
+
+ case VIDIOC_S_CTRL_OLD: /* ??? */
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *ctrl = arg;
+ u8 i, n;
+
+
+ n = sizeof(em28xx_qctrl) / sizeof(em28xx_qctrl[0]);
+ for (i = 0; i < n; i++)
+ if (ctrl->id == em28xx_qctrl[i].id) {
+ if (ctrl->value <
+ em28xx_qctrl[i].minimum
+ || ctrl->value >
+ em28xx_qctrl[i].maximum)
+ return -ERANGE;
+
+ return em28xx_set_ctrl(dev, ctrl);
+ }
+ return -EINVAL;
+ }
+
+ /* --- tuner ioctls ------------------------------------------ */
+ case VIDIOC_G_TUNER:
+ {
+ struct v4l2_tuner *t = arg;
+ int status = 0;
+
+ if (0 != t->index)
+ return -EINVAL;
+
+ memset(t, 0, sizeof(*t));
+ strcpy(t->name, "Tuner");
+ t->type = V4L2_TUNER_ANALOG_TV;
+ t->capability = V4L2_TUNER_CAP_NORM;
+ t->rangehigh = 0xffffffffUL; /* FIXME: set correct range */
+/* t->signal = 0xffff;*/
+/* em28xx_i2c_call_clients(dev,VIDIOC_G_TUNER,t);*/
+ /* No way to get signal strength? */
+ down(&dev->lock);
+ em28xx_i2c_call_clients(dev, DECODER_GET_STATUS,
+ &status);
+ up(&dev->lock);
+ t->signal =
+ (status & DECODER_STATUS_GOOD) != 0 ? 0xffff : 0;
+
+ em28xx_videodbg("VIDIO_G_TUNER: signal=%x, afc=%x\n", t->signal,
+ t->afc);
+ return 0;
+ }
+ case VIDIOC_S_TUNER:
+ {
+ struct v4l2_tuner *t = arg;
+ int status = 0;
+
+ if (0 != t->index)
+ return -EINVAL;
+ memset(t, 0, sizeof(*t));
+ strcpy(t->name, "Tuner");
+ t->type = V4L2_TUNER_ANALOG_TV;
+ t->capability = V4L2_TUNER_CAP_NORM;
+ t->rangehigh = 0xffffffffUL; /* FIXME: set correct range */
+/* t->signal = 0xffff; */
+ /* No way to get signal strength? */
+ down(&dev->lock);
+ em28xx_i2c_call_clients(dev, DECODER_GET_STATUS,
+ &status);
+ up(&dev->lock);
+ t->signal =
+ (status & DECODER_STATUS_GOOD) != 0 ? 0xffff : 0;
+
+ em28xx_videodbg("VIDIO_S_TUNER: signal=%x, afc=%x\n",
+ t->signal, t->afc);
+ return 0;
+ }
+ case VIDIOC_G_FREQUENCY:
+ {
+ struct v4l2_frequency *f = arg;
+
+ memset(f, 0, sizeof(*f));
+ f->type = V4L2_TUNER_ANALOG_TV;
+ f->frequency = dev->ctl_freq;
+
+ return 0;
+ }
+ case VIDIOC_S_FREQUENCY:
+ {
+ struct v4l2_frequency *f = arg;
+
+ if (0 != f->tuner)
+ return -EINVAL;
+
+ if (V4L2_TUNER_ANALOG_TV != f->type)
+ return -EINVAL;
+
+ down(&dev->lock);
+ dev->ctl_freq = f->frequency;
+ em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f);
+ up(&dev->lock);
+ return 0;
+ }
+
+ case VIDIOC_CROPCAP:
+ {
+ struct v4l2_cropcap *cc = arg;
+
+ if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ cc->bounds.left = 0;
+ cc->bounds.top = 0;
+ cc->bounds.width = dev->width;
+ cc->bounds.height = dev->height;
+ cc->defrect = cc->bounds;
+ cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */
+ cc->pixelaspect.denominator = 59;
+ return 0;
+ }
+ case VIDIOC_STREAMON:
+ {
+ int *type = arg;
+
+ if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE
+ || dev->io != IO_MMAP)
+ return -EINVAL;
+
+ if (list_empty(&dev->inqueue))
+ return -EINVAL;
+
+ dev->stream = STREAM_ON; /* FIXME: Start video capture here? */
+
+ em28xx_videodbg("VIDIOC_STREAMON: starting stream\n");
+
+ return 0;
+ }
+ case VIDIOC_STREAMOFF:
+ {
+ int *type = arg;
+ int ret;
+
+ if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE
+ || dev->io != IO_MMAP)
+ return -EINVAL;
+
+ if (dev->stream == STREAM_ON) {
+ em28xx_videodbg ("VIDIOC_STREAMOFF: interrupting stream\n");
+ if ((ret = em28xx_stream_interrupt(dev)))
+ return ret;
+ }
+ em28xx_empty_framequeues(dev);
+
+ return 0;
+ }
+ default:
+ return v4l_compat_translate_ioctl(inode, filp, cmd, arg,
+ driver_ioctl);
+ }
+ return 0;
+}
+
+/*
+ * em28xx_v4l2_do_ioctl()
+ * This function is _not_ called directly, but from
+ * em28xx_v4l2_ioctl. Userspace
+ * copying is done already, arg is a kernel pointer.
+ */
+static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, void *arg)
+{
+ struct em28xx *dev = filp->private_data;
+
+ if (!dev)
+ return -ENODEV;
+
+ if (video_debug > 1)
+ em28xx_print_ioctl(dev->name,cmd);
+
+ switch (cmd) {
+
+ /* --- capabilities ------------------------------------------ */
+ case VIDIOC_QUERYCAP:
+ {
+ struct v4l2_capability *cap = arg;
+
+ memset(cap, 0, sizeof(*cap));
+ strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
+ strlcpy(cap->card, em28xx_boards[dev->model].name,
+ sizeof(cap->card));
+ strlcpy(cap->bus_info, dev->udev->dev.bus_id,
+ sizeof(cap->bus_info));
+ cap->version = EM28XX_VERSION_CODE;
+ cap->capabilities =
+ V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_AUDIO |
+ V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+ if (dev->has_tuner)
+ cap->capabilities |= V4L2_CAP_TUNER;
+ return 0;
+ }
+
+ /* --- capture ioctls ---------------------------------------- */
+ case VIDIOC_ENUM_FMT:
+ {
+ struct v4l2_fmtdesc *fmtd = arg;
+
+ if (fmtd->index != 0)
+ return -EINVAL;
+ memset(fmtd, 0, sizeof(*fmtd));
+ fmtd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ strcpy(fmtd->description, "Packed YUY2");
+ fmtd->pixelformat = V4L2_PIX_FMT_YUYV;
+ memset(fmtd->reserved, 0, sizeof(fmtd->reserved));
+ return 0;
+ }
+
+ case VIDIOC_G_FMT:
+ {
+ struct v4l2_format *format = arg;
+
+ em28xx_videodbg("VIDIOC_G_FMT: type=%s\n",
+ format->type ==
+ V4L2_BUF_TYPE_VIDEO_CAPTURE ?
+ "V4L2_BUF_TYPE_VIDEO_CAPTURE" : format->type ==
+ V4L2_BUF_TYPE_VBI_CAPTURE ?
+ "V4L2_BUF_TYPE_VBI_CAPTURE " :
+ "not supported");
+
+ if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ format->fmt.pix.width = dev->width;
+ format->fmt.pix.height = dev->height;
+ format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+ format->fmt.pix.bytesperline = dev->bytesperline;
+ format->fmt.pix.sizeimage = dev->frame_size;
+ format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ format->fmt.pix.field = dev->interlaced ? V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */
+
+ em28xx_videodbg("VIDIOC_G_FMT: %dx%d\n", dev->width,
+ dev->height);
+ return 0;
+ }
+
+ case VIDIOC_TRY_FMT:
+ case VIDIOC_S_FMT:
+ {
+ struct v4l2_format *format = arg;
+ u32 i;
+ int ret = 0;
+ int width = format->fmt.pix.width;
+ int height = format->fmt.pix.height;
+ unsigned int hscale, vscale;
+ unsigned int maxh, maxw;
+
+ maxw = norm_maxw(dev);
+ maxh = norm_maxh(dev);
+
+/* int both_fields; */
+
+ em28xx_videodbg("%s: type=%s\n",
+ cmd ==
+ VIDIOC_TRY_FMT ? "VIDIOC_TRY_FMT" :
+ "VIDIOC_S_FMT",
+ format->type ==
+ V4L2_BUF_TYPE_VIDEO_CAPTURE ?
+ "V4L2_BUF_TYPE_VIDEO_CAPTURE" : format->type ==
+ V4L2_BUF_TYPE_VBI_CAPTURE ?
+ "V4L2_BUF_TYPE_VBI_CAPTURE " :
+ "not supported");
+
+ if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ em28xx_videodbg("%s: requested %dx%d\n",
+ cmd ==
+ VIDIOC_TRY_FMT ? "VIDIOC_TRY_FMT" :
+ "VIDIOC_S_FMT", format->fmt.pix.width,
+ format->fmt.pix.height);
+
+ /* FIXME: Move some code away from here */
+ /* width must even because of the YUYV format */
+ /* height must be even because of interlacing */
+ height &= 0xfffe;
+ width &= 0xfffe;
+
+ if (height < 32)
+ height = 32;
+ if (height > maxh)
+ height = maxh;
+ if (width < 48)
+ width = 48;
+ if (width > maxw)
+ width = maxw;
+
+ if(dev->is_em2800){
+ /* the em2800 can only scale down to 50% */
+ if(height % (maxh / 2))
+ height=maxh;
+ if(width % (maxw / 2))
+ width=maxw;
+ /* according to empiatech support */
+ /* the MaxPacketSize is to small to support */
+ /* framesizes larger than 640x480 @ 30 fps */
+ /* or 640x576 @ 25 fps. As this would cut */
+ /* of a part of the image we prefer */
+ /* 360x576 or 360x480 for now */
+ if(width == maxw && height == maxh)
+ width /= 2;
+ }
+
+ if ((hscale =
+ (((unsigned long)maxw) << 12) / width - 4096L) >=
+ 0x4000)
+ hscale = 0x3fff;
+ width =
+ (((unsigned long)maxw) << 12) / (hscale + 4096L);
+
+ if ((vscale =
+ (((unsigned long)maxh) << 12) / height - 4096L) >=
+ 0x4000)
+ vscale = 0x3fff;
+ height =
+ (((unsigned long)maxh) << 12) / (vscale + 4096L);
+
+ format->fmt.pix.width = width;
+ format->fmt.pix.height = height;
+ format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+ format->fmt.pix.bytesperline = width * 2;
+ format->fmt.pix.sizeimage = width * 2 * height;
+ format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ format->fmt.pix.field = V4L2_FIELD_INTERLACED;
+
+ em28xx_videodbg("%s: returned %dx%d (%d, %d)\n",
+ cmd ==
+ VIDIOC_TRY_FMT ? "VIDIOC_TRY_FMT" :
+ "VIDIOC_S_FMT", format->fmt.pix.width,
+ format->fmt.pix.height, hscale, vscale);
+
+ if (cmd == VIDIOC_TRY_FMT)
+ return 0;
+
+ for (i = 0; i < dev->num_frames; i++)
+ if (dev->frame[i].vma_use_count) {
+ em28xx_videodbg("VIDIOC_S_FMT failed. "
+ "Unmap the buffers first.\n");
+ return -EINVAL;
+ }
+
+ /* stop io in case it is already in progress */
+ if (dev->stream == STREAM_ON) {
+ em28xx_videodbg("VIDIOC_SET_FMT: interupting stream\n");
+ if ((ret = em28xx_stream_interrupt(dev)))
+ return ret;
+ }
+
+ em28xx_release_buffers(dev);
+ dev->io = IO_NONE;
+
+ /* set new image size */
+ dev->width = width;
+ dev->height = height;
+ dev->frame_size = dev->width * dev->height * 2;
+ dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */
+ dev->bytesperline = dev->width * 2;
+ dev->hscale = hscale;
+ dev->vscale = vscale;
+/* dev->both_fileds = both_fileds; */
+ em28xx_uninit_isoc(dev);
+ em28xx_set_alternate(dev);
+ em28xx_capture_start(dev, 1);
+ em28xx_resolution_set(dev);
+ em28xx_init_isoc(dev);
+
+ return 0;
+ }
+
+ /* --- streaming capture ------------------------------------- */
+ case VIDIOC_REQBUFS:
+ {
+ struct v4l2_requestbuffers *rb = arg;
+ u32 i;
+ int ret;
+
+ if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ rb->memory != V4L2_MEMORY_MMAP)
+ return -EINVAL;
+
+ if (dev->io == IO_READ) {
+ em28xx_videodbg ("method is set to read;"
+ " close and open the device again to"
+ " choose the mmap I/O method\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < dev->num_frames; i++)
+ if (dev->frame[i].vma_use_count) {
+ em28xx_videodbg ("VIDIOC_REQBUFS failed; previous buffers are still mapped\n");
+ return -EINVAL;
+ }
+
+ if (dev->stream == STREAM_ON) {
+ em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n");
+ if ((ret = em28xx_stream_interrupt(dev)))
+ return ret;
+ }
+
+ em28xx_empty_framequeues(dev);
+
+ em28xx_release_buffers(dev);
+ if (rb->count)
+ rb->count =
+ em28xx_request_buffers(dev, rb->count);
+
+ dev->frame_current = NULL;
+
+ em28xx_videodbg ("VIDIOC_REQBUFS: setting io method to mmap: num bufs %i\n",
+ rb->count);
+ dev->io = rb->count ? IO_MMAP : IO_NONE;
+ return 0;
+ }
+
+ case VIDIOC_QUERYBUF:
+ {
+ struct v4l2_buffer *b = arg;
+
+ if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ b->index >= dev->num_frames || dev->io != IO_MMAP)
+ return -EINVAL;
+
+ memcpy(b, &dev->frame[b->index].buf, sizeof(*b));
+
+ if (dev->frame[b->index].vma_use_count) {
+ b->flags |= V4L2_BUF_FLAG_MAPPED;
+ }
+ if (dev->frame[b->index].state == F_DONE)
+ b->flags |= V4L2_BUF_FLAG_DONE;
+ else if (dev->frame[b->index].state != F_UNUSED)
+ b->flags |= V4L2_BUF_FLAG_QUEUED;
+ return 0;
+ }
+ case VIDIOC_QBUF:
+ {
+ struct v4l2_buffer *b = arg;
+ unsigned long lock_flags;
+
+ if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ b->index >= dev->num_frames || dev->io != IO_MMAP) {
+ return -EINVAL;
+ }
+
+ if (dev->frame[b->index].state != F_UNUSED) {
+ return -EAGAIN;
+ }
+ dev->frame[b->index].state = F_QUEUED;
+
+ /* add frame to fifo */
+ spin_lock_irqsave(&dev->queue_lock, lock_flags);
+ list_add_tail(&dev->frame[b->index].frame,
+ &dev->inqueue);
+ spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
+
+ return 0;
+ }
+ case VIDIOC_DQBUF:
+ {
+ struct v4l2_buffer *b = arg;
+ struct em28xx_frame_t *f;
+ unsigned long lock_flags;
+ int ret = 0;
+
+ if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE
+ || dev->io != IO_MMAP)
+ return -EINVAL;
+
+ if (list_empty(&dev->outqueue)) {
+ if (dev->stream == STREAM_OFF)
+ return -EINVAL;
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ ret = wait_event_interruptible
+ (dev->wait_frame,
+ (!list_empty(&dev->outqueue)) ||
+ (dev->state & DEV_DISCONNECTED));
+ if (ret)
+ return ret;
+ if (dev->state & DEV_DISCONNECTED)
+ return -ENODEV;
+ }
+
+ spin_lock_irqsave(&dev->queue_lock, lock_flags);
+ f = list_entry(dev->outqueue.next,
+ struct em28xx_frame_t, frame);
+ list_del(dev->outqueue.next);
+ spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
+
+ f->state = F_UNUSED;
+ memcpy(b, &f->buf, sizeof(*b));
+
+ if (f->vma_use_count)
+ b->flags |= V4L2_BUF_FLAG_MAPPED;
+
+ return 0;
+ }
+ default:
+ return em28xx_do_ioctl(inode, filp, dev, cmd, arg,
+ em28xx_video_do_ioctl);
+ }
+ return 0;
+}
+
+/*
+ * em28xx_v4l2_ioctl()
+ * handle v4l2 ioctl the main action happens in em28xx_v4l2_do_ioctl()
+ */
+static int em28xx_v4l2_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret = 0;
+ struct em28xx *dev = filp->private_data;
+
+ if (down_interruptible(&dev->fileop_lock))
+ return -ERESTARTSYS;
+
+ if (dev->state & DEV_DISCONNECTED) {
+ em28xx_errdev("v4l2 ioctl: device not present\n");
+ up(&dev->fileop_lock);
+ return -ENODEV;
+ }
+
+ if (dev->state & DEV_MISCONFIGURED) {
+ em28xx_errdev
+ ("v4l2 ioctl: device is misconfigured; close and open it again\n");
+ up(&dev->fileop_lock);
+ return -EIO;
+ }
+
+ ret = video_usercopy(inode, filp, cmd, arg, em28xx_video_do_ioctl);
+
+ up(&dev->fileop_lock);
+
+ return ret;
+}
+
+static struct file_operations em28xx_v4l_fops = {
+ .owner = THIS_MODULE,
+ .open = em28xx_v4l2_open,
+ .release = em28xx_v4l2_close,
+ .ioctl = em28xx_v4l2_ioctl,
+ .read = em28xx_v4l2_read,
+ .poll = em28xx_v4l2_poll,
+ .mmap = em28xx_v4l2_mmap,
+ .llseek = no_llseek,
+};
+
+/******************************** usb interface *****************************************/
+
+/*
+ * em28xx_init_dev()
+ * allocates and inits the device structs, registers i2c bus and v4l device
+ */
+static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
+ int minor, int model)
+{
+ struct em28xx *dev = *devhandle;
+ int retval = -ENOMEM;
+ int errCode, i;
+ unsigned int maxh, maxw;
+
+ dev->udev = udev;
+ dev->model = model;
+ init_MUTEX(&dev->lock);
+ init_waitqueue_head(&dev->open);
+
+ dev->em28xx_write_regs = em28xx_write_regs;
+ dev->em28xx_read_reg = em28xx_read_reg;
+ dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len;
+ dev->em28xx_write_regs_req = em28xx_write_regs_req;
+ dev->em28xx_read_reg_req = em28xx_read_reg_req;
+ dev->is_em2800 = em28xx_boards[model].is_em2800;
+ dev->has_tuner = em28xx_boards[model].has_tuner;
+ dev->has_msp34xx = em28xx_boards[model].has_msp34xx;
+ dev->tda9887_conf = em28xx_boards[model].tda9887_conf;
+ dev->decoder = em28xx_boards[model].decoder;
+
+ if (tuner >= 0)
+ dev->tuner_type = tuner;
+ else
+ dev->tuner_type = em28xx_boards[model].tuner_type;
+
+ dev->video_inputs = em28xx_boards[model].vchannels;
+
+ for (i = 0; i < TVNORMS; i++)
+ if (em28xx_boards[model].norm == tvnorms[i].mode)
+ break;
+ if (i == TVNORMS)
+ i = 0;
+
+ dev->tvnorm = &tvnorms[i]; /* set default norm */
+
+ em28xx_videodbg("tvnorm=%s\n", dev->tvnorm->name);
+
+ maxw = norm_maxw(dev);
+ maxh = norm_maxh(dev);
+
+ /* set default image size */
+ dev->width = maxw;
+ dev->height = maxh;
+ dev->interlaced = EM28XX_INTERLACED_DEFAULT;
+ dev->field_size = dev->width * dev->height;
+ dev->frame_size =
+ dev->interlaced ? dev->field_size << 1 : dev->field_size;
+ dev->bytesperline = dev->width * 2;
+ dev->hscale = 0;
+ dev->vscale = 0;
+ dev->ctl_input = 2;
+
+ /* setup video picture settings for saa7113h */
+ memset(&dev->vpic, 0, sizeof(dev->vpic));
+ dev->vpic.colour = 128 << 8;
+ dev->vpic.hue = 128 << 8;
+ dev->vpic.brightness = 128 << 8;
+ dev->vpic.contrast = 192 << 8;
+ dev->vpic.whiteness = 128 << 8; /* This one isn't used */
+ dev->vpic.depth = 16;
+ dev->vpic.palette = VIDEO_PALETTE_YUV422;
+
+#ifdef CONFIG_MODULES
+ /* request some modules */
+ if (dev->decoder == EM28XX_SAA7113 || dev->decoder == EM28XX_SAA7114)
+ request_module("saa711x");
+ if (dev->decoder == EM28XX_TVP5150)
+ request_module("tvp5150");
+ if (dev->has_tuner)
+ request_module("tuner");
+ if (dev->tda9887_conf)
+ request_module("tda9887");
+#endif
+ errCode = em28xx_config(dev);
+ if (errCode) {
+ em28xx_errdev("error configuring device\n");
+ kfree(dev);
+ return -ENOMEM;
+ }
+
+ down(&dev->lock);
+ /* register i2c bus */
+ em28xx_i2c_register(dev);
+
+ /* Do board specific init and eeprom reading */
+ em28xx_card_setup(dev);
+
+ /* configure the device */
+ em28xx_config_i2c(dev);
+
+ up(&dev->lock);
+
+ errCode = em28xx_config(dev);
+
+#ifdef CONFIG_MODULES
+ if (dev->has_msp34xx)
+ request_module("msp3400");
+#endif
+ /* allocate and fill v4l2 device struct */
+ dev->vdev = video_device_alloc();
+ if (NULL == dev->vdev) {
+ em28xx_errdev("cannot allocate video_device.\n");
+ kfree(dev);
+ return -ENOMEM;
+ }
+
+ dev->vdev->type = VID_TYPE_CAPTURE;
+ if (dev->has_tuner)
+ dev->vdev->type |= VID_TYPE_TUNER;
+ dev->vdev->hardware = 0;
+ dev->vdev->fops = &em28xx_v4l_fops;
+ dev->vdev->minor = -1;
+ dev->vdev->dev = &dev->udev->dev;
+ dev->vdev->release = video_device_release;
+ snprintf(dev->vdev->name, sizeof(dev->vdev->name), "%s",
+ "em28xx video");
+ list_add_tail(&dev->devlist,&em28xx_devlist);
+
+ /* register v4l2 device */
+ down(&dev->lock);
+ if ((retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, -1))) {
+ em28xx_errdev("unable to register video device (error=%i).\n",
+ retval);
+ up(&dev->lock);
+ list_del(&dev->devlist);
+ video_device_release(dev->vdev);
+ kfree(dev);
+ return -ENODEV;
+ }
+ if (dev->has_msp34xx) {
+ /* Send a reset to other chips via gpio */
+ em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1);
+ udelay(2500);
+ em28xx_write_regs_req(dev, 0x00, 0x08, "\xff", 1);
+ udelay(2500);
+
+ }
+ video_mux(dev, 0);
+
+ up(&dev->lock);
+
+ em28xx_info("V4L2 device registered as /dev/video%d\n",
+ dev->vdev->minor);
+
+ return 0;
+}
+
+/*
+ * em28xx_usb_probe()
+ * checks for supported devices
+ */
+static int em28xx_usb_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ const struct usb_endpoint_descriptor *endpoint;
+ struct usb_device *udev;
+ struct usb_interface *uif;
+ struct em28xx *dev = NULL;
+ int retval = -ENODEV;
+ int model,i,nr,ifnum;
+
+ udev = usb_get_dev(interface_to_usbdev(interface));
+ ifnum = interface->altsetting[0].desc.bInterfaceNumber;
+
+
+ /* Don't register audio interfaces */
+ if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
+ em28xx_err(DRIVER_NAME " audio device (%04x:%04x): interface %i, class %i\n",
+ udev->descriptor.idVendor,udev->descriptor.idProduct,
+ ifnum,
+ interface->altsetting[0].desc.bInterfaceClass);
+ return -ENODEV;
+ }
+
+ em28xx_err(DRIVER_NAME " new video device (%04x:%04x): interface %i, class %i\n",
+ udev->descriptor.idVendor,udev->descriptor.idProduct,
+ ifnum,
+ interface->altsetting[0].desc.bInterfaceClass);
+
+ endpoint = &interface->cur_altsetting->endpoint[1].desc;
+
+ /* check if the the device has the iso in endpoint at the correct place */
+ if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
+ USB_ENDPOINT_XFER_ISOC) {
+ em28xx_err(DRIVER_NAME " probing error: endpoint is non-ISO endpoint!\n");
+ return -ENODEV;
+ }
+ if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
+ em28xx_err(DRIVER_NAME " probing error: endpoint is ISO OUT endpoint!\n");
+ return -ENODEV;
+ }
+
+ model=id->driver_info;
+ nr=interface->minor;
+
+ if (nr>EM28XX_MAXBOARDS) {
+ printk (DRIVER_NAME ": Supports only %i em28xx boards.\n",EM28XX_MAXBOARDS);
+ return -ENOMEM;
+ }
+
+ /* allocate memory for our device state and initialize it */
+ dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL) {
+ em28xx_err(DRIVER_NAME ": out of memory!\n");
+ return -ENOMEM;
+ }
+ memset(dev, 0, sizeof(*dev));
+
+ /* compute alternate max packet sizes */
+ uif = udev->actconfig->interface[0];
+
+ dev->num_alt=uif->num_altsetting;
+ printk(DRIVER_NAME ": Alternate settings: %i\n",dev->num_alt);
+// dev->alt_max_pkt_size = kmalloc(sizeof(*dev->alt_max_pkt_size)*
+ dev->alt_max_pkt_size = kmalloc(32*
+ dev->num_alt,GFP_KERNEL);
+ if (dev->alt_max_pkt_size == NULL) {
+ em28xx_err(DRIVER_NAME ": out of memory!\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < dev->num_alt ; i++) {
+ u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[1].desc.
+ wMaxPacketSize);
+ dev->alt_max_pkt_size[i] =
+ (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
+ printk(DRIVER_NAME ": Alternate setting %i, max size= %i\n",i,
+ dev->alt_max_pkt_size[i]);
+ }
+
+ snprintf(dev->name, 29, "em28xx #%d", nr);
+
+ if ((card[nr]>=0)&&(card[nr]<em28xx_bcount))
+ model=card[nr];
+
+ if ((model==EM2800_BOARD_UNKNOWN)||(model==EM2820_BOARD_UNKNOWN)) {
+ printk( "%s: Your board has no eeprom inside it and thus can't\n"
+ "%s: be autodetected. Please pass card=<n> insmod option to\n"
+ "%s: workaround that. Redirect complaints to the vendor of\n"
+ "%s: the TV card. Best regards,\n"
+ "%s: -- tux\n",
+ dev->name,dev->name,dev->name,dev->name,dev->name);
+ printk("%s: Here is a list of valid choices for the card=<n> insmod option:\n",
+ dev->name);
+ for (i = 0; i < em28xx_bcount; i++) {
+ printk("%s: card=%d -> %s\n",
+ dev->name, i, em28xx_boards[i].name);
+ }
+ }
+
+ /* allocate device struct */
+ retval = em28xx_init_dev(&dev, udev, nr, model);
+ if (retval)
+ return retval;
+
+ em28xx_info("Found %s\n", em28xx_boards[model].name);
+
+ /* save our data pointer in this interface device */
+ usb_set_intfdata(interface, dev);
+ return 0;
+}
+
+/*
+ * em28xx_usb_disconnect()
+ * called when the device gets diconencted
+ * video device will be unregistered on v4l2_close in case it is still open
+ */
+static void em28xx_usb_disconnect(struct usb_interface *interface)
+{
+ struct em28xx *dev = usb_get_intfdata(interface);
+ usb_set_intfdata(interface, NULL);
+
+ if (!dev)
+ return;
+
+ down_write(&em28xx_disconnect);
+
+ down(&dev->lock);
+
+ em28xx_info("disconnecting %s\n", dev->vdev->name);
+
+ wake_up_interruptible_all(&dev->open);
+
+ if (dev->users) {
+ em28xx_warn
+ ("device /dev/video%d is open! Deregistration and memory "
+ "deallocation are deferred on close.\n", dev->vdev->minor);
+ dev->state |= DEV_MISCONFIGURED;
+ em28xx_uninit_isoc(dev);
+ dev->state |= DEV_DISCONNECTED;
+ wake_up_interruptible(&dev->wait_frame);
+ wake_up_interruptible(&dev->wait_stream);
+ } else {
+ dev->state |= DEV_DISCONNECTED;
+ em28xx_release_resources(dev);
+ }
+
+ up(&dev->lock);
+
+ if (!dev->users) {
+ kfree(dev->alt_max_pkt_size);
+ kfree(dev);
+ }
+
+ up_write(&em28xx_disconnect);
+}
+
+static struct usb_driver em28xx_usb_driver = {
+ .owner = THIS_MODULE,
+ .name = "em28xx",
+ .probe = em28xx_usb_probe,
+ .disconnect = em28xx_usb_disconnect,
+ .id_table = em28xx_id_table,
+};
+
+static int __init em28xx_module_init(void)
+{
+ int result;
+
+ printk(KERN_INFO DRIVER_NAME " v4l2 driver version %d.%d.%d loaded\n",
+ (EM28XX_VERSION_CODE >> 16) & 0xff,
+ (EM28XX_VERSION_CODE >> 8) & 0xff, EM28XX_VERSION_CODE & 0xff);
+#ifdef SNAPSHOT
+ printk(KERN_INFO DRIVER_NAME " snapshot date %04d-%02d-%02d\n",
+ SNAPSHOT / 10000, (SNAPSHOT / 100) % 100, SNAPSHOT % 100);
+#endif
+
+ /* register this driver with the USB subsystem */
+ result = usb_register(&em28xx_usb_driver);
+ if (result)
+ em28xx_err(DRIVER_NAME
+ " usb_register failed. Error number %d.\n", result);
+
+ return result;
+}
+
+static void __exit em28xx_module_exit(void)
+{
+ /* deregister this driver with the USB subsystem */
+ usb_deregister(&em28xx_usb_driver);
+}
+
+module_init(em28xx_module_init);
+module_exit(em28xx_module_exit);
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
new file mode 100644
index 00000000000..5c7a41ce69f
--- /dev/null
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -0,0 +1,513 @@
+/*
+ em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+
+ Copyright (C) 2005 Markus Rechberger <mrechberger@gmail.com>
+ Ludovico Cavedon <cavedon@sssup.it>
+ Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+
+ Based on the em2800 driver from Sascha Sommer <saschasommer@freenet.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _EM28XX_H
+#define _EM28XX_H
+
+#include <linux/videodev.h>
+#include <linux/i2c.h>
+#include <media/ir-kbd-i2c.h>
+
+/* Boards supported by driver */
+
+#define EM2800_BOARD_UNKNOWN 0
+#define EM2820_BOARD_UNKNOWN 1
+#define EM2820_BOARD_TERRATEC_CINERGY_250 2
+#define EM2820_BOARD_PINNACLE_USB_2 3
+#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 4
+#define EM2820_BOARD_MSI_VOX_USB_2 5
+#define EM2800_BOARD_TERRATEC_CINERGY_200 6
+#define EM2800_BOARD_LEADTEK_WINFAST_USBII 7
+#define EM2800_BOARD_KWORLD_USB2800 8
+#define EM2820_BOARD_PINNACLE_DVC_90 9
+
+#define UNSET -1
+
+/* maximum number of em28xx boards */
+#define EM28XX_MAXBOARDS 1 /*FIXME: should be bigger */
+
+/* maximum number of frames that can be queued */
+#define EM28XX_NUM_FRAMES 5
+/* number of frames that get used for v4l2_read() */
+#define EM28XX_NUM_READ_FRAMES 2
+
+/* number of buffers for isoc transfers */
+#define EM28XX_NUM_BUFS 5
+
+/* number of packets for each buffer
+ windows requests only 40 packets .. so we better do the same
+ this is what I found out for all alternate numbers there!
+ */
+#define EM28XX_NUM_PACKETS 40
+
+/* default alternate; 0 means choose the best */
+#define EM28XX_PINOUT 0
+
+#define EM28XX_INTERLACED_DEFAULT 1
+
+/*
+#define (use usbview if you want to get the other alternate number infos)
+#define
+#define alternate number 2
+#define Endpoint Address: 82
+ Direction: in
+ Attribute: 1
+ Type: Isoc
+ Max Packet Size: 1448
+ Interval: 125us
+
+ alternate number 7
+
+ Endpoint Address: 82
+ Direction: in
+ Attribute: 1
+ Type: Isoc
+ Max Packet Size: 3072
+ Interval: 125us
+*/
+
+/* time to wait when stopping the isoc transfer */
+#define EM28XX_URB_TIMEOUT msecs_to_jiffies(EM28XX_NUM_BUFS * EM28XX_NUM_PACKETS)
+
+/* time in msecs to wait for i2c writes to finish */
+#define EM2800_I2C_WRITE_TIMEOUT 20
+
+/* the various frame states */
+enum em28xx_frame_state {
+ F_UNUSED = 0,
+ F_QUEUED,
+ F_GRABBING,
+ F_DONE,
+ F_ERROR,
+};
+
+/* stream states */
+enum em28xx_stream_state {
+ STREAM_OFF,
+ STREAM_INTERRUPT,
+ STREAM_ON,
+};
+
+/* frames */
+struct em28xx_frame_t {
+ void *bufmem;
+ struct v4l2_buffer buf;
+ enum em28xx_frame_state state;
+ struct list_head frame;
+ unsigned long vma_use_count;
+ int top_field;
+ int fieldbytesused;
+};
+
+/* io methods */
+enum em28xx_io_method {
+ IO_NONE,
+ IO_READ,
+ IO_MMAP,
+};
+
+/* inputs */
+
+#define MAX_EM28XX_INPUT 4
+enum enum28xx_itype {
+ EM28XX_VMUX_COMPOSITE1 = 1,
+ EM28XX_VMUX_COMPOSITE2,
+ EM28XX_VMUX_COMPOSITE3,
+ EM28XX_VMUX_COMPOSITE4,
+ EM28XX_VMUX_SVIDEO,
+ EM28XX_VMUX_TELEVISION,
+ EM28XX_VMUX_CABLE,
+ EM28XX_VMUX_DVB,
+ EM28XX_VMUX_DEBUG,
+ EM28XX_RADIO,
+};
+
+struct em28xx_input {
+ enum enum28xx_itype type;
+ unsigned int vmux;
+ unsigned int amux;
+};
+
+#define INPUT(nr) (&em28xx_boards[dev->model].input[nr])
+
+enum em28xx_decoder {
+ EM28XX_TVP5150,
+ EM28XX_SAA7113,
+ EM28XX_SAA7114
+};
+
+struct em28xx_board {
+ char *name;
+ int vchannels;
+ int norm;
+ int tuner_type;
+
+ /* i2c flags */
+ unsigned int is_em2800;
+ unsigned int tda9887_conf;
+
+ unsigned int has_tuner:1;
+ unsigned int has_msp34xx:1;
+
+ enum em28xx_decoder decoder;
+
+ struct em28xx_input input[MAX_EM28XX_INPUT];
+};
+
+struct em28xx_eeprom {
+ u32 id; /* 0x9567eb1a */
+ u16 vendor_ID;
+ u16 product_ID;
+
+ u16 chip_conf;
+
+ u16 board_conf;
+
+ u16 string1, string2, string3;
+
+ u8 string_idx_table;
+};
+
+/* device states */
+enum em28xx_dev_state {
+ DEV_INITIALIZED = 0x01,
+ DEV_DISCONNECTED = 0x02,
+ DEV_MISCONFIGURED = 0x04,
+};
+
+/* tvnorms */
+struct em28xx_tvnorm {
+ char *name;
+ v4l2_std_id id;
+ /* mode for saa7113h */
+ int mode;
+};
+
+/* main device struct */
+struct em28xx {
+ /* generic device properties */
+ char name[30]; /* name (including minor) of the device */
+ int model; /* index in the device_data struct */
+ unsigned int is_em2800;
+ int video_inputs; /* number of video inputs */
+ struct list_head devlist;
+ unsigned int has_tuner:1;
+ unsigned int has_msp34xx:1;
+ unsigned int has_tda9887:1;
+
+ enum em28xx_decoder decoder;
+
+ int tuner_type; /* type of the tuner */
+ int tuner_addr; /* tuner address */
+ int tda9887_conf;
+ /* i2c i/o */
+ struct i2c_adapter i2c_adap;
+ struct i2c_client i2c_client;
+ /* video for linux */
+ int users; /* user count for exclusive use */
+ struct video_device *vdev; /* video for linux device struct */
+ struct video_picture vpic; /* picture settings only used to init saa7113h */
+ struct em28xx_tvnorm *tvnorm; /* selected tv norm */
+ int ctl_freq; /* selected frequency */
+ unsigned int ctl_input; /* selected input */
+ unsigned int ctl_ainput; /* slected audio input */
+ int mute;
+ int volume;
+ /* frame properties */
+ struct em28xx_frame_t frame[EM28XX_NUM_FRAMES]; /* list of frames */
+ int num_frames; /* number of frames currently in use */
+ unsigned int frame_count; /* total number of transfered frames */
+ struct em28xx_frame_t *frame_current; /* the frame that is being filled */
+ int width; /* current frame width */
+ int height; /* current frame height */
+ int frame_size; /* current frame size */
+ int field_size; /* current field size */
+ int bytesperline;
+ int hscale; /* horizontal scale factor (see datasheet) */
+ int vscale; /* vertical scale factor (see datasheet) */
+ int interlaced; /* 1=interlace fileds, 0=just top fileds */
+ int type;
+
+ /* states */
+ enum em28xx_dev_state state;
+ enum em28xx_stream_state stream;
+ enum em28xx_io_method io;
+ /* locks */
+ struct semaphore lock, fileop_lock;
+ spinlock_t queue_lock;
+ struct list_head inqueue, outqueue;
+ wait_queue_head_t open, wait_frame, wait_stream;
+ struct video_device *vbi_dev;
+
+ unsigned char eedata[256];
+
+ /* usb transfer */
+ struct usb_device *udev; /* the usb device */
+ int alt; /* alternate */
+ int max_pkt_size; /* max packet size of isoc transaction */
+ int num_alt; /* Number of alternative settings */
+ unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */
+ struct urb *urb[EM28XX_NUM_BUFS]; /* urb for isoc transfers */
+ char *transfer_buffer[EM28XX_NUM_BUFS]; /* transfer buffers for isoc transfer */
+ /* helper funcs that call usb_control_msg */
+ int (*em28xx_write_regs) (struct em28xx * dev, u16 reg, char *buf,
+ int len);
+ int (*em28xx_read_reg) (struct em28xx * dev, u16 reg);
+ int (*em28xx_read_reg_req_len) (struct em28xx * dev, u8 req, u16 reg,
+ char *buf, int len);
+ int (*em28xx_write_regs_req) (struct em28xx * dev, u8 req, u16 reg,
+ char *buf, int len);
+ int (*em28xx_read_reg_req) (struct em28xx * dev, u8 req, u16 reg);
+};
+
+/* Provided by em28xx-i2c.c */
+
+void em28xx_i2c_call_clients(struct em28xx *dev, unsigned int cmd, void *arg);
+int em28xx_i2c_register(struct em28xx *dev);
+int em28xx_i2c_unregister(struct em28xx *dev);
+
+/* Provided by em28xx-input.c */
+
+void em28xx_set_ir(struct em28xx * dev,struct IR_i2c *ir);
+
+/* Provided by em28xx-core.c */
+
+void em28xx_print_ioctl(char *name, unsigned int cmd);
+
+u32 em28xx_request_buffers(struct em28xx *dev, u32 count);
+void em28xx_queue_unusedframes(struct em28xx *dev);
+void em28xx_release_buffers(struct em28xx *dev);
+
+int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
+ char *buf, int len);
+int em28xx_read_reg_req(struct em28xx *dev, u8 req, u16 reg);
+int em28xx_read_reg(struct em28xx *dev, u16 reg);
+int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
+ int len);
+int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len);
+int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
+ u8 bitmask);
+int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 * val);
+int em28xx_audio_analog_set(struct em28xx *dev);
+int em28xx_colorlevels_set_default(struct em28xx *dev);
+int em28xx_capture_start(struct em28xx *dev, int start);
+int em28xx_outfmt_set_yuv422(struct em28xx *dev);
+int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, u8 ymin,
+ u8 ymax);
+int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
+ u16 width, u16 height);
+int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v);
+int em28xx_resolution_set(struct em28xx *dev);
+void em28xx_isocIrq(struct urb *urb, struct pt_regs *regs);
+int em28xx_init_isoc(struct em28xx *dev);
+void em28xx_uninit_isoc(struct em28xx *dev);
+int em28xx_set_alternate(struct em28xx *dev);
+
+/* Provided by em28xx-cards.c */
+extern int em2800_variant_detect(struct usb_device* udev,int model);
+extern void em28xx_card_setup(struct em28xx *dev);
+extern struct em28xx_board em28xx_boards[];
+extern struct usb_device_id em28xx_id_table[];
+extern const unsigned int em28xx_bcount;
+
+/* em28xx registers */
+#define CHIPID_REG 0x0a
+#define USBSUSP_REG 0x0c /* */
+
+#define AUDIOSRC_REG 0x0e
+#define XCLK_REG 0x0f
+
+#define VINMODE_REG 0x10
+#define VINCTRL_REG 0x11
+#define VINENABLE_REG 0x12 /* */
+
+#define GAMMA_REG 0x14
+#define RGAIN_REG 0x15
+#define GGAIN_REG 0x16
+#define BGAIN_REG 0x17
+#define ROFFSET_REG 0x18
+#define GOFFSET_REG 0x19
+#define BOFFSET_REG 0x1a
+
+#define OFLOW_REG 0x1b
+#define HSTART_REG 0x1c
+#define VSTART_REG 0x1d
+#define CWIDTH_REG 0x1e
+#define CHEIGHT_REG 0x1f
+
+#define YGAIN_REG 0x20
+#define YOFFSET_REG 0x21
+#define UVGAIN_REG 0x22
+#define UOFFSET_REG 0x23
+#define VOFFSET_REG 0x24
+#define SHARPNESS_REG 0x25
+
+#define COMPR_REG 0x26
+#define OUTFMT_REG 0x27
+
+#define XMIN_REG 0x28
+#define XMAX_REG 0x29
+#define YMIN_REG 0x2a
+#define YMAX_REG 0x2b
+
+#define HSCALELOW_REG 0x30
+#define HSCALEHIGH_REG 0x31
+#define VSCALELOW_REG 0x32
+#define VSCALEHIGH_REG 0x33
+
+#define AC97LSB_REG 0x40
+#define AC97MSB_REG 0x41
+#define AC97ADDR_REG 0x42
+#define AC97BUSY_REG 0x43
+
+/* em202 registers */
+#define MASTER_AC97 0x02
+#define VIDEO_AC97 0x14
+
+/* register settings */
+#define EM28XX_AUDIO_SRC_TUNER 0xc0
+#define EM28XX_AUDIO_SRC_LINE 0x80
+
+/* printk macros */
+
+#define em28xx_err(fmt, arg...) do {\
+ printk(KERN_ERR fmt , ##arg); } while (0)
+
+#define em28xx_errdev(fmt, arg...) do {\
+ printk(KERN_ERR "%s: "fmt,\
+ dev->name , ##arg); } while (0)
+
+#define em28xx_info(fmt, arg...) do {\
+ printk(KERN_INFO "%s: "fmt,\
+ dev->name , ##arg); } while (0)
+#define em28xx_warn(fmt, arg...) do {\
+ printk(KERN_WARNING "%s: "fmt,\
+ dev->name , ##arg); } while (0)
+
+inline static int em28xx_audio_source(struct em28xx *dev, int input)
+{
+ return em28xx_write_reg_bits(dev, AUDIOSRC_REG, input, 0xc0);
+}
+
+inline static int em28xx_audio_usb_mute(struct em28xx *dev, int mute)
+{
+ return em28xx_write_reg_bits(dev, XCLK_REG, mute ? 0x00 : 0x80, 0x80);
+}
+
+inline static int em28xx_audio_analog_setup(struct em28xx *dev)
+{
+ /* unmute video mixer with default volume level */
+ return em28xx_write_ac97(dev, VIDEO_AC97, "\x08\x08");
+}
+
+inline static int em28xx_compression_disable(struct em28xx *dev)
+{
+ /* side effect of disabling scaler and mixer */
+ return em28xx_write_regs(dev, COMPR_REG, "\x00", 1);
+}
+
+inline static int em28xx_contrast_get(struct em28xx *dev)
+{
+ return em28xx_read_reg(dev, YGAIN_REG) & 0x1f;
+}
+
+inline static int em28xx_brightness_get(struct em28xx *dev)
+{
+ return em28xx_read_reg(dev, YOFFSET_REG);
+}
+
+inline static int em28xx_saturation_get(struct em28xx *dev)
+{
+ return em28xx_read_reg(dev, UVGAIN_REG) & 0x1f;
+}
+
+inline static int em28xx_u_balance_get(struct em28xx *dev)
+{
+ return em28xx_read_reg(dev, UOFFSET_REG);
+}
+
+inline static int em28xx_v_balance_get(struct em28xx *dev)
+{
+ return em28xx_read_reg(dev, VOFFSET_REG);
+}
+
+inline static int em28xx_gamma_get(struct em28xx *dev)
+{
+ return em28xx_read_reg(dev, GAMMA_REG) & 0x3f;
+}
+
+inline static int em28xx_contrast_set(struct em28xx *dev, s32 val)
+{
+ u8 tmp = (u8) val;
+ return em28xx_write_regs(dev, YGAIN_REG, &tmp, 1);
+}
+
+inline static int em28xx_brightness_set(struct em28xx *dev, s32 val)
+{
+ u8 tmp = (u8) val;
+ return em28xx_write_regs(dev, YOFFSET_REG, &tmp, 1);
+}
+
+inline static int em28xx_saturation_set(struct em28xx *dev, s32 val)
+{
+ u8 tmp = (u8) val;
+ return em28xx_write_regs(dev, UVGAIN_REG, &tmp, 1);
+}
+
+inline static int em28xx_u_balance_set(struct em28xx *dev, s32 val)
+{
+ u8 tmp = (u8) val;
+ return em28xx_write_regs(dev, UOFFSET_REG, &tmp, 1);
+}
+
+inline static int em28xx_v_balance_set(struct em28xx *dev, s32 val)
+{
+ u8 tmp = (u8) val;
+ return em28xx_write_regs(dev, VOFFSET_REG, &tmp, 1);
+}
+
+inline static int em28xx_gamma_set(struct em28xx *dev, s32 val)
+{
+ u8 tmp = (u8) val;
+ return em28xx_write_regs(dev, GAMMA_REG, &tmp, 1);
+}
+
+/*FIXME: maxw should be dependent of alt mode */
+inline static unsigned int norm_maxw(struct em28xx *dev)
+{
+ switch(dev->model){
+ case (EM2820_BOARD_MSI_VOX_USB_2): return(640);
+ default: return(720);
+ }
+}
+
+inline static unsigned int norm_maxh(struct em28xx *dev)
+{
+ switch(dev->model){
+ case (EM2820_BOARD_MSI_VOX_USB_2): return(480);
+ default: return (dev->tvnorm->id & V4L2_STD_625_50) ? 576 : 480;
+ }
+}
+
+#endif
diff --git a/drivers/media/video/indycam.c b/drivers/media/video/indycam.c
index 26dd06ec89a..deeef125eb9 100644
--- a/drivers/media/video/indycam.c
+++ b/drivers/media/video/indycam.c
@@ -27,15 +27,15 @@
#include "indycam.h"
-//#define INDYCAM_DEBUG
-
-#define INDYCAM_MODULE_VERSION "0.0.3"
+#define INDYCAM_MODULE_VERSION "0.0.5"
MODULE_DESCRIPTION("SGI IndyCam driver");
MODULE_VERSION(INDYCAM_MODULE_VERSION);
MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>");
MODULE_LICENSE("GPL");
+// #define INDYCAM_DEBUG
+
#ifdef INDYCAM_DEBUG
#define dprintk(x...) printk("IndyCam: " x);
#define indycam_regdump(client) indycam_regdump_debug(client)
@@ -46,14 +46,14 @@ MODULE_LICENSE("GPL");
struct indycam {
struct i2c_client *client;
- int version;
+ u8 version;
};
static struct i2c_driver i2c_driver_indycam;
-static const unsigned char initseq[] = {
+static const u8 initseq[] = {
INDYCAM_CONTROL_AGCENA, /* INDYCAM_CONTROL */
- INDYCAM_SHUTTER_DEFAULT, /* INDYCAM_SHUTTER */
+ INDYCAM_SHUTTER_60, /* INDYCAM_SHUTTER */
INDYCAM_GAIN_DEFAULT, /* INDYCAM_GAIN */
0x00, /* INDYCAM_BRIGHTNESS (read-only) */
INDYCAM_RED_BALANCE_DEFAULT, /* INDYCAM_RED_BALANCE */
@@ -64,12 +64,11 @@ static const unsigned char initseq[] = {
/* IndyCam register handling */
-static int indycam_read_reg(struct i2c_client *client, unsigned char reg,
- unsigned char *value)
+static int indycam_read_reg(struct i2c_client *client, u8 reg, u8 *value)
{
int ret;
- if (reg == INDYCAM_RESET) {
+ if (reg == INDYCAM_REG_RESET) {
dprintk("indycam_read_reg(): "
"skipping write-only register %d\n", reg);
*value = 0;
@@ -77,24 +76,24 @@ static int indycam_read_reg(struct i2c_client *client, unsigned char reg,
}
ret = i2c_smbus_read_byte_data(client, reg);
+
if (ret < 0) {
printk(KERN_ERR "IndyCam: indycam_read_reg(): read failed, "
"register = 0x%02x\n", reg);
return ret;
}
- *value = (unsigned char)ret;
+ *value = (u8)ret;
return 0;
}
-static int indycam_write_reg(struct i2c_client *client, unsigned char reg,
- unsigned char value)
+static int indycam_write_reg(struct i2c_client *client, u8 reg, u8 value)
{
int err;
- if ((reg == INDYCAM_BRIGHTNESS)
- || (reg == INDYCAM_VERSION)) {
+ if ((reg == INDYCAM_REG_BRIGHTNESS)
+ || (reg == INDYCAM_REG_VERSION)) {
dprintk("indycam_write_reg(): "
"skipping read-only register %d\n", reg);
return 0;
@@ -102,6 +101,7 @@ static int indycam_write_reg(struct i2c_client *client, unsigned char reg,
dprintk("Writing Reg %d = 0x%02x\n", reg, value);
err = i2c_smbus_write_byte_data(client, reg, value);
+
if (err) {
printk(KERN_ERR "IndyCam: indycam_write_reg(): write failed, "
"register = 0x%02x, value = 0x%02x\n", reg, value);
@@ -109,13 +109,12 @@ static int indycam_write_reg(struct i2c_client *client, unsigned char reg,
return err;
}
-static int indycam_write_block(struct i2c_client *client, unsigned char reg,
- unsigned char length, unsigned char *data)
+static int indycam_write_block(struct i2c_client *client, u8 reg,
+ u8 length, u8 *data)
{
- unsigned char i;
- int err;
+ int i, err;
- for (i = reg; i < length; i++) {
+ for (i = 0; i < length; i++) {
err = indycam_write_reg(client, reg + i, data[i]);
if (err)
return err;
@@ -130,7 +129,7 @@ static int indycam_write_block(struct i2c_client *client, unsigned char reg,
static void indycam_regdump_debug(struct i2c_client *client)
{
int i;
- unsigned char val;
+ u8 val;
for (i = 0; i < 9; i++) {
indycam_read_reg(client, i, &val);
@@ -139,76 +138,144 @@ static void indycam_regdump_debug(struct i2c_client *client)
}
#endif
-static int indycam_get_controls(struct i2c_client *client,
- struct indycam_control *ctrl)
+static int indycam_get_control(struct i2c_client *client,
+ struct indycam_control *ctrl)
{
- unsigned char ctrl_reg;
-
- indycam_read_reg(client, INDYCAM_CONTROL, &ctrl_reg);
- ctrl->agc = (ctrl_reg & INDYCAM_CONTROL_AGCENA)
- ? INDYCAM_VALUE_ENABLED
- : INDYCAM_VALUE_DISABLED;
- ctrl->awb = (ctrl_reg & INDYCAM_CONTROL_AWBCTL)
- ? INDYCAM_VALUE_ENABLED
- : INDYCAM_VALUE_DISABLED;
- indycam_read_reg(client, INDYCAM_SHUTTER,
- (unsigned char *)&ctrl->shutter);
- indycam_read_reg(client, INDYCAM_GAIN,
- (unsigned char *)&ctrl->gain);
- indycam_read_reg(client, INDYCAM_RED_BALANCE,
- (unsigned char *)&ctrl->red_balance);
- indycam_read_reg(client, INDYCAM_BLUE_BALANCE,
- (unsigned char *)&ctrl->blue_balance);
- indycam_read_reg(client, INDYCAM_RED_SATURATION,
- (unsigned char *)&ctrl->red_saturation);
- indycam_read_reg(client, INDYCAM_BLUE_SATURATION,
- (unsigned char *)&ctrl->blue_saturation);
- indycam_read_reg(client, INDYCAM_GAMMA,
- (unsigned char *)&ctrl->gamma);
+ struct indycam *camera = i2c_get_clientdata(client);
+ u8 reg;
+ int ret = 0;
+
+ switch (ctrl->type) {
+ case INDYCAM_CONTROL_AGC:
+ case INDYCAM_CONTROL_AWB:
+ ret = indycam_read_reg(client, INDYCAM_REG_CONTROL, &reg);
+ if (ret)
+ return -EIO;
+ if (ctrl->type == INDYCAM_CONTROL_AGC)
+ ctrl->value = (reg & INDYCAM_CONTROL_AGCENA)
+ ? 1 : 0;
+ else
+ ctrl->value = (reg & INDYCAM_CONTROL_AWBCTL)
+ ? 1 : 0;
+ break;
+ case INDYCAM_CONTROL_SHUTTER:
+ ret = indycam_read_reg(client, INDYCAM_REG_SHUTTER, &reg);
+ if (ret)
+ return -EIO;
+ ctrl->value = ((s32)reg == 0x00) ? 0xff : ((s32)reg - 1);
+ break;
+ case INDYCAM_CONTROL_GAIN:
+ ret = indycam_read_reg(client, INDYCAM_REG_GAIN, &reg);
+ if (ret)
+ return -EIO;
+ ctrl->value = (s32)reg;
+ break;
+ case INDYCAM_CONTROL_RED_BALANCE:
+ ret = indycam_read_reg(client, INDYCAM_REG_RED_BALANCE, &reg);
+ if (ret)
+ return -EIO;
+ ctrl->value = (s32)reg;
+ break;
+ case INDYCAM_CONTROL_BLUE_BALANCE:
+ ret = indycam_read_reg(client, INDYCAM_REG_BLUE_BALANCE, &reg);
+ if (ret)
+ return -EIO;
+ ctrl->value = (s32)reg;
+ break;
+ case INDYCAM_CONTROL_RED_SATURATION:
+ ret = indycam_read_reg(client,
+ INDYCAM_REG_RED_SATURATION, &reg);
+ if (ret)
+ return -EIO;
+ ctrl->value = (s32)reg;
+ break;
+ case INDYCAM_CONTROL_BLUE_SATURATION:
+ ret = indycam_read_reg(client,
+ INDYCAM_REG_BLUE_SATURATION, &reg);
+ if (ret)
+ return -EIO;
+ ctrl->value = (s32)reg;
+ break;
+ case INDYCAM_CONTROL_GAMMA:
+ if (camera->version == CAMERA_VERSION_MOOSE) {
+ ret = indycam_read_reg(client,
+ INDYCAM_REG_GAMMA, &reg);
+ if (ret)
+ return -EIO;
+ ctrl->value = (s32)reg;
+ } else {
+ ctrl->value = INDYCAM_GAMMA_DEFAULT;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ }
- return 0;
+ return ret;
}
-static int indycam_set_controls(struct i2c_client *client,
- struct indycam_control *ctrl)
+static int indycam_set_control(struct i2c_client *client,
+ struct indycam_control *ctrl)
{
- unsigned char ctrl_reg;
+ struct indycam *camera = i2c_get_clientdata(client);
+ u8 reg;
+ int ret = 0;
+
+ switch (ctrl->type) {
+ case INDYCAM_CONTROL_AGC:
+ case INDYCAM_CONTROL_AWB:
+ ret = indycam_read_reg(client, INDYCAM_REG_CONTROL, &reg);
+ if (ret)
+ break;
- indycam_read_reg(client, INDYCAM_CONTROL, &ctrl_reg);
- if (ctrl->agc != INDYCAM_VALUE_UNCHANGED) {
- if (ctrl->agc)
- ctrl_reg |= INDYCAM_CONTROL_AGCENA;
- else
- ctrl_reg &= ~INDYCAM_CONTROL_AGCENA;
- }
- if (ctrl->awb != INDYCAM_VALUE_UNCHANGED) {
- if (ctrl->awb)
- ctrl_reg |= INDYCAM_CONTROL_AWBCTL;
- else
- ctrl_reg &= ~INDYCAM_CONTROL_AWBCTL;
+ if (ctrl->type == INDYCAM_CONTROL_AGC) {
+ if (ctrl->value)
+ reg |= INDYCAM_CONTROL_AGCENA;
+ else
+ reg &= ~INDYCAM_CONTROL_AGCENA;
+ } else {
+ if (ctrl->value)
+ reg |= INDYCAM_CONTROL_AWBCTL;
+ else
+ reg &= ~INDYCAM_CONTROL_AWBCTL;
+ }
+
+ ret = indycam_write_reg(client, INDYCAM_REG_CONTROL, reg);
+ break;
+ case INDYCAM_CONTROL_SHUTTER:
+ reg = (ctrl->value == 0xff) ? 0x00 : (ctrl->value + 1);
+ ret = indycam_write_reg(client, INDYCAM_REG_SHUTTER, reg);
+ break;
+ case INDYCAM_CONTROL_GAIN:
+ ret = indycam_write_reg(client, INDYCAM_REG_GAIN, ctrl->value);
+ break;
+ case INDYCAM_CONTROL_RED_BALANCE:
+ ret = indycam_write_reg(client, INDYCAM_REG_RED_BALANCE,
+ ctrl->value);
+ break;
+ case INDYCAM_CONTROL_BLUE_BALANCE:
+ ret = indycam_write_reg(client, INDYCAM_REG_BLUE_BALANCE,
+ ctrl->value);
+ break;
+ case INDYCAM_CONTROL_RED_SATURATION:
+ ret = indycam_write_reg(client, INDYCAM_REG_RED_SATURATION,
+ ctrl->value);
+ break;
+ case INDYCAM_CONTROL_BLUE_SATURATION:
+ ret = indycam_write_reg(client, INDYCAM_REG_BLUE_SATURATION,
+ ctrl->value);
+ break;
+ case INDYCAM_CONTROL_GAMMA:
+ if (camera->version == CAMERA_VERSION_MOOSE) {
+ ret = indycam_write_reg(client, INDYCAM_REG_GAMMA,
+ ctrl->value);
+ }
+ break;
+ default:
+ ret = -EINVAL;
}
- indycam_write_reg(client, INDYCAM_CONTROL, ctrl_reg);
-
- if (ctrl->shutter >= 0)
- indycam_write_reg(client, INDYCAM_SHUTTER, ctrl->shutter);
- if (ctrl->gain >= 0)
- indycam_write_reg(client, INDYCAM_GAIN, ctrl->gain);
- if (ctrl->red_balance >= 0)
- indycam_write_reg(client, INDYCAM_RED_BALANCE,
- ctrl->red_balance);
- if (ctrl->blue_balance >= 0)
- indycam_write_reg(client, INDYCAM_BLUE_BALANCE,
- ctrl->blue_balance);
- if (ctrl->red_saturation >= 0)
- indycam_write_reg(client, INDYCAM_RED_SATURATION,
- ctrl->red_saturation);
- if (ctrl->blue_saturation >= 0)
- indycam_write_reg(client, INDYCAM_BLUE_SATURATION,
- ctrl->blue_saturation);
- if (ctrl->gamma >= 0)
- indycam_write_reg(client, INDYCAM_GAMMA, ctrl->gamma);
- return 0;
+ return ret;
}
/* I2C-interface */
@@ -247,7 +314,8 @@ static int indycam_attach(struct i2c_adapter *adap, int addr, int kind)
if (err)
goto out_free_camera;
- camera->version = i2c_smbus_read_byte_data(client, INDYCAM_VERSION);
+ camera->version = i2c_smbus_read_byte_data(client,
+ INDYCAM_REG_VERSION);
if (camera->version != CAMERA_VERSION_INDY &&
camera->version != CAMERA_VERSION_MOOSE) {
err = -ENODEV;
@@ -260,8 +328,7 @@ static int indycam_attach(struct i2c_adapter *adap, int addr, int kind)
indycam_regdump(client);
// initialize
- err = indycam_write_block(client, 0, sizeof(initseq),
- (unsigned char *)&initseq);
+ err = indycam_write_block(client, 0, sizeof(initseq), (u8 *)&initseq);
if (err) {
printk(KERN_ERR "IndyCam initalization failed\n");
err = -EIO;
@@ -271,11 +338,10 @@ static int indycam_attach(struct i2c_adapter *adap, int addr, int kind)
indycam_regdump(client);
// white balance
- err = indycam_write_reg(client, INDYCAM_CONTROL,
+ err = indycam_write_reg(client, INDYCAM_REG_CONTROL,
INDYCAM_CONTROL_AGCENA | INDYCAM_CONTROL_AWBCTL);
if (err) {
- printk(KERN_ERR "IndyCam white balance "
- "initialization failed\n");
+ printk(KERN_ERR "IndyCam: White balancing camera failed\n");
err = -EIO;
goto out_detach_client;
}
@@ -371,13 +437,11 @@ static int indycam_command(struct i2c_client *client, unsigned int cmd,
/* TODO: convert values for indycam_set_controls() */
break;
}
- case DECODER_INDYCAM_GET_CONTROLS: {
- struct indycam_control *ctrl = arg;
- indycam_get_controls(client, ctrl);
+ case DECODER_INDYCAM_GET_CONTROL: {
+ return indycam_get_control(client, arg);
}
- case DECODER_INDYCAM_SET_CONTROLS: {
- struct indycam_control *ctrl = arg;
- indycam_set_controls(client, ctrl);
+ case DECODER_INDYCAM_SET_CONTROL: {
+ return indycam_set_control(client, arg);
}
default:
return -EINVAL;
@@ -388,12 +452,12 @@ static int indycam_command(struct i2c_client *client, unsigned int cmd,
static struct i2c_driver i2c_driver_indycam = {
.owner = THIS_MODULE,
- .name = "indycam",
- .id = I2C_DRIVERID_INDYCAM,
- .flags = I2C_DF_NOTIFY,
+ .name = "indycam",
+ .id = I2C_DRIVERID_INDYCAM,
+ .flags = I2C_DF_NOTIFY,
.attach_adapter = indycam_probe,
- .detach_client = indycam_detach,
- .command = indycam_command,
+ .detach_client = indycam_detach,
+ .command = indycam_command,
};
static int __init indycam_init(void)
diff --git a/drivers/media/video/indycam.h b/drivers/media/video/indycam.h
index d9ddb6b79a0..e6ee82063ed 100644
--- a/drivers/media/video/indycam.h
+++ b/drivers/media/video/indycam.h
@@ -22,21 +22,21 @@
#define INDYCAM_VERSION_MINOR(x) ((x) & 0x0f)
/* Register bus addresses */
-#define INDYCAM_CONTROL 0x00
-#define INDYCAM_SHUTTER 0x01
-#define INDYCAM_GAIN 0x02
-#define INDYCAM_BRIGHTNESS 0x03 /* read-only */
-#define INDYCAM_RED_BALANCE 0x04
-#define INDYCAM_BLUE_BALANCE 0x05
-#define INDYCAM_RED_SATURATION 0x06
-#define INDYCAM_BLUE_SATURATION 0x07
-#define INDYCAM_GAMMA 0x08
-#define INDYCAM_VERSION 0x0e /* read-only */
-#define INDYCAM_RESET 0x0f /* write-only */
-
-#define INDYCAM_LED 0x46
-#define INDYCAM_ORIENTATION 0x47
-#define INDYCAM_BUTTON 0x48
+#define INDYCAM_REG_CONTROL 0x00
+#define INDYCAM_REG_SHUTTER 0x01
+#define INDYCAM_REG_GAIN 0x02
+#define INDYCAM_REG_BRIGHTNESS 0x03 /* read-only */
+#define INDYCAM_REG_RED_BALANCE 0x04
+#define INDYCAM_REG_BLUE_BALANCE 0x05
+#define INDYCAM_REG_RED_SATURATION 0x06
+#define INDYCAM_REG_BLUE_SATURATION 0x07
+#define INDYCAM_REG_GAMMA 0x08
+#define INDYCAM_REG_VERSION 0x0e /* read-only */
+#define INDYCAM_REG_RESET 0x0f /* write-only */
+
+#define INDYCAM_REG_LED 0x46
+#define INDYCAM_REG_ORIENTATION 0x47
+#define INDYCAM_REG_BUTTON 0x48
/* Field definitions of registers */
#define INDYCAM_CONTROL_AGCENA (1<<0) /* automatic gain control */
@@ -59,13 +59,14 @@
#define INDYCAM_ORIENTATION_BOTTOM_TO_TOP 0x40
#define INDYCAM_BUTTON_RELEASED 0x10
+/* Values for controls */
#define INDYCAM_SHUTTER_MIN 0x00
#define INDYCAM_SHUTTER_MAX 0xff
#define INDYCAM_GAIN_MIN 0x00
#define INDYCAM_GAIN_MAX 0xff
-#define INDYCAM_RED_BALANCE_MIN 0x00 /* the effect is the opposite? */
-#define INDYCAM_RED_BALANCE_MAX 0xff
-#define INDYCAM_BLUE_BALANCE_MIN 0x00 /* the effect is the opposite? */
+#define INDYCAM_RED_BALANCE_MIN 0x00
+#define INDYCAM_RED_BALANCE_MAX 0xff
+#define INDYCAM_BLUE_BALANCE_MIN 0x00
#define INDYCAM_BLUE_BALANCE_MAX 0xff
#define INDYCAM_RED_SATURATION_MIN 0x00
#define INDYCAM_RED_SATURATION_MAX 0xff
@@ -74,34 +75,9 @@
#define INDYCAM_GAMMA_MIN 0x00
#define INDYCAM_GAMMA_MAX 0xff
-/* Driver interface definitions */
-
-#define INDYCAM_VALUE_ENABLED 1
-#define INDYCAM_VALUE_DISABLED 0
-#define INDYCAM_VALUE_UNCHANGED -1
-
-/* When setting controls, a value of -1 leaves the control unchanged. */
-struct indycam_control {
- int agc; /* boolean */
- int awb; /* boolean */
- int shutter;
- int gain;
- int red_balance;
- int blue_balance;
- int red_saturation;
- int blue_saturation;
- int gamma;
-};
-
-#define DECODER_INDYCAM_GET_CONTROLS _IOR('d', 193, struct indycam_control)
-#define DECODER_INDYCAM_SET_CONTROLS _IOW('d', 194, struct indycam_control)
-
-/* Default values for controls */
-
-#define INDYCAM_AGC_DEFAULT INDYCAM_VALUE_ENABLED
-#define INDYCAM_AWB_DEFAULT INDYCAM_VALUE_ENABLED
-
-#define INDYCAM_SHUTTER_DEFAULT INDYCAM_SHUTTER_60
+#define INDYCAM_AGC_DEFAULT 1
+#define INDYCAM_AWB_DEFAULT 0
+#define INDYCAM_SHUTTER_DEFAULT 0xff
#define INDYCAM_GAIN_DEFAULT 0x80
#define INDYCAM_RED_BALANCE_DEFAULT 0x18
#define INDYCAM_BLUE_BALANCE_DEFAULT 0xa4
@@ -109,4 +85,24 @@ struct indycam_control {
#define INDYCAM_BLUE_SATURATION_DEFAULT 0xc0
#define INDYCAM_GAMMA_DEFAULT 0x80
+/* Driver interface definitions */
+
+#define INDYCAM_CONTROL_AGC 0 /* boolean */
+#define INDYCAM_CONTROL_AWB 1 /* boolean */
+#define INDYCAM_CONTROL_SHUTTER 2
+#define INDYCAM_CONTROL_GAIN 3
+#define INDYCAM_CONTROL_RED_BALANCE 4
+#define INDYCAM_CONTROL_BLUE_BALANCE 5
+#define INDYCAM_CONTROL_RED_SATURATION 6
+#define INDYCAM_CONTROL_BLUE_SATURATION 7
+#define INDYCAM_CONTROL_GAMMA 8
+
+struct indycam_control {
+ u8 type;
+ s32 value;
+};
+
+#define DECODER_INDYCAM_GET_CONTROL _IOR('d', 193, struct indycam_control)
+#define DECODER_INDYCAM_SET_CONTROL _IOW('d', 194, struct indycam_control)
+
#endif
diff --git a/drivers/media/video/ir-kbd-gpio.c b/drivers/media/video/ir-kbd-gpio.c
index 234151e48ed..5abfc0fbf6d 100644
--- a/drivers/media/video/ir-kbd-gpio.c
+++ b/drivers/media/video/ir-kbd-gpio.c
@@ -156,24 +156,164 @@ static IR_KEYTAB_TYPE ir_codes_apac_viewcomp[IR_KEYTAB_SIZE] = {
/* ---------------------------------------------------------------------- */
+/* Ricardo Cerqueira <v4l@cerqueira.org> */
+/* Weird matching, since the remote has "uncommon" keys */
+
+static IR_KEYTAB_TYPE ir_codes_conceptronic[IR_KEYTAB_SIZE] = {
+
+ [ 30 ] = KEY_POWER, // power
+ [ 7 ] = KEY_MEDIA, // source
+ [ 28 ] = KEY_SEARCH, // scan
+
+/* FIXME: duplicate keycodes?
+ *
+ * These four keys seem to share the same GPIO as CH+, CH-, <<< and >>>
+ * The GPIO values are
+ * 6397fb for both "Scan <" and "CH -",
+ * 639ffb for "Scan >" and "CH+",
+ * 6384fb for "Tune <" and "<<<",
+ * 638cfb for "Tune >" and ">>>", regardless of the mask.
+ *
+ * [ 23 ] = KEY_BACK, // fm scan <<
+ * [ 31 ] = KEY_FORWARD, // fm scan >>
+ *
+ * [ 4 ] = KEY_LEFT, // fm tuning <
+ * [ 12 ] = KEY_RIGHT, // fm tuning >
+ *
+ * For now, these four keys are disabled. Pressing them will generate
+ * the CH+/CH-/<<</>>> events
+ */
+
+ [ 3 ] = KEY_TUNER, // TV/FM
+
+ [ 0 ] = KEY_RECORD,
+ [ 8 ] = KEY_STOP,
+ [ 17 ] = KEY_PLAY,
+
+ [ 26 ] = KEY_PLAYPAUSE, // freeze
+ [ 25 ] = KEY_ZOOM, // zoom
+ [ 15 ] = KEY_TEXT, // min
+
+ [ 1 ] = KEY_KP1,
+ [ 11 ] = KEY_KP2,
+ [ 27 ] = KEY_KP3,
+ [ 5 ] = KEY_KP4,
+ [ 9 ] = KEY_KP5,
+ [ 21 ] = KEY_KP6,
+ [ 6 ] = KEY_KP7,
+ [ 10 ] = KEY_KP8,
+ [ 18 ] = KEY_KP9,
+ [ 2 ] = KEY_KP0,
+ [ 16 ] = KEY_LAST, // +100
+ [ 19 ] = KEY_LIST, // recall
+
+ [ 31 ] = KEY_CHANNELUP, // chn down
+ [ 23 ] = KEY_CHANNELDOWN, // chn up
+ [ 22 ] = KEY_VOLUMEUP, // vol down
+ [ 20 ] = KEY_VOLUMEDOWN, // vol up
+
+ [ 4 ] = KEY_KPMINUS, // <<<
+ [ 14 ] = KEY_SETUP, // function
+ [ 12 ] = KEY_KPPLUS, // >>>
+
+ [ 13 ] = KEY_GOTO, // mts
+ [ 29 ] = KEY_REFRESH, // reset
+ [ 24 ] = KEY_MUTE // mute/unmute
+};
+
+static IR_KEYTAB_TYPE ir_codes_nebula[IR_KEYTAB_SIZE] = {
+ [0x00] = KEY_KP0,
+ [0x01] = KEY_KP1,
+ [0x02] = KEY_KP2,
+ [0x03] = KEY_KP3,
+ [0x04] = KEY_KP4,
+ [0x05] = KEY_KP5,
+ [0x06] = KEY_KP6,
+ [0x07] = KEY_KP7,
+ [0x08] = KEY_KP8,
+ [0x09] = KEY_KP9,
+ [0x0a] = KEY_TV,
+ [0x0b] = KEY_AUX,
+ [0x0c] = KEY_DVD,
+ [0x0d] = KEY_POWER,
+ [0x0e] = KEY_MHP, /* labelled 'Picture' */
+ [0x0f] = KEY_AUDIO,
+ [0x10] = KEY_INFO,
+ [0x11] = KEY_F13, /* 16:9 */
+ [0x12] = KEY_F14, /* 14:9 */
+ [0x13] = KEY_EPG,
+ [0x14] = KEY_EXIT,
+ [0x15] = KEY_MENU,
+ [0x16] = KEY_UP,
+ [0x17] = KEY_DOWN,
+ [0x18] = KEY_LEFT,
+ [0x19] = KEY_RIGHT,
+ [0x1a] = KEY_ENTER,
+ [0x1b] = KEY_CHANNELUP,
+ [0x1c] = KEY_CHANNELDOWN,
+ [0x1d] = KEY_VOLUMEUP,
+ [0x1e] = KEY_VOLUMEDOWN,
+ [0x1f] = KEY_RED,
+ [0x20] = KEY_GREEN,
+ [0x21] = KEY_YELLOW,
+ [0x22] = KEY_BLUE,
+ [0x23] = KEY_SUBTITLE,
+ [0x24] = KEY_F15, /* AD */
+ [0x25] = KEY_TEXT,
+ [0x26] = KEY_MUTE,
+ [0x27] = KEY_REWIND,
+ [0x28] = KEY_STOP,
+ [0x29] = KEY_PLAY,
+ [0x2a] = KEY_FASTFORWARD,
+ [0x2b] = KEY_F16, /* chapter */
+ [0x2c] = KEY_PAUSE,
+ [0x2d] = KEY_PLAY,
+ [0x2e] = KEY_RECORD,
+ [0x2f] = KEY_F17, /* picture in picture */
+ [0x30] = KEY_KPPLUS, /* zoom in */
+ [0x31] = KEY_KPMINUS, /* zoom out */
+ [0x32] = KEY_F18, /* capture */
+ [0x33] = KEY_F19, /* web */
+ [0x34] = KEY_EMAIL,
+ [0x35] = KEY_PHONE,
+ [0x36] = KEY_PC
+};
+
struct IR {
struct bttv_sub_device *sub;
struct input_dev *input;
struct ir_input_state ir;
char name[32];
char phys[32];
+
+ /* Usual gpio signalling */
+
u32 mask_keycode;
u32 mask_keydown;
u32 mask_keyup;
-
- int polling;
+ u32 polling;
u32 last_gpio;
struct work_struct work;
struct timer_list timer;
+
+ /* RC5 gpio */
+
+ u32 rc5_gpio;
+ struct timer_list timer_end; /* timer_end for code completion */
+ struct timer_list timer_keyup; /* timer_end for key release */
+ u32 last_rc5; /* last good rc5 code */
+ u32 last_bit; /* last raw bit seen */
+ u32 code; /* raw code under construction */
+ struct timeval base_time; /* time of last seen code */
+ int active; /* building raw code */
};
static int debug;
module_param(debug, int, 0644); /* debug level (0,1,2) */
+static int repeat_delay = 500;
+module_param(repeat_delay, int, 0644);
+static int repeat_period = 33;
+module_param(repeat_period, int, 0644);
#define DEVNAME "ir-kbd-gpio"
#define dprintk(fmt, arg...) if (debug) \
@@ -189,7 +329,7 @@ static struct bttv_sub_driver driver = {
.probe = ir_probe,
.remove = ir_remove,
},
- .gpio_irq = ir_irq,
+ .gpio_irq = ir_irq,
};
/* ---------------------------------------------------------------------- */
@@ -262,6 +402,173 @@ static void ir_work(void *data)
mod_timer(&ir->timer, timeout);
}
+/* ---------------------------------------------------------------*/
+
+static int rc5_remote_gap = 885;
+module_param(rc5_remote_gap, int, 0644);
+static int rc5_key_timeout = 200;
+module_param(rc5_key_timeout, int, 0644);
+
+#define RC5_START(x) (((x)>>12)&3)
+#define RC5_TOGGLE(x) (((x)>>11)&1)
+#define RC5_ADDR(x) (((x)>>6)&31)
+#define RC5_INSTR(x) ((x)&63)
+
+/* decode raw bit pattern to RC5 code */
+static u32 rc5_decode(unsigned int code)
+{
+ unsigned int org_code = code;
+ unsigned int pair;
+ unsigned int rc5 = 0;
+ int i;
+
+ code = (code << 1) | 1;
+ for (i = 0; i < 14; ++i) {
+ pair = code & 0x3;
+ code >>= 2;
+
+ rc5 <<= 1;
+ switch (pair) {
+ case 0:
+ case 2:
+ break;
+ case 1:
+ rc5 |= 1;
+ break;
+ case 3:
+ dprintk("bad code: %x\n", org_code);
+ return 0;
+ }
+ }
+ dprintk("code=%x, rc5=%x, start=%x, toggle=%x, address=%x, "
+ "instr=%x\n", rc5, org_code, RC5_START(rc5),
+ RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
+ return rc5;
+}
+
+static int ir_rc5_irq(struct bttv_sub_device *sub)
+{
+ struct IR *ir = dev_get_drvdata(&sub->dev);
+ struct timeval tv;
+ u32 gpio;
+ u32 gap;
+ unsigned long current_jiffies, timeout;
+
+ /* read gpio port */
+ gpio = bttv_gpio_read(ir->sub->core);
+
+ /* remote IRQ? */
+ if (!(gpio & 0x20))
+ return 0;
+
+ /* get time of bit */
+ current_jiffies = jiffies;
+ do_gettimeofday(&tv);
+
+ /* avoid overflow with gap >1s */
+ if (tv.tv_sec - ir->base_time.tv_sec > 1) {
+ gap = 200000;
+ } else {
+ gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) +
+ tv.tv_usec - ir->base_time.tv_usec;
+ }
+
+ /* active code => add bit */
+ if (ir->active) {
+ /* only if in the code (otherwise spurious IRQ or timer
+ late) */
+ if (ir->last_bit < 28) {
+ ir->last_bit = (gap - rc5_remote_gap / 2) /
+ rc5_remote_gap;
+ ir->code |= 1 << ir->last_bit;
+ }
+ /* starting new code */
+ } else {
+ ir->active = 1;
+ ir->code = 0;
+ ir->base_time = tv;
+ ir->last_bit = 0;
+
+ timeout = current_jiffies + (500 + 30 * HZ) / 1000;
+ mod_timer(&ir->timer_end, timeout);
+ }
+
+ /* toggle GPIO pin 4 to reset the irq */
+ bttv_gpio_write(ir->sub->core, gpio & ~(1 << 4));
+ bttv_gpio_write(ir->sub->core, gpio | (1 << 4));
+ return 1;
+}
+
+static void ir_rc5_timer_end(unsigned long data)
+{
+ struct IR *ir = (struct IR *)data;
+ struct timeval tv;
+ unsigned long current_jiffies, timeout;
+ u32 gap;
+
+ /* get time */
+ current_jiffies = jiffies;
+ do_gettimeofday(&tv);
+
+ /* avoid overflow with gap >1s */
+ if (tv.tv_sec - ir->base_time.tv_sec > 1) {
+ gap = 200000;
+ } else {
+ gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) +
+ tv.tv_usec - ir->base_time.tv_usec;
+ }
+
+ /* Allow some timmer jitter (RC5 is ~24ms anyway so this is ok) */
+ if (gap < 28000) {
+ dprintk("spurious timer_end\n");
+ return;
+ }
+
+ ir->active = 0;
+ if (ir->last_bit < 20) {
+ /* ignore spurious codes (caused by light/other remotes) */
+ dprintk("short code: %x\n", ir->code);
+ } else {
+ u32 rc5 = rc5_decode(ir->code);
+
+ /* two start bits? */
+ if (RC5_START(rc5) != 3) {
+ dprintk("rc5 start bits invalid: %u\n", RC5_START(rc5));
+
+ /* right address? */
+ } else if (RC5_ADDR(rc5) == 0x0) {
+ u32 toggle = RC5_TOGGLE(rc5);
+ u32 instr = RC5_INSTR(rc5);
+
+ /* Good code, decide if repeat/repress */
+ if (toggle != RC5_TOGGLE(ir->last_rc5) ||
+ instr != RC5_INSTR(ir->last_rc5)) {
+ dprintk("instruction %x, toggle %x\n", instr,
+ toggle);
+ ir_input_nokey(ir->input, &ir->ir);
+ ir_input_keydown(ir->input, &ir->ir, instr,
+ instr);
+ }
+
+ /* Set/reset key-up timer */
+ timeout = current_jiffies + (500 + rc5_key_timeout
+ * HZ) / 1000;
+ mod_timer(&ir->timer_keyup, timeout);
+
+ /* Save code for repeat test */
+ ir->last_rc5 = rc5;
+ }
+ }
+}
+
+static void ir_rc5_timer_keyup(unsigned long data)
+{
+ struct IR *ir = (struct IR *)data;
+
+ dprintk("key released\n");
+ ir_input_nokey(ir->input, &ir->ir);
+}
+
/* ---------------------------------------------------------------------- */
static int ir_probe(struct device *dev)
@@ -282,53 +589,65 @@ static int ir_probe(struct device *dev)
/* detect & configure */
switch (sub->core->type) {
- case BTTV_AVERMEDIA:
- case BTTV_AVPHONE98:
- case BTTV_AVERMEDIA98:
+ case BTTV_BOARD_AVERMEDIA:
+ case BTTV_BOARD_AVPHONE98:
+ case BTTV_BOARD_AVERMEDIA98:
ir_codes = ir_codes_avermedia;
ir->mask_keycode = 0xf88000;
ir->mask_keydown = 0x010000;
ir->polling = 50; // ms
break;
- case BTTV_AVDVBT_761:
- case BTTV_AVDVBT_771:
+ case BTTV_BOARD_AVDVBT_761:
+ case BTTV_BOARD_AVDVBT_771:
ir_codes = ir_codes_avermedia_dvbt;
ir->mask_keycode = 0x0f00c0;
ir->mask_keydown = 0x000020;
ir->polling = 50; // ms
break;
- case BTTV_PXELVWPLTVPAK:
+ case BTTV_BOARD_PXELVWPLTVPAK:
ir_codes = ir_codes_pixelview;
ir->mask_keycode = 0x003e00;
ir->mask_keyup = 0x010000;
ir->polling = 50; // ms
- break;
- case BTTV_PV_BT878P_9B:
- case BTTV_PV_BT878P_PLUS:
+ break;
+ case BTTV_BOARD_PV_BT878P_9B:
+ case BTTV_BOARD_PV_BT878P_PLUS:
ir_codes = ir_codes_pixelview;
ir->mask_keycode = 0x001f00;
ir->mask_keyup = 0x008000;
ir->polling = 50; // ms
- break;
+ break;
- case BTTV_WINFAST2000:
+ case BTTV_BOARD_WINFAST2000:
ir_codes = ir_codes_winfast;
ir->mask_keycode = 0x1f8;
break;
- case BTTV_MAGICTVIEW061:
- case BTTV_MAGICTVIEW063:
+ case BTTV_BOARD_MAGICTVIEW061:
+ case BTTV_BOARD_MAGICTVIEW063:
ir_codes = ir_codes_winfast;
ir->mask_keycode = 0x0008e000;
ir->mask_keydown = 0x00200000;
break;
- case BTTV_APAC_VIEWCOMP:
+ case BTTV_BOARD_APAC_VIEWCOMP:
ir_codes = ir_codes_apac_viewcomp;
ir->mask_keycode = 0x001f00;
ir->mask_keyup = 0x008000;
ir->polling = 50; // ms
break;
+ case BTTV_BOARD_CONCEPTRONIC_CTVFMI2:
+ ir_codes = ir_codes_conceptronic;
+ ir->mask_keycode = 0x001F00;
+ ir->mask_keyup = 0x006000;
+ ir->polling = 50; // ms
+ break;
+ case BTTV_BOARD_NEBULA_DIGITV:
+ ir_codes = ir_codes_nebula;
+ driver.any_irq = ir_rc5_irq;
+ driver.gpio_irq = NULL;
+ ir->rc5_gpio = 1;
+ break;
}
if (NULL == ir_codes) {
kfree(ir);
@@ -336,9 +655,17 @@ static int ir_probe(struct device *dev)
return -ENODEV;
}
- /* init hardware-specific stuff */
- bttv_gpio_inout(sub->core, ir->mask_keycode | ir->mask_keydown, 0);
- ir->sub = sub;
+ if (ir->rc5_gpio) {
+ u32 gpio;
+ /* enable remote irq */
+ bttv_gpio_inout(sub->core, (1 << 4), 1 << 4);
+ gpio = bttv_gpio_read(sub->core);
+ bttv_gpio_write(sub->core, gpio & ~(1 << 4));
+ bttv_gpio_write(sub->core, gpio | (1 << 4));
+ } else {
+ /* init hardware-specific stuff */
+ bttv_gpio_inout(sub->core, ir->mask_keycode | ir->mask_keydown, 0);
+ }
/* init input device */
snprintf(ir->name, sizeof(ir->name), "bttv IR (card=%d)",
@@ -346,6 +673,7 @@ static int ir_probe(struct device *dev)
snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0",
pci_name(sub->core->pci));
+ ir->sub = sub;
ir_input_init(input_dev, &ir->ir, ir_type, ir_codes);
input_dev->name = ir->name;
input_dev->phys = ir->phys;
@@ -366,11 +694,25 @@ static int ir_probe(struct device *dev)
ir->timer.function = ir_timer;
ir->timer.data = (unsigned long)ir;
schedule_work(&ir->work);
+ } else if (ir->rc5_gpio) {
+ /* set timer_end for code completion */
+ init_timer(&ir->timer_end);
+ ir->timer_end.function = ir_rc5_timer_end;
+ ir->timer_end.data = (unsigned long)ir;
+
+ init_timer(&ir->timer_keyup);
+ ir->timer_keyup.function = ir_rc5_timer_keyup;
+ ir->timer_keyup.data = (unsigned long)ir;
}
/* all done */
dev_set_drvdata(dev, ir);
input_register_device(ir->input);
+ printk(DEVNAME ": %s detected at %s\n",ir->name,ir->phys);
+
+ /* the remote isn't as bouncy as a keyboard */
+ ir->input->rep[REP_DELAY] = repeat_delay;
+ ir->input->rep[REP_PERIOD] = repeat_period;
return 0;
}
@@ -383,6 +725,15 @@ static int ir_remove(struct device *dev)
del_timer(&ir->timer);
flush_scheduled_work();
}
+ if (ir->rc5_gpio) {
+ u32 gpio;
+
+ del_timer(&ir->timer_end);
+ flush_scheduled_work();
+
+ gpio = bttv_gpio_read(ir->sub->core);
+ bttv_gpio_write(ir->sub->core, gpio & ~(1 << 4));
+ }
input_unregister_device(ir->input);
kfree(ir);
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index 9703d3d351f..801c736e932 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -8,6 +8,8 @@
* Christoph Bartelmus <lirc@bartelmus.de>
* modified for KNC ONE TV Station/Anubis Typhoon TView Tuner by
* Ulrich Mueller <ulrich.mueller42@web.de>
+ * modified for em2820 based USB TV tuners by
+ * Markus Rechberger <mrechberger@gmail.com>
*
* 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
@@ -37,10 +39,9 @@
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/workqueue.h>
-
#include <asm/semaphore.h>
-
#include <media/ir-common.h>
+#include <media/ir-kbd-i2c.h>
/* Mark Phalan <phalanm@o2.ie> */
static IR_KEYTAB_TYPE ir_codes_pv951[IR_KEYTAB_SIZE] = {
@@ -81,57 +82,6 @@ static IR_KEYTAB_TYPE ir_codes_pv951[IR_KEYTAB_SIZE] = {
[ 28 ] = KEY_MEDIA, /* PC/TV */
};
-static IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE] = {
- [ 0x3 ] = KEY_POWER,
- [ 0x6f ] = KEY_MUTE,
- [ 0x10 ] = KEY_BACKSPACE, /* Recall */
-
- [ 0x11 ] = KEY_KP0,
- [ 0x4 ] = KEY_KP1,
- [ 0x5 ] = KEY_KP2,
- [ 0x6 ] = KEY_KP3,
- [ 0x8 ] = KEY_KP4,
- [ 0x9 ] = KEY_KP5,
- [ 0xa ] = KEY_KP6,
- [ 0xc ] = KEY_KP7,
- [ 0xd ] = KEY_KP8,
- [ 0xe ] = KEY_KP9,
- [ 0x12 ] = KEY_KPDOT, /* 100+ */
-
- [ 0x7 ] = KEY_VOLUMEUP,
- [ 0xb ] = KEY_VOLUMEDOWN,
- [ 0x1a ] = KEY_KPPLUS,
- [ 0x18 ] = KEY_KPMINUS,
- [ 0x15 ] = KEY_UP,
- [ 0x1d ] = KEY_DOWN,
- [ 0xf ] = KEY_CHANNELUP,
- [ 0x13 ] = KEY_CHANNELDOWN,
- [ 0x48 ] = KEY_ZOOM,
-
- [ 0x1b ] = KEY_VIDEO, /* Video source */
- [ 0x49 ] = KEY_LANGUAGE, /* MTS Select */
- [ 0x19 ] = KEY_SEARCH, /* Auto Scan */
-
- [ 0x4b ] = KEY_RECORD,
- [ 0x46 ] = KEY_PLAY,
- [ 0x45 ] = KEY_PAUSE, /* Pause */
- [ 0x44 ] = KEY_STOP,
- [ 0x40 ] = KEY_FORWARD, /* Forward ? */
- [ 0x42 ] = KEY_REWIND, /* Backward ? */
-
-};
-
-struct IR {
- struct i2c_client c;
- struct input_dev *input;
- struct ir_input_state ir;
-
- struct work_struct work;
- struct timer_list timer;
- char phys[32];
- int (*get_key)(struct IR*, u32*, u32*);
-};
-
/* ----------------------------------------------------------------------- */
/* insmod parameters */
@@ -144,7 +94,7 @@ module_param(debug, int, 0644); /* debug level (0,1,2) */
/* ----------------------------------------------------------------------- */
-static int get_key_haup(struct IR *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
{
unsigned char buf[3];
int start, toggle, dev, code;
@@ -171,9 +121,9 @@ static int get_key_haup(struct IR *ir, u32 *ir_key, u32 *ir_raw)
return 1;
}
-static int get_key_pixelview(struct IR *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_pixelview(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
{
- unsigned char b;
+ unsigned char b;
/* poll IR chip */
if (1 != i2c_master_recv(&ir->c,&b,1)) {
@@ -185,9 +135,9 @@ static int get_key_pixelview(struct IR *ir, u32 *ir_key, u32 *ir_raw)
return 1;
}
-static int get_key_pv951(struct IR *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
{
- unsigned char b;
+ unsigned char b;
/* poll IR chip */
if (1 != i2c_master_recv(&ir->c,&b,1)) {
@@ -205,7 +155,7 @@ static int get_key_pv951(struct IR *ir, u32 *ir_key, u32 *ir_raw)
return 1;
}
-static int get_key_knc1(struct IR *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
{
unsigned char b;
@@ -216,15 +166,15 @@ static int get_key_knc1(struct IR *ir, u32 *ir_key, u32 *ir_raw)
}
/* it seems that 0xFE indicates that a button is still hold
- down, while 0xFF indicates that no button is hold
- down. 0xFE sequences are sometimes interrupted by 0xFF */
+ down, while 0xff indicates that no button is hold
+ down. 0xfe sequences are sometimes interrupted by 0xFF */
dprintk(2,"key %02x\n", b);
- if (b == 0xFF)
+ if (b == 0xff)
return 0;
- if (b == 0xFE)
+ if (b == 0xfe)
/* keep old data */
return 1;
@@ -233,31 +183,61 @@ static int get_key_knc1(struct IR *ir, u32 *ir_key, u32 *ir_raw)
return 1;
}
-static int get_key_purpletv(struct IR *ir, u32 *ir_key, u32 *ir_raw)
+/* The new pinnacle PCTV remote (with the colored buttons)
+ *
+ * Ricardo Cerqueira <v4l@cerqueira.org>
+ */
+
+int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
{
- unsigned char b;
+ unsigned char b[4];
+ unsigned int start = 0,parity = 0,code = 0;
/* poll IR chip */
- if (1 != i2c_master_recv(&ir->c,&b,1)) {
- dprintk(1,"read error\n");
+ if (4 != i2c_master_recv(&ir->c,b,4)) {
+ dprintk(2,"read error\n");
return -EIO;
}
- /* no button press */
- if (b==0)
+ for (start = 0; start<4; start++) {
+ if (b[start] == 0x80) {
+ code=b[(start+3)%4];
+ parity=b[(start+2)%4];
+ }
+ }
+
+ /* Empty Request */
+ if (parity==0)
return 0;
- /* repeating */
- if (b & 0x80)
- return 1;
+ /* Repeating... */
+ if (ir->old == parity)
+ return 0;
+
+
+ ir->old = parity;
+
+ /* Reduce code value to fit inside IR_KEYTAB_SIZE
+ *
+ * this is the only value that results in 42 unique
+ * codes < 128
+ */
+
+ code %= 0x88;
+
+ *ir_raw = code;
+ *ir_key = code;
+
+ dprintk(1,"Pinnacle PCTV key %02x\n", code);
- *ir_key = b;
- *ir_raw = b;
return 1;
}
+
+EXPORT_SYMBOL_GPL(get_key_pinnacle);
+
/* ----------------------------------------------------------------------- */
-static void ir_key_poll(struct IR *ir)
+static void ir_key_poll(struct IR_i2c *ir)
{
static u32 ir_key, ir_raw;
int rc;
@@ -278,13 +258,13 @@ static void ir_key_poll(struct IR *ir)
static void ir_timer(unsigned long data)
{
- struct IR *ir = (struct IR*)data;
+ struct IR_i2c *ir = (struct IR_i2c*)data;
schedule_work(&ir->work);
}
static void ir_work(void *data)
{
- struct IR *ir = data;
+ struct IR_i2c *ir = data;
ir_key_poll(ir);
mod_timer(&ir->timer, jiffies+HZ/10);
}
@@ -297,17 +277,17 @@ static int ir_detach(struct i2c_client *client);
static int ir_probe(struct i2c_adapter *adap);
static struct i2c_driver driver = {
- .name = "ir remote kbd driver",
- .id = I2C_DRIVERID_EXP3, /* FIXME */
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = ir_probe,
- .detach_client = ir_detach,
+ .name = "ir remote kbd driver",
+ .id = I2C_DRIVERID_EXP3, /* FIXME */
+ .flags = I2C_DF_NOTIFY,
+ .attach_adapter = ir_probe,
+ .detach_client = ir_detach,
};
static struct i2c_client client_template =
{
- .name = "unset",
- .driver = &driver
+ .name = "unset",
+ .driver = &driver
};
static int ir_attach(struct i2c_adapter *adap, int addr,
@@ -316,10 +296,10 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
IR_KEYTAB_TYPE *ir_codes = NULL;
char *name;
int ir_type;
- struct IR *ir;
+ struct IR_i2c *ir;
struct input_dev *input_dev;
- ir = kzalloc(sizeof(struct IR), GFP_KERNEL);
+ ir = kzalloc(sizeof(struct IR_i2c), GFP_KERNEL);
input_dev = input_allocate_device();
if (!ir || !input_dev) {
kfree(ir);
@@ -361,10 +341,10 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
ir_codes = ir_codes_empty;
break;
case 0x7a:
- name = "Purple TV";
- ir->get_key = get_key_purpletv;
+ case 0x47:
+ /* Handled by saa7134-input */
+ name = "SAA713x remote";
ir_type = IR_TYPE_OTHER;
- ir_codes = ir_codes_purpletv;
break;
default:
/* shouldn't happen */
@@ -373,9 +353,24 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
return -1;
}
- /* register i2c device */
- i2c_attach_client(&ir->c);
+ /* Sets name */
snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (%s)", name);
+ ir->ir_codes=ir_codes;
+
+ /* register i2c device
+ * At device register, IR codes may be changed to be
+ * board dependent.
+ */
+ i2c_attach_client(&ir->c);
+
+ /* If IR not supported or disabled, unregisters driver */
+ if (ir->get_key == NULL) {
+ i2c_detach_client(&ir->c);
+ kfree(ir);
+ return -1;
+ }
+
+ /* Phys addr can only be set after attaching (for ir->c.dev.bus_id) */
snprintf(ir->phys, sizeof(ir->phys), "%s/%s/ir0",
ir->c.adapter->dev.bus_id,
ir->c.dev.bus_id);
@@ -386,6 +381,7 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
input_dev->name = ir->c.name;
input_dev->phys = ir->phys;
+ /* register event device */
input_register_device(ir->input);
/* start polling via eventd */
@@ -400,7 +396,7 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
static int ir_detach(struct i2c_client *client)
{
- struct IR *ir = i2c_get_clientdata(client);
+ struct IR_i2c *ir = i2c_get_clientdata(client);
/* kill outstanding polls */
del_timer(&ir->timer);
@@ -428,9 +424,12 @@ static int ir_probe(struct i2c_adapter *adap)
*/
static const int probe_bttv[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1};
- static const int probe_saa7134[] = { 0x7a, -1 };
+ static const int probe_saa7134[] = { 0x7a, 0x47, -1 };
+ static const int probe_em28XX[] = { 0x30, 0x47, -1 };
const int *probe = NULL;
- struct i2c_client c; char buf; int i,rc;
+ struct i2c_client c;
+ unsigned char buf;
+ int i,rc;
switch (adap->id) {
case I2C_HW_B_BT848:
@@ -439,6 +438,9 @@ static int ir_probe(struct i2c_adapter *adap)
case I2C_HW_SAA7134:
probe = probe_saa7134;
break;
+ case I2C_HW_B_EM28XX:
+ probe = probe_em28XX;
+ break;
}
if (NULL == probe)
return 0;
@@ -447,11 +449,11 @@ static int ir_probe(struct i2c_adapter *adap)
c.adapter = adap;
for (i = 0; -1 != probe[i]; i++) {
c.addr = probe[i];
- rc = i2c_master_recv(&c,&buf,1);
+ rc = i2c_master_recv(&c,&buf,0);
dprintk(1,"probe 0x%02x @ %s: %s\n",
probe[i], adap->name,
- (1 == rc) ? "yes" : "no");
- if (1 == rc) {
+ (0 == rc) ? "yes" : "no");
+ if (0 == rc) {
ir_attach(adap,probe[i],0,0);
break;
}
diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c
index 262890cb20a..a23fb033898 100644
--- a/drivers/media/video/msp3400.c
+++ b/drivers/media/video/msp3400.c
@@ -54,9 +54,41 @@
#include <asm/pgtable.h>
#include <media/audiochip.h>
-#include <media/id.h>
#include "msp3400.h"
+#define msp3400_dbg(fmt, arg...) \
+ do { \
+ if (debug) \
+ printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); \
+ } while (0)
+
+/* Medium volume debug. */
+#define msp3400_dbg_mediumvol(fmt, arg...) \
+ do { \
+ if (debug >= 2) \
+ printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); \
+ } while (0)
+
+/* High volume debug. Use with care. */
+#define msp3400_dbg_highvol(fmt, arg...) \
+ do { \
+ if (debug >= 16) \
+ printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); \
+ } while (0)
+
+#define msp3400_err(fmt, arg...) do { \
+ printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+#define msp3400_warn(fmt, arg...) do { \
+ printk(KERN_WARNING "%s %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+#define msp3400_info(fmt, arg...) do { \
+ printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+
#define OPMODE_AUTO -1
#define OPMODE_MANUAL 0
#define OPMODE_SIMPLE 1 /* use short programming (>= msp3410 only) */
@@ -73,15 +105,26 @@ static int dolby = 0;
static int stereo_threshold = 0x190; /* a2 threshold for stereo/bilingual
(msp34xxg only) 0x00a0-0x03c0 */
+#define DFP_COUNT 0x41
+static const int bl_dfp[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x06, 0x08, 0x09, 0x0a,
+ 0x0b, 0x0d, 0x0e, 0x10
+};
+
+#define IS_MSP34XX_G(msp) ((msp)->opmode==2)
struct msp3400c {
int rev1,rev2;
int opmode;
+ int nicam;
int mode;
int norm;
+ int stereo;
int nicam_on;
int acb;
+ int in_scart;
+ int i2s_mode;
int main, second; /* sound carrier */
int input;
int source; /* see msp34xxg_set_source */
@@ -91,9 +134,12 @@ struct msp3400c {
int rxsubchans;
int muted;
- int volume, balance;
+ int left, right; /* volume */
int bass, treble;
+ /* shadow register set */
+ int dfp_regs[DFP_COUNT];
+
/* thread */
struct task_struct *kthread;
wait_queue_head_t wq;
@@ -101,6 +147,8 @@ struct msp3400c {
int watch_stereo:1;
};
+#define MIN(a,b) (((a)>(b))?(b):(a))
+#define MAX(a,b) (((a)>(b))?(a):(b))
#define HAVE_NICAM(msp) (((msp->rev2>>8) & 0xff) != 00)
#define HAVE_SIMPLE(msp) ((msp->rev1 & 0xff) >= 'D'-'@')
#define HAVE_SIMPLER(msp) ((msp->rev1 & 0xff) >= 'G'-'@')
@@ -110,9 +158,6 @@ struct msp3400c {
/* ---------------------------------------------------------------------- */
-#define dprintk if (debug >= 1) printk
-#define d2printk if (debug >= 2) printk
-
/* read-only */
module_param(opmode, int, 0444);
@@ -132,11 +177,6 @@ MODULE_PARM_DESC(standard, "Specify audio standard: 32 = NTSC, 64 = radio, Defau
MODULE_PARM_DESC(amsound, "Hardwire AM sound at 6.5Hz (France), FM can autoscan");
MODULE_PARM_DESC(dolby, "Activates Dolby processsing");
-
-MODULE_DESCRIPTION("device driver for msp34xx TV sound processor");
-MODULE_AUTHOR("Gerd Knorr");
-MODULE_LICENSE("Dual BSD/GPL"); /* FreeBSD uses this too */
-
/* ---------------------------------------------------------------------- */
#define I2C_MSP3400C 0x80
@@ -153,6 +193,10 @@ static unsigned short normal_i2c[] = {
};
I2C_CLIENT_INSMOD;
+MODULE_DESCRIPTION("device driver for msp34xx TV sound processor");
+MODULE_AUTHOR("Gerd Knorr");
+MODULE_LICENSE("GPL");
+
/* ----------------------------------------------------------------------- */
/* functions for talking to the MSP3400C Sound processor */
@@ -172,68 +216,73 @@ static int msp3400c_reset(struct i2c_client *client)
{ client->addr, I2C_M_RD, 2, read },
};
+ msp3400_dbg_highvol("msp3400c_reset\n");
if ( (1 != i2c_transfer(client->adapter,&reset[0],1)) ||
(1 != i2c_transfer(client->adapter,&reset[1],1)) ||
(2 != i2c_transfer(client->adapter,test,2)) ) {
- printk(KERN_ERR "msp3400: chip reset failed\n");
+ msp3400_err("chip reset failed\n");
return -1;
- }
+ }
return 0;
}
-static int
-msp3400c_read(struct i2c_client *client, int dev, int addr)
+static int msp3400c_read(struct i2c_client *client, int dev, int addr)
{
- int err;
+ int err,retval;
+
+ unsigned char write[3];
+ unsigned char read[2];
+ struct i2c_msg msgs[2] = {
+ { client->addr, 0, 3, write },
+ { client->addr, I2C_M_RD, 2, read }
+ };
- unsigned char write[3];
- unsigned char read[2];
- struct i2c_msg msgs[2] = {
- { client->addr, 0, 3, write },
- { client->addr, I2C_M_RD, 2, read }
- };
- write[0] = dev+1;
- write[1] = addr >> 8;
- write[2] = addr & 0xff;
+ write[0] = dev+1;
+ write[1] = addr >> 8;
+ write[2] = addr & 0xff;
for (err = 0; err < 3;) {
if (2 == i2c_transfer(client->adapter,msgs,2))
break;
err++;
- printk(KERN_WARNING "msp34xx: I/O error #%d (read 0x%02x/0x%02x)\n",
- err, dev, addr);
- msleep(10);
+ msp3400_warn("I/O error #%d (read 0x%02x/0x%02x)\n", err,
+ dev, addr);
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(msecs_to_jiffies(10));
}
if (3 == err) {
- printk(KERN_WARNING "msp34xx: giving up, reseting chip. Sound will go off, sorry folks :-|\n");
+ msp3400_warn("giving up, resetting chip. Sound will go off, sorry folks :-|\n");
msp3400c_reset(client);
return -1;
}
- return read[0] << 8 | read[1];
+ retval = read[0] << 8 | read[1];
+ msp3400_dbg_highvol("msp3400c_read(0x%x, 0x%x): 0x%x\n", dev, addr, retval);
+ return retval;
}
-static int
-msp3400c_write(struct i2c_client *client, int dev, int addr, int val)
+static int msp3400c_write(struct i2c_client *client, int dev, int addr, int val)
{
int err;
- unsigned char buffer[5];
+ unsigned char buffer[5];
- buffer[0] = dev;
- buffer[1] = addr >> 8;
- buffer[2] = addr & 0xff;
- buffer[3] = val >> 8;
- buffer[4] = val & 0xff;
+ buffer[0] = dev;
+ buffer[1] = addr >> 8;
+ buffer[2] = addr & 0xff;
+ buffer[3] = val >> 8;
+ buffer[4] = val & 0xff;
+ msp3400_dbg_highvol("msp3400c_write(0x%x, 0x%x, 0x%x)\n", dev, addr, val);
for (err = 0; err < 3;) {
if (5 == i2c_master_send(client, buffer, 5))
break;
err++;
- printk(KERN_WARNING "msp34xx: I/O error #%d (write 0x%02x/0x%02x)\n",
- err, dev, addr);
- msleep(10);
+ msp3400_warn("I/O error #%d (write 0x%02x/0x%02x)\n", err,
+ dev, addr);
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(msecs_to_jiffies(10));
}
if (3 == err) {
- printk(KERN_WARNING "msp34xx: giving up, reseting chip. Sound will go off, sorry folks :-|\n");
+ msp3400_warn("giving up, reseting chip. Sound will go off, sorry folks :-|\n");
msp3400c_reset(client);
return -1;
}
@@ -266,45 +315,47 @@ static struct MSP_INIT_DATA_DEM {
int dfp_src;
int dfp_matrix;
} msp_init_data[] = {
- /* AM (for carrier detect / msp3400) */
- { { 75, 19, 36, 35, 39, 40 }, { 75, 19, 36, 35, 39, 40 },
- MSP_CARRIER(5.5), MSP_CARRIER(5.5),
- 0x00d0, 0x0500, 0x0020, 0x3000},
-
- /* AM (for carrier detect / msp3410) */
- { { -1, -1, -8, 2, 59, 126 }, { -1, -1, -8, 2, 59, 126 },
- MSP_CARRIER(5.5), MSP_CARRIER(5.5),
- 0x00d0, 0x0100, 0x0020, 0x3000},
-
- /* FM Radio */
- { { -8, -8, 4, 6, 78, 107 }, { -8, -8, 4, 6, 78, 107 },
- MSP_CARRIER(10.7), MSP_CARRIER(10.7),
- 0x00d0, 0x0480, 0x0020, 0x3000 },
-
- /* Terrestial FM-mono + FM-stereo */
- { { 3, 18, 27, 48, 66, 72 }, { 3, 18, 27, 48, 66, 72 },
- MSP_CARRIER(5.5), MSP_CARRIER(5.5),
- 0x00d0, 0x0480, 0x0030, 0x3000},
-
- /* Sat FM-mono */
- { { 1, 9, 14, 24, 33, 37 }, { 3, 18, 27, 48, 66, 72 },
- MSP_CARRIER(6.5), MSP_CARRIER(6.5),
- 0x00c6, 0x0480, 0x0000, 0x3000},
-
- /* NICAM/FM -- B/G (5.5/5.85), D/K (6.5/5.85) */
- { { -2, -8, -10, 10, 50, 86 }, { 3, 18, 27, 48, 66, 72 },
- MSP_CARRIER(5.5), MSP_CARRIER(5.5),
- 0x00d0, 0x0040, 0x0120, 0x3000},
-
- /* NICAM/FM -- I (6.0/6.552) */
- { { 2, 4, -6, -4, 40, 94 }, { 3, 18, 27, 48, 66, 72 },
- MSP_CARRIER(6.0), MSP_CARRIER(6.0),
- 0x00d0, 0x0040, 0x0120, 0x3000},
-
- /* NICAM/AM -- L (6.5/5.85) */
- { { -2, -8, -10, 10, 50, 86 }, { -4, -12, -9, 23, 79, 126 },
- MSP_CARRIER(6.5), MSP_CARRIER(6.5),
- 0x00c6, 0x0140, 0x0120, 0x7c03},
+ { /* AM (for carrier detect / msp3400) */
+ {75, 19, 36, 35, 39, 40},
+ {75, 19, 36, 35, 39, 40},
+ MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+ 0x00d0, 0x0500, 0x0020, 0x3000
+ },{ /* AM (for carrier detect / msp3410) */
+ {-1, -1, -8, 2, 59, 126},
+ {-1, -1, -8, 2, 59, 126},
+ MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+ 0x00d0, 0x0100, 0x0020, 0x3000
+ },{ /* FM Radio */
+ {-8, -8, 4, 6, 78, 107},
+ {-8, -8, 4, 6, 78, 107},
+ MSP_CARRIER(10.7), MSP_CARRIER(10.7),
+ 0x00d0, 0x0480, 0x0020, 0x3000
+ },{ /* Terrestial FM-mono + FM-stereo */
+ {3, 18, 27, 48, 66, 72},
+ {3, 18, 27, 48, 66, 72},
+ MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+ 0x00d0, 0x0480, 0x0030, 0x3000
+ },{ /* Sat FM-mono */
+ { 1, 9, 14, 24, 33, 37},
+ { 3, 18, 27, 48, 66, 72},
+ MSP_CARRIER(6.5), MSP_CARRIER(6.5),
+ 0x00c6, 0x0480, 0x0000, 0x3000
+ },{ /* NICAM/FM -- B/G (5.5/5.85), D/K (6.5/5.85) */
+ {-2, -8, -10, 10, 50, 86},
+ {3, 18, 27, 48, 66, 72},
+ MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+ 0x00d0, 0x0040, 0x0120, 0x3000
+ },{ /* NICAM/FM -- I (6.0/6.552) */
+ {2, 4, -6, -4, 40, 94},
+ {3, 18, 27, 48, 66, 72},
+ MSP_CARRIER(6.0), MSP_CARRIER(6.0),
+ 0x00d0, 0x0040, 0x0120, 0x3000
+ },{ /* NICAM/AM -- L (6.5/5.85) */
+ {-2, -8, -10, 10, 50, 86},
+ {-4, -12, -9, 23, 79, 126},
+ MSP_CARRIER(6.5), MSP_CARRIER(6.5),
+ 0x00c6, 0x0140, 0x0120, 0x7c03
+ },
};
struct CARRIER_DETECT {
@@ -338,32 +389,68 @@ static struct CARRIER_DETECT carrier_detect_65[] = {
#define CARRIER_COUNT(x) (sizeof(x)/sizeof(struct CARRIER_DETECT))
-/* ----------------------------------------------------------------------- */
+/* ----------------------------------------------------------------------- *
+ * bits 9 8 5 - SCART DSP input Select:
+ * 0 0 0 - SCART 1 to DSP input (reset position)
+ * 0 1 0 - MONO to DSP input
+ * 1 0 0 - SCART 2 to DSP input
+ * 1 1 1 - Mute DSP input
+ *
+ * bits 11 10 6 - SCART 1 Output Select:
+ * 0 0 0 - undefined (reset position)
+ * 0 1 0 - SCART 2 Input to SCART 1 Output (for devices with 2 SCARTS)
+ * 1 0 0 - MONO input to SCART 1 Output
+ * 1 1 0 - SCART 1 DA to SCART 1 Output
+ * 0 0 1 - SCART 2 DA to SCART 1 Output
+ * 0 1 1 - SCART 1 Input to SCART 1 Output
+ * 1 1 1 - Mute SCART 1 Output
+ *
+ * bits 13 12 7 - SCART 2 Output Select (for devices with 2 Output SCART):
+ * 0 0 0 - SCART 1 DA to SCART 2 Output (reset position)
+ * 0 1 0 - SCART 1 Input to SCART 2 Output
+ * 1 0 0 - MONO input to SCART 2 Output
+ * 0 0 1 - SCART 2 DA to SCART 2 Output
+ * 0 1 1 - SCART 2 Input to SCART 2 Output
+ * 1 1 0 - Mute SCART 2 Output
+ *
+ * Bits 4 to 0 should be zero.
+ * ----------------------------------------------------------------------- */
static int scarts[3][9] = {
- /* MASK IN1 IN2 IN1_DA IN2_DA IN3 IN4 MONO MUTE */
- { 0x0320, 0x0000, 0x0200, -1, -1, 0x0300, 0x0020, 0x0100, 0x0320 },
- { 0x0c40, 0x0440, 0x0400, 0x0c00, 0x0040, 0x0000, 0x0840, 0x0800, 0x0c40 },
- { 0x3080, 0x1000, 0x1080, 0x0000, 0x0080, 0x2080, 0x3080, 0x2000, 0x3000 },
+ /* MASK IN1 IN2 IN1_DA IN2_DA IN3 IN4 MONO MUTE */
+ /* SCART DSP Input select */
+ { 0x0320, 0x0000, 0x0200, -1, -1, 0x0300, 0x0020, 0x0100, 0x0320 },
+ /* SCART1 Output select */
+ { 0x0c40, 0x0440, 0x0400, 0x0c00, 0x0040, 0x0000, 0x0840, 0x0800, 0x0c40 },
+ /* SCART2 Output select */
+ { 0x3080, 0x1000, 0x1080, 0x0000, 0x0080, 0x2080, 0x3080, 0x2000, 0x3000 },
};
static char *scart_names[] = {
- "mask", "in1", "in2", "in1 da", "in2 da", "in3", "in4", "mono", "mute"
+ "mask", "in1", "in2", "in1 da", "in2 da", "in3", "in4", "mono", "mute"
};
-static void
-msp3400c_set_scart(struct i2c_client *client, int in, int out)
+static void msp3400c_set_scart(struct i2c_client *client, int in, int out)
{
struct msp3400c *msp = i2c_get_clientdata(client);
- if (-1 == scarts[out][in])
- return;
+ msp->in_scart=in;
+
+ if (in >= 1 && in <= 8 && out >= 0 && out <= 2) {
+ if (-1 == scarts[out][in])
+ return;
- dprintk(KERN_DEBUG
- "msp34xx: scart switch: %s => %d\n",scart_names[in],out);
- msp->acb &= ~scarts[out][SCART_MASK];
- msp->acb |= scarts[out][in];
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x0013, msp->acb);
+ msp->acb &= ~scarts[out][SCART_MASK];
+ msp->acb |= scarts[out][in];
+ } else
+ msp->acb = 0xf60; /* Mute Input and SCART 1 Output */
+
+ msp3400_dbg("scart switch: %s => %d (ACB=0x%04x)\n",
+ scart_names[in], out, msp->acb);
+ msp3400c_write(client,I2C_MSP3400C_DFP, 0x13, msp->acb);
+
+ /* Sets I2S speed 0 = 1.024 Mbps, 1 = 2.048 Mbps */
+ msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode);
}
/* ------------------------------------------------------------------------ */
@@ -378,33 +465,34 @@ static void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2)
}
static void msp3400c_setvolume(struct i2c_client *client,
- int muted, int volume, int balance)
-{
- int val = 0, bal = 0;
+ int muted, int left, int right)
+ {
+ int vol = 0, val = 0, balance = 0;
if (!muted) {
/* 0x7f instead if 0x73 here has sound quality issues,
* probably due to overmodulation + clipping ... */
- val = (volume * 0x73 / 65535) << 8;
+ vol = (left > right) ? left : right;
+ val = (vol * 0x73 / 65535) << 8;
}
- if (val) {
- bal = (balance / 256) - 128;
+ if (vol > 0) {
+ balance = ((right - left) * 127) / vol;
}
- dprintk(KERN_DEBUG
- "msp34xx: setvolume: mute=%s %d:%d v=0x%02x b=0x%02x\n",
- muted ? "on" : "off", volume, balance, val>>8, bal);
+
+ msp3400_dbg("setvolume: mute=%s %d:%d v=0x%02x b=0x%02x\n",
+ muted ? "on" : "off", left, right, val >> 8, balance);
msp3400c_write(client,I2C_MSP3400C_DFP, 0x0000, val); /* loudspeaker */
msp3400c_write(client,I2C_MSP3400C_DFP, 0x0006, val); /* headphones */
msp3400c_write(client,I2C_MSP3400C_DFP, 0x0007,
- muted ? 0x01 : (val | 0x01));
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x0001, bal << 8);
+ muted ? 0x1 : (val | 0x1));
+ msp3400c_write(client, I2C_MSP3400C_DFP, 0x0001, balance << 8);
}
static void msp3400c_setbass(struct i2c_client *client, int bass)
{
int val = ((bass-32768) * 0x60 / 65535) << 8;
- dprintk(KERN_DEBUG "msp34xx: setbass: %d 0x%02x\n",bass, val>>8);
+ msp3400_dbg("setbass: %d 0x%02x\n", bass, val >> 8);
msp3400c_write(client,I2C_MSP3400C_DFP, 0x0002, val); /* loudspeaker */
}
@@ -412,7 +500,7 @@ static void msp3400c_settreble(struct i2c_client *client, int treble)
{
int val = ((treble-32768) * 0x60 / 65535) << 8;
- dprintk(KERN_DEBUG "msp34xx: settreble: %d 0x%02x\n",treble, val>>8);
+ msp3400_dbg("settreble: %d 0x%02x\n",treble, val>>8);
msp3400c_write(client,I2C_MSP3400C_DFP, 0x0003, val); /* loudspeaker */
}
@@ -421,7 +509,7 @@ static void msp3400c_setmode(struct i2c_client *client, int type)
struct msp3400c *msp = i2c_get_clientdata(client);
int i;
- dprintk(KERN_DEBUG "msp3400: setmode: %d\n",type);
+ msp3400_dbg("setmode: %d\n",type);
msp->mode = type;
msp->audmode = V4L2_TUNER_MODE_MONO;
msp->rxsubchans = V4L2_TUNER_SUB_MONO;
@@ -474,7 +562,8 @@ static void msp3400c_setmode(struct i2c_client *client, int type)
}
}
-static int best_audio_mode(int rxsubchans)
+/* given a bitmask of VIDEO_SOUND_XXX returns the "best" in the bitmask */
+static int best_video_sound(int rxsubchans)
{
if (rxsubchans & V4L2_TUNER_SUB_STEREO)
return V4L2_TUNER_MODE_STEREO;
@@ -486,31 +575,31 @@ static int best_audio_mode(int rxsubchans)
}
/* turn on/off nicam + stereo */
-static void msp3400c_set_audmode(struct i2c_client *client, int audmode)
+static void msp3400c_setstereo(struct i2c_client *client, int mode)
{
- static char *strmode[16] = {
-#if __GNUC__ >= 3
- [ 0 ... 15 ] = "invalid",
-#endif
- [ V4L2_TUNER_MODE_MONO ] = "mono",
- [ V4L2_TUNER_MODE_STEREO ] = "stereo",
- [ V4L2_TUNER_MODE_LANG1 ] = "lang1",
- [ V4L2_TUNER_MODE_LANG2 ] = "lang2",
+ static char *strmode[] = { "0", "mono", "stereo", "3",
+ "lang1", "5", "6", "7", "lang2"
};
struct msp3400c *msp = i2c_get_clientdata(client);
- int nicam=0; /* channel source: FM/AM or nicam */
- int src=0;
+ int nicam = 0; /* channel source: FM/AM or nicam */
+ int src = 0;
- BUG_ON(msp->opmode == OPMODE_SIMPLER);
- msp->audmode = audmode;
+ if (IS_MSP34XX_G(msp)) {
+ /* this method would break everything, let's make sure
+ * it's never called
+ */
+ msp3400_dbg
+ ("DEBUG WARNING setstereo called with mode=%d instead of set_source (ignored)\n",
+ mode);
+ return;
+ }
/* switch demodulator */
switch (msp->mode) {
case MSP_MODE_FM_TERRA:
- dprintk(KERN_DEBUG "msp3400: FM setstereo: %s\n",
- strmode[audmode]);
+ msp3400_dbg("FM setstereo: %s\n", strmode[mode]);
msp3400c_setcarrier(client,msp->second,msp->main);
- switch (audmode) {
+ switch (mode) {
case V4L2_TUNER_MODE_STEREO:
msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, 0x3001);
break;
@@ -522,9 +611,8 @@ static void msp3400c_set_audmode(struct i2c_client *client, int audmode)
}
break;
case MSP_MODE_FM_SAT:
- dprintk(KERN_DEBUG "msp3400: SAT setstereo: %s\n",
- strmode[audmode]);
- switch (audmode) {
+ msp3400_dbg("SAT setstereo: %s\n", strmode[mode]);
+ switch (mode) {
case V4L2_TUNER_MODE_MONO:
msp3400c_setcarrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5));
break;
@@ -542,39 +630,35 @@ static void msp3400c_set_audmode(struct i2c_client *client, int audmode)
case MSP_MODE_FM_NICAM1:
case MSP_MODE_FM_NICAM2:
case MSP_MODE_AM_NICAM:
- dprintk(KERN_DEBUG "msp3400: NICAM setstereo: %s\n",
- strmode[audmode]);
+ msp3400_dbg("NICAM setstereo: %s\n",strmode[mode]);
msp3400c_setcarrier(client,msp->second,msp->main);
if (msp->nicam_on)
nicam=0x0100;
break;
case MSP_MODE_BTSC:
- dprintk(KERN_DEBUG "msp3400: BTSC setstereo: %s\n",
- strmode[audmode]);
+ msp3400_dbg("BTSC setstereo: %s\n",strmode[mode]);
nicam=0x0300;
break;
case MSP_MODE_EXTERN:
- dprintk(KERN_DEBUG "msp3400: extern setstereo: %s\n",
- strmode[audmode]);
+ msp3400_dbg("extern setstereo: %s\n",strmode[mode]);
nicam = 0x0200;
break;
case MSP_MODE_FM_RADIO:
- dprintk(KERN_DEBUG "msp3400: FM-Radio setstereo: %s\n",
- strmode[audmode]);
+ msp3400_dbg("FM-Radio setstereo: %s\n",strmode[mode]);
break;
default:
- dprintk(KERN_DEBUG "msp3400: mono setstereo\n");
+ msp3400_dbg("mono setstereo\n");
return;
}
/* switch audio */
- switch (audmode) {
+ switch (best_video_sound(mode)) {
case V4L2_TUNER_MODE_STEREO:
src = 0x0020 | nicam;
break;
case V4L2_TUNER_MODE_MONO:
if (msp->mode == MSP_MODE_AM_NICAM) {
- dprintk("msp3400: switching to AM mono\n");
+ msp3400_dbg("switching to AM mono\n");
/* AM mono decoding is handled by tuner, not MSP chip */
/* SCART switching control register */
msp3400c_set_scart(client,SCART_MONO,0);
@@ -588,8 +672,7 @@ static void msp3400c_set_audmode(struct i2c_client *client, int audmode)
src = 0x0010 | nicam;
break;
}
- dprintk(KERN_DEBUG
- "msp3400: setstereo final source/matrix = 0x%x\n", src);
+ msp3400_dbg("setstereo final source/matrix = 0x%x\n", src);
if (dolby) {
msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,0x0520);
@@ -605,29 +688,55 @@ static void msp3400c_set_audmode(struct i2c_client *client, int audmode)
}
static void
-msp3400c_print_mode(struct msp3400c *msp)
+msp3400c_print_mode(struct i2c_client *client)
{
+ struct msp3400c *msp = i2c_get_clientdata(client);
+
if (msp->main == msp->second) {
- printk(KERN_DEBUG "msp3400: mono sound carrier: %d.%03d MHz\n",
+ msp3400_dbg("mono sound carrier: %d.%03d MHz\n",
msp->main/910000,(msp->main/910)%1000);
} else {
- printk(KERN_DEBUG "msp3400: main sound carrier: %d.%03d MHz\n",
+ msp3400_dbg("main sound carrier: %d.%03d MHz\n",
msp->main/910000,(msp->main/910)%1000);
}
- if (msp->mode == MSP_MODE_FM_NICAM1 ||
- msp->mode == MSP_MODE_FM_NICAM2)
- printk(KERN_DEBUG "msp3400: NICAM/FM carrier : %d.%03d MHz\n",
+ if (msp->mode == MSP_MODE_FM_NICAM1 || msp->mode == MSP_MODE_FM_NICAM2)
+ msp3400_dbg("NICAM/FM carrier : %d.%03d MHz\n",
msp->second/910000,(msp->second/910)%1000);
if (msp->mode == MSP_MODE_AM_NICAM)
- printk(KERN_DEBUG "msp3400: NICAM/AM carrier : %d.%03d MHz\n",
+ msp3400_dbg("NICAM/AM carrier : %d.%03d MHz\n",
msp->second/910000,(msp->second/910)%1000);
if (msp->mode == MSP_MODE_FM_TERRA &&
msp->main != msp->second) {
- printk(KERN_DEBUG "msp3400: FM-stereo carrier : %d.%03d MHz\n",
+ msp3400_dbg("FM-stereo carrier : %d.%03d MHz\n",
msp->second/910000,(msp->second/910)%1000);
}
}
+#define MSP3400_MAX 4
+static struct i2c_client *msps[MSP3400_MAX];
+static void msp3400c_restore_dfp(struct i2c_client *client)
+{
+ struct msp3400c *msp = i2c_get_clientdata(client);
+ int i;
+
+ for (i = 0; i < DFP_COUNT; i++) {
+ if (-1 == msp->dfp_regs[i])
+ continue;
+ msp3400c_write(client, I2C_MSP3400C_DFP, i, msp->dfp_regs[i]);
+ }
+}
+
+/* if the dfp_regs is set, set what's in there. Otherwise, set the default value */
+static int msp3400c_write_dfp_with_default(struct i2c_client *client,
+ int addr, int default_value)
+{
+ struct msp3400c *msp = i2c_get_clientdata(client);
+ int value = default_value;
+ if (addr < DFP_COUNT && -1 != msp->dfp_regs[addr])
+ value = msp->dfp_regs[addr];
+ return msp3400c_write(client, I2C_MSP3400C_DFP, addr, value);
+}
+
/* ----------------------------------------------------------------------- */
struct REGISTER_DUMP {
@@ -635,8 +744,15 @@ struct REGISTER_DUMP {
char *name;
};
-static int
-autodetect_stereo(struct i2c_client *client)
+struct REGISTER_DUMP d1[] = {
+ {0x007e, "autodetect"},
+ {0x0023, "C_AD_BITS "},
+ {0x0038, "ADD_BITS "},
+ {0x003e, "CIB_BITS "},
+ {0x0057, "ERROR_RATE"},
+};
+
+static int autodetect_stereo(struct i2c_client *client)
{
struct msp3400c *msp = i2c_get_clientdata(client);
int val;
@@ -649,8 +765,7 @@ autodetect_stereo(struct i2c_client *client)
val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x18);
if (val > 32767)
val -= 65536;
- dprintk(KERN_DEBUG
- "msp34xx: stereo detect register: %d\n",val);
+ msp3400_dbg("stereo detect register: %d\n",val);
if (val > 4096) {
rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
} else if (val < -4096) {
@@ -664,8 +779,7 @@ autodetect_stereo(struct i2c_client *client)
case MSP_MODE_FM_NICAM2:
case MSP_MODE_AM_NICAM:
val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x23);
- dprintk(KERN_DEBUG
- "msp34xx: nicam sync=%d, mode=%d\n",
+ msp3400_dbg("nicam sync=%d, mode=%d\n",
val & 1, (val & 0x1e) >> 1);
if (val & 1) {
@@ -698,8 +812,7 @@ autodetect_stereo(struct i2c_client *client)
break;
case MSP_MODE_BTSC:
val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x200);
- dprintk(KERN_DEBUG
- "msp3410: status=0x%x (pri=%s, sec=%s, %s%s%s)\n",
+ msp3400_dbg("status=0x%x (pri=%s, sec=%s, %s%s%s)\n",
val,
(val & 0x0002) ? "no" : "yes",
(val & 0x0004) ? "no" : "yes",
@@ -713,13 +826,13 @@ autodetect_stereo(struct i2c_client *client)
}
if (rxsubchans != msp->rxsubchans) {
update = 1;
- dprintk(KERN_DEBUG "msp34xx: watch: rxsubchans %d => %d\n",
+ msp3400_dbg("watch: rxsubchans %d => %d\n",
msp->rxsubchans,rxsubchans);
msp->rxsubchans = rxsubchans;
}
if (newnicam != msp->nicam_on) {
update = 1;
- dprintk(KERN_DEBUG "msp34xx: watch: nicam %d => %d\n",
+ msp3400_dbg("watch: nicam %d => %d\n",
msp->nicam_on,newnicam);
msp->nicam_on = newnicam;
}
@@ -741,8 +854,8 @@ static int msp34xx_sleep(struct msp3400c *msp, int timeout)
set_current_state(TASK_INTERRUPTIBLE);
schedule();
} else {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(msecs_to_jiffies(timeout));
+ schedule_timeout_interruptible
+ (msecs_to_jiffies(timeout));
}
}
@@ -756,8 +869,15 @@ static void watch_stereo(struct i2c_client *client)
{
struct msp3400c *msp = i2c_get_clientdata(client);
- if (autodetect_stereo(client))
- msp3400c_set_audmode(client,best_audio_mode(msp->rxsubchans));
+ if (autodetect_stereo(client)) {
+ if (msp->stereo & V4L2_TUNER_MODE_STEREO)
+ msp3400c_setstereo(client, V4L2_TUNER_MODE_STEREO);
+ else if (msp->stereo & VIDEO_SOUND_LANG1)
+ msp3400c_setstereo(client, V4L2_TUNER_MODE_LANG1);
+ else
+ msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
+ }
+
if (once)
msp->watch_stereo = 0;
}
@@ -769,14 +889,14 @@ static int msp3400c_thread(void *data)
struct CARRIER_DETECT *cd;
int count, max1,max2,val1,val2, val,this;
- printk("msp3400: kthread started\n");
+ msp3400_info("msp3400 daemon started\n");
for (;;) {
- d2printk("msp3400: thread: sleep\n");
+ msp3400_dbg_mediumvol("msp3400 thread: sleep\n");
msp34xx_sleep(msp,-1);
- d2printk("msp3400: thread: wakeup\n");
+ msp3400_dbg_mediumvol("msp3400 thread: wakeup\n");
restart:
- dprintk("msp3410: thread: restart scan\n");
+ msp3400_dbg("thread: restart scan\n");
msp->restart = 0;
if (kthread_should_stop())
break;
@@ -784,9 +904,8 @@ static int msp3400c_thread(void *data)
if (VIDEO_MODE_RADIO == msp->norm ||
MSP_MODE_EXTERN == msp->mode) {
/* no carrier scan, just unmute */
- printk("msp3400: thread: no carrier scan\n");
- msp3400c_setvolume(client, msp->muted,
- msp->volume, msp->balance);
+ msp3400_info("thread: no carrier scan\n");
+ msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
continue;
}
@@ -802,13 +921,14 @@ static int msp3400c_thread(void *data)
goto restart;
/* carrier detect pass #1 -- main carrier */
- cd = carrier_detect_main; count = CARRIER_COUNT(carrier_detect_main);
+ cd = carrier_detect_main;
+ count = CARRIER_COUNT(carrier_detect_main);
if (amsound && (msp->norm == VIDEO_MODE_SECAM)) {
/* autodetect doesn't work well with AM ... */
max1 = 3;
count = 0;
- dprintk("msp3400: AM sound override\n");
+ msp3400_dbg("AM sound override\n");
}
for (this = 0; this < count; this++) {
@@ -820,7 +940,7 @@ static int msp3400c_thread(void *data)
val -= 65536;
if (val1 < val)
val1 = val, max1 = this;
- dprintk("msp3400: carrier1 val: %5d / %s\n", val,cd[this].name);
+ msp3400_dbg("carrier1 val: %5d / %s\n", val,cd[this].name);
}
/* carrier detect pass #2 -- second (stereo) carrier */
@@ -836,13 +956,16 @@ static int msp3400c_thread(void *data)
case 0: /* 4.5 */
case 2: /* 6.0 */
default:
- cd = NULL; count = 0;
+ cd = NULL;
+ count = 0;
break;
}
if (amsound && (msp->norm == VIDEO_MODE_SECAM)) {
/* autodetect doesn't work well with AM ... */
- cd = NULL; count = 0; max2 = 0;
+ cd = NULL;
+ count = 0;
+ max2 = 0;
}
for (this = 0; this < count; this++) {
msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo);
@@ -853,7 +976,7 @@ static int msp3400c_thread(void *data)
val -= 65536;
if (val2 < val)
val2 = val, max2 = this;
- dprintk("msp3400: carrier2 val: %5d / %s\n", val,cd[this].name);
+ msp3400_dbg("carrier2 val: %5d / %s\n", val,cd[this].name);
}
/* programm the msp3400 according to the results */
@@ -865,7 +988,7 @@ static int msp3400c_thread(void *data)
msp->second = carrier_detect_55[max2].cdo;
msp3400c_setmode(client, MSP_MODE_FM_TERRA);
msp->nicam_on = 0;
- msp3400c_set_audmode(client, V4L2_TUNER_MODE_MONO);
+ msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
msp->watch_stereo = 1;
} else if (max2 == 1 && HAVE_NICAM(msp)) {
/* B/G NICAM */
@@ -892,7 +1015,7 @@ static int msp3400c_thread(void *data)
msp->second = carrier_detect_65[max2].cdo;
msp3400c_setmode(client, MSP_MODE_FM_TERRA);
msp->nicam_on = 0;
- msp3400c_set_audmode(client, V4L2_TUNER_MODE_MONO);
+ msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
msp->watch_stereo = 1;
} else if (max2 == 0 &&
msp->norm == VIDEO_MODE_SECAM) {
@@ -900,7 +1023,7 @@ static int msp3400c_thread(void *data)
msp->second = carrier_detect_65[max2].cdo;
msp3400c_setmode(client, MSP_MODE_AM_NICAM);
msp->nicam_on = 0;
- msp3400c_set_audmode(client, V4L2_TUNER_MODE_MONO);
+ msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
msp3400c_setcarrier(client, msp->second, msp->main);
/* volume prescale for SCART (AM mono input) */
msp3400c_write(client,I2C_MSP3400C_DFP, 0x000d, 0x1900);
@@ -924,15 +1047,16 @@ static int msp3400c_thread(void *data)
msp->nicam_on = 0;
msp3400c_setcarrier(client, msp->second, msp->main);
msp->rxsubchans = V4L2_TUNER_SUB_MONO;
- msp3400c_set_audmode(client, V4L2_TUNER_MODE_MONO);
+ msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
break;
}
/* unmute */
- msp3400c_setvolume(client, msp->muted,
- msp->volume, msp->balance);
+ msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
+ msp3400c_restore_dfp(client);
+
if (debug)
- msp3400c_print_mode(msp);
+ msp3400c_print_mode(client);
/* monitor tv audio mode */
while (msp->watch_stereo) {
@@ -941,7 +1065,7 @@ static int msp3400c_thread(void *data)
watch_stereo(client);
}
}
- dprintk(KERN_DEBUG "msp3400: thread: exit\n");
+ msp3400_dbg("thread: exit\n");
return 0;
}
@@ -985,10 +1109,12 @@ static inline const char *msp34xx_standard_mode_name(int mode)
return "unknown";
}
-static int msp34xx_modus(int norm)
+static int msp34xx_modus(struct i2c_client *client, int norm)
{
switch (norm) {
case VIDEO_MODE_PAL:
+ msp3400_dbg("video mode selected to PAL\n");
+
#if 1
/* experimental: not sure this works with all chip versions */
return 0x7003;
@@ -997,12 +1123,16 @@ static int msp34xx_modus(int norm)
return 0x1003;
#endif
case VIDEO_MODE_NTSC: /* BTSC */
+ msp3400_dbg("video mode selected to NTSC\n");
return 0x2003;
case VIDEO_MODE_SECAM:
+ msp3400_dbg("video mode selected to SECAM\n");
return 0x0003;
case VIDEO_MODE_RADIO:
+ msp3400_dbg("video mode selected to Radio\n");
return 0x0003;
case VIDEO_MODE_AUTO:
+ msp3400_dbg("video mode selected to Auto\n");
return 0x2003;
default:
return 0x0003;
@@ -1031,23 +1161,22 @@ static int msp3410d_thread(void *data)
struct msp3400c *msp = i2c_get_clientdata(client);
int mode,val,i,std;
- printk("msp3410: daemon started\n");
+ msp3400_info("msp3410 daemon started\n");
for (;;) {
- d2printk(KERN_DEBUG "msp3410: thread: sleep\n");
+ msp3400_dbg_mediumvol("msp3410 thread: sleep\n");
msp34xx_sleep(msp,-1);
- d2printk(KERN_DEBUG "msp3410: thread: wakeup\n");
+ msp3400_dbg_mediumvol("msp3410 thread: wakeup\n");
restart:
- dprintk("msp3410: thread: restart scan\n");
+ msp3400_dbg("thread: restart scan\n");
msp->restart = 0;
if (kthread_should_stop())
break;
if (msp->mode == MSP_MODE_EXTERN) {
/* no carrier scan needed, just unmute */
- dprintk(KERN_DEBUG "msp3410: thread: no carrier scan\n");
- msp3400c_setvolume(client, msp->muted,
- msp->volume, msp->balance);
+ msp3400_dbg("thread: no carrier scan\n");
+ msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
continue;
}
@@ -1059,14 +1188,14 @@ static int msp3410d_thread(void *data)
goto restart;
/* start autodetect */
- mode = msp34xx_modus(msp->norm);
+ mode = msp34xx_modus(client, msp->norm);
std = msp34xx_standard(msp->norm);
msp3400c_write(client, I2C_MSP3400C_DEM, 0x30, mode);
msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, std);
msp->watch_stereo = 0;
if (debug)
- printk(KERN_DEBUG "msp3410: setting mode: %s (0x%04x)\n",
+ msp3400_dbg("setting mode: %s (0x%04x)\n",
msp34xx_standard_mode_name(std) ,std);
if (std != 1) {
@@ -1082,13 +1211,13 @@ static int msp3410d_thread(void *data)
val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x7e);
if (val < 0x07ff)
break;
- dprintk(KERN_DEBUG "msp3410: detection still in progress\n");
+ msp3400_dbg("detection still in progress\n");
}
}
for (i = 0; modelist[i].name != NULL; i++)
if (modelist[i].retval == val)
break;
- dprintk(KERN_DEBUG "msp3410: current mode: %s (0x%04x)\n",
+ msp3400_dbg("current mode: %s (0x%04x)\n",
modelist[i].name ? modelist[i].name : "unknown",
val);
msp->main = modelist[i].main;
@@ -1096,7 +1225,7 @@ static int msp3410d_thread(void *data)
if (amsound && (msp->norm == VIDEO_MODE_SECAM) && (val != 0x0009)) {
/* autodetection has failed, let backup */
- dprintk(KERN_DEBUG "msp3410: autodetection failed,"
+ msp3400_dbg("autodetection failed,"
" switching to backup mode: %s (0x%04x)\n",
modelist[8].name ? modelist[8].name : "unknown",val);
val = 0x0009;
@@ -1120,13 +1249,13 @@ static int msp3410d_thread(void *data)
msp->rxsubchans = V4L2_TUNER_SUB_STEREO;
msp->nicam_on = 1;
msp->watch_stereo = 1;
- msp3400c_set_audmode(client,V4L2_TUNER_MODE_STEREO);
+ msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO);
break;
case 0x0009:
msp->mode = MSP_MODE_AM_NICAM;
msp->rxsubchans = V4L2_TUNER_SUB_MONO;
msp->nicam_on = 1;
- msp3400c_set_audmode(client,V4L2_TUNER_MODE_MONO);
+ msp3400c_setstereo(client,V4L2_TUNER_MODE_MONO);
msp->watch_stereo = 1;
break;
case 0x0020: /* BTSC */
@@ -1135,7 +1264,7 @@ static int msp3410d_thread(void *data)
msp->rxsubchans = V4L2_TUNER_SUB_STEREO;
msp->nicam_on = 0;
msp->watch_stereo = 1;
- msp3400c_set_audmode(client,V4L2_TUNER_MODE_STEREO);
+ msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO);
break;
case 0x0040: /* FM radio */
msp->mode = MSP_MODE_FM_RADIO;
@@ -1169,9 +1298,10 @@ static int msp3410d_thread(void *data)
/* unmute, restore misc registers */
msp3400c_setbass(client, msp->bass);
msp3400c_settreble(client, msp->treble);
- msp3400c_setvolume(client, msp->muted,
- msp->volume, msp->balance);
- msp3400c_write(client, I2C_MSP3400C_DFP, 0x0013, msp->acb);
+ msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
+ msp3400c_write(client, I2C_MSP3400C_DFP, 0x13, msp->acb);
+ msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode);
+ msp3400c_restore_dfp(client);
/* monitor tv audio mode */
while (msp->watch_stereo) {
@@ -1180,7 +1310,7 @@ static int msp3410d_thread(void *data)
watch_stereo(client);
}
}
- dprintk(KERN_DEBUG "msp3410: thread: exit\n");
+ msp3400_dbg("thread: exit\n");
return 0;
}
@@ -1195,7 +1325,7 @@ static void msp34xxg_set_source(struct i2c_client *client, int source);
/* (re-)initialize the msp34xxg, according to the current norm in msp->norm
* return 0 if it worked, -1 if it failed
*/
-static int msp34xxg_init(struct i2c_client *client)
+static int msp34xxg_reset(struct i2c_client *client)
{
struct msp3400c *msp = i2c_get_clientdata(client);
int modus,std;
@@ -1210,8 +1340,10 @@ static int msp34xxg_init(struct i2c_client *client)
0x0f20 /* mute DSP input, mute SCART 1 */))
return -1;
+ msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode);
+
/* step-by-step initialisation, as described in the manual */
- modus = msp34xx_modus(msp->norm);
+ modus = msp34xx_modus(client, msp->norm);
std = msp34xx_standard(msp->norm);
modus &= ~0x03; /* STATUS_CHANGE=0 */
modus |= 0x01; /* AUTOMATIC_SOUND_DETECTION=1 */
@@ -1222,7 +1354,7 @@ static int msp34xxg_init(struct i2c_client *client)
return -1;
if (msp3400c_write(client,
I2C_MSP3400C_DEM,
- 0x20/*stanard*/,
+ 0x20/*standard*/,
std))
return -1;
@@ -1230,21 +1362,18 @@ static int msp34xxg_init(struct i2c_client *client)
standard/audio autodetection right now */
msp34xxg_set_source(client, msp->source);
- if (msp3400c_write(client, I2C_MSP3400C_DFP,
- 0x0e, /* AM/FM Prescale */
- 0x3000 /* default: [15:8] 75khz deviation */))
+ if (msp3400c_write_dfp_with_default(client, 0x0e, /* AM/FM Prescale */
+ 0x3000
+ /* default: [15:8] 75khz deviation */
+ ))
return -1;
- if (msp3400c_write(client, I2C_MSP3400C_DFP,
- 0x10, /* NICAM Prescale */
- 0x5a00 /* default: 9db gain (as recommended) */))
+ if (msp3400c_write_dfp_with_default(client, 0x10, /* NICAM Prescale */
+ 0x5a00
+ /* default: 9db gain (as recommended) */
+ ))
return -1;
- if (msp3400c_write(client,
- I2C_MSP3400C_DEM,
- 0x20, /* STANDARD SELECT */
- standard /* default: 0x01 for automatic standard select*/))
- return -1;
return 0;
}
@@ -1254,27 +1383,27 @@ static int msp34xxg_thread(void *data)
struct msp3400c *msp = i2c_get_clientdata(client);
int val, std, i;
- printk("msp34xxg: daemon started\n");
+ msp3400_info("msp34xxg daemon started\n");
msp->source = 1; /* default */
for (;;) {
- d2printk(KERN_DEBUG "msp34xxg: thread: sleep\n");
+ msp3400_dbg_mediumvol("msp34xxg thread: sleep\n");
msp34xx_sleep(msp,-1);
- d2printk(KERN_DEBUG "msp34xxg: thread: wakeup\n");
+ msp3400_dbg_mediumvol("msp34xxg thread: wakeup\n");
restart:
- dprintk("msp34xxg: thread: restart scan\n");
+ msp3400_dbg("thread: restart scan\n");
msp->restart = 0;
if (kthread_should_stop())
break;
/* setup the chip*/
- msp34xxg_init(client);
+ msp34xxg_reset(client);
std = standard;
if (std != 0x01)
goto unmute;
/* watch autodetect */
- dprintk("msp34xxg: triggered autodetect, waiting for result\n");
+ msp3400_dbg("triggered autodetect, waiting for result\n");
for (i = 0; i < 10; i++) {
if (msp34xx_sleep(msp,100))
goto restart;
@@ -1285,23 +1414,23 @@ static int msp34xxg_thread(void *data)
std = val;
break;
}
- dprintk("msp34xxg: detection still in progress\n");
+ msp3400_dbg("detection still in progress\n");
}
if (0x01 == std) {
- dprintk("msp34xxg: detection still in progress after 10 tries. giving up.\n");
+ msp3400_dbg("detection still in progress after 10 tries. giving up.\n");
continue;
}
unmute:
- dprintk("msp34xxg: current mode: %s (0x%04x)\n",
+ msp3400_dbg("current mode: %s (0x%04x)\n",
msp34xx_standard_mode_name(std), std);
/* unmute: dispatch sound to scart output, set scart volume */
- dprintk("msp34xxg: unmute\n");
+ msp3400_dbg("unmute\n");
msp3400c_setbass(client, msp->bass);
msp3400c_settreble(client, msp->treble);
- msp3400c_setvolume(client, msp->muted, msp->volume, msp->balance);
+ msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
/* restore ACB */
if (msp3400c_write(client,
@@ -1309,8 +1438,10 @@ static int msp34xxg_thread(void *data)
0x13, /* ACB */
msp->acb))
return -1;
+
+ msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode);
}
- dprintk(KERN_DEBUG "msp34xxg: thread: exit\n");
+ msp3400_dbg("thread: exit\n");
return 0;
}
@@ -1329,7 +1460,7 @@ static void msp34xxg_set_source(struct i2c_client *client, int source)
* for MONO (source==0) downmixing set bit[7:0] to 0x30
*/
int value = (source&0x07)<<8|(source==0 ? 0x30:0x20);
- dprintk("msp34xxg: set source to %d (0x%x)\n", source, value);
+ msp3400_dbg("set source to %d (0x%x)\n", source, value);
msp3400c_write(client,
I2C_MSP3400C_DFP,
0x08, /* Loudspeaker Output */
@@ -1380,7 +1511,7 @@ static void msp34xxg_detect_stereo(struct i2c_client *client)
* this is a problem, I'll handle SAP just like lang1/lang2.
*/
}
- dprintk("msp34xxg: status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n",
+ msp3400_dbg("status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n",
status, is_stereo, is_bilingual, msp->rxsubchans);
}
@@ -1427,7 +1558,7 @@ static void msp_wake_thread(struct i2c_client *client);
static struct i2c_driver driver = {
.owner = THIS_MODULE,
- .name = "i2c msp3400 driver",
+ .name = "msp3400",
.id = I2C_DRIVERID_MSP3400,
.flags = I2C_DF_NOTIFY,
.attach_adapter = msp_probe,
@@ -1449,57 +1580,64 @@ static struct i2c_client client_template =
static int msp_attach(struct i2c_adapter *adap, int addr, int kind)
{
struct msp3400c *msp;
- struct i2c_client *c;
+ struct i2c_client *client = &client_template;
int (*thread_func)(void *data) = NULL;
+ int i;
- client_template.adapter = adap;
- client_template.addr = addr;
+ client_template.adapter = adap;
+ client_template.addr = addr;
- if (-1 == msp3400c_reset(&client_template)) {
- dprintk("msp34xx: no chip found\n");
- return -1;
- }
+ if (-1 == msp3400c_reset(&client_template)) {
+ msp3400_dbg("no chip found\n");
+ return -1;
+ }
- if (NULL == (c = kmalloc(sizeof(struct i2c_client),GFP_KERNEL)))
- return -ENOMEM;
- memcpy(c,&client_template,sizeof(struct i2c_client));
+ if (NULL == (client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL)))
+ return -ENOMEM;
+ memcpy(client,&client_template,sizeof(struct i2c_client));
if (NULL == (msp = kmalloc(sizeof(struct msp3400c),GFP_KERNEL))) {
- kfree(c);
+ kfree(client);
return -ENOMEM;
}
memset(msp,0,sizeof(struct msp3400c));
- msp->volume = 58880; /* 0db gain */
- msp->balance = 32768;
- msp->bass = 32768;
- msp->treble = 32768;
- msp->input = -1;
- msp->muted = 1;
-
- i2c_set_clientdata(c, msp);
+ msp->norm = VIDEO_MODE_NTSC;
+ msp->left = 58880; /* 0db gain */
+ msp->right = 58880; /* 0db gain */
+ msp->bass = 32768;
+ msp->treble = 32768;
+ msp->input = -1;
+ msp->muted = 0;
+ msp->i2s_mode = 0;
+ for (i = 0; i < DFP_COUNT; i++)
+ msp->dfp_regs[i] = -1;
+
+ i2c_set_clientdata(client, msp);
init_waitqueue_head(&msp->wq);
- if (-1 == msp3400c_reset(c)) {
+ if (-1 == msp3400c_reset(client)) {
kfree(msp);
- kfree(c);
- dprintk("msp34xx: no chip found\n");
+ kfree(client);
+ msp3400_dbg("no chip found\n");
return -1;
}
- msp->rev1 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1e);
+ msp->rev1 = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1e);
if (-1 != msp->rev1)
- msp->rev2 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1f);
+ msp->rev2 = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1f);
if ((-1 == msp->rev1) || (0 == msp->rev1 && 0 == msp->rev2)) {
kfree(msp);
- kfree(c);
- dprintk("msp34xx: error while reading chip version\n");
+ kfree(client);
+ msp3400_dbg("error while reading chip version\n");
return -1;
}
+ msp3400_dbg("rev1=0x%04x, rev2=0x%04x\n", msp->rev1, msp->rev2);
- msp3400c_setvolume(c, msp->muted, msp->volume, msp->balance);
+ msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
- snprintf(c->name, sizeof(c->name), "MSP34%02d%c-%c%d",
- (msp->rev2>>8)&0xff, (msp->rev1&0xff)+'@',
+ snprintf(client->name, sizeof(client->name), "MSP%c4%02d%c-%c%d",
+ ((msp->rev1>>4)&0x0f) + '3',
+ (msp->rev2>>8)&0xff, (msp->rev1&0x0f)+'@',
((msp->rev1>>8)&0xff)+'@', msp->rev2&0x1f);
msp->opmode = opmode;
@@ -1513,7 +1651,7 @@ static int msp_attach(struct i2c_adapter *adap, int addr, int kind)
}
/* hello world :-) */
- printk(KERN_INFO "msp34xx: init: chip=%s", c->name);
+ msp3400_info("chip=%s", client->name);
if (HAVE_NICAM(msp))
printk(" +nicam");
if (HAVE_SIMPLE(msp))
@@ -1542,29 +1680,49 @@ static int msp_attach(struct i2c_adapter *adap, int addr, int kind)
/* startup control thread if needed */
if (thread_func) {
- msp->kthread = kthread_run(thread_func, c, "msp34xx");
+ msp->kthread = kthread_run(thread_func, client, "msp34xx");
+
if (NULL == msp->kthread)
- printk(KERN_WARNING "msp34xx: kernel_thread() failed\n");
- msp_wake_thread(c);
+ msp3400_warn("kernel_thread() failed\n");
+ msp_wake_thread(client);
}
/* done */
- i2c_attach_client(c);
+ i2c_attach_client(client);
+
+ /* update our own array */
+ for (i = 0; i < MSP3400_MAX; i++) {
+ if (NULL == msps[i]) {
+ msps[i] = client;
+ break;
+ }
+ }
+
return 0;
}
static int msp_detach(struct i2c_client *client)
{
struct msp3400c *msp = i2c_get_clientdata(client);
+ int i;
/* shutdown control thread */
- if (msp->kthread >= 0) {
+ if (msp->kthread) {
msp->restart = 1;
kthread_stop(msp->kthread);
}
- msp3400c_reset(client);
+ msp3400c_reset(client);
+
+ /* update our own array */
+ for (i = 0; i < MSP3400_MAX; i++) {
+ if (client == msps[i]) {
+ msps[i] = NULL;
+ break;
+ }
+ }
i2c_detach_client(client);
+
kfree(msp);
kfree(client);
return 0;
@@ -1640,7 +1798,7 @@ static void msp_any_set_audmode(struct i2c_client *client, int audmode)
case OPMODE_MANUAL:
case OPMODE_SIMPLE:
msp->watch_stereo = 0;
- msp3400c_set_audmode(client, audmode);
+ msp3400c_setstereo(client, audmode);
break;
case OPMODE_SIMPLER:
msp34xxg_set_audmode(client, audmode);
@@ -1648,16 +1806,18 @@ static void msp_any_set_audmode(struct i2c_client *client, int audmode)
}
}
+
static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct msp3400c *msp = i2c_get_clientdata(client);
- __u16 *sarg = arg;
+ __u16 *sarg = arg;
int scart = 0;
switch (cmd) {
case AUDC_SET_INPUT:
- dprintk(KERN_DEBUG "msp34xx: AUDC_SET_INPUT(%d)\n",*sarg);
+ msp3400_dbg("AUDC_SET_INPUT(%d)\n",*sarg);
+
if (*sarg == msp->input)
break;
msp->input = *sarg;
@@ -1691,15 +1851,15 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
msp3400c_set_scart(client,scart,0);
msp3400c_write(client,I2C_MSP3400C_DFP,0x000d,0x1900);
if (msp->opmode != OPMODE_SIMPLER)
- msp3400c_set_audmode(client, msp->audmode);
+ msp3400c_setstereo(client, msp->audmode);
}
msp_wake_thread(client);
break;
case AUDC_SET_RADIO:
- dprintk(KERN_DEBUG "msp34xx: AUDC_SET_RADIO\n");
+ msp3400_dbg("AUDC_SET_RADIO\n");
msp->norm = VIDEO_MODE_RADIO;
- dprintk(KERN_DEBUG "msp34xx: switching to radio mode\n");
+ msp3400_dbg("switching to radio mode\n");
msp->watch_stereo = 0;
switch (msp->opmode) {
case OPMODE_MANUAL:
@@ -1707,8 +1867,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
msp3400c_setmode(client,MSP_MODE_FM_RADIO);
msp3400c_setcarrier(client, MSP_CARRIER(10.7),
MSP_CARRIER(10.7));
- msp3400c_setvolume(client, msp->muted,
- msp->volume, msp->balance);
+ msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
break;
case OPMODE_SIMPLE:
case OPMODE_SIMPLER:
@@ -1717,6 +1876,30 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
break;
}
break;
+ /* work-in-progress: hook to control the DFP registers */
+ case MSP_SET_DFPREG:
+ {
+ struct msp_dfpreg *r = arg;
+ int i;
+
+ if (r->reg < 0 || r->reg >= DFP_COUNT)
+ return -EINVAL;
+ for (i = 0; i < sizeof(bl_dfp) / sizeof(int); i++)
+ if (r->reg == bl_dfp[i])
+ return -EINVAL;
+ msp->dfp_regs[r->reg] = r->value;
+ msp3400c_write(client, I2C_MSP3400C_DFP, r->reg, r->value);
+ return 0;
+ }
+ case MSP_GET_DFPREG:
+ {
+ struct msp_dfpreg *r = arg;
+
+ if (r->reg < 0 || r->reg >= DFP_COUNT)
+ return -EINVAL;
+ r->value = msp3400c_read(client, I2C_MSP3400C_DFP, r->reg);
+ return 0;
+ }
/* --- v4l ioctls --- */
/* take care: bttv does userspace copying, we'll get a
@@ -1725,7 +1908,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct video_audio *va = arg;
- dprintk(KERN_DEBUG "msp34xx: VIDIOCGAUDIO\n");
+ msp3400_dbg("VIDIOCGAUDIO\n");
va->flags |= VIDEO_AUDIO_VOLUME |
VIDEO_AUDIO_BASS |
VIDEO_AUDIO_TREBLE |
@@ -1733,8 +1916,15 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
if (msp->muted)
va->flags |= VIDEO_AUDIO_MUTE;
- va->volume = msp->volume;
- va->balance = (va->volume) ? msp->balance : 32768;
+ if (msp->muted)
+ va->flags |= VIDEO_AUDIO_MUTE;
+ va->volume = MAX(msp->left, msp->right);
+ va->balance = (32768 * MIN(msp->left, msp->right)) /
+ (va->volume ? va->volume : 1);
+ va->balance = (msp->left < msp->right) ?
+ (65535 - va->balance) : va->balance;
+ if (0 == va->volume)
+ va->balance = 32768;
va->bass = msp->bass;
va->treble = msp->treble;
@@ -1746,27 +1936,43 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct video_audio *va = arg;
- dprintk(KERN_DEBUG "msp34xx: VIDIOCSAUDIO\n");
+ msp3400_dbg("VIDIOCSAUDIO\n");
msp->muted = (va->flags & VIDEO_AUDIO_MUTE);
- msp->volume = va->volume;
- msp->balance = va->balance;
+ msp->left = (MIN(65536 - va->balance, 32768) *
+ va->volume) / 32768;
+ msp->right = (MIN(va->balance, 32768) * va->volume) / 32768;
msp->bass = va->bass;
msp->treble = va->treble;
-
- msp3400c_setvolume(client, msp->muted,
- msp->volume, msp->balance);
- msp3400c_setbass(client,msp->bass);
- msp3400c_settreble(client,msp->treble);
+ msp3400_dbg("VIDIOCSAUDIO setting va->volume to %d\n",
+ va->volume);
+ msp3400_dbg("VIDIOCSAUDIO setting va->balance to %d\n",
+ va->balance);
+ msp3400_dbg("VIDIOCSAUDIO setting va->flags to %d\n",
+ va->flags);
+ msp3400_dbg("VIDIOCSAUDIO setting msp->left to %d\n",
+ msp->left);
+ msp3400_dbg("VIDIOCSAUDIO setting msp->right to %d\n",
+ msp->right);
+ msp3400_dbg("VIDIOCSAUDIO setting msp->bass to %d\n",
+ msp->bass);
+ msp3400_dbg("VIDIOCSAUDIO setting msp->treble to %d\n",
+ msp->treble);
+ msp3400_dbg("VIDIOCSAUDIO setting msp->mode to %d\n",
+ msp->mode);
+ msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
+ msp3400c_setbass(client, msp->bass);
+ msp3400c_settreble(client, msp->treble);
if (va->mode != 0 && msp->norm != VIDEO_MODE_RADIO)
msp_any_set_audmode(client,mode_v4l1_to_v4l2(va->mode));
break;
}
+
case VIDIOCSCHAN:
{
struct video_channel *vc = arg;
- dprintk(KERN_DEBUG "msp34xx: VIDIOCSCHAN (norm=%d)\n",vc->norm);
+ msp3400_dbg("VIDIOCSCHAN (norm=%d)\n",vc->norm);
msp->norm = vc->norm;
msp_wake_thread(client);
break;
@@ -1776,12 +1982,135 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
case VIDIOC_S_FREQUENCY:
{
/* new channel -- kick audio carrier scan */
- dprintk(KERN_DEBUG "msp34xx: VIDIOCSFREQ\n");
+ msp3400_dbg("VIDIOCSFREQ\n");
msp_wake_thread(client);
break;
}
+ /* msp34xx specific */
+ case MSP_SET_MATRIX:
+ {
+ struct msp_matrix *mspm = arg;
+
+ msp3400_dbg("MSP_SET_MATRIX\n");
+ msp3400c_set_scart(client, mspm->input, mspm->output);
+ break;
+ }
+
/* --- v4l2 ioctls --- */
+ case VIDIOC_S_STD:
+ {
+ v4l2_std_id *id = arg;
+
+ /*FIXME: use V4L2 mode flags on msp3400 instead of V4L1*/
+ if (*id & V4L2_STD_PAL) {
+ msp->norm=VIDEO_MODE_PAL;
+ } else if (*id & V4L2_STD_SECAM) {
+ msp->norm=VIDEO_MODE_SECAM;
+ } else {
+ msp->norm=VIDEO_MODE_NTSC;
+ }
+
+ msp_wake_thread(client);
+ return 0;
+ }
+
+ case VIDIOC_ENUMINPUT:
+ {
+ struct v4l2_input *i = arg;
+
+ if (i->index != 0)
+ return -EINVAL;
+
+ i->type = V4L2_INPUT_TYPE_TUNER;
+ switch (i->index) {
+ case AUDIO_RADIO:
+ strcpy(i->name,"Radio");
+ break;
+ case AUDIO_EXTERN_1:
+ strcpy(i->name,"Extern 1");
+ break;
+ case AUDIO_EXTERN_2:
+ strcpy(i->name,"Extern 2");
+ break;
+ case AUDIO_TUNER:
+ strcpy(i->name,"Television");
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+ }
+
+ case VIDIOC_G_AUDIO:
+ {
+ struct v4l2_audio *a = arg;
+
+ memset(a,0,sizeof(*a));
+
+ switch (a->index) {
+ case AUDIO_RADIO:
+ strcpy(a->name,"Radio");
+ break;
+ case AUDIO_EXTERN_1:
+ strcpy(a->name,"Extern 1");
+ break;
+ case AUDIO_EXTERN_2:
+ strcpy(a->name,"Extern 2");
+ break;
+ case AUDIO_TUNER:
+ strcpy(a->name,"Television");
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ msp_any_detect_stereo(client);
+ if (msp->audmode == V4L2_TUNER_MODE_STEREO) {
+ a->capability=V4L2_AUDCAP_STEREO;
+ }
+
+ break;
+ }
+ case VIDIOC_S_AUDIO:
+ {
+ struct v4l2_audio *sarg = arg;
+
+ switch (sarg->index) {
+ case AUDIO_RADIO:
+ /* Hauppauge uses IN2 for the radio */
+ msp->mode = MSP_MODE_FM_RADIO;
+ scart = SCART_IN2;
+ break;
+ case AUDIO_EXTERN_1:
+ /* IN1 is often used for external input ... */
+ msp->mode = MSP_MODE_EXTERN;
+ scart = SCART_IN1;
+ break;
+ case AUDIO_EXTERN_2:
+ /* ... sometimes it is IN2 through ;) */
+ msp->mode = MSP_MODE_EXTERN;
+ scart = SCART_IN2;
+ break;
+ case AUDIO_TUNER:
+ msp->mode = -1;
+ break;
+ }
+ if (scart) {
+ msp->rxsubchans = V4L2_TUNER_SUB_STEREO;
+ msp->audmode = V4L2_TUNER_MODE_STEREO;
+ msp3400c_set_scart(client,scart,0);
+ msp3400c_write(client,I2C_MSP3400C_DFP,0x000d,0x1900);
+ }
+ if (sarg->capability==V4L2_AUDCAP_STEREO) {
+ msp->audmode = V4L2_TUNER_MODE_STEREO;
+ } else {
+ msp->audmode &= ~V4L2_TUNER_MODE_STEREO;
+ }
+ msp_any_set_audmode(client, msp->audmode);
+ msp_wake_thread(client);
+ break;
+ }
case VIDIOC_G_TUNER:
{
struct v4l2_tuner *vt = arg;
@@ -1804,13 +2133,46 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
break;
}
- /* msp34xx specific */
- case MSP_SET_MATRIX:
+ case VIDIOC_G_AUDOUT:
{
- struct msp_matrix *mspm = arg;
+ struct v4l2_audioout *a=(struct v4l2_audioout *)arg;
+ int idx=a->index;
+
+ memset(a,0,sizeof(*a));
+
+ switch (idx) {
+ case 0:
+ strcpy(a->name,"Scart1 Out");
+ break;
+ case 1:
+ strcpy(a->name,"Scart2 Out");
+ break;
+ case 2:
+ strcpy(a->name,"I2S Out");
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+
+ }
+ case VIDIOC_S_AUDOUT:
+ {
+ struct v4l2_audioout *a=(struct v4l2_audioout *)arg;
+
+ if (a->index<0||a->index>2)
+ return -EINVAL;
+
+ if (a->index==2) {
+ if (a->mode == V4L2_AUDMODE_32BITS)
+ msp->i2s_mode=1;
+ else
+ msp->i2s_mode=0;
+ }
+ msp3400_dbg("Setting audio out on msp34xx to input %i, mode %i\n",
+ a->index,msp->i2s_mode);
+ msp3400c_set_scart(client,msp->in_scart,a->index+1);
- dprintk(KERN_DEBUG "msp34xx: MSP_SET_MATRIX\n");
- msp3400c_set_scart(client, mspm->input, mspm->output);
break;
}
@@ -1823,19 +2185,19 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
static int msp_suspend(struct device * dev, pm_message_t state)
{
- struct i2c_client *c = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
- dprintk("msp34xx: suspend\n");
- msp3400c_reset(c);
+ msp3400_dbg("msp34xx: suspend\n");
+ msp3400c_reset(client);
return 0;
}
static int msp_resume(struct device * dev)
{
- struct i2c_client *c = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
- dprintk("msp34xx: resume\n");
- msp_wake_thread(c);
+ msp3400_dbg("msp34xx: resume\n");
+ msp_wake_thread(client);
return 0;
}
diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c
index 972aa5e0aee..2180018f06d 100644
--- a/drivers/media/video/mt20xx.c
+++ b/drivers/media/video/mt20xx.c
@@ -76,17 +76,17 @@ static int mt2032_compute_freq(struct i2c_client *c,
unsigned int xogc) //all in Hz
{
struct tuner *t = i2c_get_clientdata(c);
- unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1,
+ unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1,
desired_lo2,lo2,lo2n,lo2a,lo2num,lo2freq;
- fref= 5250 *1000; //5.25MHz
+ fref= 5250 *1000; //5.25MHz
desired_lo1=rfin+if1;
lo1=(2*(desired_lo1/1000)+(fref/1000)) / (2*fref/1000);
- lo1n=lo1/8;
- lo1a=lo1-(lo1n*8);
+ lo1n=lo1/8;
+ lo1a=lo1-(lo1n*8);
- s=rfin/1000/1000+1090;
+ s=rfin/1000/1000+1090;
if(optimize_vco) {
if(s>1890) sel=0;
@@ -96,34 +96,34 @@ static int mt2032_compute_freq(struct i2c_client *c,
else sel=4; // >1090
}
else {
- if(s>1790) sel=0; // <1958
- else if(s>1617) sel=1;
- else if(s>1449) sel=2;
- else if(s>1291) sel=3;
- else sel=4; // >1090
+ if(s>1790) sel=0; // <1958
+ else if(s>1617) sel=1;
+ else if(s>1449) sel=2;
+ else if(s>1291) sel=3;
+ else sel=4; // >1090
}
*ret_sel=sel;
- lo1freq=(lo1a+8*lo1n)*fref;
+ lo1freq=(lo1a+8*lo1n)*fref;
tuner_dbg("mt2032: rfin=%d lo1=%d lo1n=%d lo1a=%d sel=%d, lo1freq=%d\n",
rfin,lo1,lo1n,lo1a,sel,lo1freq);
- desired_lo2=lo1freq-rfin-if2;
- lo2=(desired_lo2)/fref;
- lo2n=lo2/8;
- lo2a=lo2-(lo2n*8);
- lo2num=((desired_lo2/1000)%(fref/1000))* 3780/(fref/1000); //scale to fit in 32bit arith
- lo2freq=(lo2a+8*lo2n)*fref + lo2num*(fref/1000)/3780*1000;
+ desired_lo2=lo1freq-rfin-if2;
+ lo2=(desired_lo2)/fref;
+ lo2n=lo2/8;
+ lo2a=lo2-(lo2n*8);
+ lo2num=((desired_lo2/1000)%(fref/1000))* 3780/(fref/1000); //scale to fit in 32bit arith
+ lo2freq=(lo2a+8*lo2n)*fref + lo2num*(fref/1000)/3780*1000;
tuner_dbg("mt2032: rfin=%d lo2=%d lo2n=%d lo2a=%d num=%d lo2freq=%d\n",
rfin,lo2,lo2n,lo2a,lo2num,lo2freq);
- if(lo1a<0 || lo1a>7 || lo1n<17 ||lo1n>48 || lo2a<0 ||lo2a >7 ||lo2n<17 || lo2n>30) {
+ if(lo1a<0 || lo1a>7 || lo1n<17 ||lo1n>48 || lo2a<0 ||lo2a >7 ||lo2n<17 || lo2n>30) {
tuner_info("mt2032: frequency parameters out of range: %d %d %d %d\n",
lo1a, lo1n, lo2a,lo2n);
- return(-1);
- }
+ return(-1);
+ }
mt2032_spurcheck(c, lo1freq, desired_lo2, spectrum_from, spectrum_to);
// should recalculate lo1 (one step up/down)
@@ -135,10 +135,10 @@ static int mt2032_compute_freq(struct i2c_client *c,
buf[3]=0x0f; //reserved
buf[4]=0x1f;
buf[5]=(lo2n-1) | (lo2a<<5);
- if(rfin >400*1000*1000)
- buf[6]=0xe4;
- else
- buf[6]=0xf4; // set PKEN per rev 1.2
+ if(rfin >400*1000*1000)
+ buf[6]=0xe4;
+ else
+ buf[6]=0xf4; // set PKEN per rev 1.2
buf[7]=8+xogc;
buf[8]=0xc3; //reserved
buf[9]=0x4e; //reserved
@@ -168,7 +168,7 @@ static int mt2032_check_lo_lock(struct i2c_client *c)
tuner_dbg("mt2032: pll wait 1ms for lock (0x%2x)\n",buf[0]);
udelay(1000);
}
- return lock;
+ return lock;
}
static int mt2032_optimize_vco(struct i2c_client *c,int sel,int lock)
@@ -202,7 +202,7 @@ static int mt2032_optimize_vco(struct i2c_client *c,int sel,int lock)
buf[0]=0x0f;
buf[1]=sel;
- i2c_master_send(c,buf,2);
+ i2c_master_send(c,buf,2);
lock=mt2032_check_lo_lock(c);
return lock;
}
@@ -219,23 +219,23 @@ static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin,
tuner_dbg("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n",
rfin,if1,if2,from,to);
- buf[0]=0;
- ret=i2c_master_send(c,buf,1);
- i2c_master_recv(c,buf,21);
+ buf[0]=0;
+ ret=i2c_master_send(c,buf,1);
+ i2c_master_recv(c,buf,21);
buf[0]=0;
ret=mt2032_compute_freq(c,rfin,if1,if2,from,to,&buf[1],&sel,t->xogc);
if (ret<0)
return;
- // send only the relevant registers per Rev. 1.2
- buf[0]=0;
- ret=i2c_master_send(c,buf,4);
- buf[5]=5;
- ret=i2c_master_send(c,buf+5,4);
- buf[11]=11;
- ret=i2c_master_send(c,buf+11,3);
- if(ret!=3)
+ // send only the relevant registers per Rev. 1.2
+ buf[0]=0;
+ ret=i2c_master_send(c,buf,4);
+ buf[5]=5;
+ ret=i2c_master_send(c,buf+5,4);
+ buf[11]=11;
+ ret=i2c_master_send(c,buf+11,3);
+ if(ret!=3)
tuner_warn("i2c i/o error: rc == %d (should be 3)\n",ret);
// wait for PLLs to lock (per manual), retry LINT if not.
@@ -253,7 +253,7 @@ static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin,
mdelay(10);
buf[1]=8+t->xogc;
i2c_master_send(c,buf,2);
- }
+ }
if (lock!=6)
tuner_warn("MT2032 Fatal Error: PLLs didn't lock.\n");
@@ -284,7 +284,7 @@ static void mt2032_set_tv_freq(struct i2c_client *c, unsigned int freq)
if2 = 38900*1000;
}
- mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */,
+ mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */,
1090*1000*1000, if2, from, to);
}
@@ -294,7 +294,7 @@ static void mt2032_set_radio_freq(struct i2c_client *c, unsigned int freq)
int if2 = t->radio_if2;
// per Manual for FM tuning: first if center freq. 1085 MHz
- mt2032_set_if_freq(c, freq * 1000 / 16,
+ mt2032_set_if_freq(c, freq * 1000 / 16,
1085*1000*1000,if2,if2,if2);
}
@@ -302,57 +302,57 @@ static void mt2032_set_radio_freq(struct i2c_client *c, unsigned int freq)
static int mt2032_init(struct i2c_client *c)
{
struct tuner *t = i2c_get_clientdata(c);
- unsigned char buf[21];
- int ret,xogc,xok=0;
+ unsigned char buf[21];
+ int ret,xogc,xok=0;
// Initialize Registers per spec.
- buf[1]=2; // Index to register 2
- buf[2]=0xff;
- buf[3]=0x0f;
- buf[4]=0x1f;
- ret=i2c_master_send(c,buf+1,4);
-
- buf[5]=6; // Index register 6
- buf[6]=0xe4;
- buf[7]=0x8f;
- buf[8]=0xc3;
- buf[9]=0x4e;
- buf[10]=0xec;
- ret=i2c_master_send(c,buf+5,6);
-
- buf[12]=13; // Index register 13
- buf[13]=0x32;
- ret=i2c_master_send(c,buf+12,2);
-
- // Adjust XOGC (register 7), wait for XOK
- xogc=7;
- do {
+ buf[1]=2; // Index to register 2
+ buf[2]=0xff;
+ buf[3]=0x0f;
+ buf[4]=0x1f;
+ ret=i2c_master_send(c,buf+1,4);
+
+ buf[5]=6; // Index register 6
+ buf[6]=0xe4;
+ buf[7]=0x8f;
+ buf[8]=0xc3;
+ buf[9]=0x4e;
+ buf[10]=0xec;
+ ret=i2c_master_send(c,buf+5,6);
+
+ buf[12]=13; // Index register 13
+ buf[13]=0x32;
+ ret=i2c_master_send(c,buf+12,2);
+
+ // Adjust XOGC (register 7), wait for XOK
+ xogc=7;
+ do {
tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07);
- mdelay(10);
- buf[0]=0x0e;
- i2c_master_send(c,buf,1);
- i2c_master_recv(c,buf,1);
- xok=buf[0]&0x01;
- tuner_dbg("mt2032: xok = 0x%02x\n",xok);
- if (xok == 1) break;
-
- xogc--;
- tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07);
- if (xogc == 3) {
- xogc=4; // min. 4 per spec
- break;
- }
- buf[0]=0x07;
- buf[1]=0x88 + xogc;
- ret=i2c_master_send(c,buf,2);
- if (ret!=2)
+ mdelay(10);
+ buf[0]=0x0e;
+ i2c_master_send(c,buf,1);
+ i2c_master_recv(c,buf,1);
+ xok=buf[0]&0x01;
+ tuner_dbg("mt2032: xok = 0x%02x\n",xok);
+ if (xok == 1) break;
+
+ xogc--;
+ tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07);
+ if (xogc == 3) {
+ xogc=4; // min. 4 per spec
+ break;
+ }
+ buf[0]=0x07;
+ buf[1]=0x88 + xogc;
+ ret=i2c_master_send(c,buf,2);
+ if (ret!=2)
tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret);
- } while (xok != 1 );
+ } while (xok != 1 );
t->xogc=xogc;
t->tv_freq = mt2032_set_tv_freq;
t->radio_freq = mt2032_set_radio_freq;
- return(1);
+ return(1);
}
static void mt2050_set_antenna(struct i2c_client *c, unsigned char antenna)
@@ -426,7 +426,7 @@ static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned
}
ret=i2c_master_send(c,buf,6);
- if (ret!=6)
+ if (ret!=6)
tuner_warn("i2c i/o error: rc == %d (should be 6)\n",ret);
}
@@ -437,11 +437,11 @@ static void mt2050_set_tv_freq(struct i2c_client *c, unsigned int freq)
if (t->std & V4L2_STD_525_60) {
// NTSC
- if2 = 45750*1000;
- } else {
- // PAL
- if2 = 38900*1000;
- }
+ if2 = 45750*1000;
+ } else {
+ // PAL
+ if2 = 38900*1000;
+ }
if (V4L2_TUNER_DIGITAL_TV == t->mode) {
// DVB (pinnacle 300i)
if2 = 36150*1000;
@@ -455,7 +455,7 @@ static void mt2050_set_radio_freq(struct i2c_client *c, unsigned int freq)
struct tuner *t = i2c_get_clientdata(c);
int if2 = t->radio_if2;
- mt2050_set_if_freq(c, freq*62500, if2);
+ mt2050_set_if_freq(c, freq * 1000 / 16, if2);
mt2050_set_antenna(c, radio_antenna);
}
@@ -487,7 +487,7 @@ int microtune_init(struct i2c_client *c)
{
struct tuner *t = i2c_get_clientdata(c);
char *name;
- unsigned char buf[21];
+ unsigned char buf[21];
int company_code;
memset(buf,0,sizeof(buf));
@@ -496,17 +496,17 @@ int microtune_init(struct i2c_client *c)
t->standby = NULL;
name = "unknown";
- i2c_master_send(c,buf,1);
- i2c_master_recv(c,buf,21);
- if (tuner_debug) {
- int i;
+ i2c_master_send(c,buf,1);
+ i2c_master_recv(c,buf,21);
+ if (tuner_debug) {
+ int i;
tuner_dbg("MT20xx hexdump:");
- for(i=0;i<21;i++) {
- printk(" %02x",buf[i]);
- if(((i+1)%8)==0) printk(" ");
- }
- printk("\n");
- }
+ for(i=0;i<21;i++) {
+ printk(" %02x",buf[i]);
+ if(((i+1)%8)==0) printk(" ");
+ }
+ printk("\n");
+ }
company_code = buf[0x11] << 8 | buf[0x12];
tuner_info("microtune: companycode=%04x part=%02x rev=%02x\n",
company_code,buf[0x13],buf[0x14]);
@@ -525,8 +525,8 @@ int microtune_init(struct i2c_client *c)
default:
tuner_info("microtune %s found, not (yet?) supported, sorry :-/\n",
name);
- return 0;
- }
+ return 0;
+ }
strlcpy(c->name, name, sizeof(c->name));
tuner_info("microtune %s found, OK\n",name);
diff --git a/drivers/media/video/saa6588.c b/drivers/media/video/saa6588.c
index 72b70eb5da1..dca3ddfd510 100644
--- a/drivers/media/video/saa6588.c
+++ b/drivers/media/video/saa6588.c
@@ -31,7 +31,6 @@
#include <linux/wait.h>
#include <asm/uaccess.h>
-#include <media/id.h>
#include "rds.h"
@@ -246,7 +245,7 @@ static void block_to_buf(struct saa6588 *s, unsigned char *blockbuf)
s->wr_index = 0;
if (s->wr_index == s->rd_index) {
- s->rd_index++;
+ s->rd_index += 3;
if (s->rd_index >= s->buf_size)
s->rd_index = 0;
} else
@@ -328,7 +327,7 @@ static void saa6588_work(void *data)
struct saa6588 *s = (struct saa6588 *)data;
saa6588_i2c_poll(s);
- mod_timer(&s->timer, jiffies + HZ / 50); /* 20 msec */
+ mod_timer(&s->timer, jiffies + msecs_to_jiffies(20));
}
static int saa6588_configure(struct saa6588 *s)
@@ -434,9 +433,9 @@ static int saa6588_probe(struct i2c_adapter *adap)
return i2c_probe(adap, &addr_data, saa6588_attach);
#else
switch (adap->id) {
- case I2C_ALGO_BIT | I2C_HW_B_BT848:
- case I2C_ALGO_BIT | I2C_HW_B_RIVA:
- case I2C_ALGO_SAA7134:
+ case I2C_HW_B_BT848:
+ case I2C_HW_B_RIVA:
+ case I2C_HW_SAA7134:
return i2c_probe(adap, &addr_data, saa6588_attach);
break;
}
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
new file mode 100644
index 00000000000..0235cef07b3
--- /dev/null
+++ b/drivers/media/video/saa7115.c
@@ -0,0 +1,1376 @@
+/* saa7115 - Philips SAA7114/SAA7115 video decoder driver
+ *
+ * Based on saa7114 driver by Maxim Yevtyushkin, which is based on
+ * the saa7111 driver by Dave Perks.
+ *
+ * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+ * Copyright (C) 2002 Maxim Yevtyushkin <max@linuxmedialabs.com>
+ *
+ * Slight changes for video timing and attachment output by
+ * Wolfgang Scherr <scherr@net4you.net>
+ *
+ * Moved over to the linux >= 2.4.x i2c protocol (1/1/2003)
+ * by Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * Added saa7115 support by Kevin Thayer <nufan_wfk at yahoo.com>
+ * (2/17/2003)
+ *
+ * VBI support (2004) and cleanups (2005) by Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+
+MODULE_DESCRIPTION("Philips SAA7114/SAA7115 video decoder driver");
+MODULE_AUTHOR("Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+static int debug = 0;
+module_param(debug, int, 0644);
+
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+#define saa7115_dbg(fmt,arg...) \
+ do { \
+ if (debug) \
+ printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); \
+ } while (0)
+
+#define saa7115_err(fmt, arg...) do { \
+ printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+#define saa7115_info(fmt, arg...) do { \
+ printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+
+static unsigned short normal_i2c[] = { 0x42 >> 1, 0x40 >> 1, I2C_CLIENT_END };
+
+
+I2C_CLIENT_INSMOD;
+
+struct saa7115_state {
+ v4l2_std_id std;
+ int input;
+ int enable;
+ int bright;
+ int contrast;
+ int hue;
+ int sat;
+ enum v4l2_chip_ident ident;
+ enum v4l2_audio_clock_freq audclk_freq;
+};
+
+/* ----------------------------------------------------------------------- */
+
+static inline int saa7115_write(struct i2c_client *client, u8 reg, u8 value)
+{
+ return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int saa7115_writeregs(struct i2c_client *client, const unsigned char *regs)
+{
+ unsigned char reg, data;
+
+ while (*regs != 0x00) {
+ reg = *(regs++);
+ data = *(regs++);
+ if (saa7115_write(client, reg, data) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+static inline int saa7115_read(struct i2c_client *client, u8 reg)
+{
+ return i2c_smbus_read_byte_data(client, reg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* If a value differs from the Hauppauge driver values, then the comment starts with
+ 'was 0xXX' to denote the Hauppauge value. Otherwise the value is identical to what the
+ Hauppauge driver sets. */
+
+static const unsigned char saa7115_init_auto_input[] = {
+ 0x01, 0x48, /* white peak control disabled */
+ 0x03, 0x20, /* was 0x30. 0x20: long vertical blanking */
+ 0x04, 0x90, /* analog gain set to 0 */
+ 0x05, 0x90, /* analog gain set to 0 */
+ 0x06, 0xeb, /* horiz sync begin = -21 */
+ 0x07, 0xe0, /* horiz sync stop = -17 */
+ 0x0a, 0x80, /* was 0x88. decoder brightness, 0x80 is itu standard */
+ 0x0b, 0x44, /* was 0x48. decoder contrast, 0x44 is itu standard */
+ 0x0c, 0x40, /* was 0x47. decoder saturation, 0x40 is itu standard */
+ 0x0d, 0x00, /* chrominance hue control */
+ 0x0f, 0x00, /* chrominance gain control: use automicatic mode */
+ 0x10, 0x06, /* chrominance/luminance control: active adaptive combfilter */
+ 0x11, 0x00, /* delay control */
+ 0x12, 0x9d, /* RTS0 output control: VGATE */
+ 0x13, 0x80, /* X-port output control: ITU656 standard mode, RTCO output enable RTCE */
+ 0x14, 0x00, /* analog/ADC/auto compatibility control */
+ 0x18, 0x40, /* raw data gain 0x00 = nominal */
+ 0x19, 0x80, /* raw data offset 0x80 = 0 LSB */
+ 0x1a, 0x77, /* color killer level control 0x77 = recommended */
+ 0x1b, 0x42, /* misc chroma control 0x42 = recommended */
+ 0x1c, 0xa9, /* combfilter control 0xA9 = recommended */
+ 0x1d, 0x01, /* combfilter control 0x01 = recommended */
+ 0x88, 0xd0, /* reset device */
+ 0x88, 0xf0, /* set device programmed, all in operational mode */
+ 0x00, 0x00
+};
+
+static const unsigned char saa7115_cfg_reset_scaler[] = {
+ 0x87, 0x00, /* disable I-port output */
+ 0x88, 0xd0, /* reset scaler */
+ 0x88, 0xf0, /* activate scaler */
+ 0x87, 0x01, /* enable I-port output */
+ 0x00, 0x00
+};
+
+/* ============== SAA7715 VIDEO templates ============= */
+
+static const unsigned char saa7115_cfg_60hz_fullres_x[] = {
+ 0xcc, 0xd0, /* hsize low (output), hor. output window size = 0x2d0 = 720 */
+ 0xcd, 0x02, /* hsize hi (output) */
+
+ /* Why not in 60hz-Land, too? */
+ 0xd0, 0x01, /* downscale = 1 */
+ 0xd8, 0x00, /* hor lum scaling 0x0400 = 1 */
+ 0xd9, 0x04,
+ 0xdc, 0x00, /* hor chrom scaling 0x0200. must be hor lum scaling / 2 */
+ 0xdd, 0x02, /* H-scaling incr chroma */
+
+ 0x00, 0x00
+};
+static const unsigned char saa7115_cfg_60hz_fullres_y[] = {
+ 0xce, 0xf8, /* vsize low (output), ver. output window size = 248 (but 60hz is 240?) */
+ 0xcf, 0x00, /* vsize hi (output) */
+
+ /* Why not in 60hz-Land, too? */
+ 0xd5, 0x40, /* Lum contrast, nominal value = 0x40 */
+ 0xd6, 0x40, /* Chroma satur. nominal value = 0x80 */
+
+ 0xe0, 0x00, /* V-scaling incr luma low */
+ 0xe1, 0x04, /* " hi */
+ 0xe2, 0x00, /* V-scaling incr chroma low */
+ 0xe3, 0x04, /* " hi */
+
+ 0x00, 0x00
+};
+
+static const unsigned char saa7115_cfg_60hz_video[] = {
+ 0x80, 0x00, /* reset tasks */
+ 0x88, 0xd0, /* reset scaler */
+
+ 0x15, 0x03, /* VGATE pulse start */
+ 0x16, 0x11, /* VGATE pulse stop */
+ 0x17, 0x9c, /* VGATE MSB and other values */
+
+ 0x08, 0x68, /* 0xBO: auto detection, 0x68 = NTSC */
+ 0x0e, 0x07, /* lots of different stuff... video autodetection is on */
+
+ 0x5a, 0x06, /* Vertical offset, standard 60hz value for ITU656 line counting */
+
+ /* Task A */
+ 0x90, 0x80, /* Task Handling Control */
+ 0x91, 0x48, /* X-port formats/config */
+ 0x92, 0x40, /* Input Ref. signal Def. */
+ 0x93, 0x84, /* I-port config */
+ 0x94, 0x01, /* hoffset low (input), 0x0002 is minimum */
+ 0x95, 0x00, /* hoffset hi (input) */
+ 0x96, 0xd0, /* hsize low (input), 0x02d0 = 720 */
+ 0x97, 0x02, /* hsize hi (input) */
+ 0x98, 0x05, /* voffset low (input) */
+ 0x99, 0x00, /* voffset hi (input) */
+ 0x9a, 0x0c, /* vsize low (input), 0x0c = 12 */
+ 0x9b, 0x00, /* vsize hi (input) */
+ 0x9c, 0xa0, /* hsize low (output), 0x05a0 = 1440 */
+ 0x9d, 0x05, /* hsize hi (output) */
+ 0x9e, 0x0c, /* vsize low (output), 0x0c = 12 */
+ 0x9f, 0x00, /* vsize hi (output) */
+
+ /* Task B */
+ 0xc0, 0x00, /* Task Handling Control */
+ 0xc1, 0x08, /* X-port formats/config */
+ 0xc2, 0x00, /* Input Ref. signal Def. */
+ 0xc3, 0x80, /* I-port config */
+ 0xc4, 0x02, /* hoffset low (input), 0x0002 is minimum */
+ 0xc5, 0x00, /* hoffset hi (input) */
+ 0xc6, 0xd0, /* hsize low (input), 0x02d0 = 720 */
+ 0xc7, 0x02, /* hsize hi (input) */
+ 0xc8, 0x12, /* voffset low (input), 0x12 = 18 */
+ 0xc9, 0x00, /* voffset hi (input) */
+ 0xca, 0xf8, /* vsize low (input), 0xf8 = 248 */
+ 0xcb, 0x00, /* vsize hi (input) */
+ 0xcc, 0xd0, /* hsize low (output), 0x02d0 = 720 */
+ 0xcd, 0x02, /* hsize hi (output) */
+
+ 0xf0, 0xad, /* Set PLL Register. 60hz 525 lines per frame, 27 MHz */
+ 0xf1, 0x05, /* low bit with 0xF0 */
+ 0xf5, 0xad, /* Set pulse generator register */
+ 0xf6, 0x01,
+
+ 0x87, 0x00, /* Disable I-port output */
+ 0x88, 0xd0, /* reset scaler */
+ 0x80, 0x20, /* Activate only task "B", continuous mode (was 0xA0) */
+ 0x88, 0xf0, /* activate scaler */
+ 0x87, 0x01, /* Enable I-port output */
+ 0x00, 0x00
+};
+
+static const unsigned char saa7115_cfg_50hz_fullres_x[] = {
+ 0xcc, 0xd0, /* hsize low (output), 720 same as 60hz */
+ 0xcd, 0x02, /* hsize hi (output) */
+
+ 0xd0, 0x01, /* down scale = 1 */
+ 0xd8, 0x00, /* hor lum scaling 0x0400 = 1 */
+ 0xd9, 0x04,
+ 0xdc, 0x00, /* hor chrom scaling 0x0200. must be hor lum scaling / 2 */
+ 0xdd, 0x02, /* H-scaling incr chroma */
+
+ 0x00, 0x00
+};
+static const unsigned char saa7115_cfg_50hz_fullres_y[] = {
+ 0xce, 0x20, /* vsize low (output), 0x0120 = 288 */
+ 0xcf, 0x01, /* vsize hi (output) */
+
+ 0xd5, 0x40, /* Lum contrast, nominal value = 0x40 */
+ 0xd6, 0x40, /* Chroma satur. nominal value = 0x80 */
+
+ 0xe0, 0x00, /* V-scaling incr luma low */
+ 0xe1, 0x04, /* " hi */
+ 0xe2, 0x00, /* V-scaling incr chroma low */
+ 0xe3, 0x04, /* " hi */
+
+ 0x00, 0x00
+};
+
+static const unsigned char saa7115_cfg_50hz_video[] = {
+ 0x80, 0x00, /* reset tasks */
+ 0x88, 0xd0, /* reset scaler */
+
+ 0x15, 0x37, /* VGATE start */
+ 0x16, 0x16, /* VGATE stop */
+ 0x17, 0x99, /* VGATE MSB and other values */
+
+ 0x08, 0x28, /* 0x28 = PAL */
+ 0x0e, 0x07, /* chrominance control 1 */
+
+ 0x5a, 0x03, /* Vertical offset, standard 50hz value */
+
+ /* Task A */
+ 0x90, 0x81, /* Task Handling Control */
+ 0x91, 0x48, /* X-port formats/config */
+ 0x92, 0x40, /* Input Ref. signal Def. */
+ 0x93, 0x84, /* I-port config */
+ /* This is weird: the datasheet says that you should use 2 as the minimum value, */
+ /* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */
+ 0x94, 0x00, /* hoffset low (input), 0x0002 is minimum */
+ 0x95, 0x00, /* hoffset hi (input) */
+ 0x96, 0xd0, /* hsize low (input), 0x02d0 = 720 */
+ 0x97, 0x02, /* hsize hi (input) */
+ 0x98, 0x03, /* voffset low (input) */
+ 0x99, 0x00, /* voffset hi (input) */
+ 0x9a, 0x12, /* vsize low (input), 0x12 = 18 */
+ 0x9b, 0x00, /* vsize hi (input) */
+ 0x9c, 0xa0, /* hsize low (output), 0x05a0 = 1440 */
+ 0x9d, 0x05, /* hsize hi (output) */
+ 0x9e, 0x12, /* vsize low (output), 0x12 = 18 */
+ 0x9f, 0x00, /* vsize hi (output) */
+
+ /* Task B */
+ 0xc0, 0x00, /* Task Handling Control */
+ 0xc1, 0x08, /* X-port formats/config */
+ 0xc2, 0x00, /* Input Ref. signal Def. */
+ 0xc3, 0x80, /* I-port config */
+ 0xc4, 0x00, /* hoffset low (input), 0x0002 is minimum. See comment at 0x94 above. */
+ 0xc5, 0x00, /* hoffset hi (input) */
+ 0xc6, 0xd0, /* hsize low (input), 0x02d0 = 720 */
+ 0xc7, 0x02, /* hsize hi (input) */
+ 0xc8, 0x16, /* voffset low (input), 0x16 = 22 */
+ 0xc9, 0x00, /* voffset hi (input) */
+ 0xca, 0x20, /* vsize low (input), 0x0120 = 288 */
+ 0xcb, 0x01, /* vsize hi (input) */
+ 0xcc, 0xd0, /* hsize low (output), 0x02d0 = 720 */
+ 0xcd, 0x02, /* hsize hi (output) */
+ 0xce, 0x20, /* vsize low (output), 0x0120 = 288 */
+ 0xcf, 0x01, /* vsize hi (output) */
+
+ 0xf0, 0xb0, /* Set PLL Register. 50hz 625 lines per frame, 27 MHz */
+ 0xf1, 0x05, /* low bit with 0xF0, (was 0x05) */
+ 0xf5, 0xb0, /* Set pulse generator register */
+ 0xf6, 0x01,
+
+ 0x87, 0x00, /* Disable I-port output */
+ 0x88, 0xd0, /* reset scaler (was 0xD0) */
+ 0x80, 0x20, /* Activate only task "B" */
+ 0x88, 0xf0, /* activate scaler */
+ 0x87, 0x01, /* Enable I-port output */
+ 0x00, 0x00
+};
+
+/* ============== SAA7715 VIDEO templates (end) ======= */
+
+static const unsigned char saa7115_cfg_vbi_on[] = {
+ 0x80, 0x00, /* reset tasks */
+ 0x88, 0xd0, /* reset scaler */
+ 0x80, 0x30, /* Activate both tasks */
+ 0x88, 0xf0, /* activate scaler */
+ 0x87, 0x01, /* Enable I-port output */
+ 0x00, 0x00
+};
+
+static const unsigned char saa7115_cfg_vbi_off[] = {
+ 0x80, 0x00, /* reset tasks */
+ 0x88, 0xd0, /* reset scaler */
+ 0x80, 0x20, /* Activate only task "B" */
+ 0x88, 0xf0, /* activate scaler */
+ 0x87, 0x01, /* Enable I-port output */
+ 0x00, 0x00
+};
+
+static const unsigned char saa7115_init_misc[] = {
+ 0x38, 0x03, /* audio stuff */
+ 0x39, 0x10,
+ 0x3a, 0x08,
+
+ 0x81, 0x01, /* reg 0x15,0x16 define blanking window */
+ 0x82, 0x00,
+ 0x83, 0x01, /* I port settings */
+ 0x84, 0x20,
+ 0x85, 0x21,
+ 0x86, 0xc5,
+ 0x87, 0x01,
+
+ /* Task A */
+ 0xa0, 0x01, /* down scale = 1 */
+ 0xa1, 0x00, /* prescale accumulation length = 1 */
+ 0xa2, 0x00, /* dc gain and fir prefilter control */
+ 0xa4, 0x80, /* Lum Brightness, nominal value = 0x80 */
+ 0xa5, 0x40, /* Lum contrast, nominal value = 0x40 */
+ 0xa6, 0x40, /* Chroma satur. nominal value = 0x80 */
+ 0xa8, 0x00, /* hor lum scaling 0x0200 = 2 zoom */
+ 0xa9, 0x02, /* note: 2 x zoom ensures that VBI lines have same length as video lines. */
+ 0xaa, 0x00, /* H-phase offset Luma = 0 */
+ 0xac, 0x00, /* hor chrom scaling 0x0200. must be hor lum scaling / 2 */
+ 0xad, 0x01, /* H-scaling incr chroma */
+ 0xae, 0x00, /* H-phase offset chroma. must be offset luma / 2 */
+
+ 0xb0, 0x00, /* V-scaling incr luma low */
+ 0xb1, 0x04, /* " hi */
+ 0xb2, 0x00, /* V-scaling incr chroma low */
+ 0xb3, 0x04, /* " hi */
+ 0xb4, 0x01, /* V-scaling mode control */
+ 0xb8, 0x00, /* V-phase offset chroma 00 */
+ 0xb9, 0x00, /* V-phase offset chroma 01 */
+ 0xba, 0x00, /* V-phase offset chroma 10 */
+ 0xbb, 0x00, /* V-phase offset chroma 11 */
+ 0xbc, 0x00, /* V-phase offset luma 00 */
+ 0xbd, 0x00, /* V-phase offset luma 01 */
+ 0xbe, 0x00, /* V-phase offset luma 10 */
+ 0xbf, 0x00, /* V-phase offset luma 11 */
+
+ /* Task B */
+ 0xd0, 0x01, /* down scale = 1 */
+ 0xd1, 0x00, /* prescale accumulation length = 1 */
+ 0xd2, 0x00, /* dc gain and fir prefilter control */
+ 0xd4, 0x80, /* Lum Brightness, nominal value = 0x80 */
+ 0xd5, 0x40, /* Lum contrast, nominal value = 0x40 */
+ 0xd6, 0x40, /* Chroma satur. nominal value = 0x80 */
+ 0xd8, 0x00, /* hor lum scaling 0x0400 = 1 */
+ 0xd9, 0x04,
+ 0xda, 0x00, /* H-phase offset Luma = 0 */
+ 0xdc, 0x00, /* hor chrom scaling 0x0200. must be hor lum scaling / 2 */
+ 0xdd, 0x02, /* H-scaling incr chroma */
+ 0xde, 0x00, /* H-phase offset chroma. must be offset luma / 2 */
+
+ 0xe0, 0x00, /* V-scaling incr luma low */
+ 0xe1, 0x04, /* " hi */
+ 0xe2, 0x00, /* V-scaling incr chroma low */
+ 0xe3, 0x04, /* " hi */
+ 0xe4, 0x01, /* V-scaling mode control */
+ 0xe8, 0x00, /* V-phase offset chroma 00 */
+ 0xe9, 0x00, /* V-phase offset chroma 01 */
+ 0xea, 0x00, /* V-phase offset chroma 10 */
+ 0xeb, 0x00, /* V-phase offset chroma 11 */
+ 0xec, 0x00, /* V-phase offset luma 00 */
+ 0xed, 0x00, /* V-phase offset luma 01 */
+ 0xee, 0x00, /* V-phase offset luma 10 */
+ 0xef, 0x00, /* V-phase offset luma 11 */
+
+ 0xf2, 0x50, /* crystal clock = 24.576 MHz, target = 27MHz */
+ 0xf3, 0x46,
+ 0xf4, 0x00,
+ 0xf7, 0x4b, /* not the recommended settings! */
+ 0xf8, 0x00,
+ 0xf9, 0x4b,
+ 0xfa, 0x00,
+ 0xfb, 0x4b,
+ 0xff, 0x88, /* PLL2 lock detection settings: 71 lines 50% phase error */
+
+ /* Turn off VBI */
+ 0x40, 0x20, /* No framing code errors allowed. */
+ 0x41, 0xff,
+ 0x42, 0xff,
+ 0x43, 0xff,
+ 0x44, 0xff,
+ 0x45, 0xff,
+ 0x46, 0xff,
+ 0x47, 0xff,
+ 0x48, 0xff,
+ 0x49, 0xff,
+ 0x4a, 0xff,
+ 0x4b, 0xff,
+ 0x4c, 0xff,
+ 0x4d, 0xff,
+ 0x4e, 0xff,
+ 0x4f, 0xff,
+ 0x50, 0xff,
+ 0x51, 0xff,
+ 0x52, 0xff,
+ 0x53, 0xff,
+ 0x54, 0xff,
+ 0x55, 0xff,
+ 0x56, 0xff,
+ 0x57, 0xff,
+ 0x58, 0x40,
+ 0x59, 0x47,
+ 0x5b, 0x83,
+ 0x5d, 0xbd,
+ 0x5e, 0x35,
+
+ 0x02, 0x84, /* input tuner -> input 4, amplifier active */
+ 0x09, 0x53, /* 0x53, was 0x56 for 60hz. luminance control */
+
+ 0x80, 0x20, /* enable task B */
+ 0x88, 0xd0,
+ 0x88, 0xf0,
+ 0x00, 0x00
+};
+
+/* ============== SAA7715 AUDIO settings ============= */
+
+/* 48.0 kHz */
+static const unsigned char saa7115_cfg_48_audio[] = {
+ 0x34, 0xce,
+ 0x35, 0xfb,
+ 0x36, 0x30,
+ 0x00, 0x00
+};
+
+/* 44.1 kHz */
+static const unsigned char saa7115_cfg_441_audio[] = {
+ 0x34, 0xf2,
+ 0x35, 0x00,
+ 0x36, 0x2d,
+ 0x00, 0x00
+};
+
+/* 32.0 kHz */
+static const unsigned char saa7115_cfg_32_audio[] = {
+ 0x34, 0xdf,
+ 0x35, 0xa7,
+ 0x36, 0x20,
+ 0x00, 0x00
+};
+
+/* 48.0 kHz 60hz */
+static const unsigned char saa7115_cfg_60hz_48_audio[] = {
+ 0x30, 0xcd,
+ 0x31, 0x20,
+ 0x32, 0x03,
+ 0x00, 0x00
+};
+
+/* 48.0 kHz 50hz */
+static const unsigned char saa7115_cfg_50hz_48_audio[] = {
+ 0x30, 0x00,
+ 0x31, 0xc0,
+ 0x32, 0x03,
+ 0x00, 0x00
+};
+
+/* 44.1 kHz 60hz */
+static const unsigned char saa7115_cfg_60hz_441_audio[] = {
+ 0x30, 0xbc,
+ 0x31, 0xdf,
+ 0x32, 0x02,
+ 0x00, 0x00
+};
+
+/* 44.1 kHz 50hz */
+static const unsigned char saa7115_cfg_50hz_441_audio[] = {
+ 0x30, 0x00,
+ 0x31, 0x72,
+ 0x32, 0x03,
+ 0x00, 0x00
+};
+
+/* 32.0 kHz 60hz */
+static const unsigned char saa7115_cfg_60hz_32_audio[] = {
+ 0x30, 0xde,
+ 0x31, 0x15,
+ 0x32, 0x02,
+ 0x00, 0x00
+};
+
+/* 32.0 kHz 50hz */
+static const unsigned char saa7115_cfg_50hz_32_audio[] = {
+ 0x30, 0x00,
+ 0x31, 0x80,
+ 0x32, 0x02,
+ 0x00, 0x00
+};
+
+static int saa7115_odd_parity(u8 c)
+{
+ c ^= (c >> 4);
+ c ^= (c >> 2);
+ c ^= (c >> 1);
+
+ return c & 1;
+}
+
+static int saa7115_decode_vps(u8 * dst, u8 * p)
+{
+ static const u8 biphase_tbl[] = {
+ 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+ 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+ 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
+ 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
+ 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
+ 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
+ 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+ 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+ 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
+ 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
+ 0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87,
+ 0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3,
+ 0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85,
+ 0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1,
+ 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
+ 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
+ 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
+ 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
+ 0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86,
+ 0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2,
+ 0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84,
+ 0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0,
+ 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
+ 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
+ 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+ 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+ 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
+ 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
+ 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
+ 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
+ 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+ 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+ };
+ int i;
+ u8 c, err = 0;
+
+ for (i = 0; i < 2 * 13; i += 2) {
+ err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]];
+ c = (biphase_tbl[p[i + 1]] & 0xf) | ((biphase_tbl[p[i]] & 0xf) << 4);
+ dst[i / 2] = c;
+ }
+ return err & 0xf0;
+}
+
+static int saa7115_decode_wss(u8 * p)
+{
+ static const int wss_bits[8] = {
+ 0, 0, 0, 1, 0, 1, 1, 1
+ };
+ unsigned char parity;
+ int wss = 0;
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ int b1 = wss_bits[p[i] & 7];
+ int b2 = wss_bits[(p[i] >> 3) & 7];
+
+ if (b1 == b2)
+ return -1;
+ wss |= b2 << i;
+ }
+ parity = wss & 15;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+
+ if (!(parity & 1))
+ return -1;
+
+ return wss;
+}
+
+
+static int saa7115_set_audio_clock_freq(struct i2c_client *client, enum v4l2_audio_clock_freq freq)
+{
+ struct saa7115_state *state = i2c_get_clientdata(client);
+
+ saa7115_dbg("set audio clock freq: %d\n", freq);
+ switch (freq) {
+ case V4L2_AUDCLK_32_KHZ:
+ saa7115_writeregs(client, saa7115_cfg_32_audio);
+ if (state->std & V4L2_STD_525_60) {
+ saa7115_writeregs(client, saa7115_cfg_60hz_32_audio);
+ } else {
+ saa7115_writeregs(client, saa7115_cfg_50hz_32_audio);
+ }
+ break;
+ case V4L2_AUDCLK_441_KHZ:
+ saa7115_writeregs(client, saa7115_cfg_441_audio);
+ if (state->std & V4L2_STD_525_60) {
+ saa7115_writeregs(client, saa7115_cfg_60hz_441_audio);
+ } else {
+ saa7115_writeregs(client, saa7115_cfg_50hz_441_audio);
+ }
+ break;
+ case V4L2_AUDCLK_48_KHZ:
+ saa7115_writeregs(client, saa7115_cfg_48_audio);
+ if (state->std & V4L2_STD_525_60) {
+ saa7115_writeregs(client, saa7115_cfg_60hz_48_audio);
+ } else {
+ saa7115_writeregs(client, saa7115_cfg_50hz_48_audio);
+ }
+ break;
+ default:
+ saa7115_dbg("invalid audio setting %d\n", freq);
+ return -EINVAL;
+ }
+ state->audclk_freq = freq;
+ return 0;
+}
+
+static int saa7115_set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+{
+ struct saa7115_state *state = i2c_get_clientdata(client);
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ if (ctrl->value < 0 || ctrl->value > 255) {
+ saa7115_err("invalid brightness setting %d\n", ctrl->value);
+ return -ERANGE;
+ }
+
+ state->bright = ctrl->value;
+ saa7115_write(client, 0x0a, state->bright);
+ break;
+
+ case V4L2_CID_CONTRAST:
+ if (ctrl->value < 0 || ctrl->value > 127) {
+ saa7115_err("invalid contrast setting %d\n", ctrl->value);
+ return -ERANGE;
+ }
+
+ state->contrast = ctrl->value;
+ saa7115_write(client, 0x0b, state->contrast);
+ break;
+
+ case V4L2_CID_SATURATION:
+ if (ctrl->value < 0 || ctrl->value > 127) {
+ saa7115_err("invalid saturation setting %d\n", ctrl->value);
+ return -ERANGE;
+ }
+
+ state->sat = ctrl->value;
+ saa7115_write(client, 0x0c, state->sat);
+ break;
+
+ case V4L2_CID_HUE:
+ if (ctrl->value < -127 || ctrl->value > 127) {
+ saa7115_err("invalid hue setting %d\n", ctrl->value);
+ return -ERANGE;
+ }
+
+ state->hue = ctrl->value;
+ saa7115_write(client, 0x0d, state->hue);
+ break;
+ }
+
+ return 0;
+}
+
+static int saa7115_get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+{
+ struct saa7115_state *state = i2c_get_clientdata(client);
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ctrl->value = state->bright;
+ break;
+ case V4L2_CID_CONTRAST:
+ ctrl->value = state->contrast;
+ break;
+ case V4L2_CID_SATURATION:
+ ctrl->value = state->sat;
+ break;
+ case V4L2_CID_HUE:
+ ctrl->value = state->hue;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void saa7115_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
+{
+ struct saa7115_state *state = i2c_get_clientdata(client);
+ int taskb = saa7115_read(client, 0x80) & 0x10;
+
+ // This works for NTSC-M, SECAM-L and the 50Hz PAL variants.
+ if (std & V4L2_STD_525_60) {
+ saa7115_dbg("decoder set standard 60 Hz\n");
+ saa7115_writeregs(client, saa7115_cfg_60hz_video);
+ } else {
+ saa7115_dbg("decoder set standard 50 Hz\n");
+ saa7115_writeregs(client, saa7115_cfg_50hz_video);
+ }
+
+ state->std = std;
+
+ /* restart task B if needed */
+ if (taskb && state->ident == V4L2_IDENT_SAA7114) {
+ saa7115_writeregs(client, saa7115_cfg_vbi_on);
+ }
+
+ /* switch audio mode too! */
+ saa7115_set_audio_clock_freq(client, state->audclk_freq);
+}
+
+static v4l2_std_id saa7115_get_v4lstd(struct i2c_client *client)
+{
+ struct saa7115_state *state = i2c_get_clientdata(client);
+
+ return state->std;
+}
+
+static void saa7115_log_status(struct i2c_client *client)
+{
+ static const char * const audclk_freq_strs[] = {
+ "44.1 kHz",
+ "48 kHz",
+ "32 kHz"
+ };
+ struct saa7115_state *state = i2c_get_clientdata(client);
+ int reg1e, reg1f;
+ int signalOk;
+ int vcr;
+
+ saa7115_info("Audio frequency: %s\n", audclk_freq_strs[state->audclk_freq]);
+ if (client->name[6] == '4') {
+ /* status for the saa7114 */
+ reg1f = saa7115_read(client, 0x1f);
+ signalOk = (reg1f & 0xc1) == 0x81;
+ saa7115_info("Video signal: %s\n", signalOk ? "ok" : "bad");
+ saa7115_info("Frequency: %s\n", (reg1f & 0x20) ? "60Hz" : "50Hz");
+ return;
+ }
+
+ /* status for the saa7115 */
+ reg1e = saa7115_read(client, 0x1e);
+ reg1f = saa7115_read(client, 0x1f);
+
+ signalOk = (reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80;
+ vcr = !(reg1f & 0x10);
+
+ saa7115_info("Video signal: %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad");
+ saa7115_info("Frequency: %s\n", (reg1f & 0x20) ? "60Hz" : "50Hz");
+
+ switch (reg1e & 0x03) {
+ case 1:
+ saa7115_info("Detected format: NTSC\n");
+ break;
+ case 2:
+ saa7115_info("Detected format: PAL\n");
+ break;
+ case 3:
+ saa7115_info("Detected format: SECAM\n");
+ break;
+ default:
+ saa7115_info("Detected format: BW/No color\n");
+ break;
+ }
+}
+
+/* setup the sliced VBI lcr registers according to the sliced VBI format */
+static void saa7115_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_format *fmt)
+{
+ struct saa7115_state *state = i2c_get_clientdata(client);
+ int is_50hz = (state->std & V4L2_STD_625_50);
+ u8 lcr[24];
+ int i, x;
+
+ /* saa7114 doesn't yet support VBI */
+ if (state->ident == V4L2_IDENT_SAA7114)
+ return;
+
+ for (i = 0; i <= 23; i++)
+ lcr[i] = 0xff;
+
+ if (fmt->service_set == 0) {
+ /* raw VBI */
+ if (is_50hz)
+ for (i = 6; i <= 23; i++)
+ lcr[i] = 0xdd;
+ else
+ for (i = 10; i <= 21; i++)
+ lcr[i] = 0xdd;
+ } else {
+ /* sliced VBI */
+ /* first clear lines that cannot be captured */
+ if (is_50hz) {
+ for (i = 0; i <= 5; i++)
+ fmt->service_lines[0][i] =
+ fmt->service_lines[1][i] = 0;
+ }
+ else {
+ for (i = 0; i <= 9; i++)
+ fmt->service_lines[0][i] =
+ fmt->service_lines[1][i] = 0;
+ for (i = 22; i <= 23; i++)
+ fmt->service_lines[0][i] =
+ fmt->service_lines[1][i] = 0;
+ }
+
+ /* Now set the lcr values according to the specified service */
+ for (i = 6; i <= 23; i++) {
+ lcr[i] = 0;
+ for (x = 0; x <= 1; x++) {
+ switch (fmt->service_lines[1-x][i]) {
+ case 0:
+ lcr[i] |= 0xf << (4 * x);
+ break;
+ case V4L2_SLICED_TELETEXT_B:
+ lcr[i] |= 1 << (4 * x);
+ break;
+ case V4L2_SLICED_CAPTION_525:
+ lcr[i] |= 4 << (4 * x);
+ break;
+ case V4L2_SLICED_WSS_625:
+ lcr[i] |= 5 << (4 * x);
+ break;
+ case V4L2_SLICED_VPS:
+ lcr[i] |= 7 << (4 * x);
+ break;
+ }
+ }
+ }
+ }
+
+ /* write the lcr registers */
+ for (i = 2; i <= 23; i++) {
+ saa7115_write(client, i - 2 + 0x41, lcr[i]);
+ }
+
+ /* enable/disable raw VBI capturing */
+ saa7115_writeregs(client, fmt->service_set == 0 ? saa7115_cfg_vbi_on : saa7115_cfg_vbi_off);
+}
+
+static int saa7115_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
+{
+ static u16 lcr2vbi[] = {
+ 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */
+ 0, V4L2_SLICED_CAPTION_525, /* 4 */
+ V4L2_SLICED_WSS_625, 0, /* 5 */
+ V4L2_SLICED_VPS, 0, 0, 0, 0, /* 7 */
+ 0, 0, 0, 0
+ };
+ struct v4l2_sliced_vbi_format *sliced = &fmt->fmt.sliced;
+ int i;
+
+ if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+ return -EINVAL;
+ memset(sliced, 0, sizeof(*sliced));
+ /* done if using raw VBI */
+ if (saa7115_read(client, 0x80) & 0x10)
+ return 0;
+ for (i = 2; i <= 23; i++) {
+ u8 v = saa7115_read(client, i - 2 + 0x41);
+
+ sliced->service_lines[0][i] = lcr2vbi[v >> 4];
+ sliced->service_lines[1][i] = lcr2vbi[v & 0xf];
+ sliced->service_set |=
+ sliced->service_lines[0][i] | sliced->service_lines[1][i];
+ }
+ return 0;
+}
+
+static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
+{
+ struct saa7115_state *state = i2c_get_clientdata(client);
+ struct v4l2_pix_format *pix;
+ int HPSC, HFSC;
+ int VSCY, Vsrc;
+ int is_50hz = state->std & V4L2_STD_625_50;
+
+ if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
+ saa7115_set_lcr(client, &fmt->fmt.sliced);
+ return 0;
+ }
+ if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ pix = &(fmt->fmt.pix);
+
+ saa7115_dbg("decoder set size\n");
+
+ /* FIXME need better bounds checking here */
+ if ((pix->width < 1) || (pix->width > 1440))
+ return -EINVAL;
+ if ((pix->height < 1) || (pix->height > 960))
+ return -EINVAL;
+
+ /* probably have a valid size, let's set it */
+ /* Set output width/height */
+ /* width */
+ saa7115_write(client, 0xcc, (u8) (pix->width & 0xff));
+ saa7115_write(client, 0xcd, (u8) ((pix->width >> 8) & 0xff));
+ /* height */
+ saa7115_write(client, 0xce, (u8) (pix->height & 0xff));
+ saa7115_write(client, 0xcf, (u8) ((pix->height >> 8) & 0xff));
+
+ /* Scaling settings */
+ /* Hprescaler is floor(inres/outres) */
+ /* FIXME hardcoding input res */
+ if (pix->width != 720) {
+ HPSC = (int)(720 / pix->width);
+ /* 0 is not allowed (div. by zero) */
+ HPSC = HPSC ? HPSC : 1;
+ HFSC = (int)((1024 * 720) / (HPSC * pix->width));
+
+ saa7115_dbg("Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);
+ /* FIXME hardcodes to "Task B"
+ * write H prescaler integer */
+ saa7115_write(client, 0xd0, (u8) (HPSC & 0x3f));
+
+ /* write H fine-scaling (luminance) */
+ saa7115_write(client, 0xd8, (u8) (HFSC & 0xff));
+ saa7115_write(client, 0xd9, (u8) ((HFSC >> 8) & 0xff));
+ /* write H fine-scaling (chrominance)
+ * must be lum/2, so i'll just bitshift :) */
+ saa7115_write(client, 0xDC, (u8) ((HFSC >> 1) & 0xff));
+ saa7115_write(client, 0xDD, (u8) ((HFSC >> 9) & 0xff));
+ } else {
+ if (is_50hz) {
+ saa7115_dbg("Setting full 50hz width\n");
+ saa7115_writeregs(client, saa7115_cfg_50hz_fullres_x);
+ } else {
+ saa7115_dbg("Setting full 60hz width\n");
+ saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);
+ }
+ }
+
+ Vsrc = is_50hz ? 576 : 480;
+
+ if (pix->height != Vsrc) {
+ VSCY = (int)((1024 * Vsrc) / pix->height);
+ saa7115_dbg("Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
+
+ /* Correct Contrast and Luminance */
+ saa7115_write(client, 0xd5, (u8) (64 * 1024 / VSCY));
+ saa7115_write(client, 0xd6, (u8) (64 * 1024 / VSCY));
+
+ /* write V fine-scaling (luminance) */
+ saa7115_write(client, 0xe0, (u8) (VSCY & 0xff));
+ saa7115_write(client, 0xe1, (u8) ((VSCY >> 8) & 0xff));
+ /* write V fine-scaling (chrominance) */
+ saa7115_write(client, 0xe2, (u8) (VSCY & 0xff));
+ saa7115_write(client, 0xe3, (u8) ((VSCY >> 8) & 0xff));
+ } else {
+ if (is_50hz) {
+ saa7115_dbg("Setting full 50Hz height\n");
+ saa7115_writeregs(client, saa7115_cfg_50hz_fullres_y);
+ } else {
+ saa7115_dbg("Setting full 60hz height\n");
+ saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
+ }
+ }
+
+ saa7115_writeregs(client, saa7115_cfg_reset_scaler);
+ return 0;
+}
+
+/* Decode the sliced VBI data stream as created by the saa7115.
+ The format is described in the saa7115 datasheet in Tables 25 and 26
+ and in Figure 33.
+ The current implementation uses SAV/EAV codes and not the ancillary data
+ headers. The vbi->p pointer points to the SDID byte right after the SAV
+ code. */
+static void saa7115_decode_vbi_line(struct i2c_client *client,
+ struct v4l2_decode_vbi_line *vbi)
+{
+ static const char vbi_no_data_pattern[] = {
+ 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0
+ };
+ struct saa7115_state *state = i2c_get_clientdata(client);
+ u8 *p = vbi->p;
+ u32 wss;
+ int id1, id2; /* the ID1 and ID2 bytes from the internal header */
+
+ vbi->type = 0; /* mark result as a failure */
+ id1 = p[2];
+ id2 = p[3];
+ /* Note: the field bit is inverted for 60 Hz video */
+ if (state->std & V4L2_STD_525_60)
+ id1 ^= 0x40;
+
+ /* Skip internal header, p now points to the start of the payload */
+ p += 4;
+ vbi->p = p;
+
+ /* calculate field and line number of the VBI packet (1-23) */
+ vbi->is_second_field = ((id1 & 0x40) != 0);
+ vbi->line = (id1 & 0x3f) << 3;
+ vbi->line |= (id2 & 0x70) >> 4;
+
+ /* Obtain data type */
+ id2 &= 0xf;
+
+ /* If the VBI slicer does not detect any signal it will fill up
+ the payload buffer with 0xa0 bytes. */
+ if (!memcmp(p, vbi_no_data_pattern, sizeof(vbi_no_data_pattern)))
+ return;
+
+ /* decode payloads */
+ switch (id2) {
+ case 1:
+ vbi->type = V4L2_SLICED_TELETEXT_B;
+ break;
+ case 4:
+ if (!saa7115_odd_parity(p[0]) || !saa7115_odd_parity(p[1]))
+ return;
+ vbi->type = V4L2_SLICED_CAPTION_525;
+ break;
+ case 5:
+ wss = saa7115_decode_wss(p);
+ if (wss == -1)
+ return;
+ p[0] = wss & 0xff;
+ p[1] = wss >> 8;
+ vbi->type = V4L2_SLICED_WSS_625;
+ break;
+ case 7:
+ if (saa7115_decode_vps(p, p) != 0)
+ return;
+ vbi->type = V4L2_SLICED_VPS;
+ break;
+ default:
+ return;
+ }
+}
+
+/* ============ SAA7115 AUDIO settings (end) ============= */
+
+static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+ struct saa7115_state *state = i2c_get_clientdata(client);
+ int *iarg = arg;
+
+ /* ioctls to allow direct access to the saa7115 registers for testing */
+ switch (cmd) {
+ case VIDIOC_S_FMT:
+ return saa7115_set_v4lfmt(client, (struct v4l2_format *)arg);
+
+ case VIDIOC_G_FMT:
+ return saa7115_get_v4lfmt(client, (struct v4l2_format *)arg);
+
+ case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+ return saa7115_set_audio_clock_freq(client, *(enum v4l2_audio_clock_freq *)arg);
+
+ case VIDIOC_G_TUNER:
+ {
+ struct v4l2_tuner *vt = arg;
+ int status;
+
+ status = saa7115_read(client, 0x1f);
+
+ saa7115_dbg("status: 0x%02x\n", status);
+ vt->signal = ((status & (1 << 6)) == 0) ? 0xffff : 0x0;
+ break;
+ }
+
+ case VIDIOC_LOG_STATUS:
+ saa7115_log_status(client);
+ break;
+
+ case VIDIOC_G_CTRL:
+ return saa7115_get_v4lctrl(client, (struct v4l2_control *)arg);
+
+ case VIDIOC_S_CTRL:
+ return saa7115_set_v4lctrl(client, (struct v4l2_control *)arg);
+
+ case VIDIOC_G_STD:
+ *(v4l2_std_id *)arg = saa7115_get_v4lstd(client);
+ break;
+
+ case VIDIOC_S_STD:
+ saa7115_set_v4lstd(client, *(v4l2_std_id *)arg);
+ break;
+
+ case VIDIOC_G_INPUT:
+ *(int *)arg = state->input;
+ break;
+
+ case VIDIOC_S_INPUT:
+ saa7115_dbg("decoder set input %d\n", *iarg);
+ /* inputs from 0-9 are available */
+ if (*iarg < 0 || *iarg > 9) {
+ return -EINVAL;
+ }
+
+ if (state->input == *iarg)
+ break;
+ saa7115_dbg("now setting %s input\n",
+ *iarg >= 6 ? "S-Video" : "Composite");
+ state->input = *iarg;
+
+ /* select mode */
+ saa7115_write(client, 0x02,
+ (saa7115_read(client, 0x02) & 0xf0) |
+ state->input);
+
+ /* bypass chrominance trap for modes 6..9 */
+ saa7115_write(client, 0x09,
+ (saa7115_read(client, 0x09) & 0x7f) |
+ (state->input < 6 ? 0x0 : 0x80));
+ break;
+
+ case VIDIOC_STREAMON:
+ case VIDIOC_STREAMOFF:
+ saa7115_dbg("%s output\n",
+ (cmd == VIDIOC_STREAMON) ? "enable" : "disable");
+
+ if (state->enable != (cmd == VIDIOC_STREAMON)) {
+ state->enable = (cmd == VIDIOC_STREAMON);
+ saa7115_write(client, 0x87, state->enable);
+ }
+ break;
+
+ case VIDIOC_INT_DECODE_VBI_LINE:
+ saa7115_decode_vbi_line(client, arg);
+ break;
+
+ case VIDIOC_INT_RESET:
+ saa7115_dbg("decoder RESET\n");
+ saa7115_writeregs(client, saa7115_cfg_reset_scaler);
+ break;
+
+ case VIDIOC_INT_G_VBI_DATA:
+ {
+ struct v4l2_sliced_vbi_data *data = arg;
+
+ switch (data->id) {
+ case V4L2_SLICED_WSS_625:
+ if (saa7115_read(client, 0x6b) & 0xc0)
+ return -EIO;
+ data->data[0] = saa7115_read(client, 0x6c);
+ data->data[1] = saa7115_read(client, 0x6d);
+ return 0;
+ case V4L2_SLICED_CAPTION_525:
+ if (data->field == 0) {
+ /* CC */
+ if (saa7115_read(client, 0x66) & 0xc0)
+ return -EIO;
+ data->data[0] = saa7115_read(client, 0x67);
+ data->data[1] = saa7115_read(client, 0x68);
+ return 0;
+ }
+ /* XDS */
+ if (saa7115_read(client, 0x66) & 0x30)
+ return -EIO;
+ data->data[0] = saa7115_read(client, 0x69);
+ data->data[1] = saa7115_read(client, 0x6a);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+ break;
+ }
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ case VIDIOC_INT_G_REGISTER:
+ {
+ struct v4l2_register *reg = arg;
+
+ if (reg->i2c_id != I2C_DRIVERID_SAA711X)
+ return -EINVAL;
+ reg->val = saa7115_read(client, reg->reg & 0xff);
+ break;
+ }
+
+ case VIDIOC_INT_S_REGISTER:
+ {
+ struct v4l2_register *reg = arg;
+
+ if (reg->i2c_id != I2C_DRIVERID_SAA711X)
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ saa7115_write(client, reg->reg & 0xff, reg->val & 0xff);
+ break;
+ }
+#endif
+
+ case VIDIOC_INT_G_CHIP_IDENT:
+ *iarg = state->ident;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_driver i2c_driver_saa7115;
+
+static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct i2c_client *client;
+ struct saa7115_state *state;
+ u8 chip_id;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return 0;
+
+ client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (client == 0)
+ return -ENOMEM;
+ memset(client, 0, sizeof(struct i2c_client));
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &i2c_driver_saa7115;
+ client->flags = I2C_CLIENT_ALLOW_USE;
+ snprintf(client->name, sizeof(client->name) - 1, "saa7115");
+
+ saa7115_dbg("detecting saa7115 client on address 0x%x\n", address << 1);
+
+ saa7115_write(client, 0, 5);
+ chip_id = saa7115_read(client, 0) & 0x0f;
+ if (chip_id != 4 && chip_id != 5) {
+ saa7115_dbg("saa7115 not found\n");
+ kfree(client);
+ return 0;
+ }
+ if (chip_id == 4) {
+ snprintf(client->name, sizeof(client->name) - 1, "saa7114");
+ }
+ saa7115_info("saa711%d found @ 0x%x (%s)\n", chip_id, address << 1, adapter->name);
+
+ state = kmalloc(sizeof(struct saa7115_state), GFP_KERNEL);
+ i2c_set_clientdata(client, state);
+ if (state == NULL) {
+ kfree(client);
+ return -ENOMEM;
+ }
+ memset(state, 0, sizeof(struct saa7115_state));
+ state->std = V4L2_STD_NTSC;
+ state->input = -1;
+ state->enable = 1;
+ state->bright = 128;
+ state->contrast = 64;
+ state->hue = 0;
+ state->sat = 64;
+ state->ident = (chip_id == 4) ? V4L2_IDENT_SAA7114 : V4L2_IDENT_SAA7115;
+ state->audclk_freq = V4L2_AUDCLK_48_KHZ;
+
+ saa7115_dbg("writing init values\n");
+
+ /* init to 60hz/48khz */
+ saa7115_writeregs(client, saa7115_init_auto_input);
+ saa7115_writeregs(client, saa7115_init_misc);
+ saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);
+ saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
+ saa7115_writeregs(client, saa7115_cfg_60hz_video);
+ saa7115_writeregs(client, saa7115_cfg_48_audio);
+ saa7115_writeregs(client, saa7115_cfg_60hz_48_audio);
+ saa7115_writeregs(client, saa7115_cfg_reset_scaler);
+
+ i2c_attach_client(client);
+
+ saa7115_dbg("status: (1E) 0x%02x, (1F) 0x%02x\n",
+ saa7115_read(client, 0x1e), saa7115_read(client, 0x1f));
+
+ return 0;
+}
+
+static int saa7115_probe(struct i2c_adapter *adapter)
+{
+#ifdef I2C_CLASS_TV_ANALOG
+ if (adapter->class & I2C_CLASS_TV_ANALOG)
+#else
+ if (adapter->id == I2C_HW_B_BT848)
+#endif
+ return i2c_probe(adapter, &addr_data, &saa7115_attach);
+ return 0;
+}
+
+static int saa7115_detach(struct i2c_client *client)
+{
+ struct saa7115_state *state = i2c_get_clientdata(client);
+ int err;
+
+ err = i2c_detach_client(client);
+ if (err) {
+ return err;
+ }
+
+ kfree(state);
+ kfree(client);
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+static struct i2c_driver i2c_driver_saa7115 = {
+ .name = "saa7115",
+ .id = I2C_DRIVERID_SAA711X,
+ .flags = I2C_DF_NOTIFY,
+ .attach_adapter = saa7115_probe,
+ .detach_client = saa7115_detach,
+ .command = saa7115_command,
+ .owner = THIS_MODULE,
+};
+
+
+static int __init saa7115_init_module(void)
+{
+ return i2c_add_driver(&i2c_driver_saa7115);
+}
+
+static void __exit saa7115_cleanup_module(void)
+{
+ i2c_del_driver(&i2c_driver_saa7115);
+}
+
+module_init(saa7115_init_module);
+module_exit(saa7115_cleanup_module);
diff --git a/drivers/media/video/saa711x.c b/drivers/media/video/saa711x.c
new file mode 100644
index 00000000000..25b30f352d8
--- /dev/null
+++ b/drivers/media/video/saa711x.c
@@ -0,0 +1,592 @@
+/*
+ * saa711x - Philips SAA711x video decoder driver version 0.0.1
+ *
+ * To do: Now, it handles only saa7113/7114. Should be improved to
+ * handle all Philips saa711x devices.
+ *
+ * Based on saa7113 driver from Dave Perks <dperks@ibm.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <asm/uaccess.h>
+#include <linux/videodev.h>
+
+MODULE_DESCRIPTION("Philips SAA711x video decoder driver");
+MODULE_AUTHOR("Dave Perks, Jose Ignacio Gijon, Joerg Heckenbach, Mark McClelland, Dwaine Garden");
+MODULE_LICENSE("GPL");
+
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+
+#define I2C_NAME(s) (s)->name
+
+#include <linux/video_decoder.h>
+
+static int debug = 0;
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, " Set the default Debug level. Default: 0 (Off) - (0-1)");
+
+
+#define dprintk(num, format, args...) \
+ do { \
+ if (debug >= num) \
+ printk(format , ##args); \
+ } while (0)
+
+/* ----------------------------------------------------------------------- */
+
+struct saa711x {
+ unsigned char reg[32];
+
+ int norm;
+ int input;
+ int enable;
+ int bright;
+ int contrast;
+ int hue;
+ int sat;
+};
+
+#define I2C_SAA7113 0x4A
+#define I2C_SAA7114 0x42
+
+/* ----------------------------------------------------------------------- */
+
+static inline int
+saa711x_write (struct i2c_client *client,
+ u8 reg,
+ u8 value)
+{
+ struct saa711x *decoder = i2c_get_clientdata(client);
+
+ decoder->reg[reg] = value;
+ return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int
+saa711x_write_block (struct i2c_client *client,
+ const u8 *data,
+ unsigned int len)
+{
+ int ret = -1;
+ u8 reg;
+
+ /* the saa711x has an autoincrement function, use it if
+ * the adapter understands raw I2C */
+ if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ /* do raw I2C, not smbus compatible */
+ struct saa711x *decoder = i2c_get_clientdata(client);
+ struct i2c_msg msg;
+ u8 block_data[32];
+
+ msg.addr = client->addr;
+ msg.flags = 0;
+ while (len >= 2) {
+ msg.buf = (char *) block_data;
+ msg.len = 0;
+ block_data[msg.len++] = reg = data[0];
+ do {
+ block_data[msg.len++] =
+ decoder->reg[reg++] = data[1];
+ len -= 2;
+ data += 2;
+ } while (len >= 2 && data[0] == reg &&
+ msg.len < 32);
+ if ((ret = i2c_transfer(client->adapter,
+ &msg, 1)) < 0)
+ break;
+ }
+ } else {
+ /* do some slow I2C emulation kind of thing */
+ while (len >= 2) {
+ reg = *data++;
+ if ((ret = saa711x_write(client, reg,
+ *data++)) < 0)
+ break;
+ len -= 2;
+ }
+ }
+
+ return ret;
+}
+
+static int
+saa711x_init_decoder (struct i2c_client *client,
+ struct video_decoder_init *init)
+{
+ return saa711x_write_block(client, init->data, init->len);
+}
+
+static inline int
+saa711x_read (struct i2c_client *client,
+ u8 reg)
+{
+ return i2c_smbus_read_byte_data(client, reg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const unsigned char saa711x_i2c_init[] = {
+ 0x00, 0x00, /* PH711x_CHIP_VERSION 00 - ID byte */
+ 0x01, 0x08, /* PH711x_INCREMENT_DELAY - (1) (1) (1) (1) IDEL3 IDEL2 IDELL1 IDEL0 */
+ 0x02, 0xc0, /* PH711x_ANALOG_INPUT_CONTR_1 - FUSE1 FUSE0 GUDL1 GUDL0 MODE3 MODE2 MODE1 MODE0 */
+ 0x03, 0x23, /* PH711x_ANALOG_INPUT_CONTR_2 - (1) HLNRS VBSL WPOFF HOLDG GAFIX GAI28 GAI18 */
+ 0x04, 0x00, /* PH711x_ANALOG_INPUT_CONTR_3 - GAI17 GAI16 GAI15 GAI14 GAI13 GAI12 GAI11 GAI10 */
+ 0x05, 0x00, /* PH711x_ANALOG_INPUT_CONTR_4 - GAI27 GAI26 GAI25 GAI24 GAI23 GAI22 GAI21 GAI20 */
+ 0x06, 0xeb, /* PH711x_HORIZONTAL_SYNC_START - HSB7 HSB6 HSB5 HSB4 HSB3 HSB2 HSB1 HSB0 */
+ 0x07, 0xe0, /* PH711x_HORIZONTAL_SYNC_STOP - HSS7 HSS6 HSS5 HSS4 HSS3 HSS2 HSS1 HSS0 */
+ 0x08, 0x88, /* PH711x_SYNC_CONTROL - AUFD FSEL FOET HTC1 HTC0 HPLL VNOI1 VNOI0 */
+ 0x09, 0x00, /* PH711x_LUMINANCE_CONTROL - BYPS PREF BPSS1 BPSS0 VBLB UPTCV APER1 APER0 */
+ 0x0a, 0x80, /* PH711x_LUMINANCE_BRIGHTNESS - BRIG7 BRIG6 BRIG5 BRIG4 BRIG3 BRIG2 BRIG1 BRIG0 */
+ 0x0b, 0x47, /* PH711x_LUMINANCE_CONTRAST - CONT7 CONT6 CONT5 CONT4 CONT3 CONT2 CONT1 CONT0 */
+ 0x0c, 0x40, /* PH711x_CHROMA_SATURATION - SATN7 SATN6 SATN5 SATN4 SATN3 SATN2 SATN1 SATN0 */
+ 0x0d, 0x00, /* PH711x_CHROMA_HUE_CONTROL - HUEC7 HUEC6 HUEC5 HUEC4 HUEC3 HUEC2 HUEC1 HUEC0 */
+ 0x0e, 0x01, /* PH711x_CHROMA_CONTROL - CDTO CSTD2 CSTD1 CSTD0 DCCF FCTC CHBW1 CHBW0 */
+ 0x0f, 0xaa, /* PH711x_CHROMA_GAIN_CONTROL - ACGC CGAIN6 CGAIN5 CGAIN4 CGAIN3 CGAIN2 CGAIN1 CGAIN0 */
+ 0x10, 0x00, /* PH711x_FORMAT_DELAY_CONTROL - OFTS1 OFTS0 HDEL1 HDEL0 VRLN YDEL2 YDEL1 YDEL0 */
+ 0x11, 0x1C, /* PH711x_OUTPUT_CONTROL_1 - GPSW1 CM99 GPSW0 HLSEL OEYC OERT VIPB COLO */
+ 0x12, 0x01, /* PH711x_OUTPUT_CONTROL_2 - RTSE13 RTSE12 RTSE11 RTSE10 RTSE03 RTSE02 RTSE01 RTSE00 */
+ 0x13, 0x00, /* PH711x_OUTPUT_CONTROL_3 - ADLSB (1) (1) OLDSB FIDP (1) AOSL1 AOSL0 */
+ 0x14, 0x00, /* RESERVED 14 - (1) (1) (1) (1) (1) (1) (1) (1) */
+ 0x15, 0x00, /* PH711x_V_GATE1_START - VSTA7 VSTA6 VSTA5 VSTA4 VSTA3 VSTA2 VSTA1 VSTA0 */
+ 0x16, 0x00, /* PH711x_V_GATE1_STOP - VSTO7 VSTO6 VSTO5 VSTO4 VSTO3 VSTO2 VSTO1 VSTO0 */
+ 0x17, 0x00, /* PH711x_V_GATE1_MSB - (1) (1) (1) (1) (1) (1) VSTO8 VSTA8 */
+};
+
+static int
+saa711x_command (struct i2c_client *client,
+ unsigned int cmd,
+ void *arg)
+{
+ struct saa711x *decoder = i2c_get_clientdata(client);
+
+ switch (cmd) {
+
+ case 0:
+ case DECODER_INIT:
+ {
+ struct video_decoder_init *init = arg;
+ if (NULL != init)
+ return saa711x_init_decoder(client, init);
+ else {
+ struct video_decoder_init vdi;
+ vdi.data = saa711x_i2c_init;
+ vdi.len = sizeof(saa711x_i2c_init);
+ return saa711x_init_decoder(client, &vdi);
+ }
+ }
+
+ case DECODER_DUMP:
+ {
+ int i;
+
+ for (i = 0; i < 32; i += 16) {
+ int j;
+
+ printk(KERN_DEBUG "%s: %03x", I2C_NAME(client), i);
+ for (j = 0; j < 16; ++j) {
+ printk(" %02x",
+ saa711x_read(client, i + j));
+ }
+ printk("\n");
+ }
+ }
+ break;
+
+ case DECODER_GET_CAPABILITIES:
+ {
+ struct video_decoder_capability *cap = arg;
+
+ cap->flags = VIDEO_DECODER_PAL |
+ VIDEO_DECODER_NTSC |
+ VIDEO_DECODER_SECAM |
+ VIDEO_DECODER_AUTO |
+ VIDEO_DECODER_CCIR;
+ cap->inputs = 8;
+ cap->outputs = 1;
+ }
+ break;
+
+ case DECODER_GET_STATUS:
+ {
+ int *iarg = arg;
+ int status;
+ int res;
+
+ status = saa711x_read(client, 0x1f);
+ dprintk(1, KERN_DEBUG "%s status: 0x%02x\n", I2C_NAME(client),
+ status);
+ res = 0;
+ if ((status & (1 << 6)) == 0) {
+ res |= DECODER_STATUS_GOOD;
+ }
+ switch (decoder->norm) {
+ case VIDEO_MODE_NTSC:
+ res |= DECODER_STATUS_NTSC;
+ break;
+ case VIDEO_MODE_PAL:
+ res |= DECODER_STATUS_PAL;
+ break;
+ case VIDEO_MODE_SECAM:
+ res |= DECODER_STATUS_SECAM;
+ break;
+ default:
+ case VIDEO_MODE_AUTO:
+ if ((status & (1 << 5)) != 0) {
+ res |= DECODER_STATUS_NTSC;
+ } else {
+ res |= DECODER_STATUS_PAL;
+ }
+ break;
+ }
+ if ((status & (1 << 0)) != 0) {
+ res |= DECODER_STATUS_COLOR;
+ }
+ *iarg = res;
+ }
+ break;
+
+ case DECODER_SET_GPIO:
+ {
+ int *iarg = arg;
+ if (0 != *iarg) {
+ saa711x_write(client, 0x11,
+ (decoder->reg[0x11] | 0x80));
+ } else {
+ saa711x_write(client, 0x11,
+ (decoder->reg[0x11] & 0x7f));
+ }
+ break;
+ }
+
+ case DECODER_SET_VBI_BYPASS:
+ {
+ int *iarg = arg;
+ if (0 != *iarg) {
+ saa711x_write(client, 0x13,
+ (decoder->reg[0x13] & 0xf0) | 0x0a);
+ } else {
+ saa711x_write(client, 0x13,
+ (decoder->reg[0x13] & 0xf0));
+ }
+ break;
+ }
+
+ case DECODER_SET_NORM:
+ {
+ int *iarg = arg;
+
+ switch (*iarg) {
+
+ case VIDEO_MODE_NTSC:
+ saa711x_write(client, 0x08,
+ (decoder->reg[0x08] & 0x3f) | 0x40);
+ saa711x_write(client, 0x0e,
+ (decoder->reg[0x0e] & 0x8f));
+ break;
+
+ case VIDEO_MODE_PAL:
+ saa711x_write(client, 0x08,
+ (decoder->reg[0x08] & 0x3f) | 0x00);
+ saa711x_write(client, 0x0e,
+ (decoder->reg[0x0e] & 0x8f));
+ break;
+
+ case VIDEO_MODE_SECAM:
+ saa711x_write(client, 0x08,
+ (decoder->reg[0x0e] & 0x3f) | 0x00);
+ saa711x_write(client, 0x0e,
+ (decoder->reg[0x0e] & 0x8f) | 0x50);
+ break;
+
+ case VIDEO_MODE_AUTO:
+ saa711x_write(client, 0x08,
+ (decoder->reg[0x08] & 0x3f) | 0x80);
+ saa711x_write(client, 0x0e,
+ (decoder->reg[0x0e] & 0x8f));
+ break;
+
+ default:
+ return -EINVAL;
+
+ }
+ decoder->norm = *iarg;
+ }
+ break;
+
+ case DECODER_SET_INPUT:
+ {
+ int *iarg = arg;
+ if (*iarg < 0 || *iarg > 9) {
+ return -EINVAL;
+ }
+ if (decoder->input != *iarg) {
+ decoder->input = *iarg;
+ /* select mode */
+ saa711x_write(client, 0x02,
+ (decoder->reg[0x02] & 0xf0) | decoder->input);
+ /* bypass chrominance trap for modes 4..7 */
+ saa711x_write(client, 0x09,
+ (decoder->reg[0x09] & 0x7f) | ((decoder->input > 3) ? 0x80 : 0));
+ }
+ }
+ break;
+
+ case DECODER_SET_OUTPUT:
+ {
+ int *iarg = arg;
+
+ /* not much choice of outputs */
+ if (*iarg != 0) {
+ return -EINVAL;
+ }
+ }
+ break;
+
+ case DECODER_ENABLE_OUTPUT:
+ {
+ int *iarg = arg;
+ int enable = (*iarg != 0);
+
+ if (decoder->enable != enable) {
+ decoder->enable = enable;
+
+ /* RJ: If output should be disabled (for
+ * playing videos), we also need a open PLL.
+ * The input is set to 0 (where no input
+ * source is connected), although this
+ * is not necessary.
+ *
+ * If output should be enabled, we have to
+ * reverse the above.
+ */
+
+ if (decoder->enable) {
+ saa711x_write(client, 0x02,
+ (decoder->
+ reg[0x02] & 0xf8) |
+ decoder->input);
+ saa711x_write(client, 0x08,
+ (decoder->reg[0x08] & 0xfb));
+ saa711x_write(client, 0x11,
+ (decoder->
+ reg[0x11] & 0xf3) | 0x0c);
+ } else {
+ saa711x_write(client, 0x02,
+ (decoder->reg[0x02] & 0xf8));
+ saa711x_write(client, 0x08,
+ (decoder->
+ reg[0x08] & 0xfb) | 0x04);
+ saa711x_write(client, 0x11,
+ (decoder->reg[0x11] & 0xf3));
+ }
+ }
+ }
+ break;
+
+ case DECODER_SET_PICTURE:
+ {
+ struct video_picture *pic = arg;
+
+ if (decoder->bright != pic->brightness) {
+ /* We want 0 to 255 we get 0-65535 */
+ decoder->bright = pic->brightness;
+ saa711x_write(client, 0x0a, decoder->bright >> 8);
+ }
+ if (decoder->contrast != pic->contrast) {
+ /* We want 0 to 127 we get 0-65535 */
+ decoder->contrast = pic->contrast;
+ saa711x_write(client, 0x0b,
+ decoder->contrast >> 9);
+ }
+ if (decoder->sat != pic->colour) {
+ /* We want 0 to 127 we get 0-65535 */
+ decoder->sat = pic->colour;
+ saa711x_write(client, 0x0c, decoder->sat >> 9);
+ }
+ if (decoder->hue != pic->hue) {
+ /* We want -128 to 127 we get 0-65535 */
+ decoder->hue = pic->hue;
+ saa711x_write(client, 0x0d,
+ (decoder->hue - 32768) >> 8);
+ }
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+
+/* standard i2c insmod options */
+static unsigned short normal_i2c[] = {
+ I2C_SAA7113>>1, /* saa7113 */
+ I2C_SAA7114>>1, /* saa7114 */
+ I2C_CLIENT_END
+};
+
+I2C_CLIENT_INSMOD;
+
+
+static struct i2c_driver i2c_driver_saa711x;
+
+static int
+saa711x_detect_client (struct i2c_adapter *adapter,
+ int address,
+ int kind)
+{
+ int i;
+ struct i2c_client *client;
+ struct saa711x *decoder;
+ struct video_decoder_init vdi;
+
+ dprintk(1,
+ KERN_INFO
+ "saa711x.c: detecting saa711x client on address 0x%x\n",
+ address << 1);
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return 0;
+
+ client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (client == 0)
+ return -ENOMEM;
+ memset(client, 0, sizeof(struct i2c_client));
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &i2c_driver_saa711x;
+ client->flags = I2C_CLIENT_ALLOW_USE;
+ strlcpy(I2C_NAME(client), "saa711x", sizeof(I2C_NAME(client)));
+ decoder = kmalloc(sizeof(struct saa711x), GFP_KERNEL);
+ if (decoder == NULL) {
+ kfree(client);
+ return -ENOMEM;
+ }
+ memset(decoder, 0, sizeof(struct saa711x));
+ decoder->norm = VIDEO_MODE_NTSC;
+ decoder->input = 0;
+ decoder->enable = 1;
+ decoder->bright = 32768;
+ decoder->contrast = 32768;
+ decoder->hue = 32768;
+ decoder->sat = 32768;
+ i2c_set_clientdata(client, decoder);
+
+ i = i2c_attach_client(client);
+ if (i) {
+ kfree(client);
+ kfree(decoder);
+ return i;
+ }
+
+ vdi.data = saa711x_i2c_init;
+ vdi.len = sizeof(saa711x_i2c_init);
+ i = saa711x_init_decoder(client, &vdi);
+ if (i < 0) {
+ dprintk(1, KERN_ERR "%s_attach error: init status %d\n",
+ I2C_NAME(client), i);
+ } else {
+ dprintk(1,
+ KERN_INFO
+ "%s_attach: chip version %x at address 0x%x\n",
+ I2C_NAME(client), saa711x_read(client, 0x00) >> 4,
+ client->addr << 1);
+ }
+
+ return 0;
+}
+
+static int
+saa711x_attach_adapter (struct i2c_adapter *adapter)
+{
+ dprintk(1,
+ KERN_INFO
+ "saa711x.c: starting probe for adapter %s (0x%x)\n",
+ I2C_NAME(adapter), adapter->id);
+ return i2c_probe(adapter, &addr_data, &saa711x_detect_client);
+}
+
+static int
+saa711x_detach_client (struct i2c_client *client)
+{
+ struct saa711x *decoder = i2c_get_clientdata(client);
+ int err;
+
+ err = i2c_detach_client(client);
+ if (err) {
+ return err;
+ }
+
+ kfree(decoder);
+ kfree(client);
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_driver i2c_driver_saa711x = {
+ .owner = THIS_MODULE,
+ .name = "saa711x",
+
+ .id = I2C_DRIVERID_SAA711X,
+ .flags = I2C_DF_NOTIFY,
+
+ .attach_adapter = saa711x_attach_adapter,
+ .detach_client = saa711x_detach_client,
+ .command = saa711x_command,
+};
+
+static int __init
+saa711x_init (void)
+{
+ return i2c_add_driver(&i2c_driver_saa711x);
+}
+
+static void __exit
+saa711x_exit (void)
+{
+ i2c_del_driver(&i2c_driver_saa711x);
+}
+
+module_init(saa711x_init);
+module_exit(saa711x_exit);
diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c
new file mode 100644
index 00000000000..843431f10e3
--- /dev/null
+++ b/drivers/media/video/saa7127.c
@@ -0,0 +1,849 @@
+/*
+ * saa7127 - Philips SAA7127/SAA7129 video encoder driver
+ *
+ * Copyright (C) 2003 Roy Bulter <rbulter@hetnet.nl>
+ *
+ * Based on SAA7126 video encoder driver by Gillem & Andreas Oberritter
+ *
+ * Copyright (C) 2000-2001 Gillem <htoa@gmx.net>
+ * Copyright (C) 2002 Andreas Oberritter <obi@saftware.de>
+ *
+ * Based on Stadis 4:2:2 MPEG-2 Decoder Driver by Nathan Laredo
+ *
+ * Copyright (C) 1999 Nathan Laredo <laredo@gnu.org>
+ *
+ * This driver is designed for the Hauppauge 250/350 Linux driver
+ * from the ivtv Project
+ *
+ * Copyright (C) 2003 Kevin Thayer <nufan_wfk@yahoo.com>
+ *
+ * Dual output support:
+ * Copyright (C) 2004 Eric Varsanyi
+ *
+ * NTSC Tuning and 7.5 IRE Setup
+ * Copyright (C) 2004 Chris Kennedy <c@groovy.org>
+ *
+ * VBI additions & cleanup:
+ * Copyright (C) 2004, 2005 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * Note: the saa7126 is identical to the saa7127, and the saa7128 is
+ * identical to the saa7129, except that the saa7126 and saa7128 have
+ * macrovision anti-taping support. This driver will almost certainly
+ * work find for those chips, except of course for the missing anti-taping
+ * support.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+
+static int debug = 0;
+static int test_image = 0;
+
+MODULE_DESCRIPTION("Philips SAA7127/9 video encoder driver");
+MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil");
+MODULE_LICENSE("GPL");
+module_param(debug, int, 0644);
+module_param(test_image, int, 0644);
+MODULE_PARM_DESC(debug, "debug level (0-2)");
+MODULE_PARM_DESC(test_image, "test_image (0-1)");
+
+#define saa7127_dbg(fmt, arg...) \
+ do { \
+ if (debug >= 1) \
+ printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); \
+ } while (0)
+
+/* High volume debug. Use with care. */
+#define saa7127_dbg_highvol(fmt, arg...) \
+ do { \
+ if (debug == 2) \
+ printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); \
+ } while (0)
+
+#define saa7127_err(fmt, arg...) do { \
+ printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+#define saa7127_info(fmt, arg...) do { \
+ printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+
+static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
+
+
+I2C_CLIENT_INSMOD;
+
+/*
+ * SAA7127 registers
+ */
+
+#define SAA7127_REG_STATUS 0x00
+#define SAA7127_REG_WIDESCREEN_CONFIG 0x26
+#define SAA7127_REG_WIDESCREEN_ENABLE 0x27
+#define SAA7127_REG_BURST_START 0x28
+#define SAA7127_REG_BURST_END 0x29
+#define SAA7127_REG_COPYGEN_0 0x2a
+#define SAA7127_REG_COPYGEN_1 0x2b
+#define SAA7127_REG_COPYGEN_2 0x2c
+#define SAA7127_REG_OUTPUT_PORT_CONTROL 0x2d
+#define SAA7127_REG_GAIN_LUMINANCE_RGB 0x38
+#define SAA7127_REG_GAIN_COLORDIFF_RGB 0x39
+#define SAA7127_REG_INPUT_PORT_CONTROL_1 0x3a
+#define SAA7129_REG_FADE_KEY_COL2 0x4f
+#define SAA7127_REG_CHROMA_PHASE 0x5a
+#define SAA7127_REG_GAINU 0x5b
+#define SAA7127_REG_GAINV 0x5c
+#define SAA7127_REG_BLACK_LEVEL 0x5d
+#define SAA7127_REG_BLANKING_LEVEL 0x5e
+#define SAA7127_REG_VBI_BLANKING 0x5f
+#define SAA7127_REG_DAC_CONTROL 0x61
+#define SAA7127_REG_BURST_AMP 0x62
+#define SAA7127_REG_SUBC3 0x63
+#define SAA7127_REG_SUBC2 0x64
+#define SAA7127_REG_SUBC1 0x65
+#define SAA7127_REG_SUBC0 0x66
+#define SAA7127_REG_LINE_21_ODD_0 0x67
+#define SAA7127_REG_LINE_21_ODD_1 0x68
+#define SAA7127_REG_LINE_21_EVEN_0 0x69
+#define SAA7127_REG_LINE_21_EVEN_1 0x6a
+#define SAA7127_REG_RCV_PORT_CONTROL 0x6b
+#define SAA7127_REG_VTRIG 0x6c
+#define SAA7127_REG_HTRIG_HI 0x6d
+#define SAA7127_REG_MULTI 0x6e
+#define SAA7127_REG_CLOSED_CAPTION 0x6f
+#define SAA7127_REG_RCV2_OUTPUT_START 0x70
+#define SAA7127_REG_RCV2_OUTPUT_END 0x71
+#define SAA7127_REG_RCV2_OUTPUT_MSBS 0x72
+#define SAA7127_REG_TTX_REQUEST_H_START 0x73
+#define SAA7127_REG_TTX_REQUEST_H_DELAY_LENGTH 0x74
+#define SAA7127_REG_CSYNC_ADVANCE_VSYNC_SHIFT 0x75
+#define SAA7127_REG_TTX_ODD_REQ_VERT_START 0x76
+#define SAA7127_REG_TTX_ODD_REQ_VERT_END 0x77
+#define SAA7127_REG_TTX_EVEN_REQ_VERT_START 0x78
+#define SAA7127_REG_TTX_EVEN_REQ_VERT_END 0x79
+#define SAA7127_REG_FIRST_ACTIVE 0x7a
+#define SAA7127_REG_LAST_ACTIVE 0x7b
+#define SAA7127_REG_MSB_VERTICAL 0x7c
+#define SAA7127_REG_DISABLE_TTX_LINE_LO_0 0x7e
+#define SAA7127_REG_DISABLE_TTX_LINE_LO_1 0x7f
+
+/*
+ **********************************************************************
+ *
+ * Arrays with configuration parameters for the SAA7127
+ *
+ **********************************************************************
+ */
+
+struct i2c_reg_value {
+ unsigned char reg;
+ unsigned char value;
+};
+
+static const struct i2c_reg_value saa7129_init_config_extra[] = {
+ { SAA7127_REG_OUTPUT_PORT_CONTROL, 0x38 },
+ { SAA7127_REG_VTRIG, 0xfa },
+};
+
+static const struct i2c_reg_value saa7127_init_config_common[] = {
+ { SAA7127_REG_WIDESCREEN_CONFIG, 0x0d },
+ { SAA7127_REG_WIDESCREEN_ENABLE, 0x00 },
+ { SAA7127_REG_COPYGEN_0, 0x77 },
+ { SAA7127_REG_COPYGEN_1, 0x41 },
+ { SAA7127_REG_COPYGEN_2, 0x00 }, /* Macrovision enable/disable */
+ { SAA7127_REG_OUTPUT_PORT_CONTROL, 0x9e },
+ { SAA7127_REG_GAIN_LUMINANCE_RGB, 0x00 },
+ { SAA7127_REG_GAIN_COLORDIFF_RGB, 0x00 },
+ { SAA7127_REG_INPUT_PORT_CONTROL_1, 0x80 }, /* for color bars */
+ { SAA7127_REG_LINE_21_ODD_0, 0x77 },
+ { SAA7127_REG_LINE_21_ODD_1, 0x41 },
+ { SAA7127_REG_LINE_21_EVEN_0, 0x88 },
+ { SAA7127_REG_LINE_21_EVEN_1, 0x41 },
+ { SAA7127_REG_RCV_PORT_CONTROL, 0x12 },
+ { SAA7127_REG_VTRIG, 0xf9 },
+ { SAA7127_REG_HTRIG_HI, 0x00 },
+ { SAA7127_REG_RCV2_OUTPUT_START, 0x41 },
+ { SAA7127_REG_RCV2_OUTPUT_END, 0xc3 },
+ { SAA7127_REG_RCV2_OUTPUT_MSBS, 0x00 },
+ { SAA7127_REG_TTX_REQUEST_H_START, 0x3e },
+ { SAA7127_REG_TTX_REQUEST_H_DELAY_LENGTH, 0xb8 },
+ { SAA7127_REG_CSYNC_ADVANCE_VSYNC_SHIFT, 0x03 },
+ { SAA7127_REG_TTX_ODD_REQ_VERT_START, 0x15 },
+ { SAA7127_REG_TTX_ODD_REQ_VERT_END, 0x16 },
+ { SAA7127_REG_TTX_EVEN_REQ_VERT_START, 0x15 },
+ { SAA7127_REG_TTX_EVEN_REQ_VERT_END, 0x16 },
+ { SAA7127_REG_FIRST_ACTIVE, 0x1a },
+ { SAA7127_REG_LAST_ACTIVE, 0x01 },
+ { SAA7127_REG_MSB_VERTICAL, 0xc0 },
+ { SAA7127_REG_DISABLE_TTX_LINE_LO_0, 0x00 },
+ { SAA7127_REG_DISABLE_TTX_LINE_LO_1, 0x00 },
+ { 0, 0 }
+};
+
+#define SAA7127_60HZ_DAC_CONTROL 0x15
+static const struct i2c_reg_value saa7127_init_config_60hz[] = {
+ { SAA7127_REG_BURST_START, 0x19 },
+ /* BURST_END is also used as a chip ID in saa7127_detect_client */
+ { SAA7127_REG_BURST_END, 0x1d },
+ { SAA7127_REG_CHROMA_PHASE, 0xa3 },
+ { SAA7127_REG_GAINU, 0x98 },
+ { SAA7127_REG_GAINV, 0xd3 },
+ { SAA7127_REG_BLACK_LEVEL, 0x39 },
+ { SAA7127_REG_BLANKING_LEVEL, 0x2e },
+ { SAA7127_REG_VBI_BLANKING, 0x2e },
+ { SAA7127_REG_DAC_CONTROL, 0x15 },
+ { SAA7127_REG_BURST_AMP, 0x4d },
+ { SAA7127_REG_SUBC3, 0x1f },
+ { SAA7127_REG_SUBC2, 0x7c },
+ { SAA7127_REG_SUBC1, 0xf0 },
+ { SAA7127_REG_SUBC0, 0x21 },
+ { SAA7127_REG_MULTI, 0x90 },
+ { SAA7127_REG_CLOSED_CAPTION, 0x11 },
+ { 0, 0 }
+};
+
+#define SAA7127_50HZ_DAC_CONTROL 0x02
+struct i2c_reg_value saa7127_init_config_50hz[] = {
+ { SAA7127_REG_BURST_START, 0x21 },
+ /* BURST_END is also used as a chip ID in saa7127_detect_client */
+ { SAA7127_REG_BURST_END, 0x1d },
+ { SAA7127_REG_CHROMA_PHASE, 0x3f },
+ { SAA7127_REG_GAINU, 0x7d },
+ { SAA7127_REG_GAINV, 0xaf },
+ { SAA7127_REG_BLACK_LEVEL, 0x33 },
+ { SAA7127_REG_BLANKING_LEVEL, 0x35 },
+ { SAA7127_REG_VBI_BLANKING, 0x35 },
+ { SAA7127_REG_DAC_CONTROL, 0x02 },
+ { SAA7127_REG_BURST_AMP, 0x2f },
+ { SAA7127_REG_SUBC3, 0xcb },
+ { SAA7127_REG_SUBC2, 0x8a },
+ { SAA7127_REG_SUBC1, 0x09 },
+ { SAA7127_REG_SUBC0, 0x2a },
+ { SAA7127_REG_MULTI, 0xa0 },
+ { SAA7127_REG_CLOSED_CAPTION, 0x00 },
+ { 0, 0 }
+};
+
+/* Enumeration for the Supported input types */
+enum saa7127_input_type {
+ SAA7127_INPUT_TYPE_NORMAL,
+ SAA7127_INPUT_TYPE_TEST_IMAGE
+};
+
+/* Enumeration for the Supported Output signal types */
+enum saa7127_output_type {
+ SAA7127_OUTPUT_TYPE_BOTH,
+ SAA7127_OUTPUT_TYPE_COMPOSITE,
+ SAA7127_OUTPUT_TYPE_SVIDEO,
+ SAA7127_OUTPUT_TYPE_RGB,
+ SAA7127_OUTPUT_TYPE_YUV_C,
+ SAA7127_OUTPUT_TYPE_YUV_V
+};
+
+/*
+ **********************************************************************
+ *
+ * Encoder Struct, holds the configuration state of the encoder
+ *
+ **********************************************************************
+ */
+
+struct saa7127_state {
+ v4l2_std_id std;
+ enum v4l2_chip_ident ident;
+ enum saa7127_input_type input_type;
+ enum saa7127_output_type output_type;
+ int video_enable;
+ int wss_enable;
+ u16 wss_mode;
+ int cc_enable;
+ u16 cc_data;
+ int xds_enable;
+ u16 xds_data;
+ int vps_enable;
+ u8 vps_data[5];
+ u8 reg_2d;
+ u8 reg_3a;
+ u8 reg_3a_cb; /* colorbar bit */
+ u8 reg_61;
+};
+
+static const char * const output_strs[] =
+{
+ "S-Video + Composite",
+ "Composite",
+ "S-Video",
+ "RGB",
+ "YUV C",
+ "YUV V"
+};
+
+static const char * const wss_strs[] = {
+ "invalid",
+ "letterbox 14:9 center",
+ "letterbox 14:9 top",
+ "invalid",
+ "letterbox 16:9 top",
+ "invalid",
+ "invalid",
+ "16:9 full format anamorphic"
+ "4:3 full format",
+ "invalid",
+ "invalid",
+ "letterbox 16:9 center",
+ "invalid",
+ "letterbox >16:9 center",
+ "14:9 full format center",
+ "invalid",
+};
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_read(struct i2c_client *client, u8 reg)
+{
+ return i2c_smbus_read_byte_data(client, reg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_write(struct i2c_client *client, u8 reg, u8 val)
+{
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ if (i2c_smbus_write_byte_data(client, reg, val) == 0)
+ return 0;
+ }
+ saa7127_err("I2C Write Problem\n");
+ return -1;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_write_inittab(struct i2c_client *client,
+ const struct i2c_reg_value *regs)
+{
+ while (regs->reg != 0) {
+ saa7127_write(client, regs->reg, regs->value);
+ regs++;
+ }
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_vps(struct i2c_client *client, struct v4l2_sliced_vbi_data *data)
+{
+ struct saa7127_state *state = i2c_get_clientdata(client);
+ int enable = (data->line != 0);
+
+ if (enable && (data->field != 0 || data->line != 16))
+ return -EINVAL;
+ if (state->vps_enable != enable) {
+ saa7127_dbg("Turn VPS Signal %s\n", enable ? "on" : "off");
+ saa7127_write(client, 0x54, enable << 7);
+ state->vps_enable = enable;
+ }
+ if (!enable)
+ return 0;
+
+ state->vps_data[0] = data->data[4];
+ state->vps_data[1] = data->data[10];
+ state->vps_data[2] = data->data[11];
+ state->vps_data[3] = data->data[12];
+ state->vps_data[4] = data->data[13];
+ saa7127_dbg("Set VPS data %02x %02x %02x %02x %02x\n",
+ state->vps_data[0], state->vps_data[1],
+ state->vps_data[2], state->vps_data[3],
+ state->vps_data[4]);
+ saa7127_write(client, 0x55, state->vps_data[0]);
+ saa7127_write(client, 0x56, state->vps_data[1]);
+ saa7127_write(client, 0x57, state->vps_data[2]);
+ saa7127_write(client, 0x58, state->vps_data[3]);
+ saa7127_write(client, 0x59, state->vps_data[4]);
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_cc(struct i2c_client *client, struct v4l2_sliced_vbi_data *data)
+{
+ struct saa7127_state *state = i2c_get_clientdata(client);
+ u16 cc = data->data[0] << 8 | data->data[1];
+ int enable = (data->line != 0);
+
+ if (enable && (data->field != 0 || data->line != 21))
+ return -EINVAL;
+ if (state->cc_enable != enable) {
+ saa7127_dbg("Turn CC %s\n", enable ? "on" : "off");
+ saa7127_write(client, SAA7127_REG_CLOSED_CAPTION,
+ (enable << 6) | 0x11);
+ state->cc_enable = enable;
+ }
+ if (!enable)
+ return 0;
+
+ saa7127_dbg_highvol("CC data: %04x\n", cc);
+ saa7127_write(client, SAA7127_REG_LINE_21_ODD_0, cc & 0xff);
+ saa7127_write(client, SAA7127_REG_LINE_21_ODD_1, cc >> 8);
+ state->cc_data = cc;
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_xds(struct i2c_client *client, struct v4l2_sliced_vbi_data *data)
+{
+ struct saa7127_state *state = i2c_get_clientdata(client);
+ u16 xds = data->data[1] << 8 | data->data[0];
+ int enable = (data->line != 0);
+
+ if (enable && (data->field != 1 || data->line != 21))
+ return -EINVAL;
+ if (state->xds_enable != enable) {
+ saa7127_dbg("Turn XDS %s\n", enable ? "on" : "off");
+ saa7127_write(client, SAA7127_REG_CLOSED_CAPTION,
+ (enable << 7) | 0x11);
+ state->xds_enable = enable;
+ }
+ if (!enable)
+ return 0;
+
+ saa7127_dbg_highvol("XDS data: %04x\n", xds);
+ saa7127_write(client, SAA7127_REG_LINE_21_EVEN_0, xds & 0xff);
+ saa7127_write(client, SAA7127_REG_LINE_21_EVEN_1, xds >> 8);
+ state->xds_data = xds;
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_wss(struct i2c_client *client, struct v4l2_sliced_vbi_data *data)
+{
+ struct saa7127_state *state = i2c_get_clientdata(client);
+ int enable = (data->line != 0);
+
+ if (enable && (data->field != 0 || data->line != 23))
+ return -EINVAL;
+ if (state->wss_enable != enable) {
+ saa7127_dbg("Turn WSS %s\n", enable ? "on" : "off");
+ saa7127_write(client, 0x27, enable << 7);
+ state->wss_enable = enable;
+ }
+ if (!enable)
+ return 0;
+
+ saa7127_write(client, 0x26, data->data[0]);
+ saa7127_write(client, 0x27, 0x80 | (data->data[1] & 0x3f));
+ saa7127_dbg("WSS mode: %s\n", wss_strs[data->data[0] & 0xf]);
+ state->wss_mode = (data->data[1] & 0x3f) << 8 | data->data[0];
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_video_enable(struct i2c_client *client, int enable)
+{
+ struct saa7127_state *state = i2c_get_clientdata(client);
+
+ if (enable) {
+ saa7127_dbg("Enable Video Output\n");
+ saa7127_write(client, 0x2d, state->reg_2d);
+ saa7127_write(client, 0x61, state->reg_61);
+ } else {
+ saa7127_dbg("Disable Video Output\n");
+ saa7127_write(client, 0x2d, (state->reg_2d & 0xf0));
+ saa7127_write(client, 0x61, (state->reg_61 | 0xc0));
+ }
+ state->video_enable = enable;
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_std(struct i2c_client *client, v4l2_std_id std)
+{
+ struct saa7127_state *state = i2c_get_clientdata(client);
+ const struct i2c_reg_value *inittab;
+
+ if (std & V4L2_STD_525_60) {
+ saa7127_dbg("Selecting 60 Hz video Standard\n");
+ inittab = saa7127_init_config_60hz;
+ state->reg_61 = SAA7127_60HZ_DAC_CONTROL;
+ } else {
+ saa7127_dbg("Selecting 50 Hz video Standard\n");
+ inittab = saa7127_init_config_50hz;
+ state->reg_61 = SAA7127_50HZ_DAC_CONTROL;
+ }
+
+ /* Write Table */
+ saa7127_write_inittab(client, inittab);
+ state->std = std;
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_output_type(struct i2c_client *client, int output)
+{
+ struct saa7127_state *state = i2c_get_clientdata(client);
+
+ switch (output) {
+ case SAA7127_OUTPUT_TYPE_RGB:
+ state->reg_2d = 0x0f; /* RGB + CVBS (for sync) */
+ state->reg_3a = 0x13; /* by default switch YUV to RGB-matrix on */
+ break;
+
+ case SAA7127_OUTPUT_TYPE_COMPOSITE:
+ state->reg_2d = 0x08; /* 00001000 CVBS only, RGB DAC's off (high impedance mode) */
+ state->reg_3a = 0x13; /* by default switch YUV to RGB-matrix on */
+ break;
+
+ case SAA7127_OUTPUT_TYPE_SVIDEO:
+ state->reg_2d = 0xff; /* 11111111 croma -> R, luma -> CVBS + G + B */
+ state->reg_3a = 0x13; /* by default switch YUV to RGB-matrix on */
+ break;
+
+ case SAA7127_OUTPUT_TYPE_YUV_V:
+ state->reg_2d = 0x4f; /* reg 2D = 01001111, all DAC's on, RGB + VBS */
+ state->reg_3a = 0x0b; /* reg 3A = 00001011, bypass RGB-matrix */
+ break;
+
+ case SAA7127_OUTPUT_TYPE_YUV_C:
+ state->reg_2d = 0x0f; /* reg 2D = 00001111, all DAC's on, RGB + CVBS */
+ state->reg_3a = 0x0b; /* reg 3A = 00001011, bypass RGB-matrix */
+ break;
+
+ case SAA7127_OUTPUT_TYPE_BOTH:
+ state->reg_2d = 0xbf;
+ state->reg_3a = 0x13; /* by default switch YUV to RGB-matrix on */
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ saa7127_dbg("Selecting %s output type\n", output_strs[output]);
+
+ /* Configure Encoder */
+ saa7127_write(client, 0x2d, state->reg_2d);
+ saa7127_write(client, 0x3a, state->reg_3a | state->reg_3a_cb);
+ state->output_type = output;
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_input_type(struct i2c_client *client, int input)
+{
+ struct saa7127_state *state = i2c_get_clientdata(client);
+
+ switch (input) {
+ case SAA7127_INPUT_TYPE_NORMAL: /* avia */
+ saa7127_dbg("Selecting Normal Encoder Input\n");
+ state->reg_3a_cb = 0;
+ break;
+
+ case SAA7127_INPUT_TYPE_TEST_IMAGE: /* color bar */
+ saa7127_dbg("Selecting Color Bar generator\n");
+ state->reg_3a_cb = 0x80;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ saa7127_write(client, 0x3a, state->reg_3a | state->reg_3a_cb);
+ state->input_type = input;
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_command(struct i2c_client *client,
+ unsigned int cmd, void *arg)
+{
+ struct saa7127_state *state = i2c_get_clientdata(client);
+ struct v4l2_format *fmt = arg;
+ int *iarg = arg;
+
+ switch (cmd) {
+ case VIDIOC_S_STD:
+ if (state->std == *(v4l2_std_id *)arg)
+ break;
+ return saa7127_set_std(client, *(v4l2_std_id *)arg);
+
+ case VIDIOC_G_STD:
+ *(v4l2_std_id *)arg = state->std;
+ break;
+
+ case VIDIOC_S_INPUT:
+ if (state->input_type == *iarg)
+ break;
+ return saa7127_set_input_type(client, *iarg);
+
+ case VIDIOC_S_OUTPUT:
+ if (state->output_type == *iarg)
+ break;
+ return saa7127_set_output_type(client, *iarg);
+
+ case VIDIOC_STREAMON:
+ case VIDIOC_STREAMOFF:
+ if (state->video_enable == (cmd == VIDIOC_STREAMON))
+ break;
+ return saa7127_set_video_enable(client, cmd == VIDIOC_STREAMON);
+
+ case VIDIOC_G_FMT:
+ if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+ return -EINVAL;
+
+ memset(&fmt->fmt.sliced, 0, sizeof(fmt->fmt.sliced));
+ if (state->vps_enable)
+ fmt->fmt.sliced.service_lines[0][16] = V4L2_SLICED_VPS;
+ if (state->wss_enable)
+ fmt->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
+ if (state->cc_enable) {
+ fmt->fmt.sliced.service_lines[0][21] = V4L2_SLICED_CAPTION_525;
+ fmt->fmt.sliced.service_lines[1][21] = V4L2_SLICED_CAPTION_525;
+ }
+ fmt->fmt.sliced.service_set =
+ (state->vps_enable ? V4L2_SLICED_VPS : 0) |
+ (state->wss_enable ? V4L2_SLICED_WSS_625 : 0) |
+ (state->cc_enable ? V4L2_SLICED_CAPTION_525 : 0);
+ break;
+
+ case VIDIOC_LOG_STATUS:
+ saa7127_info("Standard: %s\n", (state->std & V4L2_STD_525_60) ? "60 Hz" : "50 Hz");
+ saa7127_info("Input: %s\n", state->input_type ? "color bars" : "normal");
+ saa7127_info("Output: %s\n", state->video_enable ?
+ output_strs[state->output_type] : "disabled");
+ saa7127_info("WSS: %s\n", state->wss_enable ?
+ wss_strs[state->wss_mode] : "disabled");
+ saa7127_info("VPS: %s\n", state->vps_enable ? "enabled" : "disabled");
+ saa7127_info("CC: %s\n", state->cc_enable ? "enabled" : "disabled");
+ break;
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ case VIDIOC_INT_G_REGISTER:
+ {
+ struct v4l2_register *reg = arg;
+
+ if (reg->i2c_id != I2C_DRIVERID_SAA7127)
+ return -EINVAL;
+ reg->val = saa7127_read(client, reg->reg & 0xff);
+ break;
+ }
+
+ case VIDIOC_INT_S_REGISTER:
+ {
+ struct v4l2_register *reg = arg;
+
+ if (reg->i2c_id != I2C_DRIVERID_SAA7127)
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ saa7127_write(client, reg->reg & 0xff, reg->val & 0xff);
+ break;
+ }
+#endif
+
+ case VIDIOC_INT_S_VBI_DATA:
+ {
+ struct v4l2_sliced_vbi_data *data = arg;
+
+ switch (data->id) {
+ case V4L2_SLICED_WSS_625:
+ return saa7127_set_wss(client, data);
+ case V4L2_SLICED_VPS:
+ return saa7127_set_vps(client, data);
+ case V4L2_SLICED_CAPTION_525:
+ if (data->field == 0)
+ return saa7127_set_cc(client, data);
+ return saa7127_set_xds(client, data);
+ default:
+ return -EINVAL;
+ }
+ break;
+ }
+
+ case VIDIOC_INT_G_CHIP_IDENT:
+ *(enum v4l2_chip_ident *)arg = state->ident;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+struct i2c_driver i2c_driver_saa7127;
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct i2c_client *client;
+ struct saa7127_state *state;
+ struct v4l2_sliced_vbi_data vbi = { 0, 0, 0, 0 }; /* set to disabled */
+ int read_result = 0;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return 0;
+
+ client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (client == 0)
+ return -ENOMEM;
+
+ memset(client, 0, sizeof(struct i2c_client));
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &i2c_driver_saa7127;
+ client->flags = I2C_CLIENT_ALLOW_USE;
+ snprintf(client->name, sizeof(client->name) - 1, "saa7127");
+
+ saa7127_dbg("detecting saa7127 client on address 0x%x\n", address << 1);
+
+ /* First test register 0: Bits 5-7 are a version ID (should be 0),
+ and bit 2 should also be 0.
+ This is rather general, so the second test is more specific and
+ looks at the 'ending point of burst in clock cycles' which is
+ 0x1d after a reset and not expected to ever change. */
+ if ((saa7127_read(client, 0) & 0xe4) != 0 ||
+ (saa7127_read(client, 0x29) & 0x3f) != 0x1d) {
+ saa7127_dbg("saa7127 not found\n");
+ kfree(client);
+ return 0;
+ }
+ state = kmalloc(sizeof(struct saa7127_state), GFP_KERNEL);
+
+ if (state == NULL) {
+ kfree(client);
+ return (-ENOMEM);
+ }
+
+ i2c_set_clientdata(client, state);
+ memset(state, 0, sizeof(struct saa7127_state));
+
+ /* Configure Encoder */
+
+ saa7127_dbg("Configuring encoder\n");
+ saa7127_write_inittab(client, saa7127_init_config_common);
+ saa7127_set_std(client, V4L2_STD_NTSC);
+ saa7127_set_output_type(client, SAA7127_OUTPUT_TYPE_BOTH);
+ saa7127_set_vps(client, &vbi);
+ saa7127_set_wss(client, &vbi);
+ saa7127_set_cc(client, &vbi);
+ saa7127_set_xds(client, &vbi);
+ if (test_image == 1) {
+ /* The Encoder has an internal Colorbar generator */
+ /* This can be used for debugging */
+ saa7127_set_input_type(client, SAA7127_INPUT_TYPE_TEST_IMAGE);
+ } else {
+ saa7127_set_input_type(client, SAA7127_INPUT_TYPE_NORMAL);
+ }
+ saa7127_set_video_enable(client, 1);
+
+ /* Detect if it's an saa7129 */
+ read_result = saa7127_read(client, SAA7129_REG_FADE_KEY_COL2);
+ saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, 0xaa);
+ if (saa7127_read(client, SAA7129_REG_FADE_KEY_COL2) == 0xaa) {
+ saa7127_info("saa7129 found @ 0x%x (%s)\n", address << 1, adapter->name);
+ saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, read_result);
+ saa7127_write_inittab(client, saa7129_init_config_extra);
+ state->ident = V4L2_IDENT_SAA7129;
+ } else {
+ saa7127_info("saa7127 found @ 0x%x (%s)\n", address << 1, adapter->name);
+ state->ident = V4L2_IDENT_SAA7127;
+ }
+
+ i2c_attach_client(client);
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_probe(struct i2c_adapter *adapter)
+{
+#ifdef I2C_CLASS_TV_ANALOG
+ if (adapter->class & I2C_CLASS_TV_ANALOG)
+#else
+ if (adapter->id == I2C_HW_B_BT848)
+#endif
+ return i2c_probe(adapter, &addr_data, saa7127_attach);
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_detach(struct i2c_client *client)
+{
+ struct saa7127_state *state = i2c_get_clientdata(client);
+ int err;
+
+ /* Turn off TV output */
+ saa7127_set_video_enable(client, 0);
+
+ err = i2c_detach_client(client);
+
+ if (err) {
+ return err;
+ }
+
+ kfree(state);
+ kfree(client);
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+struct i2c_driver i2c_driver_saa7127 = {
+ .name = "saa7127",
+ .id = I2C_DRIVERID_SAA7127,
+ .flags = I2C_DF_NOTIFY,
+ .attach_adapter = saa7127_probe,
+ .detach_client = saa7127_detach,
+ .command = saa7127_command,
+ .owner = THIS_MODULE,
+};
+
+
+/* ----------------------------------------------------------------------- */
+
+static int __init saa7127_init_module(void)
+{
+ return i2c_add_driver(&i2c_driver_saa7127);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void __exit saa7127_cleanup_module(void)
+{
+ i2c_del_driver(&i2c_driver_saa7127);
+}
+
+/* ----------------------------------------------------------------------- */
+
+module_init(saa7127_init_module);
+module_exit(saa7127_cleanup_module);
diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig
new file mode 100644
index 00000000000..7bdeabe638c
--- /dev/null
+++ b/drivers/media/video/saa7134/Kconfig
@@ -0,0 +1,69 @@
+config VIDEO_SAA7134
+ tristate "Philips SAA7134 support"
+ depends on VIDEO_DEV && PCI && I2C && SOUND && SND
+ select VIDEO_BUF
+ select VIDEO_IR
+ select VIDEO_TUNER
+ select CRC32
+ select SND_PCM_OSS
+ ---help---
+ This is a video4linux driver for Philips SAA713x based
+ TV cards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called saa7134.
+
+config VIDEO_SAA7134_DVB
+ tristate "DVB/ATSC Support for saa7134 based TV cards"
+ depends on VIDEO_SAA7134 && DVB_CORE
+ select VIDEO_BUF_DVB
+ ---help---
+ This adds support for DVB cards based on the
+ Philips saa7134 chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called saa7134-dvb.
+
+ You must also select one or more DVB demodulators.
+ If you are unsure which you need, choose all of them.
+
+config VIDEO_SAA7134_DVB_ALL_FRONTENDS
+ bool "Build all supported frontends for saa7134 based TV cards"
+ default y
+ depends on VIDEO_SAA7134_DVB
+ select DVB_MT352
+ select DVB_TDA1004X
+ select DVB_NXT200X
+ ---help---
+ This builds saa7134-dvb with all currently supported frontend
+ demodulators. If you wish to tweak your configuration, and
+ only include support for the hardware that you need, choose N here.
+
+ If you are unsure, choose Y.
+
+config VIDEO_SAA7134_DVB_MT352
+ tristate "Zarlink MT352 DVB-T Support"
+ default m
+ depends on VIDEO_SAA7134_DVB && !VIDEO_SAA7134_DVB_ALL_FRONTENDS
+ select DVB_MT352
+ ---help---
+ This adds DVB-T support for cards based on the
+ Philips saa7134 chip and the MT352 demodulator.
+
+config VIDEO_SAA7134_DVB_TDA1004X
+ tristate "Phillips TDA10045H/TDA10046H DVB-T Support"
+ default m
+ depends on VIDEO_SAA7134_DVB && !VIDEO_SAA7134_DVB_ALL_FRONTENDS
+ select DVB_TDA1004X
+ ---help---
+ This adds DVB-T support for cards based on the
+ Philips saa7134 chip and the TDA10045H/TDA10046H demodulator.
+
+config VIDEO_SAA7134_DVB_NXT200X
+ tristate "NXT2002/NXT2004 ATSC Support"
+ default m
+ depends on VIDEO_SAA7134_DVB && !VIDEO_SAA7134_DVB_ALL_FRONTENDS
+ select DVB_NXT200X
+ ---help---
+ This adds ATSC 8VSB and QAM64/256 support for cards based on the
+ Philips saa7134 chip and the NXT2002/NXT2004 demodulator.
diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile
index b778ffd94e6..4226b61cc61 100644
--- a/drivers/media/video/saa7134/Makefile
+++ b/drivers/media/video/saa7134/Makefile
@@ -1,17 +1,25 @@
saa7134-objs := saa7134-cards.o saa7134-core.o saa7134-i2c.o \
- saa7134-oss.o saa7134-ts.o saa7134-tvaudio.o \
- saa7134-vbi.o saa7134-video.o saa7134-input.o
+ saa7134-ts.o saa7134-tvaudio.o saa7134-vbi.o \
+ saa7134-video.o saa7134-input.o
-obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o saa7134-empress.o saa6752hs.o
+obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o saa7134-empress.o \
+ saa6752hs.o saa7134-alsa.o \
+ saa7134-oss.o
obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o
EXTRA_CFLAGS += -I$(src)/..
EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core
EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/frontends
+ifneq ($(CONFIG_VIDEO_BUF_DVB),n)
+ EXTRA_CFLAGS += -DHAVE_VIDEO_BUF_DVB=1
+endif
ifneq ($(CONFIG_DVB_MT352),n)
EXTRA_CFLAGS += -DHAVE_MT352=1
endif
ifneq ($(CONFIG_DVB_TDA1004X),n)
EXTRA_CFLAGS += -DHAVE_TDA1004X=1
endif
+ifneq ($(CONFIG_DVB_NXT200X),n)
+ EXTRA_CFLAGS += -DHAVE_NXT200X=1
+endif
diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c
index 382911c6ef2..cdd1ed9c806 100644
--- a/drivers/media/video/saa7134/saa6752hs.c
+++ b/drivers/media/video/saa7134/saa6752hs.c
@@ -13,7 +13,6 @@
#include <linux/init.h>
#include <linux/crc32.h>
-#include <media/id.h>
#define MPEG_VIDEO_TARGET_BITRATE_MAX 27000
#define MPEG_VIDEO_MAX_BITRATE_MAX 27000
@@ -57,6 +56,7 @@ struct saa6752hs_state {
struct i2c_client client;
struct v4l2_mpeg_compression params;
enum saa6752hs_videoformat video_format;
+ v4l2_std_id standard;
};
enum saa6752hs_command {
@@ -74,58 +74,58 @@ enum saa6752hs_command {
/* ---------------------------------------------------------------------- */
static u8 PAT[] = {
- 0xc2, // i2c register
- 0x00, // table number for encoder
+ 0xc2, /* i2c register */
+ 0x00, /* table number for encoder */
- 0x47, // sync
- 0x40, 0x00, // transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid(0)
- 0x10, // transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0)
+ 0x47, /* sync */
+ 0x40, 0x00, /* transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid(0) */
+ 0x10, /* transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) */
- 0x00, // PSI pointer to start of table
+ 0x00, /* PSI pointer to start of table */
- 0x00, // tid(0)
- 0xb0, 0x0d, // section_syntax_indicator(1), section_length(13)
+ 0x00, /* tid(0) */
+ 0xb0, 0x0d, /* section_syntax_indicator(1), section_length(13) */
- 0x00, 0x01, // transport_stream_id(1)
+ 0x00, 0x01, /* transport_stream_id(1) */
- 0xc1, // version_number(0), current_next_indicator(1)
+ 0xc1, /* version_number(0), current_next_indicator(1) */
- 0x00, 0x00, // section_number(0), last_section_number(0)
+ 0x00, 0x00, /* section_number(0), last_section_number(0) */
- 0x00, 0x01, // program_number(1)
+ 0x00, 0x01, /* program_number(1) */
- 0xe0, 0x00, // PMT PID
+ 0xe0, 0x00, /* PMT PID */
- 0x00, 0x00, 0x00, 0x00 // CRC32
+ 0x00, 0x00, 0x00, 0x00 /* CRC32 */
};
static u8 PMT[] = {
- 0xc2, // i2c register
- 0x01, // table number for encoder
+ 0xc2, /* i2c register */
+ 0x01, /* table number for encoder */
- 0x47, // sync
- 0x40, 0x00, // transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid
- 0x10, // transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0)
+ 0x47, /* sync */
+ 0x40, 0x00, /* transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid */
+ 0x10, /* transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) */
- 0x00, // PSI pointer to start of table
+ 0x00, /* PSI pointer to start of table */
- 0x02, // tid(2)
- 0xb0, 0x17, // section_syntax_indicator(1), section_length(23)
+ 0x02, /* tid(2) */
+ 0xb0, 0x17, /* section_syntax_indicator(1), section_length(23) */
- 0x00, 0x01, // program_number(1)
+ 0x00, 0x01, /* program_number(1) */
- 0xc1, // version_number(0), current_next_indicator(1)
+ 0xc1, /* version_number(0), current_next_indicator(1) */
- 0x00, 0x00, // section_number(0), last_section_number(0)
+ 0x00, 0x00, /* section_number(0), last_section_number(0) */
- 0xe0, 0x00, // PCR_PID
+ 0xe0, 0x00, /* PCR_PID */
- 0xf0, 0x00, // program_info_length(0)
+ 0xf0, 0x00, /* program_info_length(0) */
- 0x02, 0xe0, 0x00, 0xf0, 0x00, // video stream type(2), pid
- 0x04, 0xe0, 0x00, 0xf0, 0x00, // audio stream type(4), pid
+ 0x02, 0xe0, 0x00, 0xf0, 0x00, /* video stream type(2), pid */
+ 0x04, 0xe0, 0x00, 0xf0, 0x00, /* audio stream type(4), pid */
- 0x00, 0x00, 0x00, 0x00 // CRC32
+ 0x00, 0x00, 0x00, 0x00 /* CRC32 */
};
static struct v4l2_mpeg_compression param_defaults =
@@ -166,33 +166,33 @@ static int saa6752hs_chip_command(struct i2c_client* client,
unsigned long timeout;
int status = 0;
- // execute the command
+ /* execute the command */
switch(command) {
- case SAA6752HS_COMMAND_RESET:
- buf[0] = 0x00;
+ case SAA6752HS_COMMAND_RESET:
+ buf[0] = 0x00;
break;
case SAA6752HS_COMMAND_STOP:
- buf[0] = 0x03;
+ buf[0] = 0x03;
break;
case SAA6752HS_COMMAND_START:
- buf[0] = 0x02;
+ buf[0] = 0x02;
break;
case SAA6752HS_COMMAND_PAUSE:
- buf[0] = 0x04;
+ buf[0] = 0x04;
break;
case SAA6752HS_COMMAND_RECONFIGURE:
buf[0] = 0x05;
break;
- case SAA6752HS_COMMAND_SLEEP:
- buf[0] = 0x06;
+ case SAA6752HS_COMMAND_SLEEP:
+ buf[0] = 0x06;
break;
- case SAA6752HS_COMMAND_RECONFIGURE_FORCE:
+ case SAA6752HS_COMMAND_RECONFIGURE_FORCE:
buf[0] = 0x07;
break;
@@ -200,13 +200,13 @@ static int saa6752hs_chip_command(struct i2c_client* client,
return -EINVAL;
}
- // set it and wait for it to be so
+ /* set it and wait for it to be so */
i2c_master_send(client, buf, 1);
timeout = jiffies + HZ * 3;
for (;;) {
- // get the current status
+ /* get the current status */
buf[0] = 0x10;
- i2c_master_send(client, buf, 1);
+ i2c_master_send(client, buf, 1);
i2c_master_recv(client, buf, 1);
if (!(buf[0] & 0x20))
@@ -216,61 +216,58 @@ static int saa6752hs_chip_command(struct i2c_client* client,
break;
}
- // wait a bit
msleep(10);
}
- // delay a bit to let encoder settle
+ /* delay a bit to let encoder settle */
msleep(50);
- // done
- return status;
+ return status;
}
static int saa6752hs_set_bitrate(struct i2c_client* client,
struct v4l2_mpeg_compression* params)
{
- u8 buf[3];
+ u8 buf[3];
- // set the bitrate mode
+ /* set the bitrate mode */
buf[0] = 0x71;
buf[1] = (params->vi_bitrate.mode == V4L2_BITRATE_VBR) ? 0 : 1;
i2c_master_send(client, buf, 2);
- // set the video bitrate
+ /* set the video bitrate */
if (params->vi_bitrate.mode == V4L2_BITRATE_VBR) {
- // set the target bitrate
+ /* set the target bitrate */
buf[0] = 0x80;
buf[1] = params->vi_bitrate.target >> 8;
- buf[2] = params->vi_bitrate.target & 0xff;
+ buf[2] = params->vi_bitrate.target & 0xff;
i2c_master_send(client, buf, 3);
- // set the max bitrate
+ /* set the max bitrate */
buf[0] = 0x81;
buf[1] = params->vi_bitrate.max >> 8;
- buf[2] = params->vi_bitrate.max & 0xff;
+ buf[2] = params->vi_bitrate.max & 0xff;
i2c_master_send(client, buf, 3);
} else {
- // set the target bitrate (no max bitrate for CBR)
- buf[0] = 0x81;
+ /* set the target bitrate (no max bitrate for CBR) */
+ buf[0] = 0x81;
buf[1] = params->vi_bitrate.target >> 8;
- buf[2] = params->vi_bitrate.target & 0xff;
+ buf[2] = params->vi_bitrate.target & 0xff;
i2c_master_send(client, buf, 3);
}
- // set the audio bitrate
- buf[0] = 0x94;
+ /* set the audio bitrate */
+ buf[0] = 0x94;
buf[1] = (256 == params->au_bitrate.target) ? 0 : 1;
i2c_master_send(client, buf, 2);
- // set the total bitrate
+ /* set the total bitrate */
buf[0] = 0xb1;
- buf[1] = params->st_bitrate.target >> 8;
- buf[2] = params->st_bitrate.target & 0xff;
+ buf[1] = params->st_bitrate.target >> 8;
+ buf[2] = params->st_bitrate.target & 0xff;
i2c_master_send(client, buf, 3);
- // return success
return 0;
}
@@ -376,36 +373,43 @@ static int saa6752hs_init(struct i2c_client* client)
h = i2c_get_clientdata(client);
- // Set video format - must be done first as it resets other settings
+ /* Set video format - must be done first as it resets other settings */
buf[0] = 0x41;
buf[1] = h->video_format;
i2c_master_send(client, buf, 2);
- // set bitrate
- saa6752hs_set_bitrate(client, &h->params);
+ /* Set number of lines in input signal */
+ buf[0] = 0x40;
+ buf[1] = 0x00;
+ if (h->standard & V4L2_STD_525_60)
+ buf[1] = 0x01;
+ i2c_master_send(client, buf, 2);
+
+ /* set bitrate */
+ saa6752hs_set_bitrate(client, &h->params);
- // Set GOP structure {3, 13}
+ /* Set GOP structure {3, 13} */
buf[0] = 0x72;
buf[1] = 0x03;
buf[2] = 0x0D;
i2c_master_send(client,buf,3);
- // Set minimum Q-scale {4}
+ /* Set minimum Q-scale {4} */
buf[0] = 0x82;
buf[1] = 0x04;
i2c_master_send(client,buf,2);
- // Set maximum Q-scale {12}
+ /* Set maximum Q-scale {12} */
buf[0] = 0x83;
buf[1] = 0x0C;
i2c_master_send(client,buf,2);
- // Set Output Protocol
+ /* Set Output Protocol */
buf[0] = 0xD0;
buf[1] = 0x81;
i2c_master_send(client,buf,2);
- // Set video output stream format {TS}
+ /* Set video output stream format {TS} */
buf[0] = 0xB0;
buf[1] = 0x05;
i2c_master_send(client,buf,2);
@@ -421,9 +425,9 @@ static int saa6752hs_init(struct i2c_client* client)
localPAT[sizeof(PAT) - 1] = crc & 0xFF;
/* compute PMT */
- memcpy(localPMT, PMT, sizeof(PMT));
- localPMT[3] = 0x40 | ((h->params.ts_pid_pmt >> 8) & 0x0f);
- localPMT[4] = h->params.ts_pid_pmt & 0xff;
+ memcpy(localPMT, PMT, sizeof(PMT));
+ localPMT[3] = 0x40 | ((h->params.ts_pid_pmt >> 8) & 0x0f);
+ localPMT[4] = h->params.ts_pid_pmt & 0xff;
localPMT[15] = 0xE0 | ((h->params.ts_pid_pcr >> 8) & 0x0F);
localPMT[16] = h->params.ts_pid_pcr & 0xFF;
localPMT[20] = 0xE0 | ((h->params.ts_pid_video >> 8) & 0x0F);
@@ -436,39 +440,39 @@ static int saa6752hs_init(struct i2c_client* client)
localPMT[sizeof(PMT) - 2] = (crc >> 8) & 0xFF;
localPMT[sizeof(PMT) - 1] = crc & 0xFF;
- // Set Audio PID
+ /* Set Audio PID */
buf[0] = 0xC1;
buf[1] = (h->params.ts_pid_audio >> 8) & 0xFF;
buf[2] = h->params.ts_pid_audio & 0xFF;
i2c_master_send(client,buf,3);
- // Set Video PID
+ /* Set Video PID */
buf[0] = 0xC0;
buf[1] = (h->params.ts_pid_video >> 8) & 0xFF;
buf[2] = h->params.ts_pid_video & 0xFF;
i2c_master_send(client,buf,3);
- // Set PCR PID
+ /* Set PCR PID */
buf[0] = 0xC4;
buf[1] = (h->params.ts_pid_pcr >> 8) & 0xFF;
buf[2] = h->params.ts_pid_pcr & 0xFF;
i2c_master_send(client,buf,3);
- // Send SI tables
+ /* Send SI tables */
i2c_master_send(client,localPAT,sizeof(PAT));
i2c_master_send(client,localPMT,sizeof(PMT));
- // mute then unmute audio. This removes buzzing artefacts
+ /* mute then unmute audio. This removes buzzing artefacts */
buf[0] = 0xa4;
buf[1] = 1;
i2c_master_send(client, buf, 2);
- buf[1] = 0;
+ buf[1] = 0;
i2c_master_send(client, buf, 2);
- // start it going
+ /* start it going */
saa6752hs_chip_command(client, SAA6752HS_COMMAND_START);
- // readout current state
+ /* readout current state */
buf[0] = 0xE1;
buf[1] = 0xA7;
buf[2] = 0xFE;
@@ -477,7 +481,7 @@ static int saa6752hs_init(struct i2c_client* client)
i2c_master_send(client, buf, 5);
i2c_master_recv(client, buf2, 4);
- // change aspect ratio
+ /* change aspect ratio */
buf[0] = 0xE0;
buf[1] = 0xA7;
buf[2] = 0xFE;
@@ -498,7 +502,6 @@ static int saa6752hs_init(struct i2c_client* client)
buf[8] = buf2[3];
i2c_master_send(client, buf, 9);
- // return success
return 0;
}
@@ -506,16 +509,19 @@ static int saa6752hs_attach(struct i2c_adapter *adap, int addr, int kind)
{
struct saa6752hs_state *h;
- printk("saa6752hs: chip found @ 0x%x\n", addr<<1);
+ printk("saa6752hs: chip found @ 0x%x\n", addr<<1);
- if (NULL == (h = kmalloc(sizeof(*h), GFP_KERNEL)))
- return -ENOMEM;
+ if (NULL == (h = kmalloc(sizeof(*h), GFP_KERNEL)))
+ return -ENOMEM;
memset(h,0,sizeof(*h));
h->client = client_template;
h->params = param_defaults;
h->client.adapter = adap;
h->client.addr = addr;
+ /* Assume 625 input lines */
+ h->standard = 0;
+
i2c_set_clientdata(&h->client, h);
i2c_attach_client(&h->client);
return 0;
@@ -545,7 +551,7 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
struct v4l2_mpeg_compression *params = arg;
int err = 0;
- switch (cmd) {
+ switch (cmd) {
case VIDIOC_S_MPEGCOMP:
if (NULL == params) {
/* apply settings and start encoder */
@@ -559,7 +565,7 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
break;
case VIDIOC_G_FMT:
{
- struct v4l2_format *f = arg;
+ struct v4l2_format *f = arg;
if (h->video_format == SAA6752HS_VF_UNKNOWN)
h->video_format = SAA6752HS_VF_D1;
@@ -576,6 +582,9 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
saa6752hs_set_subsampling(client, f);
break;
}
+ case VIDIOC_S_STD:
+ h->standard = *((v4l2_std_id *) arg);
+ break;
default:
/* nothing */
break;
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
new file mode 100644
index 00000000000..5707c666660
--- /dev/null
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
@@ -0,0 +1,1013 @@
+/*
+ * SAA713x ALSA support for V4L
+ *
+ *
+ * Caveats:
+ * - Volume doesn't work (it's always at max)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <sound/driver.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/moduleparam.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <linux/interrupt.h>
+
+#include "saa7134.h"
+#include "saa7134-reg.h"
+
+static unsigned int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug,"enable debug messages [alsa]");
+
+/*
+ * Configuration macros
+ */
+
+/* defaults */
+#define MIXER_ADDR_TVTUNER 0
+#define MIXER_ADDR_LINE1 1
+#define MIXER_ADDR_LINE2 2
+#define MIXER_ADDR_LAST 2
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
+static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0};
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for SAA7134 capture interface(s).");
+
+int position;
+
+#define dprintk(fmt, arg...) if (debug) \
+ printk(KERN_DEBUG "%s/alsa: " fmt, dev->name , ## arg)
+
+/*
+ * Main chip structure
+ */
+typedef struct snd_card_saa7134 {
+ snd_card_t *card;
+ spinlock_t mixer_lock;
+ int mixer_volume[MIXER_ADDR_LAST+1][2];
+ int capture_source[MIXER_ADDR_LAST+1][2];
+ struct pci_dev *pci;
+ struct saa7134_dev *dev;
+
+ unsigned long iobase;
+ int irq;
+
+ spinlock_t lock;
+} snd_card_saa7134_t;
+
+
+
+/*
+ * PCM structure
+ */
+
+typedef struct snd_card_saa7134_pcm {
+ struct saa7134_dev *dev;
+
+ spinlock_t lock;
+
+ snd_pcm_substream_t *substream;
+} snd_card_saa7134_pcm_t;
+
+static snd_card_t *snd_saa7134_cards[SNDRV_CARDS];
+
+
+/*
+ * saa7134 DMA audio stop
+ *
+ * Called when the capture device is released or the buffer overflows
+ *
+ * - Copied verbatim from saa7134-oss's dsp_dma_stop.
+ *
+ */
+
+static void saa7134_dma_stop(struct saa7134_dev *dev)
+{
+ dev->dmasound.dma_blk = -1;
+ dev->dmasound.dma_running = 0;
+ saa7134_set_dmabits(dev);
+}
+
+/*
+ * saa7134 DMA audio start
+ *
+ * Called when preparing the capture device for use
+ *
+ * - Copied verbatim from saa7134-oss's dsp_dma_start.
+ *
+ */
+
+static void saa7134_dma_start(struct saa7134_dev *dev)
+{
+ dev->dmasound.dma_blk = 0;
+ dev->dmasound.dma_running = 1;
+ saa7134_set_dmabits(dev);
+}
+
+/*
+ * saa7134 audio DMA IRQ handler
+ *
+ * Called whenever we get an SAA7134_IRQ_REPORT_DONE_RA3 interrupt
+ * Handles shifting between the 2 buffers, manages the read counters,
+ * and notifies ALSA when periods elapse
+ *
+ * - Mostly copied from saa7134-oss's saa7134_irq_oss_done.
+ *
+ */
+
+void saa7134_irq_alsa_done(struct saa7134_dev *dev, unsigned long status)
+{
+ int next_blk, reg = 0;
+
+ spin_lock(&dev->slock);
+ if (UNSET == dev->dmasound.dma_blk) {
+ dprintk("irq: recording stopped\n");
+ goto done;
+ }
+ if (0 != (status & 0x0f000000))
+ dprintk("irq: lost %ld\n", (status >> 24) & 0x0f);
+ if (0 == (status & 0x10000000)) {
+ /* odd */
+ if (0 == (dev->dmasound.dma_blk & 0x01))
+ reg = SAA7134_RS_BA1(6);
+ } else {
+ /* even */
+ if (1 == (dev->dmasound.dma_blk & 0x01))
+ reg = SAA7134_RS_BA2(6);
+ }
+ if (0 == reg) {
+ dprintk("irq: field oops [%s]\n",
+ (status & 0x10000000) ? "even" : "odd");
+ goto done;
+ }
+
+ if (dev->dmasound.read_count >= dev->dmasound.blksize * (dev->dmasound.blocks-2)) {
+ dprintk("irq: overrun [full=%d/%d] - Blocks in %d\n",dev->dmasound.read_count,
+ dev->dmasound.bufsize, dev->dmasound.blocks);
+ spin_unlock(&dev->slock);
+ snd_pcm_stop(dev->dmasound.substream,SNDRV_PCM_STATE_XRUN);
+ return;
+ }
+
+ /* next block addr */
+ next_blk = (dev->dmasound.dma_blk + 2) % dev->dmasound.blocks;
+ saa_writel(reg,next_blk * dev->dmasound.blksize);
+ if (debug > 2)
+ dprintk("irq: ok, %s, next_blk=%d, addr=%x, blocks=%u, size=%u, read=%u\n",
+ (status & 0x10000000) ? "even" : "odd ", next_blk,
+ next_blk * dev->dmasound.blksize, dev->dmasound.blocks, dev->dmasound.blksize, dev->dmasound.read_count);
+
+ /* update status & wake waiting readers */
+ dev->dmasound.dma_blk = (dev->dmasound.dma_blk + 1) % dev->dmasound.blocks;
+ dev->dmasound.read_count += dev->dmasound.blksize;
+
+ dev->dmasound.recording_on = reg;
+
+ if (dev->dmasound.read_count >= snd_pcm_lib_period_bytes(dev->dmasound.substream)) {
+ spin_unlock(&dev->slock);
+ snd_pcm_period_elapsed(dev->dmasound.substream);
+ spin_lock(&dev->slock);
+ }
+
+ done:
+ spin_unlock(&dev->slock);
+
+}
+
+/*
+ * IRQ request handler
+ *
+ * Runs along with saa7134's IRQ handler, discards anything that isn't
+ * DMA sound
+ *
+ */
+
+static irqreturn_t saa7134_alsa_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct saa7134_dmasound *dmasound = dev_id;
+ struct saa7134_dev *dev = dmasound->priv_data;
+
+ unsigned long report, status;
+ int loop, handled = 0;
+
+ for (loop = 0; loop < 10; loop++) {
+ report = saa_readl(SAA7134_IRQ_REPORT);
+ status = saa_readl(SAA7134_IRQ_STATUS);
+
+ if (report & SAA7134_IRQ_REPORT_DONE_RA3) {
+ handled = 1;
+ saa_writel(SAA7134_IRQ_REPORT,report);
+ saa7134_irq_alsa_done(dev, status);
+ } else {
+ goto out;
+ }
+ }
+
+ if (loop == 10) {
+ dprintk("error! looping IRQ!");
+ }
+
+out:
+ return IRQ_RETVAL(handled);
+}
+
+/*
+ * ALSA capture trigger
+ *
+ * - One of the ALSA capture callbacks.
+ *
+ * Called whenever a capture is started or stopped. Must be defined,
+ * but there's nothing we want to do here
+ *
+ */
+
+static int snd_card_saa7134_capture_trigger(snd_pcm_substream_t * substream,
+ int cmd)
+{
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ snd_card_saa7134_pcm_t *pcm = runtime->private_data;
+ struct saa7134_dev *dev=pcm->dev;
+ int err = 0;
+
+ spin_lock(&dev->slock);
+ if (cmd == SNDRV_PCM_TRIGGER_START) {
+ /* start dma */
+ saa7134_dma_start(dev);
+ } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
+ /* stop dma */
+ saa7134_dma_stop(dev);
+ } else {
+ err = -EINVAL;
+ }
+ spin_unlock(&dev->slock);
+
+ return err;
+}
+
+/*
+ * DMA buffer initialization
+ *
+ * Uses V4L functions to initialize the DMA. Shouldn't be necessary in
+ * ALSA, but I was unable to use ALSA's own DMA, and had to force the
+ * usage of V4L's
+ *
+ * - Copied verbatim from saa7134-oss.
+ *
+ */
+
+static int dsp_buffer_init(struct saa7134_dev *dev)
+{
+ int err;
+
+ BUG_ON(!dev->dmasound.bufsize);
+
+ videobuf_dma_init(&dev->dmasound.dma);
+ err = videobuf_dma_init_kernel(&dev->dmasound.dma, PCI_DMA_FROMDEVICE,
+ (dev->dmasound.bufsize + PAGE_SIZE) >> PAGE_SHIFT);
+ if (0 != err)
+ return err;
+ return 0;
+}
+
+/*
+ * DMA buffer release
+ *
+ * Called after closing the device, during snd_card_saa7134_capture_close
+ *
+ */
+
+static int dsp_buffer_free(struct saa7134_dev *dev)
+{
+ if (!dev->dmasound.blksize)
+ BUG();
+
+ videobuf_dma_free(&dev->dmasound.dma);
+
+ dev->dmasound.blocks = 0;
+ dev->dmasound.blksize = 0;
+ dev->dmasound.bufsize = 0;
+
+ return 0;
+}
+
+
+/*
+ * ALSA PCM preparation
+ *
+ * - One of the ALSA capture callbacks.
+ *
+ * Called right after the capture device is opened, this function configures
+ * the buffer using the previously defined functions, allocates the memory,
+ * sets up the hardware registers, and then starts the DMA. When this function
+ * returns, the audio should be flowing.
+ *
+ */
+
+static int snd_card_saa7134_capture_prepare(snd_pcm_substream_t * substream)
+{
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ int bswap, sign;
+ u32 fmt, control;
+ snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
+ struct saa7134_dev *dev;
+ snd_card_saa7134_pcm_t *pcm = runtime->private_data;
+
+ pcm->dev->dmasound.substream = substream;
+
+ dev = saa7134->dev;
+
+ if (snd_pcm_format_width(runtime->format) == 8)
+ fmt = 0x00;
+ else
+ fmt = 0x01;
+
+ if (snd_pcm_format_signed(runtime->format))
+ sign = 1;
+ else
+ sign = 0;
+
+ if (snd_pcm_format_big_endian(runtime->format))
+ bswap = 1;
+ else
+ bswap = 0;
+
+ switch (dev->pci->device) {
+ case PCI_DEVICE_ID_PHILIPS_SAA7134:
+ if (1 == runtime->channels)
+ fmt |= (1 << 3);
+ if (2 == runtime->channels)
+ fmt |= (3 << 3);
+ if (sign)
+ fmt |= 0x04;
+
+ fmt |= (MIXER_ADDR_TVTUNER == dev->dmasound.input) ? 0xc0 : 0x80;
+ saa_writeb(SAA7134_NUM_SAMPLES0, ((dev->dmasound.blksize - 1) & 0x0000ff));
+ saa_writeb(SAA7134_NUM_SAMPLES1, ((dev->dmasound.blksize - 1) & 0x00ff00) >> 8);
+ saa_writeb(SAA7134_NUM_SAMPLES2, ((dev->dmasound.blksize - 1) & 0xff0000) >> 16);
+ saa_writeb(SAA7134_AUDIO_FORMAT_CTRL, fmt);
+
+ break;
+ case PCI_DEVICE_ID_PHILIPS_SAA7133:
+ case PCI_DEVICE_ID_PHILIPS_SAA7135:
+ if (1 == runtime->channels)
+ fmt |= (1 << 4);
+ if (2 == runtime->channels)
+ fmt |= (2 << 4);
+ if (!sign)
+ fmt |= 0x04;
+ saa_writel(SAA7133_NUM_SAMPLES, dev->dmasound.blksize -1);
+ saa_writel(SAA7133_AUDIO_CHANNEL, 0x543210 | (fmt << 24));
+ break;
+ }
+
+ dprintk("rec_start: afmt=%d ch=%d => fmt=0x%x swap=%c\n",
+ runtime->format, runtime->channels, fmt,
+ bswap ? 'b' : '-');
+ /* dma: setup channel 6 (= AUDIO) */
+ control = SAA7134_RS_CONTROL_BURST_16 |
+ SAA7134_RS_CONTROL_ME |
+ (dev->dmasound.pt.dma >> 12);
+ if (bswap)
+ control |= SAA7134_RS_CONTROL_BSWAP;
+
+ saa_writel(SAA7134_RS_BA1(6),0);
+ saa_writel(SAA7134_RS_BA2(6),dev->dmasound.blksize);
+ saa_writel(SAA7134_RS_PITCH(6),0);
+ saa_writel(SAA7134_RS_CONTROL(6),control);
+
+ dev->dmasound.rate = runtime->rate;
+
+ return 0;
+
+}
+
+/*
+ * ALSA pointer fetching
+ *
+ * - One of the ALSA capture callbacks.
+ *
+ * Called whenever a period elapses, it must return the current hardware
+ * position of the buffer.
+ * Also resets the read counter used to prevent overruns
+ *
+ */
+
+static snd_pcm_uframes_t snd_card_saa7134_capture_pointer(snd_pcm_substream_t * substream)
+{
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ snd_card_saa7134_pcm_t *pcm = runtime->private_data;
+ struct saa7134_dev *dev=pcm->dev;
+
+ if (dev->dmasound.read_count) {
+ dev->dmasound.read_count -= snd_pcm_lib_period_bytes(substream);
+ dev->dmasound.read_offset += snd_pcm_lib_period_bytes(substream);
+ if (dev->dmasound.read_offset == dev->dmasound.bufsize)
+ dev->dmasound.read_offset = 0;
+ }
+
+ return bytes_to_frames(runtime, dev->dmasound.read_offset);
+}
+
+/*
+ * ALSA hardware capabilities definition
+ */
+
+static snd_pcm_hardware_t snd_card_saa7134_capture =
+{
+ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S16_BE | \
+ SNDRV_PCM_FMTBIT_S8 | \
+ SNDRV_PCM_FMTBIT_U8 | \
+ SNDRV_PCM_FMTBIT_U16_LE | \
+ SNDRV_PCM_FMTBIT_U16_BE,
+ .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .rate_min = 32000,
+ .rate_max = 48000,
+ .channels_min = 1,
+ .channels_max = 2,
+ .buffer_bytes_max = (256*1024),
+ .period_bytes_min = 64,
+ .period_bytes_max = (256*1024),
+ .periods_min = 2,
+ .periods_max = 1024,
+};
+
+static void snd_card_saa7134_runtime_free(snd_pcm_runtime_t *runtime)
+{
+ snd_card_saa7134_pcm_t *pcm = runtime->private_data;
+
+ kfree(pcm);
+}
+
+
+/*
+ * ALSA hardware params
+ *
+ * - One of the ALSA capture callbacks.
+ *
+ * Called on initialization, right before the PCM preparation
+ *
+ */
+
+static int snd_card_saa7134_hw_params(snd_pcm_substream_t * substream,
+ snd_pcm_hw_params_t * hw_params)
+{
+ snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
+ struct saa7134_dev *dev;
+ unsigned int period_size, periods;
+ int err;
+
+ period_size = params_period_bytes(hw_params);
+ periods = params_periods(hw_params);
+
+ snd_assert(period_size >= 0x100 && period_size <= 0x10000,
+ return -EINVAL);
+ snd_assert(periods >= 2, return -EINVAL);
+ snd_assert(period_size * periods <= 1024 * 1024, return -EINVAL);
+
+ dev = saa7134->dev;
+
+ if (dev->dmasound.blocks == periods &&
+ dev->dmasound.blksize == period_size)
+ return 0;
+
+ /* release the old buffer */
+ if (substream->runtime->dma_area) {
+ saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
+ videobuf_dma_pci_unmap(dev->pci, &dev->dmasound.dma);
+ dsp_buffer_free(dev);
+ substream->runtime->dma_area = NULL;
+ }
+ dev->dmasound.blocks = periods;
+ dev->dmasound.blksize = period_size;
+ dev->dmasound.bufsize = period_size * periods;
+
+ err = dsp_buffer_init(dev);
+ if (0 != err) {
+ dev->dmasound.blocks = 0;
+ dev->dmasound.blksize = 0;
+ dev->dmasound.bufsize = 0;
+ return err;
+ }
+
+ if (0 != (err = videobuf_dma_pci_map(dev->pci, &dev->dmasound.dma))) {
+ dsp_buffer_free(dev);
+ return err;
+ }
+ if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->dmasound.pt))) {
+ videobuf_dma_pci_unmap(dev->pci, &dev->dmasound.dma);
+ dsp_buffer_free(dev);
+ return err;
+ }
+ if (0 != (err = saa7134_pgtable_build(dev->pci,&dev->dmasound.pt,
+ dev->dmasound.dma.sglist,
+ dev->dmasound.dma.sglen,
+ 0))) {
+ saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
+ videobuf_dma_pci_unmap(dev->pci, &dev->dmasound.dma);
+ dsp_buffer_free(dev);
+ return err;
+ }
+
+ /* I should be able to use runtime->dma_addr in the control
+ byte, but it doesn't work. So I allocate the DMA using the
+ V4L functions, and force ALSA to use that as the DMA area */
+
+ substream->runtime->dma_area = dev->dmasound.dma.vmalloc;
+
+ return 1;
+
+}
+
+/*
+ * ALSA hardware release
+ *
+ * - One of the ALSA capture callbacks.
+ *
+ * Called after closing the device, but before snd_card_saa7134_capture_close
+ * It stops the DMA audio and releases the buffers.
+ *
+ */
+
+static int snd_card_saa7134_hw_free(snd_pcm_substream_t * substream)
+{
+ snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
+ struct saa7134_dev *dev;
+
+ dev = saa7134->dev;
+
+ if (substream->runtime->dma_area) {
+ saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
+ videobuf_dma_pci_unmap(dev->pci, &dev->dmasound.dma);
+ dsp_buffer_free(dev);
+ substream->runtime->dma_area = NULL;
+ }
+
+ return 0;
+}
+
+/*
+ * ALSA capture finish
+ *
+ * - One of the ALSA capture callbacks.
+ *
+ * Called after closing the device.
+ *
+ */
+
+static int snd_card_saa7134_capture_close(snd_pcm_substream_t * substream)
+{
+ return 0;
+}
+
+/*
+ * ALSA capture start
+ *
+ * - One of the ALSA capture callbacks.
+ *
+ * Called when opening the device. It creates and populates the PCM
+ * structure
+ *
+ */
+
+static int snd_card_saa7134_capture_open(snd_pcm_substream_t * substream)
+{
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ snd_card_saa7134_pcm_t *pcm;
+ snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
+ struct saa7134_dev *dev = saa7134->dev;
+ int err;
+
+ down(&dev->dmasound.lock);
+
+ dev->dmasound.read_count = 0;
+ dev->dmasound.read_offset = 0;
+
+ up(&dev->dmasound.lock);
+
+ pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
+ if (pcm == NULL)
+ return -ENOMEM;
+
+ pcm->dev=saa7134->dev;
+
+ spin_lock_init(&pcm->lock);
+
+ pcm->substream = substream;
+ runtime->private_data = pcm;
+ runtime->private_free = snd_card_saa7134_runtime_free;
+ runtime->hw = snd_card_saa7134_capture;
+
+ if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
+ return err;
+
+ return 0;
+}
+
+/*
+ * ALSA capture callbacks definition
+ */
+
+static snd_pcm_ops_t snd_card_saa7134_capture_ops = {
+ .open = snd_card_saa7134_capture_open,
+ .close = snd_card_saa7134_capture_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_card_saa7134_hw_params,
+ .hw_free = snd_card_saa7134_hw_free,
+ .prepare = snd_card_saa7134_capture_prepare,
+ .trigger = snd_card_saa7134_capture_trigger,
+ .pointer = snd_card_saa7134_capture_pointer,
+};
+
+/*
+ * ALSA PCM setup
+ *
+ * Called when initializing the board. Sets up the name and hooks up
+ * the callbacks
+ *
+ */
+
+static int snd_card_saa7134_pcm(snd_card_saa7134_t *saa7134, int device)
+{
+ snd_pcm_t *pcm;
+ int err;
+
+ if ((err = snd_pcm_new(saa7134->card, "SAA7134 PCM", device, 0, 1, &pcm)) < 0)
+ return err;
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_saa7134_capture_ops);
+ pcm->private_data = saa7134;
+ pcm->info_flags = 0;
+ strcpy(pcm->name, "SAA7134 PCM");
+ return 0;
+}
+
+#define SAA713x_VOLUME(xname, xindex, addr) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+ .info = snd_saa7134_volume_info, \
+ .get = snd_saa7134_volume_get, .put = snd_saa7134_volume_put, \
+ .private_value = addr }
+
+static int snd_saa7134_volume_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 20;
+ return 0;
+}
+
+static int snd_saa7134_volume_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
+ int addr = kcontrol->private_value;
+
+ ucontrol->value.integer.value[0] = chip->mixer_volume[addr][0];
+ ucontrol->value.integer.value[1] = chip->mixer_volume[addr][1];
+ return 0;
+}
+
+static int snd_saa7134_volume_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
+ int change, addr = kcontrol->private_value;
+ int left, right;
+
+ left = ucontrol->value.integer.value[0];
+ if (left < 0)
+ left = 0;
+ if (left > 20)
+ left = 20;
+ right = ucontrol->value.integer.value[1];
+ if (right < 0)
+ right = 0;
+ if (right > 20)
+ right = 20;
+ spin_lock_irq(&chip->mixer_lock);
+ change = chip->mixer_volume[addr][0] != left ||
+ chip->mixer_volume[addr][1] != right;
+ chip->mixer_volume[addr][0] = left;
+ chip->mixer_volume[addr][1] = right;
+ spin_unlock_irq(&chip->mixer_lock);
+ return change;
+}
+
+#define SAA713x_CAPSRC(xname, xindex, addr) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+ .info = snd_saa7134_capsrc_info, \
+ .get = snd_saa7134_capsrc_get, .put = snd_saa7134_capsrc_put, \
+ .private_value = addr }
+
+static int snd_saa7134_capsrc_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int snd_saa7134_capsrc_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
+ int addr = kcontrol->private_value;
+
+ spin_lock_irq(&chip->mixer_lock);
+ ucontrol->value.integer.value[0] = chip->capture_source[addr][0];
+ ucontrol->value.integer.value[1] = chip->capture_source[addr][1];
+ spin_unlock_irq(&chip->mixer_lock);
+
+ return 0;
+}
+
+static int snd_saa7134_capsrc_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
+ int change, addr = kcontrol->private_value;
+ int left, right;
+ u32 anabar, xbarin;
+ int analog_io, rate;
+ struct saa7134_dev *dev;
+
+ dev = chip->dev;
+
+ left = ucontrol->value.integer.value[0] & 1;
+ right = ucontrol->value.integer.value[1] & 1;
+ spin_lock_irq(&chip->mixer_lock);
+
+ change = chip->capture_source[addr][0] != left ||
+ chip->capture_source[addr][1] != right;
+ chip->capture_source[addr][0] = left;
+ chip->capture_source[addr][1] = right;
+ dev->dmasound.input=addr;
+ spin_unlock_irq(&chip->mixer_lock);
+
+
+ if (change) {
+ switch (dev->pci->device) {
+
+ case PCI_DEVICE_ID_PHILIPS_SAA7134:
+ switch (addr) {
+ case MIXER_ADDR_TVTUNER:
+ saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0xc0);
+ saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, 0x00);
+ break;
+ case MIXER_ADDR_LINE1:
+ case MIXER_ADDR_LINE2:
+ analog_io = (MIXER_ADDR_LINE1 == addr) ? 0x00 : 0x08;
+ rate = (32000 == dev->dmasound.rate) ? 0x01 : 0x03;
+ saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x08, analog_io);
+ saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0x80);
+ saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, rate);
+ break;
+ }
+
+ break;
+ case PCI_DEVICE_ID_PHILIPS_SAA7133:
+ case PCI_DEVICE_ID_PHILIPS_SAA7135:
+ xbarin = 0x03; // adc
+ anabar = 0;
+ switch (addr) {
+ case MIXER_ADDR_TVTUNER:
+ xbarin = 0; // Demodulator
+ anabar = 2; // DACs
+ break;
+ case MIXER_ADDR_LINE1:
+ anabar = 0; // aux1, aux1
+ break;
+ case MIXER_ADDR_LINE2:
+ anabar = 9; // aux2, aux2
+ break;
+ }
+
+ /* output xbar always main channel */
+ saa_dsp_writel(dev, SAA7133_DIGITAL_OUTPUT_SEL1, 0xbbbb10);
+
+ if (left || right) { // We've got data, turn the input on
+ saa_dsp_writel(dev, SAA7133_DIGITAL_INPUT_XBAR1, xbarin);
+ saa_writel(SAA7133_ANALOG_IO_SELECT, anabar);
+ } else {
+ saa_dsp_writel(dev, SAA7133_DIGITAL_INPUT_XBAR1, 0);
+ saa_writel(SAA7133_ANALOG_IO_SELECT, 0);
+ }
+ break;
+ }
+ }
+
+ return change;
+}
+
+static snd_kcontrol_new_t snd_saa7134_controls[] = {
+SAA713x_VOLUME("Video Volume", 0, MIXER_ADDR_TVTUNER),
+SAA713x_CAPSRC("Video Capture Switch", 0, MIXER_ADDR_TVTUNER),
+SAA713x_VOLUME("Line Volume", 1, MIXER_ADDR_LINE1),
+SAA713x_CAPSRC("Line Capture Switch", 1, MIXER_ADDR_LINE1),
+SAA713x_VOLUME("Line Volume", 2, MIXER_ADDR_LINE2),
+SAA713x_CAPSRC("Line Capture Switch", 2, MIXER_ADDR_LINE2),
+};
+
+/*
+ * ALSA mixer setup
+ *
+ * Called when initializing the board. Sets up the name and hooks up
+ * the callbacks
+ *
+ */
+
+static int snd_card_saa7134_new_mixer(snd_card_saa7134_t * chip)
+{
+ snd_card_t *card = chip->card;
+ unsigned int idx;
+ int err;
+
+ snd_assert(chip != NULL, return -EINVAL);
+ strcpy(card->mixername, "SAA7134 Mixer");
+
+ for (idx = 0; idx < ARRAY_SIZE(snd_saa7134_controls); idx++) {
+ if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_saa7134_controls[idx], chip))) < 0)
+ return err;
+ }
+ return 0;
+}
+
+static void snd_saa7134_free(snd_card_t * card)
+{
+ snd_card_saa7134_t *chip = card->private_data;
+
+ if (chip->dev->dmasound.priv_data == NULL)
+ return;
+
+ if (chip->irq >= 0) {
+ synchronize_irq(chip->irq);
+ free_irq(chip->irq, &chip->dev->dmasound);
+ }
+
+ chip->dev->dmasound.priv_data = NULL;
+
+}
+
+/*
+ * ALSA initialization
+ *
+ * Called by the init routine, once for each saa7134 device present,
+ * it creates the basic structures and registers the ALSA devices
+ *
+ */
+
+int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum)
+{
+
+ snd_card_t *card;
+ snd_card_saa7134_t *chip;
+ int err;
+
+
+ if (devnum >= SNDRV_CARDS)
+ return -ENODEV;
+ if (!enable[devnum])
+ return -ENODEV;
+
+ card = snd_card_new(index[devnum], id[devnum], THIS_MODULE, sizeof(snd_card_saa7134_t));
+
+ if (card == NULL)
+ return -ENOMEM;
+
+ strcpy(card->driver, "SAA7134");
+
+ /* Card "creation" */
+
+ card->private_free = snd_saa7134_free;
+ chip = (snd_card_saa7134_t *) card->private_data;
+
+ spin_lock_init(&chip->lock);
+ spin_lock_init(&chip->mixer_lock);
+
+ chip->dev = dev;
+
+ chip->card = card;
+
+ chip->pci = dev->pci;
+ chip->iobase = pci_resource_start(dev->pci, 0);
+
+
+ err = request_irq(dev->pci->irq, saa7134_alsa_irq,
+ SA_SHIRQ | SA_INTERRUPT, dev->name,
+ (void*) &dev->dmasound);
+
+ if (err < 0) {
+ printk(KERN_ERR "%s: can't get IRQ %d for ALSA\n",
+ dev->name, dev->pci->irq);
+ goto __nodev;
+ }
+
+ chip->irq = dev->pci->irq;
+
+ init_MUTEX(&dev->dmasound.lock);
+
+ if ((err = snd_card_saa7134_new_mixer(chip)) < 0)
+ goto __nodev;
+
+ if ((err = snd_card_saa7134_pcm(chip, 0)) < 0)
+ goto __nodev;
+
+ snd_card_set_dev(card, &chip->pci->dev);
+
+ /* End of "creation" */
+
+ strcpy(card->shortname, "SAA7134");
+ sprintf(card->longname, "%s at 0x%lx irq %d",
+ chip->dev->name, chip->iobase, chip->irq);
+
+ if ((err = snd_card_register(card)) == 0) {
+ snd_saa7134_cards[devnum] = card;
+ return 0;
+ }
+
+__nodev:
+ snd_card_free(card);
+ return err;
+}
+
+/*
+ * Module initializer
+ *
+ * Loops through present saa7134 cards, and assigns an ALSA device
+ * to each one
+ *
+ */
+
+static int saa7134_alsa_init(void)
+{
+ struct saa7134_dev *dev = NULL;
+ struct list_head *list;
+
+ position = 0;
+
+ printk(KERN_INFO "saa7134 ALSA driver for DMA sound loaded\n");
+
+ list_for_each(list,&saa7134_devlist) {
+ dev = list_entry(list, struct saa7134_dev, devlist);
+ if (dev->dmasound.priv_data == NULL) {
+ dev->dmasound.priv_data = dev;
+ alsa_card_saa7134_create(dev,position);
+ position++;
+ } else {
+ printk(KERN_ERR "saa7134 ALSA: DMA sound is being handled by OSS. ignoring %s\n",dev->name);
+ return -EBUSY;
+ }
+ }
+
+ if (dev == NULL)
+ printk(KERN_INFO "saa7134 ALSA: no saa7134 cards found\n");
+
+ return 0;
+}
+
+/*
+ * Module destructor
+ */
+
+void saa7134_alsa_exit(void)
+{
+ int idx;
+
+ for (idx = 0; idx < SNDRV_CARDS; idx++) {
+ snd_card_free(snd_saa7134_cards[idx]);
+ }
+
+ printk(KERN_INFO "saa7134 ALSA driver for DMA sound unloaded\n");
+
+ return;
+}
+
+module_init(saa7134_alsa_init);
+module_exit(saa7134_alsa_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ricardo Cerqueira");
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index acc7a4335e2..75abc20b0cc 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -191,10 +191,14 @@ struct saa7134_board saa7134_boards[] = {
.amux = TV,
.tv = 1,
},{
- .name = name_comp1,
+ .name = name_comp1, /* Composite signal on S-Video input */
.vmux = 0,
.amux = LINE2,
},{
+ .name = name_comp2, /* Composite input */
+ .vmux = 3,
+ .amux = LINE2,
+ },{
.name = name_svideo,
.vmux = 8,
.amux = LINE2,
@@ -2109,8 +2113,449 @@ struct saa7134_board saa7134_boards[] = {
.gpio = 0x01,
},
},
-};
+ [SAA7134_BOARD_BEHOLD_409FM] = {
+ /* <http://tuner.beholder.ru>, Sergey <skiv@orel.ru> */
+ .name = "Beholder BeholdTV 409 FM",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 3,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 1,
+ .amux = LINE1,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_GOTVIEW_7135] = {
+ /* Mike Baikov <mike@baikov.com> */
+ /* Andrey Cvetcov <ays14@yandex.ru> */
+ .name = "GoTView 7135 PCI",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x00200003,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ .gpio = 0x00200003,
+ },{
+ .name = name_tv_mono,
+ .vmux = 1,
+ .amux = LINE2,
+ .gpio = 0x00200003,
+ },{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x00200003,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ .gpio = 0x00200003,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = LINE2,
+ .gpio = 0x00200003,
+ },
+ .mute = {
+ .name = name_mute,
+ .amux = TV,
+ .gpio = 0x00200003,
+ },
+ },
+ [SAA7134_BOARD_PHILIPS_EUROPA] = {
+ .name = "Philips EUROPA V3 reference design",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TD1316,
+ .radio_type = UNSET,
+ .tuner_addr = 0x61,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 3,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 0,
+ .amux = LINE2,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_VIDEOMATE_DVBT_300] = {
+ .name = "Compro Videomate DVB-T300",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TD1316,
+ .radio_type = UNSET,
+ .tuner_addr = 0x61,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 3,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 1,
+ .amux = LINE2,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_VIDEOMATE_DVBT_200] = {
+ .name = "Compro Videomate DVB-T200",
+ .tuner_type = TUNER_ABSENT,
+ .audio_clock = 0x00187de7,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .name = name_comp1,
+ .vmux = 0,
+ .amux = LINE1,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ },
+ [SAA7134_BOARD_RTD_VFG7350] = {
+ .name = "RTD Embedded Technologies VFG7350",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .name = "Composite 0",
+ .vmux = 0,
+ .amux = LINE1,
+ },{
+ .name = "Composite 1",
+ .vmux = 1,
+ .amux = LINE2,
+ },{
+ .name = "Composite 2",
+ .vmux = 2,
+ .amux = LINE1,
+ },{
+ .name = "Composite 3",
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .name = "S-Video 0",
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .name = "S-Video 1",
+ .vmux = 9,
+ .amux = LINE2,
+ }},
+ .mpeg = SAA7134_MPEG_EMPRESS,
+ .video_out = CCIR656,
+ .vid_port_opts = ( SET_T_CODE_POLARITY_NON_INVERTED |
+ SET_CLOCK_NOT_DELAYED |
+ SET_CLOCK_INVERTED |
+ SET_VSYNC_OFF ),
+ },
+ [SAA7134_BOARD_RTD_VFG7330] = {
+ .name = "RTD Embedded Technologies VFG7330",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .name = "Composite 0",
+ .vmux = 0,
+ .amux = LINE1,
+ },{
+ .name = "Composite 1",
+ .vmux = 1,
+ .amux = LINE2,
+ },{
+ .name = "Composite 2",
+ .vmux = 2,
+ .amux = LINE1,
+ },{
+ .name = "Composite 3",
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .name = "S-Video 0",
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .name = "S-Video 1",
+ .vmux = 9,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_FLYTVPLATINUM_MINI2] = {
+ .name = "LifeView FlyTV Platinum Mini2",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1, /* Composite signal on S-Video input */
+ .vmux = 0,
+ .amux = LINE2,
+ },{
+ .name = name_comp2, /* Composite input */
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180] = {
+ /* Michael Krufky <mkrufky@m1k.net>
+ * Uses Alps Electric TDHU2, containing NXT2004 ATSC Decoder
+ * AFAIK, there is no analog demod, thus,
+ * no support for analog television.
+ */
+ .name = "AVerMedia AVerTVHD MCE A180",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_MONSTERTV_MOBILE] = {
+ .name = "SKNet MonsterTV Mobile",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .name = name_svideo,
+ .vmux = 6,
+ .amux = LINE1,
+ }},
+ },
+ [SAA7134_BOARD_PINNACLE_PCTV_110i] = {
+ .name = "Pinnacle PCTV 110i (saa7133)",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x080200000,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 4,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 1,
+ .amux = LINE2,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = LINE1,
+ },
+ },
+ [SAA7134_BOARD_ASUSTeK_P7131_DUAL] = {
+ .name = "ASUSTeK P7131 Dual",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 1 << 21,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = TV,
+ .gpio = 0x0200000,
+ },
+ },
+ [SAA7134_BOARD_SEDNA_PC_TV_CARDBUS] = {
+ /* Paul Tom Zalac <pzalac@gmail.com> */
+ /* Pavel Mihaylov <bin@bash.info> */
+ .name = "Sedna/MuchTV PC TV Cardbus TV/Radio (ITO25 Rev:2B)",
+ /* Sedna/MuchTV (OEM) Cardbus TV Tuner */
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0xe880c0,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 3,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 1,
+ .amux = LINE1,
+ },{
+ .name = name_svideo,
+ .vmux = 6,
+ .amux = LINE1,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV] = {
+ /* "Cyril Lacoux (Yack)" <clacoux@ifeelgood.org> */
+ .name = "ASUS Digimatrix TV",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_FQ1216ME,
+ .tda9887_conf = TDA9887_PRESENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ },
+ [SAA7134_BOARD_PHILIPS_TIGER] = {
+ .name = "Philips Tiger reference design",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ },
+ [SAA7134_BOARD_MSI_TVATANYWHERE_PLUS] = {
+ .name = "MSI TV@Anywhere plus",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .name = name_svideo,
+ .vmux = 0,
+ .amux = LINE1,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = LINE1,
+ },
+ },
+};
const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -2145,19 +2590,19 @@ struct pci_device_id saa7134_pci_tbl[] = {
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
- .subvendor = 0x153B,
+ .subvendor = 0x153b,
.subdevice = 0x1142,
.driver_data = SAA7134_BOARD_CINERGY400,
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
- .subvendor = 0x153B,
+ .subvendor = 0x153b,
.subdevice = 0x1143,
.driver_data = SAA7134_BOARD_CINERGY600,
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
- .subvendor = 0x153B,
+ .subvendor = 0x153b,
.subdevice = 0x1158,
.driver_data = SAA7134_BOARD_CINERGY600_MK3,
},{
@@ -2193,6 +2638,18 @@ struct pci_device_id saa7134_pci_tbl[] = {
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x14c0,
+ .subdevice = 0x1212, /* minipci, LR1212 */
+ .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI2,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x4e42,
+ .subdevice = 0x0212, /* OEM minipci, LR212 */
+ .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
.subvendor = 0x5168, /* Animation Technologies (LifeView) */
.subdevice = 0x0214, /* Standard PCI, LR214WF */
.driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM,
@@ -2369,7 +2826,7 @@ struct pci_device_id saa7134_pci_tbl[] = {
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7130,
- .subvendor = 0x153B,
+ .subvendor = 0x153b,
.subdevice = 0x1152,
.driver_data = SAA7134_BOARD_CINERGY200,
},{
@@ -2434,13 +2891,18 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subvendor = 0x1421,
.subdevice = 0x0350, /* PCI version */
.driver_data = SAA7134_BOARD_ADS_INSTANT_TV,
-
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7133,
.subvendor = 0x1421,
.subdevice = 0x0370, /* cardbus version */
.driver_data = SAA7134_BOARD_ADS_INSTANT_TV,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1421,
+ .subdevice = 0x1370, /* cardbus version */
+ .driver_data = SAA7134_BOARD_ADS_INSTANT_TV,
},{ /* Typhoon DVB-T Duo Digital/Analog Cardbus */
.vendor = PCI_VENDOR_ID_PHILIPS,
@@ -2459,9 +2921,87 @@ struct pci_device_id saa7134_pci_tbl[] = {
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
.subvendor = 0x1043,
.subdevice = 0x0210, /* mini pci PAL/SECAM version */
- .driver_data = SAA7134_BOARD_FLYTV_DIGIMATRIX,
+ .driver_data = SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV,
},{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x0000, /* It shouldn't break anything, since subdevice id seems unique */
+ .subdevice = 0x4091,
+ .driver_data = SAA7134_BOARD_BEHOLD_409FM,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5456, /* GoTView */
+ .subdevice = 0x7135,
+ .driver_data = SAA7134_BOARD_GOTVIEW_7135,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = PCI_VENDOR_ID_PHILIPS,
+ .subdevice = 0x2004,
+ .driver_data = SAA7134_BOARD_PHILIPS_EUROPA,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x185b,
+ .subdevice = 0xc900,
+ .driver_data = SAA7134_BOARD_VIDEOMATE_DVBT_300,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x185b,
+ .subdevice = 0xc901,
+ .driver_data = SAA7134_BOARD_VIDEOMATE_DVBT_200,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1435,
+ .subdevice = 0x7350,
+ .driver_data = SAA7134_BOARD_RTD_VFG7350,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1435,
+ .subdevice = 0x7330,
+ .driver_data = SAA7134_BOARD_RTD_VFG7330,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461,
+ .subdevice = 0x1044,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1131,
+ .subdevice = 0x4ee9,
+ .driver_data = SAA7134_BOARD_MONSTERTV_MOBILE,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x11bd,
+ .subdevice = 0x002e,
+ .driver_data = SAA7134_BOARD_PINNACLE_PCTV_110i,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1043,
+ .subdevice = 0x4862,
+ .driver_data = SAA7134_BOARD_ASUSTeK_P7131_DUAL,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = PCI_VENDOR_ID_PHILIPS,
+ .subdevice = 0x2018,
+ .driver_data = SAA7134_BOARD_PHILIPS_TIGER,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1462,
+ .subdevice = 0x6231,
+ .driver_data = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS,
+ },{
/* --- boards without eeprom + subsystem ID --- */
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -2530,9 +3070,10 @@ int saa7134_board_init1(struct saa7134_dev *dev)
switch (dev->board) {
case SAA7134_BOARD_FLYVIDEO2000:
case SAA7134_BOARD_FLYVIDEO3000:
- dev->has_remote = 1;
+ dev->has_remote = SAA7134_REMOTE_GPIO;
board_flyvideo(dev);
break;
+ case SAA7134_BOARD_FLYTVPLATINUM_MINI2:
case SAA7134_BOARD_FLYTVPLATINUM_FM:
case SAA7134_BOARD_CINERGY400:
case SAA7134_BOARD_CINERGY600:
@@ -2550,10 +3091,16 @@ int saa7134_board_init1(struct saa7134_dev *dev)
/* case SAA7134_BOARD_SABRENT_SBTTVFM: */ /* not finished yet */
case SAA7134_BOARD_VIDEOMATE_TV_PVR:
case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII:
+ case SAA7134_BOARD_VIDEOMATE_DVBT_300:
+ case SAA7134_BOARD_VIDEOMATE_DVBT_200:
case SAA7134_BOARD_MANLI_MTV001:
case SAA7134_BOARD_MANLI_MTV002:
+ case SAA7134_BOARD_BEHOLD_409FM:
case SAA7134_BOARD_AVACSSMARTTV:
- dev->has_remote = 1;
+ case SAA7134_BOARD_GOTVIEW_7135:
+ case SAA7134_BOARD_KWORLD_TERMINATOR:
+ case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS:
+ dev->has_remote = SAA7134_REMOTE_GPIO;
break;
case SAA7134_BOARD_MD5044:
printk("%s: seems there are two different versions of the MD5044\n"
@@ -2565,11 +3112,14 @@ int saa7134_board_init1(struct saa7134_dev *dev)
/* power-up tuner chip */
saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x00040000, 0x00040000);
saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00040000, 0x00000000);
- msleep(1);
+ case SAA7134_BOARD_MONSTERTV_MOBILE:
+ /* power-up tuner chip */
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x00040000, 0x00040000);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00040000, 0x00000004);
break;
case SAA7134_BOARD_FLYDVBTDUO:
case SAA7134_BOARD_THYPHOON_DVBT_DUO_CARDBUS:
- /* turn the fan on Hac: static for the time being */
+ /* turn the fan on */
saa_writeb(SAA7134_GPIO_GPMODE3, 0x08);
saa_writeb(SAA7134_GPIO_GPSTATUS3, 0x06);
break;
@@ -2579,6 +3129,22 @@ int saa7134_board_init1(struct saa7134_dev *dev)
saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0xffffffff, 0xffffffff);
msleep(1);
break;
+ case SAA7134_BOARD_RTD_VFG7350:
+
+ /*
+ * Make sure Production Test Register at offset 0x1D1 is cleared
+ * to take chip out of test mode. Clearing bit 4 (TST_EN_AOUT)
+ * prevents pin 105 from remaining low; keeping pin 105 low
+ * continually resets the SAA6752 chip.
+ */
+
+ saa_writeb (SAA7134_PRODUCTION_TEST_MODE, 0x00);
+ break;
+ /* i2c remotes */
+ case SAA7134_BOARD_PINNACLE_PCTV_110i:
+ case SAA7134_BOARD_UPMOST_PURPLE_TV:
+ dev->has_remote = SAA7134_REMOTE_I2C;
+ break;
}
return 0;
}
@@ -2613,7 +3179,7 @@ int saa7134_board_init2(struct saa7134_dev *dev)
saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR, &tun_setup);
}
break;
-case SAA7134_BOARD_MD7134:
+ case SAA7134_BOARD_MD7134:
{
struct tuner_setup tun_setup;
u8 subaddr;
@@ -2680,6 +3246,33 @@ case SAA7134_BOARD_MD7134:
saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR,&tun_setup);
}
break;
+ case SAA7134_BOARD_PHILIPS_EUROPA:
+ case SAA7134_BOARD_VIDEOMATE_DVBT_300:
+ /* The Philips EUROPA based hybrid boards have the tuner connected through
+ * the channel decoder. We have to make it transparent to find it
+ */
+ {
+ struct tuner_setup tun_setup;
+ u8 data[] = { 0x07, 0x02};
+ struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+
+ tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
+ tun_setup.type = dev->tuner_type;
+ tun_setup.addr = dev->tuner_addr;
+
+ saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR,&tun_setup);
+ }
+ break;
+ case SAA7134_BOARD_PHILIPS_TIGER:
+ case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
+ /* this is a hybrid board, initialize to analog mode */
+ {
+ u8 data[] = { 0x3c, 0x33, 0x68};
+ struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+ }
+ break;
}
return 0;
}
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index e5e36f3c625..4275d2ddb86 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -53,9 +53,13 @@ static unsigned int gpio_tracking = 0;
module_param(gpio_tracking, int, 0644);
MODULE_PARM_DESC(gpio_tracking,"enable debug messages [gpio]");
+static unsigned int alsa = 0;
+module_param(alsa, int, 0644);
+MODULE_PARM_DESC(alsa,"enable ALSA DMA sound [dmasound]");
+
static unsigned int oss = 0;
-module_param(oss, int, 0444);
-MODULE_PARM_DESC(oss,"register oss devices (default: no)");
+module_param(oss, int, 0644);
+MODULE_PARM_DESC(oss,"enable OSS DMA sound [dmasound]");
static unsigned int latency = UNSET;
module_param(latency, int, 0444);
@@ -64,24 +68,18 @@ MODULE_PARM_DESC(latency,"pci latency timer");
static unsigned int video_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
static unsigned int vbi_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
static unsigned int radio_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
-static unsigned int dsp_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
-static unsigned int mixer_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
static unsigned int tuner[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
static unsigned int card[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
module_param_array(video_nr, int, NULL, 0444);
module_param_array(vbi_nr, int, NULL, 0444);
module_param_array(radio_nr, int, NULL, 0444);
-module_param_array(dsp_nr, int, NULL, 0444);
-module_param_array(mixer_nr, int, NULL, 0444);
module_param_array(tuner, int, NULL, 0444);
module_param_array(card, int, NULL, 0444);
MODULE_PARM_DESC(video_nr, "video device number");
MODULE_PARM_DESC(vbi_nr, "vbi device number");
MODULE_PARM_DESC(radio_nr, "radio device number");
-MODULE_PARM_DESC(dsp_nr, "oss dsp device number");
-MODULE_PARM_DESC(mixer_nr, "oss mixer device number");
MODULE_PARM_DESC(tuner, "tuner type");
MODULE_PARM_DESC(card, "card type");
@@ -190,6 +188,8 @@ void saa7134_track_gpio(struct saa7134_dev *dev, char *msg)
static int need_empress;
static int need_dvb;
+static int need_alsa;
+static int need_oss;
static int pending_call(struct notifier_block *self, unsigned long state,
void *module)
@@ -197,10 +197,14 @@ static int pending_call(struct notifier_block *self, unsigned long state,
if (module != THIS_MODULE || state != MODULE_STATE_LIVE)
return NOTIFY_DONE;
- if (need_empress)
- request_module("saa7134-empress");
- if (need_dvb)
- request_module("saa7134-dvb");
+ if (need_empress)
+ request_module("saa7134-empress");
+ if (need_dvb)
+ request_module("saa7134-dvb");
+ if (need_alsa)
+ request_module("saa7134-alsa");
+ if (need_oss)
+ request_module("saa7134-oss");
return NOTIFY_DONE;
}
@@ -211,10 +215,11 @@ static struct notifier_block pending_notifier = {
static void request_module_depend(char *name, int *flag)
{
+ int err;
switch (THIS_MODULE->state) {
case MODULE_STATE_COMING:
if (!pending_registered) {
- register_module_notifier(&pending_notifier);
+ err = register_module_notifier(&pending_notifier);
pending_registered = 1;
}
*flag = 1;
@@ -275,8 +280,8 @@ unsigned long saa7134_buffer_base(struct saa7134_buf *buf)
int saa7134_pgtable_alloc(struct pci_dev *pci, struct saa7134_pgtable *pt)
{
- __le32 *cpu;
- dma_addr_t dma_addr;
+ __le32 *cpu;
+ dma_addr_t dma_addr;
cpu = pci_alloc_consistent(pci, SAA7134_PGTABLE_SIZE, &dma_addr);
if (NULL == cpu)
@@ -436,7 +441,7 @@ int saa7134_set_dmabits(struct saa7134_dev *dev)
ctrl |= SAA7134_MAIN_CTRL_TE0;
irq |= SAA7134_IRQ1_INTE_RA0_1 |
SAA7134_IRQ1_INTE_RA0_0;
- cap = dev->video_q.curr->vb.field;
+ cap = dev->video_q.curr->vb.field;
}
/* video capture -- dma 1+2 (planar modes) */
@@ -465,7 +470,7 @@ int saa7134_set_dmabits(struct saa7134_dev *dev)
}
/* audio capture -- dma 3 */
- if (dev->oss.dma_running) {
+ if (dev->dmasound.dma_running) {
ctrl |= SAA7134_MAIN_CTRL_TE6;
irq |= SAA7134_IRQ1_INTE_RA3_1 |
SAA7134_IRQ1_INTE_RA3_0;
@@ -570,6 +575,19 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id, struct pt_regs *regs)
dev->name);
goto out;
}
+
+ /* If dmasound support is active and we get a sound report, exit
+ and let the saa7134-alsa/oss module deal with it */
+
+ if ((report & SAA7134_IRQ_REPORT_DONE_RA3) &&
+ (dev->dmasound.priv_data != NULL) )
+ {
+ if (irq_debug > 1)
+ printk(KERN_DEBUG "%s/irq: ignoring interrupt for DMA sound\n",
+ dev->name);
+ goto out;
+ }
+
handled = 1;
saa_writel(SAA7134_IRQ_REPORT,report);
if (irq_debug)
@@ -591,13 +609,11 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id, struct pt_regs *regs)
card_has_mpeg(dev))
saa7134_irq_ts_done(dev,status);
- if ((report & SAA7134_IRQ_REPORT_DONE_RA3))
- saa7134_irq_oss_done(dev,status);
-
if ((report & (SAA7134_IRQ_REPORT_GPIO16 |
SAA7134_IRQ_REPORT_GPIO18)) &&
dev->remote)
saa7134_input_irq(dev);
+
}
if (10 == loop) {
@@ -636,7 +652,7 @@ static int saa7134_hwinit1(struct saa7134_dev *dev)
saa_writel(SAA7134_IRQ1, 0);
saa_writel(SAA7134_IRQ2, 0);
- init_MUTEX(&dev->lock);
+ init_MUTEX(&dev->lock);
spin_lock_init(&dev->slock);
saa7134_track_gpio(dev,"pre-init");
@@ -646,14 +662,6 @@ static int saa7134_hwinit1(struct saa7134_dev *dev)
saa7134_ts_init1(dev);
saa7134_input_init1(dev);
- switch (dev->pci->device) {
- case PCI_DEVICE_ID_PHILIPS_SAA7134:
- case PCI_DEVICE_ID_PHILIPS_SAA7133:
- case PCI_DEVICE_ID_PHILIPS_SAA7135:
- saa7134_oss_init1(dev);
- break;
- }
-
/* RAM FIFO config */
saa_writel(SAA7134_FIFO_SIZE, 0x08070503);
saa_writel(SAA7134_THRESHOULD,0x02020202);
@@ -668,6 +676,13 @@ static int saa7134_hwinit1(struct saa7134_dev *dev)
SAA7134_MAIN_CTRL_ESFE |
SAA7134_MAIN_CTRL_EBDAC);
+ /*
+ * Initialize OSS _after_ enabling audio clock PLL and audio processing.
+ * OSS initialization writes to registers via the audio DSP; these
+ * writes will fail unless the audio clock has been started. At worst,
+ * audio will not work.
+ */
+
/* enable peripheral devices */
saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
@@ -687,7 +702,7 @@ static int saa7134_hwinit2(struct saa7134_dev *dev)
saa7134_tvaudio_init2(dev);
/* enable IRQ's */
- irq2_mask =
+ irq2_mask =
SAA7134_IRQ2_INTE_DEC3 |
SAA7134_IRQ2_INTE_DEC2 |
SAA7134_IRQ2_INTE_DEC1 |
@@ -695,7 +710,7 @@ static int saa7134_hwinit2(struct saa7134_dev *dev)
SAA7134_IRQ2_INTE_PE |
SAA7134_IRQ2_INTE_AR;
- if (dev->has_remote)
+ if (dev->has_remote == SAA7134_REMOTE_GPIO)
irq2_mask |= (SAA7134_IRQ2_INTE_GPIO18 |
SAA7134_IRQ2_INTE_GPIO18A |
SAA7134_IRQ2_INTE_GPIO16 );
@@ -711,13 +726,6 @@ static int saa7134_hwfini(struct saa7134_dev *dev)
{
dprintk("hwfini\n");
- switch (dev->pci->device) {
- case PCI_DEVICE_ID_PHILIPS_SAA7134:
- case PCI_DEVICE_ID_PHILIPS_SAA7133:
- case PCI_DEVICE_ID_PHILIPS_SAA7135:
- saa7134_oss_fini(dev);
- break;
- }
if (card_has_mpeg(dev))
saa7134_ts_fini(dev);
saa7134_input_fini(dev);
@@ -872,8 +880,8 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
/* print pci info */
pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
- pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat);
- printk(KERN_INFO "%s: found at %s, rev: %d, irq: %d, "
+ pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat);
+ printk(KERN_INFO "%s: found at %s, rev: %d, irq: %d, "
"latency: %d, mmio: 0x%lx\n", dev->name,
pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
dev->pci_lat,pci_resource_start(pci_dev,0));
@@ -897,7 +905,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
dev->tda9887_conf = saa7134_boards[dev->board].tda9887_conf;
if (UNSET != tuner[dev->nr])
dev->tuner_type = tuner[dev->nr];
- printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
+ printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
dev->name,pci_dev->subsystem_vendor,
pci_dev->subsystem_device,saa7134_boards[dev->board].name,
dev->board, card[dev->nr] == dev->board ?
@@ -947,14 +955,21 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
request_module("tuner");
if (dev->tda9887_conf)
request_module("tda9887");
- if (card_is_empress(dev)) {
+ if (card_is_empress(dev)) {
request_module("saa6752hs");
request_module_depend("saa7134-empress",&need_empress);
}
- if (card_is_dvb(dev))
+ if (card_is_dvb(dev))
request_module_depend("saa7134-dvb",&need_dvb);
+
+ if (alsa)
+ request_module_depend("saa7134-alsa",&need_alsa);
+
+ if (oss)
+ request_module_depend("saa7134-oss",&need_oss);
+
v4l2_prio_init(&dev->prio);
/* register v4l devices */
@@ -987,32 +1002,6 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
dev->name,dev->radio_dev->minor & 0x1f);
}
- /* register oss devices */
- switch (dev->pci->device) {
- case PCI_DEVICE_ID_PHILIPS_SAA7134:
- case PCI_DEVICE_ID_PHILIPS_SAA7133:
- case PCI_DEVICE_ID_PHILIPS_SAA7135:
- if (oss) {
- err = dev->oss.minor_dsp =
- register_sound_dsp(&saa7134_dsp_fops,
- dsp_nr[dev->nr]);
- if (err < 0) {
- goto fail4;
- }
- printk(KERN_INFO "%s: registered device dsp%d\n",
- dev->name,dev->oss.minor_dsp >> 4);
-
- err = dev->oss.minor_mixer =
- register_sound_mixer(&saa7134_mixer_fops,
- mixer_nr[dev->nr]);
- if (err < 0)
- goto fail5;
- printk(KERN_INFO "%s: registered device mixer%d\n",
- dev->name,dev->oss.minor_mixer >> 4);
- }
- break;
- }
-
/* everything worked */
pci_set_drvdata(pci_dev,dev);
saa7134_devcount++;
@@ -1027,17 +1016,9 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
/* check for signal */
saa7134_irq_video_intl(dev);
+
return 0;
- fail5:
- switch (dev->pci->device) {
- case PCI_DEVICE_ID_PHILIPS_SAA7134:
- case PCI_DEVICE_ID_PHILIPS_SAA7133:
- case PCI_DEVICE_ID_PHILIPS_SAA7135:
- if (oss)
- unregister_sound_dsp(dev->oss.minor_dsp);
- break;
- }
fail4:
saa7134_unregister_video(dev);
saa7134_i2c_unregister(dev);
@@ -1055,7 +1036,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
static void __devexit saa7134_finidev(struct pci_dev *pci_dev)
{
- struct saa7134_dev *dev = pci_get_drvdata(pci_dev);
+ struct saa7134_dev *dev = pci_get_drvdata(pci_dev);
struct list_head *item;
struct saa7134_mpeg_ops *mops;
@@ -1088,19 +1069,16 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev)
saa7134_devcount--;
saa7134_i2c_unregister(dev);
- switch (dev->pci->device) {
- case PCI_DEVICE_ID_PHILIPS_SAA7134:
- case PCI_DEVICE_ID_PHILIPS_SAA7133:
- case PCI_DEVICE_ID_PHILIPS_SAA7135:
- if (oss) {
- unregister_sound_mixer(dev->oss.minor_mixer);
- unregister_sound_dsp(dev->oss.minor_dsp);
- }
- break;
- }
saa7134_unregister_video(dev);
- /* release ressources */
+ /* the DMA sound modules should be unloaded before reaching
+ this, but just in case they are still present... */
+ if (dev->dmasound.priv_data != NULL) {
+ free_irq(pci_dev->irq, &dev->dmasound);
+ dev->dmasound.priv_data = NULL;
+ }
+
+ /* release resources */
free_irq(pci_dev->irq, dev);
iounmap(dev->lmmio);
release_mem_region(pci_resource_start(pci_dev,0),
@@ -1149,10 +1127,10 @@ EXPORT_SYMBOL(saa7134_ts_unregister);
/* ----------------------------------------------------------- */
static struct pci_driver saa7134_pci_driver = {
- .name = "saa7134",
- .id_table = saa7134_pci_tbl,
- .probe = saa7134_initdev,
- .remove = __devexit_p(saa7134_finidev),
+ .name = "saa7134",
+ .id_table = saa7134_pci_tbl,
+ .probe = saa7134_initdev,
+ .remove = __devexit_p(saa7134_finidev),
};
static int saa7134_init(void)
@@ -1188,6 +1166,13 @@ EXPORT_SYMBOL(saa7134_i2c_call_clients);
EXPORT_SYMBOL(saa7134_devlist);
EXPORT_SYMBOL(saa7134_boards);
+/* ----------------- for the DMA sound modules --------------- */
+
+EXPORT_SYMBOL(saa7134_pgtable_free);
+EXPORT_SYMBOL(saa7134_pgtable_build);
+EXPORT_SYMBOL(saa7134_pgtable_alloc);
+EXPORT_SYMBOL(saa7134_set_dmabits);
+
/* ----------------------------------------------------------- */
/*
* Local variables:
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index 639ae51a052..e016480c346 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -29,7 +29,6 @@
#include <linux/kthread.h>
#include <linux/suspend.h>
-
#include "saa7134-reg.h"
#include "saa7134.h"
@@ -40,6 +39,10 @@
#ifdef HAVE_TDA1004X
# include "tda1004x.h"
#endif
+#ifdef HAVE_NXT200X
+# include "nxt200x.h"
+# include "dvb-pll.h"
+#endif
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
MODULE_LICENSE("GPL");
@@ -151,25 +154,12 @@ static struct mt352_config pinnacle_300i = {
/* ------------------------------------------------------------------ */
#ifdef HAVE_TDA1004X
-static int philips_tu1216_pll_init(struct dvb_frontend *fe)
-{
- struct saa7134_dev *dev = fe->dvb->priv;
- static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab };
- struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) };
-
- /* setup PLL configuration */
- if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
- return -EIO;
- msleep(1);
- return 0;
-}
-
-static int philips_tu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tda6651_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
struct saa7134_dev *dev = fe->dvb->priv;
u8 tuner_buf[4];
- struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf,.len =
+ struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tuner_buf,.len =
sizeof(tuner_buf) };
int tuner_frequency = 0;
u8 band, cp, filter;
@@ -242,11 +232,36 @@ static int philips_tu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_p
if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
+ msleep(1);
+ return 0;
+}
+static int philips_tda6651_pll_init(u8 addr, struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab };
+ struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) };
+
+ /* setup PLL configuration */
+ if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
+ return -EIO;
msleep(1);
+
return 0;
}
+/* ------------------------------------------------------------------ */
+
+static int philips_tu1216_pll_60_init(struct dvb_frontend *fe)
+{
+ return philips_tda6651_pll_init(0x60, fe);
+}
+
+static int philips_tu1216_pll_60_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ return philips_tda6651_pll_set(0x60, fe, params);
+}
+
static int philips_tu1216_request_firmware(struct dvb_frontend *fe,
const struct firmware **fw, char *name)
{
@@ -254,22 +269,108 @@ static int philips_tu1216_request_firmware(struct dvb_frontend *fe,
return request_firmware(fw, name, &dev->pci->dev);
}
-static struct tda1004x_config philips_tu1216_config = {
+static struct tda1004x_config philips_tu1216_60_config = {
+
+ .demod_address = 0x8,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_4M,
+ .agc_config = TDA10046_AGC_DEFAULT,
+ .if_freq = TDA10046_FREQ_3617,
+ .pll_init = philips_tu1216_pll_60_init,
+ .pll_set = philips_tu1216_pll_60_set,
+ .pll_sleep = NULL,
+ .request_firmware = philips_tu1216_request_firmware,
+};
+
+/* ------------------------------------------------------------------ */
+
+static int philips_tu1216_pll_61_init(struct dvb_frontend *fe)
+{
+ return philips_tda6651_pll_init(0x61, fe);
+}
+
+static int philips_tu1216_pll_61_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ return philips_tda6651_pll_set(0x61, fe, params);
+}
+
+static struct tda1004x_config philips_tu1216_61_config = {
.demod_address = 0x8,
.invert = 1,
- .invert_oclk = 1,
+ .invert_oclk = 0,
.xtal_freq = TDA10046_XTAL_4M,
.agc_config = TDA10046_AGC_DEFAULT,
.if_freq = TDA10046_FREQ_3617,
- .pll_init = philips_tu1216_pll_init,
- .pll_set = philips_tu1216_pll_set,
+ .pll_init = philips_tu1216_pll_61_init,
+ .pll_set = philips_tu1216_pll_61_set,
.pll_sleep = NULL,
.request_firmware = philips_tu1216_request_firmware,
};
/* ------------------------------------------------------------------ */
+static int philips_europa_pll_init(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ static u8 msg[] = { 0x0b, 0xf5, 0x86, 0xab };
+ struct i2c_msg init_msg = {.addr = 0x61,.flags = 0,.buf = msg,.len = sizeof(msg) };
+
+ /* setup PLL configuration */
+ if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1)
+ return -EIO;
+ msleep(1);
+
+ /* switch the board to dvb mode */
+ init_msg.addr = 0x43;
+ init_msg.len = 0x02;
+ msg[0] = 0x00;
+ msg[1] = 0x40;
+ if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1)
+ return -EIO;
+
+ return 0;
+}
+
+static int philips_td1316_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ return philips_tda6651_pll_set(0x61, fe, params);
+}
+
+static void philips_europa_analog(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ /* this message actually turns the tuner back to analog mode */
+ static u8 msg[] = { 0x0b, 0xdc, 0x86, 0xa4 };
+ struct i2c_msg analog_msg = {.addr = 0x61,.flags = 0,.buf = msg,.len = sizeof(msg) };
+
+ i2c_transfer(&dev->i2c_adap, &analog_msg, 1);
+ msleep(1);
+
+ /* switch the board to analog mode */
+ analog_msg.addr = 0x43;
+ analog_msg.len = 0x02;
+ msg[0] = 0x00;
+ msg[1] = 0x14;
+ i2c_transfer(&dev->i2c_adap, &analog_msg, 1);
+}
+
+static struct tda1004x_config philips_europa_config = {
+
+ .demod_address = 0x8,
+ .invert = 0,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_4M,
+ .agc_config = TDA10046_AGC_IFO_AUTO_POS,
+ .if_freq = TDA10046_FREQ_052,
+ .pll_init = philips_europa_pll_init,
+ .pll_set = philips_td1316_pll_set,
+ .pll_sleep = philips_europa_analog,
+ .request_firmware = NULL,
+};
+
+/* ------------------------------------------------------------------ */
static int philips_fmd1216_pll_init(struct dvb_frontend *fe)
{
@@ -382,7 +483,6 @@ static int philips_fmd1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_
return 0;
}
-#ifdef HAVE_TDA1004X
static struct tda1004x_config medion_cardbus = {
.demod_address = 0x08,
.invert = 1,
@@ -395,7 +495,6 @@ static struct tda1004x_config medion_cardbus = {
.pll_sleep = philips_fmd1216_analog,
.request_firmware = NULL,
};
-#endif
/* ------------------------------------------------------------------ */
@@ -452,7 +551,7 @@ static int philips_tda827x_pll_set(struct dvb_frontend *fe, struct dvb_frontend_
u8 tuner_buf[14];
struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf,
- .len = sizeof(tuner_buf) };
+ .len = sizeof(tuner_buf) };
int i, tuner_freq, if_freq;
u32 N;
switch (params->u.ofdm.bandwidth) {
@@ -511,7 +610,7 @@ static void philips_tda827x_pll_sleep(struct dvb_frontend *fe)
struct saa7134_dev *dev = fe->dvb->priv;
static u8 tda827x_sleep[] = { 0x30, 0xd0};
struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tda827x_sleep,
- .len = sizeof(tda827x_sleep) };
+ .len = sizeof(tda827x_sleep) };
i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
}
@@ -527,6 +626,202 @@ static struct tda1004x_config tda827x_lifeview_config = {
.pll_sleep = philips_tda827x_pll_sleep,
.request_firmware = NULL,
};
+
+/* ------------------------------------------------------------------ */
+
+struct tda827xa_data {
+ u32 lomax;
+ u8 svco;
+ u8 spd;
+ u8 scr;
+ u8 sbs;
+ u8 gc3;
+};
+
+static struct tda827xa_data tda827xa_dvbt[] = {
+ { .lomax = 56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 1},
+ { .lomax = 67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
+ { .lomax = 81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
+ { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
+ { .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1},
+ { .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+ { .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+ { .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+ { .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+ { .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},
+ { .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},
+ { .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},
+ { .lomax = 290000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},
+ { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
+ { .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
+ { .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
+ { .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
+ { .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},
+ { .lomax = 550000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
+ { .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
+ { .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
+ { .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
+ { .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
+ { .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
+ { .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
+ { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0},
+ { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}};
+
+
+static int philips_tda827xa_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ u8 tuner_buf[14];
+ unsigned char reg2[2];
+
+ struct i2c_msg msg = {.addr = addr,.flags = 0,.buf = tuner_buf};
+ int i, tuner_freq, if_freq;
+ u32 N;
+
+ switch (params->u.ofdm.bandwidth) {
+ case BANDWIDTH_6_MHZ:
+ if_freq = 4000000;
+ break;
+ case BANDWIDTH_7_MHZ:
+ if_freq = 4500000;
+ break;
+ default: /* 8 MHz or Auto */
+ if_freq = 5000000;
+ break;
+ }
+ tuner_freq = params->frequency + if_freq;
+
+ i = 0;
+ while (tda827xa_dvbt[i].lomax < tuner_freq) {
+ if(tda827xa_dvbt[i + 1].lomax == 0)
+ break;
+ i++;
+ }
+
+ N = ((tuner_freq + 31250) / 62500) << tda827xa_dvbt[i].spd;
+ tuner_buf[0] = 0; // subaddress
+ tuner_buf[1] = N >> 8;
+ tuner_buf[2] = N & 0xff;
+ tuner_buf[3] = 0;
+ tuner_buf[4] = 0x16;
+ tuner_buf[5] = (tda827xa_dvbt[i].spd << 5) + (tda827xa_dvbt[i].svco << 3) +
+ tda827xa_dvbt[i].sbs;
+ tuner_buf[6] = 0x4b + (tda827xa_dvbt[i].gc3 << 4);
+ tuner_buf[7] = 0x0c;
+ tuner_buf[8] = 0x06;
+ tuner_buf[9] = 0x24;
+ tuner_buf[10] = 0xff;
+ tuner_buf[11] = 0x60;
+ tuner_buf[12] = 0x00;
+ tuner_buf[13] = 0x39; // lpsel
+ msg.len = 14;
+ if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1)
+ return -EIO;
+
+ msg.buf= reg2;
+ msg.len = 2;
+ reg2[0] = 0x60;
+ reg2[1] = 0x3c;
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+
+ reg2[0] = 0xa0;
+ reg2[1] = 0x40;
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+
+ msleep(2);
+ /* correct CP value */
+ reg2[0] = 0x30;
+ reg2[1] = 0x10 + tda827xa_dvbt[i].scr;
+ msg.len = 2;
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+
+ msleep(550);
+ reg2[0] = 0x50;
+ reg2[1] = 0x4f + (tda827xa_dvbt[i].gc3 << 4);
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+
+ return 0;
+
+}
+
+static void philips_tda827xa_pll_sleep(u8 addr, struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ static u8 tda827xa_sleep[] = { 0x30, 0x90};
+ struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tda827xa_sleep,
+ .len = sizeof(tda827xa_sleep) };
+ i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
+
+}
+
+/* ------------------------------------------------------------------ */
+
+static int philips_tiger_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ int ret;
+ struct saa7134_dev *dev = fe->dvb->priv;
+ static u8 tda8290_close[] = { 0x21, 0xc0};
+ static u8 tda8290_open[] = { 0x21, 0x80};
+ struct i2c_msg tda8290_msg = {.addr = 0x4b,.flags = 0, .len = 2};
+ /* close tda8290 i2c bridge */
+ tda8290_msg.buf = tda8290_close;
+ ret = i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1);
+ if (ret != 1)
+ return -EIO;
+ msleep(20);
+ ret = philips_tda827xa_pll_set(0x61, fe, params);
+ if (ret != 0)
+ return ret;
+ /* open tda8290 i2c bridge */
+ tda8290_msg.buf = tda8290_open;
+ i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1);
+ return ret;
+};
+
+static int philips_tiger_dvb_mode(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ static u8 data[] = { 0x3c, 0x33, 0x6a};
+ struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+
+ if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1)
+ return -EIO;
+ return 0;
+}
+
+static void philips_tiger_analog_mode(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ static u8 data[] = { 0x3c, 0x33, 0x68};
+ struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+ philips_tda827xa_pll_sleep( 0x61, fe);
+}
+
+static struct tda1004x_config philips_tiger_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .if_freq = TDA10046_FREQ_045,
+ .pll_init = philips_tiger_dvb_mode,
+ .pll_set = philips_tiger_pll_set,
+ .pll_sleep = philips_tiger_analog_mode,
+ .request_firmware = NULL,
+};
+
+#endif
+
+/* ------------------------------------------------------------------ */
+
+#ifdef HAVE_NXT200X
+static struct nxt200x_config avertvhda180 = {
+ .demod_address = 0x0a,
+ .pll_address = 0x61,
+ .pll_desc = &dvb_pll_tdhu2,
+};
#endif
/* ------------------------------------------------------------------ */
@@ -558,7 +853,7 @@ static int dvb_init(struct saa7134_dev *dev)
&dev->i2c_adap);
break;
case SAA7134_BOARD_PHILIPS_TOUGH:
- dev->dvb.frontend = tda10046_attach(&philips_tu1216_config,
+ dev->dvb.frontend = tda10046_attach(&philips_tu1216_60_config,
&dev->i2c_adap);
break;
case SAA7134_BOARD_FLYDVBTDUO:
@@ -569,6 +864,31 @@ static int dvb_init(struct saa7134_dev *dev)
dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config,
&dev->i2c_adap);
break;
+ case SAA7134_BOARD_PHILIPS_EUROPA:
+ dev->dvb.frontend = tda10046_attach(&philips_europa_config,
+ &dev->i2c_adap);
+ break;
+ case SAA7134_BOARD_VIDEOMATE_DVBT_300:
+ dev->dvb.frontend = tda10046_attach(&philips_europa_config,
+ &dev->i2c_adap);
+ break;
+ case SAA7134_BOARD_VIDEOMATE_DVBT_200:
+ dev->dvb.frontend = tda10046_attach(&philips_tu1216_61_config,
+ &dev->i2c_adap);
+ break;
+ case SAA7134_BOARD_PHILIPS_TIGER:
+ dev->dvb.frontend = tda10046_attach(&philips_tiger_config,
+ &dev->i2c_adap);
+ break;
+ case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
+ dev->dvb.frontend = tda10046_attach(&philips_tiger_config,
+ &dev->i2c_adap);
+ break;
+#endif
+#ifdef HAVE_NXT200X
+ case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180:
+ dev->dvb.frontend = nxt200x_attach(&avertvhda180, &dev->i2c_adap);
+ break;
#endif
default:
printk("%s: Huh? unknown DVB card?\n",dev->name);
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c
index 77b627eb648..e9ec69efb4c 100644
--- a/drivers/media/video/saa7134/saa7134-empress.c
+++ b/drivers/media/video/saa7134/saa7134-empress.c
@@ -55,7 +55,7 @@ static void ts_reset_encoder(struct saa7134_dev* dev)
saa_writeb(SAA7134_SPECIAL_MODE, 0x00);
msleep(10);
- saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
+ saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
msleep(100);
dev->empress_started = 0;
}
@@ -65,7 +65,7 @@ static int ts_init_encoder(struct saa7134_dev* dev)
ts_reset_encoder(dev);
saa7134_i2c_call_clients(dev, VIDIOC_S_MPEGCOMP, NULL);
dev->empress_started = 1;
- return 0;
+ return 0;
}
/* ------------------------------------------------------------------ */
@@ -169,7 +169,7 @@ static int ts_do_ioctl(struct inode *inode, struct file *file,
struct v4l2_capability *cap = arg;
memset(cap,0,sizeof(*cap));
- strcpy(cap->driver, "saa7134");
+ strcpy(cap->driver, "saa7134");
strlcpy(cap->card, saa7134_boards[dev->board].name,
sizeof(cap->card));
sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c
index 711aa8e85fa..7575043f087 100644
--- a/drivers/media/video/saa7134/saa7134-i2c.c
+++ b/drivers/media/video/saa7134/saa7134-i2c.c
@@ -239,7 +239,7 @@ static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap,
unsigned char data;
int addr,rc,i,byte;
- status = i2c_get_status(dev);
+ status = i2c_get_status(dev);
if (!i2c_is_idle(status))
if (!i2c_reset(dev))
return -EIO;
@@ -296,7 +296,7 @@ static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap,
rc = -EIO;
if (!i2c_is_busy_wait(dev))
goto err;
- status = i2c_get_status(dev);
+ status = i2c_get_status(dev);
if (i2c_is_error(status))
goto err;
/* ensure that the bus is idle for at least one bit slot */
@@ -335,6 +335,20 @@ static int attach_inform(struct i2c_client *client)
d1printk( "%s i2c attach [addr=0x%x,client=%s]\n",
client->driver->name, client->addr, client->name);
+ /* Am I an i2c remote control? */
+
+ switch (client->addr) {
+ case 0x7a:
+ case 0x47:
+ {
+ struct IR_i2c *ir = i2c_get_clientdata(client);
+ d1printk("%s i2c IR detected (%s).\n",
+ client->driver->name,ir->phys);
+ saa7134_set_i2c_ir(dev,ir);
+ break;
+ }
+ }
+
if (!client->driver->command)
return 0;
@@ -348,12 +362,12 @@ static int attach_inform(struct i2c_client *client)
client->driver->command(client, TUNER_SET_TYPE_ADDR, &tun_setup);
}
- }
+ }
if (tuner != UNSET) {
- tun_setup.type = tuner;
- tun_setup.addr = saa7134_boards[dev->board].tuner_addr;
+ tun_setup.type = tuner;
+ tun_setup.addr = saa7134_boards[dev->board].tuner_addr;
if ((tun_setup.addr == ADDR_UNSET)||(tun_setup.addr == client->addr)) {
@@ -361,11 +375,11 @@ static int attach_inform(struct i2c_client *client)
client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_setup);
}
- }
+ }
client->driver->command(client, TDA9887_SET_CONFIG, &conf);
- return 0;
+ return 0;
}
static struct i2c_algorithm saa7134_algo = {
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index 242cb235cf9..e648cc3bc96 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -39,6 +39,8 @@ MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
#define dprintk(fmt, arg...) if (ir_debug) \
printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg)
+#define i2cdprintk(fmt, arg...) if (ir_debug) \
+ printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg)
/* ---------------------------------------------------------------------- */
@@ -114,24 +116,24 @@ static IR_KEYTAB_TYPE cinergy_codes[IR_KEYTAB_SIZE] = {
/* Alfons Geser <a.geser@cox.net>
* updates from Job D. R. Borges <jobdrb@ig.com.br> */
static IR_KEYTAB_TYPE eztv_codes[IR_KEYTAB_SIZE] = {
- [ 18 ] = KEY_POWER,
- [ 1 ] = KEY_TV, // DVR
- [ 21 ] = KEY_DVD, // DVD
- [ 23 ] = KEY_AUDIO, // music
- // DVR mode / DVD mode / music mode
-
- [ 27 ] = KEY_MUTE, // mute
- [ 2 ] = KEY_LANGUAGE, // MTS/SAP / audio / autoseek
- [ 30 ] = KEY_SUBTITLE, // closed captioning / subtitle / seek
- [ 22 ] = KEY_ZOOM, // full screen
- [ 28 ] = KEY_VIDEO, // video source / eject / delall
- [ 29 ] = KEY_RESTART, // playback / angle / del
- [ 47 ] = KEY_SEARCH, // scan / menu / playlist
- [ 48 ] = KEY_CHANNEL, // CH surfing / bookmark / memo
-
- [ 49 ] = KEY_HELP, // help
- [ 50 ] = KEY_MODE, // num/memo
- [ 51 ] = KEY_ESC, // cancel
+ [ 18 ] = KEY_POWER,
+ [ 1 ] = KEY_TV, // DVR
+ [ 21 ] = KEY_DVD, // DVD
+ [ 23 ] = KEY_AUDIO, // music
+ // DVR mode / DVD mode / music mode
+
+ [ 27 ] = KEY_MUTE, // mute
+ [ 2 ] = KEY_LANGUAGE, // MTS/SAP / audio / autoseek
+ [ 30 ] = KEY_SUBTITLE, // closed captioning / subtitle / seek
+ [ 22 ] = KEY_ZOOM, // full screen
+ [ 28 ] = KEY_VIDEO, // video source / eject / delall
+ [ 29 ] = KEY_RESTART, // playback / angle / del
+ [ 47 ] = KEY_SEARCH, // scan / menu / playlist
+ [ 48 ] = KEY_CHANNEL, // CH surfing / bookmark / memo
+
+ [ 49 ] = KEY_HELP, // help
+ [ 50 ] = KEY_MODE, // num/memo
+ [ 51 ] = KEY_ESC, // cancel
[ 12 ] = KEY_UP, // up
[ 16 ] = KEY_DOWN, // down
@@ -148,24 +150,24 @@ static IR_KEYTAB_TYPE eztv_codes[IR_KEYTAB_SIZE] = {
[ 45 ] = KEY_PLAY, // play
[ 46 ] = KEY_SHUFFLE, // snapshot / shuffle
- [ 0 ] = KEY_KP0,
- [ 5 ] = KEY_KP1,
- [ 6 ] = KEY_KP2,
- [ 7 ] = KEY_KP3,
- [ 9 ] = KEY_KP4,
- [ 10 ] = KEY_KP5,
- [ 11 ] = KEY_KP6,
- [ 13 ] = KEY_KP7,
- [ 14 ] = KEY_KP8,
- [ 15 ] = KEY_KP9,
-
- [ 42 ] = KEY_VOLUMEUP,
- [ 17 ] = KEY_VOLUMEDOWN,
- [ 24 ] = KEY_CHANNELUP, // CH.tracking up
- [ 25 ] = KEY_CHANNELDOWN, // CH.tracking down
-
- [ 19 ] = KEY_KPENTER, // enter
- [ 33 ] = KEY_KPDOT, // . (decimal dot)
+ [ 0 ] = KEY_KP0,
+ [ 5 ] = KEY_KP1,
+ [ 6 ] = KEY_KP2,
+ [ 7 ] = KEY_KP3,
+ [ 9 ] = KEY_KP4,
+ [ 10 ] = KEY_KP5,
+ [ 11 ] = KEY_KP6,
+ [ 13 ] = KEY_KP7,
+ [ 14 ] = KEY_KP8,
+ [ 15 ] = KEY_KP9,
+
+ [ 42 ] = KEY_VOLUMEUP,
+ [ 17 ] = KEY_VOLUMEDOWN,
+ [ 24 ] = KEY_CHANNELUP, // CH.tracking up
+ [ 25 ] = KEY_CHANNELDOWN, // CH.tracking down
+
+ [ 19 ] = KEY_KPENTER, // enter
+ [ 33 ] = KEY_KPDOT, // . (decimal dot)
};
static IR_KEYTAB_TYPE avacssmart_codes[IR_KEYTAB_SIZE] = {
@@ -401,7 +403,125 @@ static IR_KEYTAB_TYPE manli_codes[IR_KEYTAB_SIZE] = {
// 0x1d unused ?
};
-/* ---------------------------------------------------------------------- */
+
+
+/* Mike Baikov <mike@baikov.com> */
+static IR_KEYTAB_TYPE gotview7135_codes[IR_KEYTAB_SIZE] = {
+
+ [ 33 ] = KEY_POWER,
+ [ 105] = KEY_TV,
+ [ 51 ] = KEY_KP0,
+ [ 81 ] = KEY_KP1,
+ [ 49 ] = KEY_KP2,
+ [ 113] = KEY_KP3,
+ [ 59 ] = KEY_KP4,
+ [ 88 ] = KEY_KP5,
+ [ 65 ] = KEY_KP6,
+ [ 72 ] = KEY_KP7,
+ [ 48 ] = KEY_KP8,
+ [ 83 ] = KEY_KP9,
+ [ 115] = KEY_AGAIN, /* LOOP */
+ [ 10 ] = KEY_AUDIO,
+ [ 97 ] = KEY_PRINT, /* PREVIEW */
+ [ 122] = KEY_VIDEO,
+ [ 32 ] = KEY_CHANNELUP,
+ [ 64 ] = KEY_CHANNELDOWN,
+ [ 24 ] = KEY_VOLUMEDOWN,
+ [ 80 ] = KEY_VOLUMEUP,
+ [ 16 ] = KEY_MUTE,
+ [ 74 ] = KEY_SEARCH,
+ [ 123] = KEY_SHUFFLE, /* SNAPSHOT */
+ [ 34 ] = KEY_RECORD,
+ [ 98 ] = KEY_STOP,
+ [ 120] = KEY_PLAY,
+ [ 57 ] = KEY_REWIND,
+ [ 89 ] = KEY_PAUSE,
+ [ 25 ] = KEY_FORWARD,
+ [ 9 ] = KEY_ZOOM,
+
+ [ 82 ] = KEY_F21, /* LIVE TIMESHIFT */
+ [ 26 ] = KEY_F22, /* MIN TIMESHIFT */
+ [ 58 ] = KEY_F23, /* TIMESHIFT */
+ [ 112] = KEY_F24, /* NORMAL TIMESHIFT */
+};
+
+static IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE] = {
+ [ 0x3 ] = KEY_POWER,
+ [ 0x6f ] = KEY_MUTE,
+ [ 0x10 ] = KEY_BACKSPACE, /* Recall */
+
+ [ 0x11 ] = KEY_KP0,
+ [ 0x4 ] = KEY_KP1,
+ [ 0x5 ] = KEY_KP2,
+ [ 0x6 ] = KEY_KP3,
+ [ 0x8 ] = KEY_KP4,
+ [ 0x9 ] = KEY_KP5,
+ [ 0xa ] = KEY_KP6,
+ [ 0xc ] = KEY_KP7,
+ [ 0xd ] = KEY_KP8,
+ [ 0xe ] = KEY_KP9,
+ [ 0x12 ] = KEY_KPDOT, /* 100+ */
+
+ [ 0x7 ] = KEY_VOLUMEUP,
+ [ 0xb ] = KEY_VOLUMEDOWN,
+ [ 0x1a ] = KEY_KPPLUS,
+ [ 0x18 ] = KEY_KPMINUS,
+ [ 0x15 ] = KEY_UP,
+ [ 0x1d ] = KEY_DOWN,
+ [ 0xf ] = KEY_CHANNELUP,
+ [ 0x13 ] = KEY_CHANNELDOWN,
+ [ 0x48 ] = KEY_ZOOM,
+
+ [ 0x1b ] = KEY_VIDEO, /* Video source */
+ [ 0x49 ] = KEY_LANGUAGE, /* MTS Select */
+ [ 0x19 ] = KEY_SEARCH, /* Auto Scan */
+
+ [ 0x4b ] = KEY_RECORD,
+ [ 0x46 ] = KEY_PLAY,
+ [ 0x45 ] = KEY_PAUSE, /* Pause */
+ [ 0x44 ] = KEY_STOP,
+ [ 0x40 ] = KEY_FORWARD, /* Forward ? */
+ [ 0x42 ] = KEY_REWIND, /* Backward ? */
+
+};
+
+/* Mapping for the 28 key remote control as seen at
+ http://www.sednacomputer.com/photo/cardbus-tv.jpg
+ Pavel Mihaylov <bin@bash.info> */
+static IR_KEYTAB_TYPE pctv_sedna_codes[IR_KEYTAB_SIZE] = {
+ [ 0 ] = KEY_KP0,
+ [ 1 ] = KEY_KP1,
+ [ 2 ] = KEY_KP2,
+ [ 3 ] = KEY_KP3,
+ [ 4 ] = KEY_KP4,
+ [ 5 ] = KEY_KP5,
+ [ 6 ] = KEY_KP6,
+ [ 7 ] = KEY_KP7,
+ [ 8 ] = KEY_KP8,
+ [ 9 ] = KEY_KP9,
+
+ [ 0x0a ] = KEY_AGAIN, /* Recall */
+ [ 0x0b ] = KEY_CHANNELUP,
+ [ 0x0c ] = KEY_VOLUMEUP,
+ [ 0x0d ] = KEY_MODE, /* Stereo */
+ [ 0x0e ] = KEY_STOP,
+ [ 0x0f ] = KEY_PREVIOUSSONG,
+ [ 0x10 ] = KEY_ZOOM,
+ [ 0x11 ] = KEY_TUNER, /* Source */
+ [ 0x12 ] = KEY_POWER,
+ [ 0x13 ] = KEY_MUTE,
+ [ 0x15 ] = KEY_CHANNELDOWN,
+ [ 0x18 ] = KEY_VOLUMEDOWN,
+ [ 0x19 ] = KEY_SHUFFLE, /* Snapshot */
+ [ 0x1a ] = KEY_NEXTSONG,
+ [ 0x1b ] = KEY_TEXT, /* Time Shift */
+ [ 0x1c ] = KEY_RADIO, /* FM Radio */
+ [ 0x1d ] = KEY_RECORD,
+ [ 0x1e ] = KEY_PAUSE,
+};
+
+
+/* -------------------- GPIO generic keycode builder -------------------- */
static int build_key(struct saa7134_dev *dev)
{
@@ -413,13 +533,13 @@ static int build_key(struct saa7134_dev *dev)
saa_setb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN);
gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2);
- if (ir->polling) {
- if (ir->last_gpio == gpio)
- return 0;
- ir->last_gpio = gpio;
- }
+ if (ir->polling) {
+ if (ir->last_gpio == gpio)
+ return 0;
+ ir->last_gpio = gpio;
+ }
- data = ir_extract_bits(gpio, ir->mask_keycode);
+ data = ir_extract_bits(gpio, ir->mask_keycode);
dprintk("build_key gpio=0x%x mask=0x%x data=%d\n",
gpio, ir->mask_keycode, data);
@@ -432,13 +552,36 @@ static int build_key(struct saa7134_dev *dev)
return 0;
}
-/* ---------------------------------------------------------------------- */
+/* --------------------- Chip specific I2C key builders ----------------- */
+
+static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+ unsigned char b;
+
+ /* poll IR chip */
+ if (1 != i2c_master_recv(&ir->c,&b,1)) {
+ i2cdprintk("read error\n");
+ return -EIO;
+ }
+
+ /* no button press */
+ if (b==0)
+ return 0;
+
+ /* repeating */
+ if (b & 0x80)
+ return 1;
+
+ *ir_key = b;
+ *ir_raw = b;
+ return 1;
+}
void saa7134_input_irq(struct saa7134_dev *dev)
{
- struct saa7134_ir *ir = dev->remote;
+ struct saa7134_ir *ir = dev->remote;
- if (!ir->polling)
+ if (!ir->polling)
build_key(dev);
}
@@ -464,7 +607,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
int polling = 0;
int ir_type = IR_TYPE_OTHER;
- if (!dev->has_remote)
+ if (dev->has_remote != SAA7134_REMOTE_GPIO)
return -ENODEV;
if (disable_ir)
return -ENODEV;
@@ -473,7 +616,8 @@ int saa7134_input_init1(struct saa7134_dev *dev)
switch (dev->board) {
case SAA7134_BOARD_FLYVIDEO2000:
case SAA7134_BOARD_FLYVIDEO3000:
- case SAA7134_BOARD_FLYTVPLATINUM_FM:
+ case SAA7134_BOARD_FLYTVPLATINUM_FM:
+ case SAA7134_BOARD_FLYTVPLATINUM_MINI2:
ir_codes = flyvideo_codes;
mask_keycode = 0xEC00000;
mask_keydown = 0x0040000;
@@ -514,14 +658,33 @@ int saa7134_input_init1(struct saa7134_dev *dev)
saa_setb(SAA7134_GPIO_GPMODE0, 0x4);
saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4);
break;
+ case SAA7134_BOARD_KWORLD_TERMINATOR:
+ ir_codes = avacssmart_codes;
+ mask_keycode = 0x00001f;
+ mask_keyup = 0x000060;
+ polling = 50; // ms
+ break;
case SAA7134_BOARD_MANLI_MTV001:
case SAA7134_BOARD_MANLI_MTV002:
+ case SAA7134_BOARD_BEHOLD_409FM:
ir_codes = manli_codes;
mask_keycode = 0x001f00;
mask_keyup = 0x004000;
- mask_keydown = 0x002000;
polling = 50; // ms
break;
+ case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS:
+ ir_codes = pctv_sedna_codes;
+ mask_keycode = 0x001f00;
+ mask_keyup = 0x004000;
+ polling = 50; // ms
+ break;
+ case SAA7134_BOARD_GOTVIEW_7135:
+ ir_codes = gotview7135_codes;
+ mask_keycode = 0x0003EC;
+ mask_keyup = 0x008000;
+ mask_keydown = 0x000010;
+ polling = 50; // ms
+ break;
case SAA7134_BOARD_VIDEOMATE_TV_PVR:
case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII:
ir_codes = videomate_tv_pvr_codes;
@@ -529,6 +692,12 @@ int saa7134_input_init1(struct saa7134_dev *dev)
mask_keyup = 0x400000;
polling = 50; // ms
break;
+ case SAA7134_BOARD_VIDEOMATE_DVBT_300:
+ case SAA7134_BOARD_VIDEOMATE_DVBT_200:
+ ir_codes = videomate_tv_pvr_codes;
+ mask_keycode = 0x003F00;
+ mask_keyup = 0x040000;
+ break;
}
if (NULL == ir_codes) {
printk("%s: Oops: IR config error [card=%d]\n",
@@ -548,7 +717,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
ir->mask_keycode = mask_keycode;
ir->mask_keydown = mask_keydown;
ir->mask_keyup = mask_keyup;
- ir->polling = polling;
+ ir->polling = polling;
/* init input device */
snprintf(ir->name, sizeof(ir->name), "saa7134 IR (%s)",
@@ -596,6 +765,31 @@ void saa7134_input_fini(struct saa7134_dev *dev)
dev->remote = NULL;
}
+void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir)
+{
+ if (disable_ir) {
+ dprintk("Found supported i2c remote, but IR has been disabled\n");
+ ir->get_key=NULL;
+ return;
+ }
+
+ switch (dev->board) {
+ case SAA7134_BOARD_PINNACLE_PCTV_110i:
+ snprintf(ir->c.name, sizeof(ir->c.name), "Pinnacle PCTV");
+ ir->get_key = get_key_pinnacle;
+ ir->ir_codes = ir_codes_pinnacle;
+ break;
+ case SAA7134_BOARD_UPMOST_PURPLE_TV:
+ snprintf(ir->c.name, sizeof(ir->c.name), "Purple TV");
+ ir->get_key = get_key_purpletv;
+ ir->ir_codes = ir_codes_purpletv;
+ break;
+ default:
+ dprintk("Shouldn't get here: Unknown board %x for I2C IR?\n",dev->board);
+ break;
+ }
+
+}
/* ----------------------------------------------------------------------
* Local variables:
* c-basic-offset: 8
diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c
index c20630c82f1..fd9ed11ab1e 100644
--- a/drivers/media/video/saa7134/saa7134-oss.c
+++ b/drivers/media/video/saa7134/saa7134-oss.c
@@ -4,6 +4,8 @@
* oss dsp interface
*
* (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ * 2005 conversion to standalone module:
+ * Ricardo Cerqueira <v4l@cerqueira.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -25,7 +27,9 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
+#include <linux/interrupt.h>
#include <linux/slab.h>
+#include <linux/sound.h>
#include <linux/soundcard.h>
#include "saa7134-reg.h"
@@ -33,17 +37,26 @@
/* ------------------------------------------------------------------ */
-static unsigned int oss_debug = 0;
-module_param(oss_debug, int, 0644);
-MODULE_PARM_DESC(oss_debug,"enable debug messages [oss]");
+static unsigned int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug,"enable debug messages [oss]");
-static unsigned int oss_rate = 0;
-module_param(oss_rate, int, 0444);
-MODULE_PARM_DESC(oss_rate,"sample rate (valid are: 32000,48000)");
+static unsigned int rate = 0;
+module_param(rate, int, 0444);
+MODULE_PARM_DESC(rate,"sample rate (valid are: 32000,48000)");
-#define dprintk(fmt, arg...) if (oss_debug) \
+static unsigned int dsp_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
+MODULE_PARM_DESC(dsp_nr, "device numbers for SAA7134 capture interface(s).");
+module_param_array(dsp_nr, int, NULL, 0444);
+
+static unsigned int mixer_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
+MODULE_PARM_DESC(mixer_nr, "mixer numbers for SAA7134 capture interface(s).");
+module_param_array(mixer_nr, int, NULL, 0444);
+
+#define dprintk(fmt, arg...) if (debug) \
printk(KERN_DEBUG "%s/oss: " fmt, dev->name , ## arg)
+
/* ------------------------------------------------------------------ */
static int dsp_buffer_conf(struct saa7134_dev *dev, int blksize, int blocks)
@@ -58,12 +71,12 @@ static int dsp_buffer_conf(struct saa7134_dev *dev, int blksize, int blocks)
if ((blksize * blocks) > 1024*1024)
blocks = 1024*1024 / blksize;
- dev->oss.blocks = blocks;
- dev->oss.blksize = blksize;
- dev->oss.bufsize = blksize * blocks;
+ dev->dmasound.blocks = blocks;
+ dev->dmasound.blksize = blksize;
+ dev->dmasound.bufsize = blksize * blocks;
dprintk("buffer config: %d blocks / %d bytes, %d kB total\n",
- blocks,blksize,blksize * blocks / 1024);
+ blocks,blksize,blksize * blocks / 1024);
return 0;
}
@@ -71,11 +84,11 @@ static int dsp_buffer_init(struct saa7134_dev *dev)
{
int err;
- if (!dev->oss.bufsize)
+ if (!dev->dmasound.bufsize)
BUG();
- videobuf_dma_init(&dev->oss.dma);
- err = videobuf_dma_init_kernel(&dev->oss.dma, PCI_DMA_FROMDEVICE,
- (dev->oss.bufsize + PAGE_SIZE) >> PAGE_SHIFT);
+ videobuf_dma_init(&dev->dmasound.dma);
+ err = videobuf_dma_init_kernel(&dev->dmasound.dma, PCI_DMA_FROMDEVICE,
+ (dev->dmasound.bufsize + PAGE_SIZE) >> PAGE_SHIFT);
if (0 != err)
return err;
return 0;
@@ -83,26 +96,26 @@ static int dsp_buffer_init(struct saa7134_dev *dev)
static int dsp_buffer_free(struct saa7134_dev *dev)
{
- if (!dev->oss.blksize)
+ if (!dev->dmasound.blksize)
BUG();
- videobuf_dma_free(&dev->oss.dma);
- dev->oss.blocks = 0;
- dev->oss.blksize = 0;
- dev->oss.bufsize = 0;
+ videobuf_dma_free(&dev->dmasound.dma);
+ dev->dmasound.blocks = 0;
+ dev->dmasound.blksize = 0;
+ dev->dmasound.bufsize = 0;
return 0;
}
static void dsp_dma_start(struct saa7134_dev *dev)
{
- dev->oss.dma_blk = 0;
- dev->oss.dma_running = 1;
+ dev->dmasound.dma_blk = 0;
+ dev->dmasound.dma_running = 1;
saa7134_set_dmabits(dev);
}
static void dsp_dma_stop(struct saa7134_dev *dev)
{
- dev->oss.dma_blk = -1;
- dev->oss.dma_running = 0;
+ dev->dmasound.dma_blk = -1;
+ dev->dmasound.dma_running = 0;
saa7134_set_dmabits(dev);
}
@@ -113,18 +126,18 @@ static int dsp_rec_start(struct saa7134_dev *dev)
unsigned long flags;
/* prepare buffer */
- if (0 != (err = videobuf_dma_pci_map(dev->pci,&dev->oss.dma)))
+ if (0 != (err = videobuf_dma_pci_map(dev->pci,&dev->dmasound.dma)))
return err;
- if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->oss.pt)))
+ if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->dmasound.pt)))
goto fail1;
- if (0 != (err = saa7134_pgtable_build(dev->pci,&dev->oss.pt,
- dev->oss.dma.sglist,
- dev->oss.dma.sglen,
+ if (0 != (err = saa7134_pgtable_build(dev->pci,&dev->dmasound.pt,
+ dev->dmasound.dma.sglist,
+ dev->dmasound.dma.sglen,
0)))
goto fail2;
/* sample format */
- switch (dev->oss.afmt) {
+ switch (dev->dmasound.afmt) {
case AFMT_U8:
case AFMT_S8: fmt = 0x00; break;
case AFMT_U16_LE:
@@ -136,14 +149,14 @@ static int dsp_rec_start(struct saa7134_dev *dev)
goto fail2;
}
- switch (dev->oss.afmt) {
+ switch (dev->dmasound.afmt) {
case AFMT_S8:
case AFMT_S16_LE:
case AFMT_S16_BE: sign = 1; break;
default: sign = 0; break;
}
- switch (dev->oss.afmt) {
+ switch (dev->dmasound.afmt) {
case AFMT_U16_BE:
case AFMT_S16_BE: bswap = 1; break;
default: bswap = 0; break;
@@ -151,58 +164,58 @@ static int dsp_rec_start(struct saa7134_dev *dev)
switch (dev->pci->device) {
case PCI_DEVICE_ID_PHILIPS_SAA7134:
- if (1 == dev->oss.channels)
+ if (1 == dev->dmasound.channels)
fmt |= (1 << 3);
- if (2 == dev->oss.channels)
+ if (2 == dev->dmasound.channels)
fmt |= (3 << 3);
if (sign)
fmt |= 0x04;
- fmt |= (TV == dev->oss.input) ? 0xc0 : 0x80;
+ fmt |= (TV == dev->dmasound.input) ? 0xc0 : 0x80;
- saa_writeb(SAA7134_NUM_SAMPLES0, ((dev->oss.blksize - 1) & 0x0000ff));
- saa_writeb(SAA7134_NUM_SAMPLES1, ((dev->oss.blksize - 1) & 0x00ff00) >> 8);
- saa_writeb(SAA7134_NUM_SAMPLES2, ((dev->oss.blksize - 1) & 0xff0000) >> 16);
+ saa_writeb(SAA7134_NUM_SAMPLES0, ((dev->dmasound.blksize - 1) & 0x0000ff));
+ saa_writeb(SAA7134_NUM_SAMPLES1, ((dev->dmasound.blksize - 1) & 0x00ff00) >> 8);
+ saa_writeb(SAA7134_NUM_SAMPLES2, ((dev->dmasound.blksize - 1) & 0xff0000) >> 16);
saa_writeb(SAA7134_AUDIO_FORMAT_CTRL, fmt);
break;
case PCI_DEVICE_ID_PHILIPS_SAA7133:
case PCI_DEVICE_ID_PHILIPS_SAA7135:
- if (1 == dev->oss.channels)
+ if (1 == dev->dmasound.channels)
fmt |= (1 << 4);
- if (2 == dev->oss.channels)
+ if (2 == dev->dmasound.channels)
fmt |= (2 << 4);
if (!sign)
fmt |= 0x04;
- saa_writel(0x588 >> 2, dev->oss.blksize -4);
- saa_writel(0x58c >> 2, 0x543210 | (fmt << 24));
+ saa_writel(SAA7133_NUM_SAMPLES, dev->dmasound.blksize -4);
+ saa_writel(SAA7133_AUDIO_CHANNEL, 0x543210 | (fmt << 24));
break;
}
dprintk("rec_start: afmt=%d ch=%d => fmt=0x%x swap=%c\n",
- dev->oss.afmt, dev->oss.channels, fmt,
+ dev->dmasound.afmt, dev->dmasound.channels, fmt,
bswap ? 'b' : '-');
/* dma: setup channel 6 (= AUDIO) */
control = SAA7134_RS_CONTROL_BURST_16 |
SAA7134_RS_CONTROL_ME |
- (dev->oss.pt.dma >> 12);
+ (dev->dmasound.pt.dma >> 12);
if (bswap)
control |= SAA7134_RS_CONTROL_BSWAP;
saa_writel(SAA7134_RS_BA1(6),0);
- saa_writel(SAA7134_RS_BA2(6),dev->oss.blksize);
+ saa_writel(SAA7134_RS_BA2(6),dev->dmasound.blksize);
saa_writel(SAA7134_RS_PITCH(6),0);
saa_writel(SAA7134_RS_CONTROL(6),control);
/* start dma */
- dev->oss.recording_on = 1;
+ dev->dmasound.recording_on = 1;
spin_lock_irqsave(&dev->slock,flags);
dsp_dma_start(dev);
spin_unlock_irqrestore(&dev->slock,flags);
return 0;
fail2:
- saa7134_pgtable_free(dev->pci,&dev->oss.pt);
+ saa7134_pgtable_free(dev->pci,&dev->dmasound.pt);
fail1:
- videobuf_dma_pci_unmap(dev->pci,&dev->oss.dma);
+ videobuf_dma_pci_unmap(dev->pci,&dev->dmasound.dma);
return err;
}
@@ -210,17 +223,17 @@ static int dsp_rec_stop(struct saa7134_dev *dev)
{
unsigned long flags;
- dprintk("rec_stop dma_blk=%d\n",dev->oss.dma_blk);
+ dprintk("rec_stop dma_blk=%d\n",dev->dmasound.dma_blk);
/* stop dma */
- dev->oss.recording_on = 0;
+ dev->dmasound.recording_on = 0;
spin_lock_irqsave(&dev->slock,flags);
dsp_dma_stop(dev);
spin_unlock_irqrestore(&dev->slock,flags);
/* unlock buffer */
- saa7134_pgtable_free(dev->pci,&dev->oss.pt);
- videobuf_dma_pci_unmap(dev->pci,&dev->oss.dma);
+ saa7134_pgtable_free(dev->pci,&dev->dmasound.pt);
+ videobuf_dma_pci_unmap(dev->pci,&dev->dmasound.dma);
return 0;
}
@@ -235,35 +248,35 @@ static int dsp_open(struct inode *inode, struct file *file)
list_for_each(list,&saa7134_devlist) {
h = list_entry(list, struct saa7134_dev, devlist);
- if (h->oss.minor_dsp == minor)
+ if (h->dmasound.minor_dsp == minor)
dev = h;
}
if (NULL == dev)
return -ENODEV;
- down(&dev->oss.lock);
+ down(&dev->dmasound.lock);
err = -EBUSY;
- if (dev->oss.users_dsp)
+ if (dev->dmasound.users_dsp)
goto fail1;
- dev->oss.users_dsp++;
+ dev->dmasound.users_dsp++;
file->private_data = dev;
- dev->oss.afmt = AFMT_U8;
- dev->oss.channels = 1;
- dev->oss.read_count = 0;
- dev->oss.read_offset = 0;
+ dev->dmasound.afmt = AFMT_U8;
+ dev->dmasound.channels = 1;
+ dev->dmasound.read_count = 0;
+ dev->dmasound.read_offset = 0;
dsp_buffer_conf(dev,PAGE_SIZE,64);
err = dsp_buffer_init(dev);
if (0 != err)
goto fail2;
- up(&dev->oss.lock);
+ up(&dev->dmasound.lock);
return 0;
fail2:
- dev->oss.users_dsp--;
+ dev->dmasound.users_dsp--;
fail1:
- up(&dev->oss.lock);
+ up(&dev->dmasound.lock);
return err;
}
@@ -271,13 +284,13 @@ static int dsp_release(struct inode *inode, struct file *file)
{
struct saa7134_dev *dev = file->private_data;
- down(&dev->oss.lock);
- if (dev->oss.recording_on)
+ down(&dev->dmasound.lock);
+ if (dev->dmasound.recording_on)
dsp_rec_stop(dev);
dsp_buffer_free(dev);
- dev->oss.users_dsp--;
+ dev->dmasound.users_dsp--;
file->private_data = NULL;
- up(&dev->oss.lock);
+ up(&dev->dmasound.lock);
return 0;
}
@@ -290,12 +303,12 @@ static ssize_t dsp_read(struct file *file, char __user *buffer,
unsigned long flags;
int err,ret = 0;
- add_wait_queue(&dev->oss.wq, &wait);
- down(&dev->oss.lock);
+ add_wait_queue(&dev->dmasound.wq, &wait);
+ down(&dev->dmasound.lock);
while (count > 0) {
/* wait for data if needed */
- if (0 == dev->oss.read_count) {
- if (!dev->oss.recording_on) {
+ if (0 == dev->dmasound.read_count) {
+ if (!dev->dmasound.recording_on) {
err = dsp_rec_start(dev);
if (err < 0) {
if (0 == ret)
@@ -303,8 +316,8 @@ static ssize_t dsp_read(struct file *file, char __user *buffer,
break;
}
}
- if (dev->oss.recording_on &&
- !dev->oss.dma_running) {
+ if (dev->dmasound.recording_on &&
+ !dev->dmasound.dma_running) {
/* recover from overruns */
spin_lock_irqsave(&dev->slock,flags);
dsp_dma_start(dev);
@@ -315,12 +328,12 @@ static ssize_t dsp_read(struct file *file, char __user *buffer,
ret = -EAGAIN;
break;
}
- up(&dev->oss.lock);
+ up(&dev->dmasound.lock);
set_current_state(TASK_INTERRUPTIBLE);
- if (0 == dev->oss.read_count)
+ if (0 == dev->dmasound.read_count)
schedule();
set_current_state(TASK_RUNNING);
- down(&dev->oss.lock);
+ down(&dev->dmasound.lock);
if (signal_pending(current)) {
if (0 == ret)
ret = -EINTR;
@@ -330,12 +343,12 @@ static ssize_t dsp_read(struct file *file, char __user *buffer,
/* copy data to userspace */
bytes = count;
- if (bytes > dev->oss.read_count)
- bytes = dev->oss.read_count;
- if (bytes > dev->oss.bufsize - dev->oss.read_offset)
- bytes = dev->oss.bufsize - dev->oss.read_offset;
+ if (bytes > dev->dmasound.read_count)
+ bytes = dev->dmasound.read_count;
+ if (bytes > dev->dmasound.bufsize - dev->dmasound.read_offset)
+ bytes = dev->dmasound.bufsize - dev->dmasound.read_offset;
if (copy_to_user(buffer + ret,
- dev->oss.dma.vmalloc + dev->oss.read_offset,
+ dev->dmasound.dma.vmalloc + dev->dmasound.read_offset,
bytes)) {
if (0 == ret)
ret = -EFAULT;
@@ -344,13 +357,13 @@ static ssize_t dsp_read(struct file *file, char __user *buffer,
ret += bytes;
count -= bytes;
- dev->oss.read_count -= bytes;
- dev->oss.read_offset += bytes;
- if (dev->oss.read_offset == dev->oss.bufsize)
- dev->oss.read_offset = 0;
+ dev->dmasound.read_count -= bytes;
+ dev->dmasound.read_offset += bytes;
+ if (dev->dmasound.read_offset == dev->dmasound.bufsize)
+ dev->dmasound.read_offset = 0;
}
- up(&dev->oss.lock);
- remove_wait_queue(&dev->oss.wq, &wait);
+ up(&dev->dmasound.lock);
+ remove_wait_queue(&dev->dmasound.wq, &wait);
return ret;
}
@@ -368,55 +381,55 @@ static int dsp_ioctl(struct inode *inode, struct file *file,
int __user *p = argp;
int val = 0;
- if (oss_debug > 1)
+ if (debug > 1)
saa7134_print_ioctl(dev->name,cmd);
- switch (cmd) {
- case OSS_GETVERSION:
- return put_user(SOUND_VERSION, p);
- case SNDCTL_DSP_GETCAPS:
+ switch (cmd) {
+ case OSS_GETVERSION:
+ return put_user(SOUND_VERSION, p);
+ case SNDCTL_DSP_GETCAPS:
return 0;
- case SNDCTL_DSP_SPEED:
+ case SNDCTL_DSP_SPEED:
if (get_user(val, p))
return -EFAULT;
/* fall through */
- case SOUND_PCM_READ_RATE:
- return put_user(dev->oss.rate, p);
+ case SOUND_PCM_READ_RATE:
+ return put_user(dev->dmasound.rate, p);
- case SNDCTL_DSP_STEREO:
+ case SNDCTL_DSP_STEREO:
if (get_user(val, p))
return -EFAULT;
- down(&dev->oss.lock);
- dev->oss.channels = val ? 2 : 1;
- if (dev->oss.recording_on) {
+ down(&dev->dmasound.lock);
+ dev->dmasound.channels = val ? 2 : 1;
+ if (dev->dmasound.recording_on) {
dsp_rec_stop(dev);
dsp_rec_start(dev);
}
- up(&dev->oss.lock);
- return put_user(dev->oss.channels-1, p);
+ up(&dev->dmasound.lock);
+ return put_user(dev->dmasound.channels-1, p);
- case SNDCTL_DSP_CHANNELS:
+ case SNDCTL_DSP_CHANNELS:
if (get_user(val, p))
return -EFAULT;
if (val != 1 && val != 2)
return -EINVAL;
- down(&dev->oss.lock);
- dev->oss.channels = val;
- if (dev->oss.recording_on) {
+ down(&dev->dmasound.lock);
+ dev->dmasound.channels = val;
+ if (dev->dmasound.recording_on) {
dsp_rec_stop(dev);
dsp_rec_start(dev);
}
- up(&dev->oss.lock);
+ up(&dev->dmasound.lock);
/* fall through */
- case SOUND_PCM_READ_CHANNELS:
- return put_user(dev->oss.channels, p);
+ case SOUND_PCM_READ_CHANNELS:
+ return put_user(dev->dmasound.channels, p);
- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
+ case SNDCTL_DSP_GETFMTS: /* Returns a mask */
return put_user(AFMT_U8 | AFMT_S8 |
AFMT_U16_LE | AFMT_U16_BE |
AFMT_S16_LE | AFMT_S16_BE, p);
- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt */
+ case SNDCTL_DSP_SETFMT: /* Selects ONE fmt */
if (get_user(val, p))
return -EFAULT;
switch (val) {
@@ -429,20 +442,20 @@ static int dsp_ioctl(struct inode *inode, struct file *file,
case AFMT_U16_BE:
case AFMT_S16_LE:
case AFMT_S16_BE:
- down(&dev->oss.lock);
- dev->oss.afmt = val;
- if (dev->oss.recording_on) {
+ down(&dev->dmasound.lock);
+ dev->dmasound.afmt = val;
+ if (dev->dmasound.recording_on) {
dsp_rec_stop(dev);
dsp_rec_start(dev);
}
- up(&dev->oss.lock);
- return put_user(dev->oss.afmt, p);
+ up(&dev->dmasound.lock);
+ return put_user(dev->dmasound.afmt, p);
default:
return -EINVAL;
}
- case SOUND_PCM_READ_BITS:
- switch (dev->oss.afmt) {
+ case SOUND_PCM_READ_BITS:
+ switch (dev->dmasound.afmt) {
case AFMT_U8:
case AFMT_S8:
return put_user(8, p);
@@ -455,23 +468,23 @@ static int dsp_ioctl(struct inode *inode, struct file *file,
return -EINVAL;
}
- case SNDCTL_DSP_NONBLOCK:
- file->f_flags |= O_NONBLOCK;
- return 0;
+ case SNDCTL_DSP_NONBLOCK:
+ file->f_flags |= O_NONBLOCK;
+ return 0;
- case SNDCTL_DSP_RESET:
- down(&dev->oss.lock);
- if (dev->oss.recording_on)
+ case SNDCTL_DSP_RESET:
+ down(&dev->dmasound.lock);
+ if (dev->dmasound.recording_on)
dsp_rec_stop(dev);
- up(&dev->oss.lock);
+ up(&dev->dmasound.lock);
return 0;
- case SNDCTL_DSP_GETBLKSIZE:
- return put_user(dev->oss.blksize, p);
+ case SNDCTL_DSP_GETBLKSIZE:
+ return put_user(dev->dmasound.blksize, p);
- case SNDCTL_DSP_SETFRAGMENT:
+ case SNDCTL_DSP_SETFRAGMENT:
if (get_user(val, p))
return -EFAULT;
- if (dev->oss.recording_on)
+ if (dev->dmasound.recording_on)
return -EBUSY;
dsp_buffer_free(dev);
/* used to be arg >> 16 instead of val >> 16; fixed */
@@ -479,16 +492,16 @@ static int dsp_ioctl(struct inode *inode, struct file *file,
dsp_buffer_init(dev);
return 0;
- case SNDCTL_DSP_SYNC:
+ case SNDCTL_DSP_SYNC:
/* NOP */
return 0;
case SNDCTL_DSP_GETISPACE:
{
audio_buf_info info;
- info.fragsize = dev->oss.blksize;
- info.fragstotal = dev->oss.blocks;
- info.bytes = dev->oss.read_count;
+ info.fragsize = dev->dmasound.blksize;
+ info.fragstotal = dev->dmasound.blocks;
+ info.bytes = dev->dmasound.read_count;
info.fragments = info.bytes / info.fragsize;
if (copy_to_user(argp, &info, sizeof(info)))
return -EFAULT;
@@ -504,13 +517,13 @@ static unsigned int dsp_poll(struct file *file, struct poll_table_struct *wait)
struct saa7134_dev *dev = file->private_data;
unsigned int mask = 0;
- poll_wait(file, &dev->oss.wq, wait);
+ poll_wait(file, &dev->dmasound.wq, wait);
- if (0 == dev->oss.read_count) {
- down(&dev->oss.lock);
- if (!dev->oss.recording_on)
+ if (0 == dev->dmasound.read_count) {
+ down(&dev->dmasound.lock);
+ if (!dev->dmasound.recording_on)
dsp_rec_start(dev);
- up(&dev->oss.lock);
+ up(&dev->dmasound.lock);
} else
mask |= (POLLIN | POLLRDNORM);
return mask;
@@ -534,7 +547,7 @@ mixer_recsrc_7134(struct saa7134_dev *dev)
{
int analog_io,rate;
- switch (dev->oss.input) {
+ switch (dev->dmasound.input) {
case TV:
saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0xc0);
saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, 0x00);
@@ -542,8 +555,8 @@ mixer_recsrc_7134(struct saa7134_dev *dev)
case LINE1:
case LINE2:
case LINE2_LEFT:
- analog_io = (LINE1 == dev->oss.input) ? 0x00 : 0x08;
- rate = (32000 == dev->oss.rate) ? 0x01 : 0x03;
+ analog_io = (LINE1 == dev->dmasound.input) ? 0x00 : 0x08;
+ rate = (32000 == dev->dmasound.rate) ? 0x01 : 0x03;
saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x08, analog_io);
saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0x80);
saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, rate);
@@ -559,10 +572,10 @@ mixer_recsrc_7133(struct saa7134_dev *dev)
xbarin = 0x03; // adc
anabar = 0;
- switch (dev->oss.input) {
+ switch (dev->dmasound.input) {
case TV:
xbarin = 0; // Demodulator
- anabar = 2; // DACs
+ anabar = 2; // DACs
break;
case LINE1:
anabar = 0; // aux1, aux1
@@ -585,9 +598,9 @@ mixer_recsrc(struct saa7134_dev *dev, enum saa7134_audio_in src)
{
static const char *iname[] = { "Oops", "TV", "LINE1", "LINE2" };
- dev->oss.count++;
- dev->oss.input = src;
- dprintk("mixer input = %s\n",iname[dev->oss.input]);
+ dev->dmasound.count++;
+ dev->dmasound.input = src;
+ dprintk("mixer input = %s\n",iname[dev->dmasound.input]);
switch (dev->pci->device) {
case PCI_DEVICE_ID_PHILIPS_SAA7134:
@@ -639,7 +652,7 @@ static int mixer_open(struct inode *inode, struct file *file)
list_for_each(list,&saa7134_devlist) {
h = list_entry(list, struct saa7134_dev, devlist);
- if (h->oss.minor_mixer == minor)
+ if (h->dmasound.minor_mixer == minor)
dev = h;
}
if (NULL == dev)
@@ -664,30 +677,30 @@ static int mixer_ioctl(struct inode *inode, struct file *file,
void __user *argp = (void __user *) arg;
int __user *p = argp;
- if (oss_debug > 1)
+ if (debug > 1)
saa7134_print_ioctl(dev->name,cmd);
- switch (cmd) {
- case OSS_GETVERSION:
- return put_user(SOUND_VERSION, p);
+ switch (cmd) {
+ case OSS_GETVERSION:
+ return put_user(SOUND_VERSION, p);
case SOUND_MIXER_INFO:
{
mixer_info info;
memset(&info,0,sizeof(info));
- strlcpy(info.id, "TV audio", sizeof(info.id));
- strlcpy(info.name, dev->name, sizeof(info.name));
- info.modify_counter = dev->oss.count;
- if (copy_to_user(argp, &info, sizeof(info)))
- return -EFAULT;
+ strlcpy(info.id, "TV audio", sizeof(info.id));
+ strlcpy(info.name, dev->name, sizeof(info.name));
+ info.modify_counter = dev->dmasound.count;
+ if (copy_to_user(argp, &info, sizeof(info)))
+ return -EFAULT;
return 0;
}
case SOUND_OLD_MIXER_INFO:
{
_old_mixer_info info;
memset(&info,0,sizeof(info));
- strlcpy(info.id, "TV audio", sizeof(info.id));
- strlcpy(info.name, dev->name, sizeof(info.name));
- if (copy_to_user(argp, &info, sizeof(info)))
- return -EFAULT;
+ strlcpy(info.id, "TV audio", sizeof(info.id));
+ strlcpy(info.name, dev->name, sizeof(info.name));
+ if (copy_to_user(argp, &info, sizeof(info)))
+ return -EFAULT;
return 0;
}
case MIXER_READ(SOUND_MIXER_CAPS):
@@ -697,26 +710,26 @@ static int mixer_ioctl(struct inode *inode, struct file *file,
case MIXER_READ(SOUND_MIXER_RECMASK):
case MIXER_READ(SOUND_MIXER_DEVMASK):
val = SOUND_MASK_LINE1 | SOUND_MASK_LINE2;
- if (32000 == dev->oss.rate)
+ if (32000 == dev->dmasound.rate)
val |= SOUND_MASK_VIDEO;
return put_user(val, p);
case MIXER_WRITE(SOUND_MIXER_RECSRC):
if (get_user(val, p))
return -EFAULT;
- input = dev->oss.input;
- if (32000 == dev->oss.rate &&
- val & SOUND_MASK_VIDEO && dev->oss.input != TV)
+ input = dev->dmasound.input;
+ if (32000 == dev->dmasound.rate &&
+ val & SOUND_MASK_VIDEO && dev->dmasound.input != TV)
input = TV;
- if (val & SOUND_MASK_LINE1 && dev->oss.input != LINE1)
+ if (val & SOUND_MASK_LINE1 && dev->dmasound.input != LINE1)
input = LINE1;
- if (val & SOUND_MASK_LINE2 && dev->oss.input != LINE2)
+ if (val & SOUND_MASK_LINE2 && dev->dmasound.input != LINE2)
input = LINE2;
- if (input != dev->oss.input)
+ if (input != dev->dmasound.input)
mixer_recsrc(dev,input);
/* fall throuth */
case MIXER_READ(SOUND_MIXER_RECSRC):
- switch (dev->oss.input) {
+ switch (dev->dmasound.input) {
case TV: ret = SOUND_MASK_VIDEO; break;
case LINE1: ret = SOUND_MASK_LINE1; break;
case LINE2: ret = SOUND_MASK_LINE2; break;
@@ -726,7 +739,7 @@ static int mixer_ioctl(struct inode *inode, struct file *file,
case MIXER_WRITE(SOUND_MIXER_VIDEO):
case MIXER_READ(SOUND_MIXER_VIDEO):
- if (32000 != dev->oss.rate)
+ if (32000 != dev->dmasound.rate)
return -EINVAL;
return put_user(100 | 100 << 8, p);
@@ -735,22 +748,22 @@ static int mixer_ioctl(struct inode *inode, struct file *file,
return -EFAULT;
val &= 0xff;
val = (val <= 50) ? 50 : 100;
- dev->oss.line1 = val;
- mixer_level(dev,LINE1,dev->oss.line1);
+ dev->dmasound.line1 = val;
+ mixer_level(dev,LINE1,dev->dmasound.line1);
/* fall throuth */
case MIXER_READ(SOUND_MIXER_LINE1):
- return put_user(dev->oss.line1 | dev->oss.line1 << 8, p);
+ return put_user(dev->dmasound.line1 | dev->dmasound.line1 << 8, p);
case MIXER_WRITE(SOUND_MIXER_LINE2):
if (get_user(val, p))
return -EFAULT;
val &= 0xff;
val = (val <= 50) ? 50 : 100;
- dev->oss.line2 = val;
- mixer_level(dev,LINE2,dev->oss.line2);
+ dev->dmasound.line2 = val;
+ mixer_level(dev,LINE2,dev->dmasound.line2);
/* fall throuth */
case MIXER_READ(SOUND_MIXER_LINE2):
- return put_user(dev->oss.line2 | dev->oss.line2 << 8, p);
+ return put_user(dev->dmasound.line2 | dev->dmasound.line2 << 8, p);
default:
return -EINVAL;
@@ -767,11 +780,44 @@ struct file_operations saa7134_mixer_fops = {
/* ------------------------------------------------------------------ */
+static irqreturn_t saa7134_oss_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct saa7134_dmasound *dmasound = dev_id;
+ struct saa7134_dev *dev = dmasound->priv_data;
+ unsigned long report, status;
+ int loop, handled = 0;
+
+ for (loop = 0; loop < 10; loop++) {
+ report = saa_readl(SAA7134_IRQ_REPORT);
+ status = saa_readl(SAA7134_IRQ_STATUS);
+
+ if (report & SAA7134_IRQ_REPORT_DONE_RA3) {
+ handled = 1;
+ saa_writel(SAA7134_IRQ_REPORT,report);
+ saa7134_irq_oss_done(dev, status);
+ } else {
+ goto out;
+ }
+ }
+
+ if (loop == 10) {
+ dprintk("error! looping IRQ!");
+ }
+out:
+ return IRQ_RETVAL(handled);
+}
+
int saa7134_oss_init1(struct saa7134_dev *dev)
{
+
+ if ((request_irq(dev->pci->irq, saa7134_oss_irq,
+ SA_SHIRQ | SA_INTERRUPT, dev->name,
+ (void*) &dev->dmasound)) < 0)
+ return -1;
+
/* general */
- init_MUTEX(&dev->oss.lock);
- init_waitqueue_head(&dev->oss.wq);
+ init_MUTEX(&dev->dmasound.lock);
+ init_waitqueue_head(&dev->dmasound.wq);
switch (dev->pci->device) {
case PCI_DEVICE_ID_PHILIPS_SAA7133:
@@ -783,17 +829,17 @@ int saa7134_oss_init1(struct saa7134_dev *dev)
}
/* dsp */
- dev->oss.rate = 32000;
- if (oss_rate)
- dev->oss.rate = oss_rate;
- dev->oss.rate = (dev->oss.rate > 40000) ? 48000 : 32000;
+ dev->dmasound.rate = 32000;
+ if (rate)
+ dev->dmasound.rate = rate;
+ dev->dmasound.rate = (dev->dmasound.rate > 40000) ? 48000 : 32000;
/* mixer */
- dev->oss.line1 = 50;
- dev->oss.line2 = 50;
- mixer_level(dev,LINE1,dev->oss.line1);
- mixer_level(dev,LINE2,dev->oss.line2);
- mixer_recsrc(dev, (dev->oss.rate == 32000) ? TV : LINE2);
+ dev->dmasound.line1 = 50;
+ dev->dmasound.line2 = 50;
+ mixer_level(dev,LINE1,dev->dmasound.line1);
+ mixer_level(dev,LINE2,dev->dmasound.line2);
+ mixer_recsrc(dev, (dev->dmasound.rate == 32000) ? TV : LINE2);
return 0;
}
@@ -809,7 +855,7 @@ void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status)
int next_blk, reg = 0;
spin_lock(&dev->slock);
- if (UNSET == dev->oss.dma_blk) {
+ if (UNSET == dev->dmasound.dma_blk) {
dprintk("irq: recording stopped\n");
goto done;
}
@@ -817,11 +863,11 @@ void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status)
dprintk("irq: lost %ld\n", (status >> 24) & 0x0f);
if (0 == (status & 0x10000000)) {
/* odd */
- if (0 == (dev->oss.dma_blk & 0x01))
+ if (0 == (dev->dmasound.dma_blk & 0x01))
reg = SAA7134_RS_BA1(6);
} else {
/* even */
- if (1 == (dev->oss.dma_blk & 0x01))
+ if (1 == (dev->dmasound.dma_blk & 0x01))
reg = SAA7134_RS_BA2(6);
}
if (0 == reg) {
@@ -829,30 +875,122 @@ void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status)
(status & 0x10000000) ? "even" : "odd");
goto done;
}
- if (dev->oss.read_count >= dev->oss.blksize * (dev->oss.blocks-2)) {
- dprintk("irq: overrun [full=%d/%d]\n",dev->oss.read_count,
- dev->oss.bufsize);
+ if (dev->dmasound.read_count >= dev->dmasound.blksize * (dev->dmasound.blocks-2)) {
+ dprintk("irq: overrun [full=%d/%d]\n",dev->dmasound.read_count,
+ dev->dmasound.bufsize);
dsp_dma_stop(dev);
goto done;
}
/* next block addr */
- next_blk = (dev->oss.dma_blk + 2) % dev->oss.blocks;
- saa_writel(reg,next_blk * dev->oss.blksize);
- if (oss_debug > 2)
+ next_blk = (dev->dmasound.dma_blk + 2) % dev->dmasound.blocks;
+ saa_writel(reg,next_blk * dev->dmasound.blksize);
+ if (debug > 2)
dprintk("irq: ok, %s, next_blk=%d, addr=%x\n",
(status & 0x10000000) ? "even" : "odd ", next_blk,
- next_blk * dev->oss.blksize);
+ next_blk * dev->dmasound.blksize);
/* update status & wake waiting readers */
- dev->oss.dma_blk = (dev->oss.dma_blk + 1) % dev->oss.blocks;
- dev->oss.read_count += dev->oss.blksize;
- wake_up(&dev->oss.wq);
+ dev->dmasound.dma_blk = (dev->dmasound.dma_blk + 1) % dev->dmasound.blocks;
+ dev->dmasound.read_count += dev->dmasound.blksize;
+ wake_up(&dev->dmasound.wq);
done:
spin_unlock(&dev->slock);
}
+int saa7134_dsp_create(struct saa7134_dev *dev)
+{
+ int err;
+
+ err = dev->dmasound.minor_dsp =
+ register_sound_dsp(&saa7134_dsp_fops,
+ dsp_nr[dev->nr]);
+ if (err < 0) {
+ goto fail;
+ }
+ printk(KERN_INFO "%s: registered device dsp%d\n",
+ dev->name,dev->dmasound.minor_dsp >> 4);
+
+ err = dev->dmasound.minor_mixer =
+ register_sound_mixer(&saa7134_mixer_fops,
+ mixer_nr[dev->nr]);
+ if (err < 0)
+ goto fail;
+ printk(KERN_INFO "%s: registered device mixer%d\n",
+ dev->name,dev->dmasound.minor_mixer >> 4);
+
+ return 0;
+
+fail:
+ unregister_sound_dsp(dev->dmasound.minor_dsp);
+ return 0;
+
+
+}
+
+static int saa7134_oss_init(void)
+{
+ struct saa7134_dev *dev = NULL;
+ struct list_head *list;
+
+ printk(KERN_INFO "saa7134 OSS driver for DMA sound loaded\n");
+
+ list_for_each(list,&saa7134_devlist) {
+ dev = list_entry(list, struct saa7134_dev, devlist);
+ if (dev->dmasound.priv_data == NULL) {
+ dev->dmasound.priv_data = dev;
+ saa7134_oss_init1(dev);
+ saa7134_dsp_create(dev);
+ } else {
+ printk(KERN_ERR "saa7134 OSS: DMA sound is being handled by ALSA, ignoring %s\n",dev->name);
+ return -EBUSY;
+ }
+ }
+
+ if (dev == NULL)
+ printk(KERN_INFO "saa7134 OSS: no saa7134 cards found\n");
+
+ return 0;
+
+}
+
+void saa7134_oss_exit(void)
+{
+ struct saa7134_dev *dev = NULL;
+ struct list_head *list;
+
+ list_for_each(list,&saa7134_devlist) {
+ dev = list_entry(list, struct saa7134_dev, devlist);
+
+ /* Device isn't registered by OSS, probably ALSA's */
+ if (!dev->dmasound.minor_dsp)
+ continue;
+
+ unregister_sound_mixer(dev->dmasound.minor_mixer);
+ unregister_sound_dsp(dev->dmasound.minor_dsp);
+
+ saa7134_oss_fini(dev);
+
+ if (dev->pci->irq > 0) {
+ synchronize_irq(dev->pci->irq);
+ free_irq(dev->pci->irq,&dev->dmasound);
+ }
+
+ dev->dmasound.priv_data = NULL;
+
+ }
+
+ printk(KERN_INFO "saa7134 OSS driver for DMA sound unloaded\n");
+
+ return;
+}
+
+module_init(saa7134_oss_init);
+module_exit(saa7134_oss_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+
/* ----------------------------------------------------------- */
/*
* Local variables:
diff --git a/drivers/media/video/saa7134/saa7134-reg.h b/drivers/media/video/saa7134/saa7134-reg.h
index ae0c7a16539..ac6431ba4fc 100644
--- a/drivers/media/video/saa7134/saa7134-reg.h
+++ b/drivers/media/video/saa7134/saa7134-reg.h
@@ -27,7 +27,7 @@
/* DMA channels, n = 0 ... 6 */
#define SAA7134_RS_BA1(n) ((0x200 >> 2) + 4*n)
-#define SAA7134_RS_BA2(n) ((0x204 >> 2) + 4*n)
+#define SAA7134_RS_BA2(n) ((0x204 >> 2) + 4*n)
#define SAA7134_RS_PITCH(n) ((0x208 >> 2) + 4*n)
#define SAA7134_RS_CONTROL(n) ((0x20c >> 2) + 4*n)
#define SAA7134_RS_CONTROL_WSWAP (0x01 << 25)
@@ -43,16 +43,24 @@
#define SAA7134_FIFO_SIZE (0x2a0 >> 2)
#define SAA7134_THRESHOULD (0x2a4 >> 2)
+#define SAA7133_NUM_SAMPLES (0x588 >> 2)
+#define SAA7133_AUDIO_CHANNEL (0x58c >> 2)
+#define SAA7133_AUDIO_FORMAT (0x58f >> 2)
+#define SAA7133_DIGITAL_OUTPUT_SEL1 (0x46c >> 2)
+#define SAA7133_DIGITAL_OUTPUT_SEL2 (0x470 >> 2)
+#define SAA7133_DIGITAL_INPUT_XBAR1 (0x464 >> 2)
+#define SAA7133_ANALOG_IO_SELECT (0x594 >> 2)
+
/* main control */
#define SAA7134_MAIN_CTRL (0x2a8 >> 2)
-#define SAA7134_MAIN_CTRL_VPLLE (1 << 15)
-#define SAA7134_MAIN_CTRL_APLLE (1 << 14)
-#define SAA7134_MAIN_CTRL_EXOSC (1 << 13)
-#define SAA7134_MAIN_CTRL_EVFE1 (1 << 12)
-#define SAA7134_MAIN_CTRL_EVFE2 (1 << 11)
-#define SAA7134_MAIN_CTRL_ESFE (1 << 10)
-#define SAA7134_MAIN_CTRL_EBADC (1 << 9)
-#define SAA7134_MAIN_CTRL_EBDAC (1 << 8)
+#define SAA7134_MAIN_CTRL_VPLLE (1 << 15)
+#define SAA7134_MAIN_CTRL_APLLE (1 << 14)
+#define SAA7134_MAIN_CTRL_EXOSC (1 << 13)
+#define SAA7134_MAIN_CTRL_EVFE1 (1 << 12)
+#define SAA7134_MAIN_CTRL_EVFE2 (1 << 11)
+#define SAA7134_MAIN_CTRL_ESFE (1 << 10)
+#define SAA7134_MAIN_CTRL_EBADC (1 << 9)
+#define SAA7134_MAIN_CTRL_EBDAC (1 << 8)
#define SAA7134_MAIN_CTRL_TE6 (1 << 6)
#define SAA7134_MAIN_CTRL_TE5 (1 << 5)
#define SAA7134_MAIN_CTRL_TE4 (1 << 4)
@@ -348,6 +356,7 @@
/* test modes */
#define SAA7134_SPECIAL_MODE 0x1d0
+#define SAA7134_PRODUCTION_TEST_MODE 0x1d1
/* audio -- saa7133 + saa7135 only */
#define SAA7135_DSP_RWSTATE 0x580
diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c
index 463885601ab..470903e2f5e 100644
--- a/drivers/media/video/saa7134/saa7134-ts.c
+++ b/drivers/media/video/saa7134/saa7134-ts.c
@@ -46,17 +46,11 @@ static int buffer_activate(struct saa7134_dev *dev,
struct saa7134_buf *buf,
struct saa7134_buf *next)
{
- u32 control;
dprintk("buffer_activate [%p]",buf);
buf->vb.state = STATE_ACTIVE;
buf->top_seen = 0;
- /* dma: setup channel 5 (= TS) */
- control = SAA7134_RS_CONTROL_BURST_16 |
- SAA7134_RS_CONTROL_ME |
- (buf->pt->dma >> 12);
-
if (NULL == next)
next = buf;
if (V4L2_FIELD_TOP == buf->vb.field) {
@@ -68,8 +62,6 @@ static int buffer_activate(struct saa7134_dev *dev,
saa_writel(SAA7134_RS_BA1(5),saa7134_buffer_base(next));
saa_writel(SAA7134_RS_BA2(5),saa7134_buffer_base(buf));
}
- saa_writel(SAA7134_RS_PITCH(5),TS_PACKET_SIZE);
- saa_writel(SAA7134_RS_CONTROL(5),control);
/* start DMA */
saa7134_set_dmabits(dev);
@@ -84,6 +76,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
struct saa7134_dev *dev = q->priv_data;
struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
unsigned int lines, llength, size;
+ u32 control;
int err;
dprintk("buffer_prepare [%p,%s]\n",buf,v4l2_field_names[field]);
@@ -115,6 +108,18 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
if (err)
goto oops;
}
+
+ /* dma: setup channel 5 (= TS) */
+ control = SAA7134_RS_CONTROL_BURST_16 |
+ SAA7134_RS_CONTROL_ME |
+ (buf->pt->dma >> 12);
+
+ saa_writeb(SAA7134_TS_DMA0, ((lines-1)&0xff));
+ saa_writeb(SAA7134_TS_DMA1, (((lines-1)>>8)&0xff));
+ saa_writeb(SAA7134_TS_DMA2, ((((lines-1)>>16)&0x3f) | 0x00)); /* TSNOPIT=0, TSCOLAP=0 */
+ saa_writel(SAA7134_RS_PITCH(5),TS_PACKET_SIZE);
+ saa_writel(SAA7134_RS_CONTROL(5),control);
+
buf->vb.state = STATE_PREPARED;
buf->activate = buffer_activate;
buf->vb.field = field;
@@ -164,11 +169,11 @@ EXPORT_SYMBOL_GPL(saa7134_ts_qops);
/* ----------------------------------------------------------- */
/* exported stuff */
-static unsigned int tsbufs = 4;
+static unsigned int tsbufs = 8;
module_param(tsbufs, int, 0444);
MODULE_PARM_DESC(tsbufs,"number of ts buffers, range 2-32");
-static unsigned int ts_nr_packets = 30;
+static unsigned int ts_nr_packets = 64;
module_param(ts_nr_packets, int, 0444);
MODULE_PARM_DESC(ts_nr_packets,"size of a ts buffers (in ts packets)");
@@ -220,10 +225,10 @@ void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status)
if (dev->ts_q.curr) {
field = dev->ts_q.curr->vb.field;
if (field == V4L2_FIELD_TOP) {
- if ((status & 0x100000) != 0x100000)
+ if ((status & 0x100000) != 0x000000)
goto done;
} else {
- if ((status & 0x100000) != 0x000000)
+ if ((status & 0x100000) != 0x100000)
goto done;
}
saa7134_buffer_finish(dev,&dev->ts_q,STATE_DONE);
diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c
index badf2f9e307..93268427750 100644
--- a/drivers/media/video/saa7134/saa7134-tvaudio.c
+++ b/drivers/media/video/saa7134/saa7134-tvaudio.c
@@ -207,6 +207,10 @@ static void tvaudio_setcarrier(struct saa7134_dev *dev,
saa_writel(SAA7134_CARRIER2_FREQ0 >> 2, tvaudio_carr2reg(secondary));
}
+#define SAA7134_MUTE_MASK 0xbb
+#define SAA7134_MUTE_ANALOG 0x04
+#define SAA7134_MUTE_I2S 0x40
+
static void mute_input_7134(struct saa7134_dev *dev)
{
unsigned int mute;
@@ -241,7 +245,11 @@ static void mute_input_7134(struct saa7134_dev *dev)
if (PCI_DEVICE_ID_PHILIPS_SAA7134 == dev->pci->device)
/* 7134 mute */
- saa_writeb(SAA7134_AUDIO_MUTE_CTRL, mute ? 0xbf : 0xbb);
+ saa_writeb(SAA7134_AUDIO_MUTE_CTRL, mute ?
+ SAA7134_MUTE_MASK |
+ SAA7134_MUTE_ANALOG |
+ SAA7134_MUTE_I2S :
+ SAA7134_MUTE_MASK);
/* switch internal audio mux */
switch (in->amux) {
@@ -342,8 +350,8 @@ static int tvaudio_sleep(struct saa7134_dev *dev, int timeout)
set_current_state(TASK_INTERRUPTIBLE);
schedule();
} else {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(msecs_to_jiffies(timeout));
+ schedule_timeout_interruptible
+ (msecs_to_jiffies(timeout));
}
}
remove_wait_queue(&dev->thread.wq, &wait);
@@ -753,17 +761,17 @@ static int mute_input_7133(struct saa7134_dev *dev)
/* switch gpio-connected external audio mux */
- if (0 != card(dev).gpiomask) {
- mask = card(dev).gpiomask;
+ if (0 != card(dev).gpiomask) {
+ mask = card(dev).gpiomask;
if (card(dev).mute.name && dev->ctl_mute)
in = &card(dev).mute;
else
in = dev->input;
- saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, mask, mask);
- saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, in->gpio);
- saa7134_track_gpio(dev,in->name);
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, mask, mask);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, in->gpio);
+ saa7134_track_gpio(dev,in->name);
}
return 0;
@@ -1016,9 +1024,12 @@ int saa7134_tvaudio_do_scan(struct saa7134_dev *dev)
return 0;
}
+EXPORT_SYMBOL(saa_dsp_writel);
+
/* ----------------------------------------------------------- */
/*
* Local variables:
* c-basic-offset: 8
* End:
*/
+
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index 35e5e85f669..45c852df13e 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -30,6 +30,9 @@
#include "saa7134-reg.h"
#include "saa7134.h"
+/* Include V4L1 specific functions. Should be removed soon */
+#include <linux/videodev.h>
+
/* ------------------------------------------------------------------ */
static unsigned int video_debug = 0;
@@ -48,6 +51,43 @@ MODULE_PARM_DESC(noninterlaced,"video input is noninterlaced");
printk(KERN_DEBUG "%s/video: " fmt, dev->name , ## arg)
/* ------------------------------------------------------------------ */
+/* Defines for Video Output Port Register at address 0x191 */
+
+/* Bit 0: VIP code T bit polarity */
+
+#define VP_T_CODE_P_NON_INVERTED 0x00
+#define VP_T_CODE_P_INVERTED 0x01
+
+/* ------------------------------------------------------------------ */
+/* Defines for Video Output Port Register at address 0x195 */
+
+/* Bit 2: Video output clock delay control */
+
+#define VP_CLK_CTRL2_NOT_DELAYED 0x00
+#define VP_CLK_CTRL2_DELAYED 0x04
+
+/* Bit 1: Video output clock invert control */
+
+#define VP_CLK_CTRL1_NON_INVERTED 0x00
+#define VP_CLK_CTRL1_INVERTED 0x02
+
+/* ------------------------------------------------------------------ */
+/* Defines for Video Output Port Register at address 0x196 */
+
+/* Bits 2 to 0: VSYNC pin video vertical sync type */
+
+#define VP_VS_TYPE_MASK 0x07
+
+#define VP_VS_TYPE_OFF 0x00
+#define VP_VS_TYPE_V123 0x01
+#define VP_VS_TYPE_V_ITU 0x02
+#define VP_VS_TYPE_VGATE_L 0x03
+#define VP_VS_TYPE_RESERVED1 0x04
+#define VP_VS_TYPE_RESERVED2 0x05
+#define VP_VS_TYPE_F_ITU 0x06
+#define VP_VS_TYPE_SC_FID 0x07
+
+/* ------------------------------------------------------------------ */
/* data structs for video */
static int video_out[][9] = {
@@ -273,12 +313,12 @@ static struct saa7134_tvnorm tvnorms[] = {
.h_start = 0,
.h_stop = 719,
- .video_v_start = 23,
- .video_v_stop = 262,
- .vbi_v_start_0 = 10,
- .vbi_v_stop_0 = 21,
- .vbi_v_start_1 = 273,
- .src_timing = 7,
+ .video_v_start = 23,
+ .video_v_stop = 262,
+ .vbi_v_start_0 = 10,
+ .vbi_v_stop_0 = 21,
+ .vbi_v_start_1 = 273,
+ .src_timing = 7,
.sync_control = 0x18,
.luma_control = 0x40,
@@ -622,7 +662,7 @@ static void set_size(struct saa7134_dev *dev, int task,
prescale = 1;
xscale = 1024 * dev->crop_current.width / prescale / width;
yscale = 512 * div * dev->crop_current.height / height;
- dprintk("prescale=%d xscale=%d yscale=%d\n",prescale,xscale,yscale);
+ dprintk("prescale=%d xscale=%d yscale=%d\n",prescale,xscale,yscale);
set_h_prescale(dev,task,prescale);
saa_writeb(SAA7134_H_SCALE_INC1(task), xscale & 0xff);
saa_writeb(SAA7134_H_SCALE_INC2(task), xscale >> 8);
@@ -752,20 +792,20 @@ static int verify_preview(struct saa7134_dev *dev, struct v4l2_window *win)
maxh = dev->crop_current.height;
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;
- }
+ 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;
+ }
win->field = field;
if (win->w.width > maxw)
@@ -1306,13 +1346,13 @@ video_poll(struct file *file, struct poll_table_struct *wait)
if (res_locked(fh->dev,RESOURCE_VIDEO)) {
up(&fh->cap.lock);
return POLLERR;
- }
- if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,fh->cap.field)) {
- up(&fh->cap.lock);
- return POLLERR;
- }
- fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
- fh->cap.read_off = 0;
+ }
+ if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,fh->cap.field)) {
+ up(&fh->cap.lock);
+ return POLLERR;
+ }
+ fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
+ fh->cap.read_off = 0;
}
up(&fh->cap.lock);
buf = fh->cap.read_buf;
@@ -1666,9 +1706,10 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_QUERYCAP:
{
struct v4l2_capability *cap = arg;
+ unsigned int tuner_type = dev->tuner_type;
memset(cap,0,sizeof(*cap));
- strcpy(cap->driver, "saa7134");
+ strcpy(cap->driver, "saa7134");
strlcpy(cap->card, saa7134_boards[dev->board].name,
sizeof(cap->card));
sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
@@ -1677,9 +1718,13 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_VIDEO_OVERLAY |
V4L2_CAP_VBI_CAPTURE |
- V4L2_CAP_TUNER |
V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING;
+ V4L2_CAP_STREAMING |
+ V4L2_CAP_TUNER;
+
+ if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET))
+ cap->capabilities &= ~V4L2_CAP_TUNER;
+
return 0;
}
@@ -1793,9 +1838,9 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
crop->c.height = b->top - crop->c.top + b->height;
if (crop->c.left < b->left)
- crop->c.top = b->left;
+ crop->c.left = b->left;
if (crop->c.left > b->left + b->width)
- crop->c.top = b->left + b->width;
+ crop->c.left = b->left + b->width;
if (crop->c.width > b->left - crop->c.left + b->width)
crop->c.width = b->left - crop->c.left + b->width;
@@ -1817,6 +1862,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
break;
if (NULL != card_in(dev,n).name) {
strcpy(t->name, "Television");
+ t->type = V4L2_TUNER_ANALOG_TV;
t->capability = V4L2_TUNER_CAP_NORM |
V4L2_TUNER_CAP_STEREO |
V4L2_TUNER_CAP_LANG1 |
@@ -1892,26 +1938,26 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
}
case VIDIOC_S_AUDIO:
return 0;
- case VIDIOC_G_PARM:
- {
- struct v4l2_captureparm *parm = arg;
- memset(parm,0,sizeof(*parm));
- return 0;
- }
-
- case VIDIOC_G_PRIORITY:
- {
- enum v4l2_priority *p = arg;
-
- *p = v4l2_prio_max(&dev->prio);
- return 0;
- }
- case VIDIOC_S_PRIORITY:
- {
- enum v4l2_priority *prio = arg;
-
- return v4l2_prio_change(&dev->prio, &fh->prio, *prio);
- }
+ case VIDIOC_G_PARM:
+ {
+ struct v4l2_captureparm *parm = arg;
+ memset(parm,0,sizeof(*parm));
+ return 0;
+ }
+
+ case VIDIOC_G_PRIORITY:
+ {
+ enum v4l2_priority *p = arg;
+
+ *p = v4l2_prio_max(&dev->prio);
+ return 0;
+ }
+ case VIDIOC_S_PRIORITY:
+ {
+ enum v4l2_priority *prio = arg;
+
+ return v4l2_prio_change(&dev->prio, &fh->prio, *prio);
+ }
/* --- preview ioctls ---------------------------------------- */
case VIDIOC_ENUM_FMT:
@@ -2018,7 +2064,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
struct v4l2_format *f = arg;
return saa7134_try_fmt(dev,fh,f);
}
-
+#ifdef HAVE_V4L1
case VIDIOCGMBUF:
{
struct video_mbuf *mbuf = arg;
@@ -2043,6 +2089,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
}
return 0;
}
+#endif
case VIDIOC_REQBUFS:
return videobuf_reqbufs(saa7134_queue(fh),arg);
@@ -2060,7 +2107,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
{
int res = saa7134_resource(fh);
- if (!res_get(dev,fh,res))
+ if (!res_get(dev,fh,res))
return -EBUSY;
return videobuf_streamon(saa7134_queue(fh));
}
@@ -2102,7 +2149,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
struct v4l2_capability *cap = arg;
memset(cap,0,sizeof(*cap));
- strcpy(cap->driver, "saa7134");
+ strcpy(cap->driver, "saa7134");
strlcpy(cap->card, saa7134_boards[dev->board].name,
sizeof(cap->card));
sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
@@ -2119,6 +2166,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
memset(t,0,sizeof(*t));
strcpy(t->name, "Radio");
+ t->type = V4L2_TUNER_RADIO;
saa7134_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
@@ -2233,7 +2281,7 @@ struct video_device saa7134_video_template =
{
.name = "saa7134-video",
.type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_OVERLAY|
- VID_TYPE_CLIPPING|VID_TYPE_SCALES,
+ VID_TYPE_CLIPPING|VID_TYPE_SCALES,
.hardware = 0,
.fops = &video_fops,
.minor = -1,
@@ -2280,7 +2328,7 @@ int saa7134_video_init1(struct saa7134_dev *dev)
dev->tda9887_conf |= TDA9887_AUTOMUTE;
dev->automute = 0;
- INIT_LIST_HEAD(&dev->video_q.queue);
+ INIT_LIST_HEAD(&dev->video_q.queue);
init_timer(&dev->video_q.timeout);
dev->video_q.timeout.function = saa7134_buffer_timeout;
dev->video_q.timeout.data = (unsigned long)(&dev->video_q);
@@ -2289,13 +2337,28 @@ int saa7134_video_init1(struct saa7134_dev *dev)
if (saa7134_boards[dev->board].video_out) {
/* enable video output */
int vo = saa7134_boards[dev->board].video_out;
+ int video_reg;
+ unsigned int vid_port_opts = saa7134_boards[dev->board].vid_port_opts;
saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]);
- saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_out[vo][1]);
+ video_reg = video_out[vo][1];
+ if (vid_port_opts & SET_T_CODE_POLARITY_NON_INVERTED)
+ video_reg &= ~VP_T_CODE_P_INVERTED;
+ saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_reg);
saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]);
saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]);
saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]);
- saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_out[vo][5]);
- saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_out[vo][6]);
+ video_reg = video_out[vo][5];
+ if (vid_port_opts & SET_CLOCK_NOT_DELAYED)
+ video_reg &= ~VP_CLK_CTRL2_DELAYED;
+ if (vid_port_opts & SET_CLOCK_INVERTED)
+ video_reg |= VP_CLK_CTRL1_INVERTED;
+ saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_reg);
+ video_reg = video_out[vo][6];
+ if (vid_port_opts & SET_VSYNC_OFF) {
+ video_reg &= ~VP_VS_TYPE_MASK;
+ video_reg |= VP_VS_TYPE_OFF;
+ }
+ saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_reg);
saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]);
saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]);
}
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index 860b89530e2..244e1973081 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -24,16 +24,18 @@
#include <linux/pci.h>
#include <linux/i2c.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
#include <linux/kdev_t.h>
#include <linux/input.h>
+#include <linux/notifier.h>
+#include <linux/delay.h>
#include <asm/io.h>
#include <media/tuner.h>
#include <media/audiochip.h>
-#include <media/id.h>
#include <media/ir-common.h>
+#include <media/ir-kbd-i2c.h>
#include <media/video-buf.h>
#include <media/video-buf-dvb.h>
@@ -45,6 +47,10 @@
#endif
#define UNSET (-1U)
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+
/* ----------------------------------------------------------- */
/* enums */
@@ -187,10 +193,40 @@ struct saa7134_format {
#define SAA7134_BOARD_FLYTV_DIGIMATRIX 64
#define SAA7134_BOARD_KWORLD_TERMINATOR 65
#define SAA7134_BOARD_YUAN_TUN900 66
+#define SAA7134_BOARD_BEHOLD_409FM 67
+#define SAA7134_BOARD_GOTVIEW_7135 68
+#define SAA7134_BOARD_PHILIPS_EUROPA 69
+#define SAA7134_BOARD_VIDEOMATE_DVBT_300 70
+#define SAA7134_BOARD_VIDEOMATE_DVBT_200 71
+#define SAA7134_BOARD_RTD_VFG7350 72
+#define SAA7134_BOARD_RTD_VFG7330 73
+#define SAA7134_BOARD_FLYTVPLATINUM_MINI2 74
+#define SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180 75
+#define SAA7134_BOARD_MONSTERTV_MOBILE 76
+#define SAA7134_BOARD_PINNACLE_PCTV_110i 77
+#define SAA7134_BOARD_ASUSTeK_P7131_DUAL 78
+#define SAA7134_BOARD_SEDNA_PC_TV_CARDBUS 79
+#define SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV 80
+#define SAA7134_BOARD_PHILIPS_TIGER 81
+#define SAA7134_BOARD_MSI_TVATANYWHERE_PLUS 82
#define SAA7134_MAXBOARDS 8
#define SAA7134_INPUT_MAX 8
+/* ----------------------------------------------------------- */
+/* Since we support 2 remote types, lets tell them apart */
+
+#define SAA7134_REMOTE_GPIO 1
+#define SAA7134_REMOTE_I2C 2
+
+/* ----------------------------------------------------------- */
+/* Video Output Port Register Initialization Options */
+
+#define SET_T_CODE_POLARITY_NON_INVERTED (1 << 0)
+#define SET_CLOCK_NOT_DELAYED (1 << 1)
+#define SET_CLOCK_INVERTED (1 << 2)
+#define SET_VSYNC_OFF (1 << 3)
+
struct saa7134_input {
char *name;
unsigned int vmux;
@@ -226,6 +262,7 @@ struct saa7134_board {
/* peripheral I/O */
enum saa7134_video_out video_out;
enum saa7134_mpeg_type mpeg;
+ unsigned int vid_port_opts;
};
#define card_has_radio(dev) (NULL != saa7134_boards[dev->board].radio.name)
@@ -319,9 +356,9 @@ struct saa7134_fh {
struct saa7134_pgtable pt_vbi;
};
-/* oss dsp status */
-struct saa7134_oss {
- struct semaphore lock;
+/* dmasound dsp status */
+struct saa7134_dmasound {
+ struct semaphore lock;
int minor_mixer;
int minor_dsp;
unsigned int users_dsp;
@@ -347,6 +384,8 @@ struct saa7134_oss {
unsigned int dma_blk;
unsigned int read_offset;
unsigned int read_count;
+ void * priv_data;
+ snd_pcm_substream_t *substream;
};
/* IR input */
@@ -358,9 +397,9 @@ struct saa7134_ir {
u32 mask_keycode;
u32 mask_keydown;
u32 mask_keyup;
- int polling;
- u32 last_gpio;
- struct timer_list timer;
+ int polling;
+ u32 last_gpio;
+ struct timer_list timer;
};
/* ts/mpeg status */
@@ -383,8 +422,8 @@ struct saa7134_mpeg_ops {
/* global device status */
struct saa7134_dev {
struct list_head devlist;
- struct semaphore lock;
- spinlock_t slock;
+ struct semaphore lock;
+ spinlock_t slock;
#ifdef VIDIOC_G_PRIORITY
struct v4l2_prio_state prio;
#endif
@@ -394,7 +433,7 @@ struct saa7134_dev {
struct video_device *video_dev;
struct video_device *radio_dev;
struct video_device *vbi_dev;
- struct saa7134_oss oss;
+ struct saa7134_dmasound dmasound;
/* infrared remote */
int has_remote;
@@ -421,7 +460,7 @@ struct saa7134_dev {
/* i2c i/o */
struct i2c_adapter i2c_adap;
struct i2c_client i2c_client;
- unsigned char eedata[64];
+ unsigned char eedata[128];
/* video overlay */
struct v4l2_framebuffer ovbuf;
@@ -626,6 +665,7 @@ void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status);
int saa7134_input_init1(struct saa7134_dev *dev);
void saa7134_input_fini(struct saa7134_dev *dev);
void saa7134_input_irq(struct saa7134_dev *dev);
+void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir);
/*
* Local variables:
diff --git a/drivers/media/video/saa7191.c b/drivers/media/video/saa7191.c
index 3ddbb62312b..cbca896e8cf 100644
--- a/drivers/media/video/saa7191.c
+++ b/drivers/media/video/saa7191.c
@@ -26,71 +26,95 @@
#include "saa7191.h"
-#define SAA7191_MODULE_VERSION "0.0.3"
+#define SAA7191_MODULE_VERSION "0.0.5"
MODULE_DESCRIPTION("Philips SAA7191 video decoder driver");
MODULE_VERSION(SAA7191_MODULE_VERSION);
MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>");
MODULE_LICENSE("GPL");
+// #define SAA7191_DEBUG
+
+#ifdef SAA7191_DEBUG
+#define dprintk(x...) printk("SAA7191: " x);
+#else
+#define dprintk(x...)
+#endif
+
+#define SAA7191_SYNC_COUNT 30
+#define SAA7191_SYNC_DELAY 100 /* milliseconds */
+
struct saa7191 {
struct i2c_client *client;
/* the register values are stored here as the actual
* I2C-registers are write-only */
- unsigned char reg[25];
+ u8 reg[25];
- unsigned char norm;
- unsigned char input;
+ int input;
+ int norm;
};
static struct i2c_driver i2c_driver_saa7191;
-static const unsigned char initseq[] = {
+static const u8 initseq[] = {
0, /* Subaddress */
- 0x50, /* SAA7191_REG_IDEL */
- 0x30, /* SAA7191_REG_HSYB */
- 0x00, /* SAA7191_REG_HSYS */
- 0xe8, /* SAA7191_REG_HCLB */
- 0xb6, /* SAA7191_REG_HCLS */
- 0xf4, /* SAA7191_REG_HPHI */
- 0x01, /* SAA7191_REG_LUMA - chrominance trap active (CVBS) */
- 0x00, /* SAA7191_REG_HUEC */
- 0xf8, /* SAA7191_REG_CKTQ */
- 0xf8, /* SAA7191_REG_CKTS */
- 0x90, /* SAA7191_REG_PLSE */
- 0x90, /* SAA7191_REG_SESE */
- 0x00, /* SAA7191_REG_GAIN */
- 0x0c, /* SAA7191_REG_STDC - not SECAM, slow time constant */
- 0x78, /* SAA7191_REG_IOCK - chrominance from CVBS, GPSW1 & 2 off */
- 0x99, /* SAA7191_REG_CTL3 - automatic field detection */
- 0x00, /* SAA7191_REG_CTL4 */
- 0x2c, /* SAA7191_REG_CHCV */
+
+ 0x50, /* (0x50) SAA7191_REG_IDEL */
+
+ /* 50 Hz signal timing */
+ 0x30, /* (0x30) SAA7191_REG_HSYB */
+ 0x00, /* (0x00) SAA7191_REG_HSYS */
+ 0xe8, /* (0xe8) SAA7191_REG_HCLB */
+ 0xb6, /* (0xb6) SAA7191_REG_HCLS */
+ 0xf4, /* (0xf4) SAA7191_REG_HPHI */
+
+ /* control */
+ SAA7191_LUMA_APER_1, /* (0x01) SAA7191_REG_LUMA - CVBS mode */
+ 0x00, /* (0x00) SAA7191_REG_HUEC */
+ 0xf8, /* (0xf8) SAA7191_REG_CKTQ */
+ 0xf8, /* (0xf8) SAA7191_REG_CKTS */
+ 0x90, /* (0x90) SAA7191_REG_PLSE */
+ 0x90, /* (0x90) SAA7191_REG_SESE */
+ 0x00, /* (0x00) SAA7191_REG_GAIN */
+ SAA7191_STDC_NFEN | SAA7191_STDC_HRMV, /* (0x0c) SAA7191_REG_STDC
+ * - not SECAM,
+ * slow time constant */
+ SAA7191_IOCK_OEDC | SAA7191_IOCK_OEHS | SAA7191_IOCK_OEVS
+ | SAA7191_IOCK_OEDY, /* (0x78) SAA7191_REG_IOCK
+ * - chroma from CVBS, GPSW1 & 2 off */
+ SAA7191_CTL3_AUFD | SAA7191_CTL3_SCEN | SAA7191_CTL3_OFTS
+ | SAA7191_CTL3_YDEL0, /* (0x99) SAA7191_REG_CTL3
+ * - automatic field detection */
+ 0x00, /* (0x00) SAA7191_REG_CTL4 */
+ 0x2c, /* (0x2c) SAA7191_REG_CHCV - PAL nominal value */
0x00, /* unused */
0x00, /* unused */
- 0x34, /* SAA7191_REG_HS6B */
- 0x0a, /* SAA7191_REG_HS6S */
- 0xf4, /* SAA7191_REG_HC6B */
- 0xce, /* SAA7191_REG_HC6S */
- 0xf4, /* SAA7191_REG_HP6I */
+
+ /* 60 Hz signal timing */
+ 0x34, /* (0x34) SAA7191_REG_HS6B */
+ 0x0a, /* (0x0a) SAA7191_REG_HS6S */
+ 0xf4, /* (0xf4) SAA7191_REG_HC6B */
+ 0xce, /* (0xce) SAA7191_REG_HC6S */
+ 0xf4, /* (0xf4) SAA7191_REG_HP6I */
};
/* SAA7191 register handling */
-static unsigned char saa7191_read_reg(struct i2c_client *client,
- unsigned char reg)
+static u8 saa7191_read_reg(struct i2c_client *client,
+ u8 reg)
{
return ((struct saa7191 *)i2c_get_clientdata(client))->reg[reg];
}
static int saa7191_read_status(struct i2c_client *client,
- unsigned char *value)
+ u8 *value)
{
int ret;
ret = i2c_master_recv(client, value, 1);
if (ret < 0) {
- printk(KERN_ERR "SAA7191: saa7191_read_status(): read failed");
+ printk(KERN_ERR "SAA7191: saa7191_read_status(): read failed\n");
return ret;
}
@@ -98,17 +122,16 @@ static int saa7191_read_status(struct i2c_client *client,
}
-static int saa7191_write_reg(struct i2c_client *client, unsigned char reg,
- unsigned char value)
+static int saa7191_write_reg(struct i2c_client *client, u8 reg,
+ u8 value)
{
-
((struct saa7191 *)i2c_get_clientdata(client))->reg[reg] = value;
return i2c_smbus_write_byte_data(client, reg, value);
}
/* the first byte of data must be the first subaddress number (register) */
static int saa7191_write_block(struct i2c_client *client,
- unsigned char length, unsigned char *data)
+ u8 length, u8 *data)
{
int i;
int ret;
@@ -121,7 +144,7 @@ static int saa7191_write_block(struct i2c_client *client,
ret = i2c_master_send(client, data, length);
if (ret < 0) {
printk(KERN_ERR "SAA7191: saa7191_write_block(): "
- "write failed");
+ "write failed\n");
return ret;
}
@@ -132,8 +155,9 @@ static int saa7191_write_block(struct i2c_client *client,
static int saa7191_set_input(struct i2c_client *client, int input)
{
- unsigned char luma = saa7191_read_reg(client, SAA7191_REG_LUMA);
- unsigned char iock = saa7191_read_reg(client, SAA7191_REG_IOCK);
+ struct saa7191 *decoder = i2c_get_clientdata(client);
+ u8 luma = saa7191_read_reg(client, SAA7191_REG_LUMA);
+ u8 iock = saa7191_read_reg(client, SAA7191_REG_IOCK);
int err;
switch (input) {
@@ -159,32 +183,20 @@ static int saa7191_set_input(struct i2c_client *client, int input)
if (err)
return -EIO;
+ decoder->input = input;
+
return 0;
}
static int saa7191_set_norm(struct i2c_client *client, int norm)
{
struct saa7191 *decoder = i2c_get_clientdata(client);
- unsigned char stdc = saa7191_read_reg(client, SAA7191_REG_STDC);
- unsigned char ctl3 = saa7191_read_reg(client, SAA7191_REG_CTL3);
- unsigned char chcv = saa7191_read_reg(client, SAA7191_REG_CHCV);
+ u8 stdc = saa7191_read_reg(client, SAA7191_REG_STDC);
+ u8 ctl3 = saa7191_read_reg(client, SAA7191_REG_CTL3);
+ u8 chcv = saa7191_read_reg(client, SAA7191_REG_CHCV);
int err;
switch(norm) {
- case SAA7191_NORM_AUTO: {
- unsigned char status;
-
- // does status depend on current norm ?
- if (saa7191_read_status(client, &status))
- return -EIO;
-
- stdc &= ~SAA7191_STDC_SECS;
- ctl3 &= ~SAA7191_CTL3_FSEL;
- ctl3 |= SAA7191_CTL3_AUFD;
- chcv = (status & SAA7191_STATUS_FIDT)
- ? SAA7191_CHCV_NTSC : SAA7191_CHCV_PAL;
- break;
- }
case SAA7191_NORM_PAL:
stdc &= ~SAA7191_STDC_SECS;
ctl3 &= ~(SAA7191_CTL3_AUFD | SAA7191_CTL3_FSEL);
@@ -217,60 +229,335 @@ static int saa7191_set_norm(struct i2c_client *client, int norm)
decoder->norm = norm;
+ dprintk("ctl3: %02x stdc: %02x chcv: %02x\n", ctl3,
+ stdc, chcv);
+ dprintk("norm: %d\n", norm);
+
return 0;
}
-static int saa7191_get_controls(struct i2c_client *client,
- struct saa7191_control *ctrl)
+static int saa7191_wait_for_signal(struct i2c_client *client, u8 *status)
{
- unsigned char hue = saa7191_read_reg(client, SAA7191_REG_HUEC);
- unsigned char stdc = saa7191_read_reg(client, SAA7191_REG_STDC);
+ int i = 0;
- if (hue < 0x80) {
- hue += 0x80;
- } else {
- hue -= 0x80;
+ dprintk("Checking for signal...\n");
+
+ for (i = 0; i < SAA7191_SYNC_COUNT; i++) {
+ if (saa7191_read_status(client, status))
+ return -EIO;
+
+ if (((*status) & SAA7191_STATUS_HLCK) == 0) {
+ dprintk("Signal found\n");
+ return 0;
+ }
+
+ msleep(SAA7191_SYNC_DELAY);
}
- ctrl->hue = hue;
- ctrl->vtrc = (stdc & SAA7191_STDC_VTRC)
- ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED;
+ dprintk("No signal\n");
- return 0;
+ return -EBUSY;
}
-static int saa7191_set_controls(struct i2c_client *client,
- struct saa7191_control *ctrl)
+static int saa7191_autodetect_norm_extended(struct i2c_client *client)
{
- int err;
+ u8 stdc = saa7191_read_reg(client, SAA7191_REG_STDC);
+ u8 ctl3 = saa7191_read_reg(client, SAA7191_REG_CTL3);
+ u8 status;
+ int err = 0;
- if (ctrl->hue >= 0) {
- unsigned char hue = ctrl->hue & 0xff;
- if (hue < 0x80) {
- hue += 0x80;
- } else {
- hue -= 0x80;
+ dprintk("SAA7191 extended signal auto-detection...\n");
+
+ stdc &= ~SAA7191_STDC_SECS;
+ ctl3 &= ~(SAA7191_CTL3_FSEL);
+
+ err = saa7191_write_reg(client, SAA7191_REG_STDC, stdc);
+ if (err) {
+ err = -EIO;
+ goto out;
+ }
+ err = saa7191_write_reg(client, SAA7191_REG_CTL3, ctl3);
+ if (err) {
+ err = -EIO;
+ goto out;
+ }
+
+ ctl3 |= SAA7191_CTL3_AUFD;
+ err = saa7191_write_reg(client, SAA7191_REG_CTL3, ctl3);
+ if (err) {
+ err = -EIO;
+ goto out;
+ }
+
+ msleep(SAA7191_SYNC_DELAY);
+
+ err = saa7191_wait_for_signal(client, &status);
+ if (err)
+ goto out;
+
+ if (status & SAA7191_STATUS_FIDT) {
+ /* 60Hz signal -> NTSC */
+ dprintk("60Hz signal: NTSC\n");
+ return saa7191_set_norm(client, SAA7191_NORM_NTSC);
+ }
+
+ /* 50Hz signal */
+ dprintk("50Hz signal: Trying PAL...\n");
+
+ /* try PAL first */
+ err = saa7191_set_norm(client, SAA7191_NORM_PAL);
+ if (err)
+ goto out;
+
+ msleep(SAA7191_SYNC_DELAY);
+
+ err = saa7191_wait_for_signal(client, &status);
+ if (err)
+ goto out;
+
+ /* not 50Hz ? */
+ if (status & SAA7191_STATUS_FIDT) {
+ dprintk("No 50Hz signal\n");
+ err = -EAGAIN;
+ goto out;
+ }
+
+ if (status & SAA7191_STATUS_CODE) {
+ dprintk("PAL\n");
+ return 0;
+ }
+
+ dprintk("No color detected with PAL - Trying SECAM...\n");
+
+ /* no color detected ? -> try SECAM */
+ err = saa7191_set_norm(client,
+ SAA7191_NORM_SECAM);
+ if (err)
+ goto out;
+
+ msleep(SAA7191_SYNC_DELAY);
+
+ err = saa7191_wait_for_signal(client, &status);
+ if (err)
+ goto out;
+
+ /* not 50Hz ? */
+ if (status & SAA7191_STATUS_FIDT) {
+ dprintk("No 50Hz signal\n");
+ err = -EAGAIN;
+ goto out;
+ }
+
+ if (status & SAA7191_STATUS_CODE) {
+ /* Color detected -> SECAM */
+ dprintk("SECAM\n");
+ return 0;
+ }
+
+ dprintk("No color detected with SECAM - Going back to PAL.\n");
+
+ /* still no color detected ?
+ * -> set norm back to PAL */
+ err = saa7191_set_norm(client,
+ SAA7191_NORM_PAL);
+ if (err)
+ goto out;
+
+out:
+ ctl3 = saa7191_read_reg(client, SAA7191_REG_CTL3);
+ if (ctl3 & SAA7191_CTL3_AUFD) {
+ ctl3 &= ~(SAA7191_CTL3_AUFD);
+ err = saa7191_write_reg(client, SAA7191_REG_CTL3, ctl3);
+ if (err) {
+ err = -EIO;
}
- err = saa7191_write_reg(client, SAA7191_REG_HUEC, hue);
- if (err)
- return -EIO;
}
- if (ctrl->vtrc >= 0) {
- unsigned char stdc =
- saa7191_read_reg(client, SAA7191_REG_STDC);
- if (ctrl->vtrc) {
- stdc |= SAA7191_STDC_VTRC;
- } else {
- stdc &= ~SAA7191_STDC_VTRC;
+ return err;
+}
+
+static int saa7191_autodetect_norm(struct i2c_client *client)
+{
+ u8 status;
+
+ dprintk("SAA7191 signal auto-detection...\n");
+
+ dprintk("Reading status...\n");
+
+ if (saa7191_read_status(client, &status))
+ return -EIO;
+
+ dprintk("Checking for signal...\n");
+
+ /* no signal ? */
+ if (status & SAA7191_STATUS_HLCK) {
+ dprintk("No signal\n");
+ return -EBUSY;
+ }
+
+ dprintk("Signal found\n");
+
+ if (status & SAA7191_STATUS_FIDT) {
+ /* 60hz signal -> NTSC */
+ dprintk("NTSC\n");
+ return saa7191_set_norm(client, SAA7191_NORM_NTSC);
+ } else {
+ /* 50hz signal -> PAL */
+ dprintk("PAL\n");
+ return saa7191_set_norm(client, SAA7191_NORM_PAL);
+ }
+}
+
+static int saa7191_get_control(struct i2c_client *client,
+ struct saa7191_control *ctrl)
+{
+ u8 reg;
+ int ret = 0;
+
+ switch (ctrl->type) {
+ case SAA7191_CONTROL_BANDPASS:
+ case SAA7191_CONTROL_BANDPASS_WEIGHT:
+ case SAA7191_CONTROL_CORING:
+ reg = saa7191_read_reg(client, SAA7191_REG_LUMA);
+ switch (ctrl->type) {
+ case SAA7191_CONTROL_BANDPASS:
+ ctrl->value = ((s32)reg & SAA7191_LUMA_BPSS_MASK)
+ >> SAA7191_LUMA_BPSS_SHIFT;
+ break;
+ case SAA7191_CONTROL_BANDPASS_WEIGHT:
+ ctrl->value = ((s32)reg & SAA7191_LUMA_APER_MASK)
+ >> SAA7191_LUMA_APER_SHIFT;
+ break;
+ case SAA7191_CONTROL_CORING:
+ ctrl->value = ((s32)reg & SAA7191_LUMA_CORI_MASK)
+ >> SAA7191_LUMA_CORI_SHIFT;
+ break;
}
+ break;
+ case SAA7191_CONTROL_FORCE_COLOUR:
+ case SAA7191_CONTROL_CHROMA_GAIN:
+ reg = saa7191_read_reg(client, SAA7191_REG_GAIN);
+ if (ctrl->type == SAA7191_CONTROL_FORCE_COLOUR)
+ ctrl->value = ((s32)reg & SAA7191_GAIN_COLO) ? 1 : 0;
+ else
+ ctrl->value = ((s32)reg & SAA7191_GAIN_LFIS_MASK)
+ >> SAA7191_GAIN_LFIS_SHIFT;
+ break;
+ case SAA7191_CONTROL_HUE:
+ reg = saa7191_read_reg(client, SAA7191_REG_HUEC);
+ if (reg < 0x80)
+ reg += 0x80;
+ else
+ reg -= 0x80;
+ ctrl->value = (s32)reg;
+ break;
+ case SAA7191_CONTROL_VTRC:
+ reg = saa7191_read_reg(client, SAA7191_REG_STDC);
+ ctrl->value = ((s32)reg & SAA7191_STDC_VTRC) ? 1 : 0;
+ break;
+ case SAA7191_CONTROL_LUMA_DELAY:
+ reg = saa7191_read_reg(client, SAA7191_REG_CTL3);
+ ctrl->value = ((s32)reg & SAA7191_CTL3_YDEL_MASK)
+ >> SAA7191_CTL3_YDEL_SHIFT;
+ if (ctrl->value >= 4)
+ ctrl->value -= 8;
+ break;
+ case SAA7191_CONTROL_VNR:
+ reg = saa7191_read_reg(client, SAA7191_REG_CTL4);
+ ctrl->value = ((s32)reg & SAA7191_CTL4_VNOI_MASK)
+ >> SAA7191_CTL4_VNOI_SHIFT;
+ break;
+ default:
+ ret = -EINVAL;
+ }
- err = saa7191_write_reg(client, SAA7191_REG_STDC, stdc);
- if (err)
- return -EIO;
+ return ret;
+}
+
+static int saa7191_set_control(struct i2c_client *client,
+ struct saa7191_control *ctrl)
+{
+ u8 reg;
+ int ret = 0;
+
+ switch (ctrl->type) {
+ case SAA7191_CONTROL_BANDPASS:
+ case SAA7191_CONTROL_BANDPASS_WEIGHT:
+ case SAA7191_CONTROL_CORING:
+ reg = saa7191_read_reg(client, SAA7191_REG_LUMA);
+ switch (ctrl->type) {
+ case SAA7191_CONTROL_BANDPASS:
+ reg &= ~SAA7191_LUMA_BPSS_MASK;
+ reg |= (ctrl->value << SAA7191_LUMA_BPSS_SHIFT)
+ & SAA7191_LUMA_BPSS_MASK;
+ break;
+ case SAA7191_CONTROL_BANDPASS_WEIGHT:
+ reg &= ~SAA7191_LUMA_APER_MASK;
+ reg |= (ctrl->value << SAA7191_LUMA_APER_SHIFT)
+ & SAA7191_LUMA_APER_MASK;
+ break;
+ case SAA7191_CONTROL_CORING:
+ reg &= ~SAA7191_LUMA_CORI_MASK;
+ reg |= (ctrl->value << SAA7191_LUMA_CORI_SHIFT)
+ & SAA7191_LUMA_CORI_MASK;
+ break;
+ }
+ ret = saa7191_write_reg(client, SAA7191_REG_LUMA, reg);
+ break;
+ case SAA7191_CONTROL_FORCE_COLOUR:
+ case SAA7191_CONTROL_CHROMA_GAIN:
+ reg = saa7191_read_reg(client, SAA7191_REG_GAIN);
+ if (ctrl->type == SAA7191_CONTROL_FORCE_COLOUR) {
+ if (ctrl->value)
+ reg |= SAA7191_GAIN_COLO;
+ else
+ reg &= ~SAA7191_GAIN_COLO;
+ } else {
+ reg &= ~SAA7191_GAIN_LFIS_MASK;
+ reg |= (ctrl->value << SAA7191_GAIN_LFIS_SHIFT)
+ & SAA7191_GAIN_LFIS_MASK;
+ }
+ ret = saa7191_write_reg(client, SAA7191_REG_GAIN, reg);
+ break;
+ case SAA7191_CONTROL_HUE:
+ reg = ctrl->value & 0xff;
+ if (reg < 0x80)
+ reg += 0x80;
+ else
+ reg -= 0x80;
+ ret = saa7191_write_reg(client, SAA7191_REG_HUEC, reg);
+ break;
+ case SAA7191_CONTROL_VTRC:
+ reg = saa7191_read_reg(client, SAA7191_REG_STDC);
+ if (ctrl->value)
+ reg |= SAA7191_STDC_VTRC;
+ else
+ reg &= ~SAA7191_STDC_VTRC;
+ ret = saa7191_write_reg(client, SAA7191_REG_STDC, reg);
+ break;
+ case SAA7191_CONTROL_LUMA_DELAY: {
+ s32 value = ctrl->value;
+ if (value < 0)
+ value += 8;
+ reg = saa7191_read_reg(client, SAA7191_REG_CTL3);
+ reg &= ~SAA7191_CTL3_YDEL_MASK;
+ reg |= (value << SAA7191_CTL3_YDEL_SHIFT)
+ & SAA7191_CTL3_YDEL_MASK;
+ ret = saa7191_write_reg(client, SAA7191_REG_CTL3, reg);
+ break;
+ }
+ case SAA7191_CONTROL_VNR:
+ reg = saa7191_read_reg(client, SAA7191_REG_CTL4);
+ reg &= ~SAA7191_CTL4_VNOI_MASK;
+ reg |= (ctrl->value << SAA7191_CTL4_VNOI_SHIFT)
+ & SAA7191_CTL4_VNOI_MASK;
+ ret = saa7191_write_reg(client, SAA7191_REG_CTL4, reg);
+ break;
+ default:
+ ret = -EINVAL;
}
- return 0;
+ return ret;
}
/* I2C-interface */
@@ -309,11 +596,7 @@ static int saa7191_attach(struct i2c_adapter *adap, int addr, int kind)
if (err)
goto out_free_decoder;
- decoder->input = SAA7191_INPUT_COMPOSITE;
- decoder->norm = SAA7191_NORM_AUTO;
-
- err = saa7191_write_block(client, sizeof(initseq),
- (unsigned char *)initseq);
+ err = saa7191_write_block(client, sizeof(initseq), (u8 *)initseq);
if (err) {
printk(KERN_ERR "SAA7191 initialization failed\n");
goto out_detach_client;
@@ -321,6 +604,14 @@ static int saa7191_attach(struct i2c_adapter *adap, int addr, int kind)
printk(KERN_INFO "SAA7191 initialized\n");
+ decoder->input = SAA7191_INPUT_COMPOSITE;
+ decoder->norm = SAA7191_NORM_PAL;
+
+ err = saa7191_autodetect_norm(client);
+ if (err && (err != -EBUSY)) {
+ printk(KERN_ERR "SAA7191: Signal auto-detection failed\n");
+ }
+
return 0;
out_detach_client:
@@ -368,7 +659,7 @@ static int saa7191_command(struct i2c_client *client, unsigned int cmd,
}
case DECODER_GET_STATUS: {
int *iarg = arg;
- unsigned char status;
+ u8 status;
int res = 0;
if (saa7191_read_status(client, &status)) {
@@ -404,7 +695,7 @@ static int saa7191_command(struct i2c_client *client, unsigned int cmd,
switch (*iarg) {
case VIDEO_MODE_AUTO:
- return saa7191_set_norm(client, SAA7191_NORM_AUTO);
+ return saa7191_autodetect_norm(client);
case VIDEO_MODE_PAL:
return saa7191_set_norm(client, SAA7191_NORM_PAL);
case VIDEO_MODE_NTSC:
@@ -446,38 +737,48 @@ static int saa7191_command(struct i2c_client *client, unsigned int cmd,
int err;
val = (pic->hue >> 8) - 0x80;
+
err = saa7191_write_reg(client, SAA7191_REG_HUEC, val);
if (err)
return -EIO;
+
break;
}
case DECODER_SAA7191_GET_STATUS: {
struct saa7191_status *status = arg;
- unsigned char status_reg;
+ u8 status_reg;
if (saa7191_read_status(client, &status_reg))
return -EIO;
+
status->signal = ((status_reg & SAA7191_STATUS_HLCK) == 0)
- ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED;
- status->ntsc = (status_reg & SAA7191_STATUS_FIDT)
- ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED;
- status->color = (status_reg & SAA7191_STATUS_CODE)
- ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED;
+ ? 1 : 0;
+ status->signal_60hz = (status_reg & SAA7191_STATUS_FIDT)
+ ? 1 : 0;
+ status->color = (status_reg & SAA7191_STATUS_CODE) ? 1 : 0;
status->input = decoder->input;
status->norm = decoder->norm;
+
+ break;
}
case DECODER_SAA7191_SET_NORM: {
int *norm = arg;
- return saa7191_set_norm(client, *norm);
+
+ switch (*norm) {
+ case SAA7191_NORM_AUTO:
+ return saa7191_autodetect_norm(client);
+ case SAA7191_NORM_AUTO_EXT:
+ return saa7191_autodetect_norm_extended(client);
+ default:
+ return saa7191_set_norm(client, *norm);
+ }
}
- case DECODER_SAA7191_GET_CONTROLS: {
- struct saa7191_control *ctrl = arg;
- return saa7191_get_controls(client, ctrl);
+ case DECODER_SAA7191_GET_CONTROL: {
+ return saa7191_get_control(client, arg);
}
- case DECODER_SAA7191_SET_CONTROLS: {
- struct saa7191_control *ctrl = arg;
- return saa7191_set_controls(client, ctrl);
+ case DECODER_SAA7191_SET_CONTROL: {
+ return saa7191_set_control(client, arg);
}
default:
return -EINVAL;
@@ -488,12 +789,12 @@ static int saa7191_command(struct i2c_client *client, unsigned int cmd,
static struct i2c_driver i2c_driver_saa7191 = {
.owner = THIS_MODULE,
- .name = "saa7191",
- .id = I2C_DRIVERID_SAA7191,
- .flags = I2C_DF_NOTIFY,
+ .name = "saa7191",
+ .id = I2C_DRIVERID_SAA7191,
+ .flags = I2C_DF_NOTIFY,
.attach_adapter = saa7191_probe,
- .detach_client = saa7191_detach,
- .command = saa7191_command
+ .detach_client = saa7191_detach,
+ .command = saa7191_command
};
static int saa7191_init(void)
diff --git a/drivers/media/video/saa7191.h b/drivers/media/video/saa7191.h
index 27204503143..a2310da1940 100644
--- a/drivers/media/video/saa7191.h
+++ b/drivers/media/video/saa7191.h
@@ -24,8 +24,8 @@
#define SAA7191_REG_HPHI 0x05
#define SAA7191_REG_LUMA 0x06
#define SAA7191_REG_HUEC 0x07
-#define SAA7191_REG_CKTQ 0x08
-#define SAA7191_REG_CKTS 0x09
+#define SAA7191_REG_CKTQ 0x08 /* bits 3-7 */
+#define SAA7191_REG_CKTS 0x09 /* bits 3-7 */
#define SAA7191_REG_PLSE 0x0a
#define SAA7191_REG_SESE 0x0b
#define SAA7191_REG_GAIN 0x0c
@@ -43,30 +43,82 @@
/* Status Register definitions */
#define SAA7191_STATUS_CODE 0x01 /* color detected flag */
-#define SAA7191_STATUS_FIDT 0x20 /* format type NTSC/PAL */
-#define SAA7191_STATUS_HLCK 0x40 /* PLL unlocked/locked */
+#define SAA7191_STATUS_FIDT 0x20 /* signal type 50/60 Hz */
+#define SAA7191_STATUS_HLCK 0x40 /* PLL unlocked(1)/locked(0) */
#define SAA7191_STATUS_STTC 0x80 /* tv/vtr time constant */
/* Luminance Control Register definitions */
+/* input mode select bit:
+ * 0=CVBS (chrominance trap active), 1=S-Video (trap bypassed) */
#define SAA7191_LUMA_BYPS 0x80
-
-/* Chroma Gain Control Settings Register definitions */
-/* 0=automatic colour-killer enabled, 1=forced colour on */
+/* pre-filter (only when chrominance trap is active) */
+#define SAA7191_LUMA_PREF 0x40
+/* aperture bandpass to select different characteristics with maximums
+ * (bits 4-5) */
+#define SAA7191_LUMA_BPSS_MASK 0x30
+#define SAA7191_LUMA_BPSS_SHIFT 4
+#define SAA7191_LUMA_BPSS_3 0x30
+#define SAA7191_LUMA_BPSS_2 0x20
+#define SAA7191_LUMA_BPSS_1 0x10
+#define SAA7191_LUMA_BPSS_0 0x00
+/* coring range for high frequency components according to 8-bit luminance
+ * (bits 2-3)
+ * 0=coring off, n= (+-)n LSB */
+#define SAA7191_LUMA_CORI_MASK 0x0c
+#define SAA7191_LUMA_CORI_SHIFT 2
+#define SAA7191_LUMA_CORI_3 0x0c
+#define SAA7191_LUMA_CORI_2 0x08
+#define SAA7191_LUMA_CORI_1 0x04
+#define SAA7191_LUMA_CORI_0 0x00
+/* aperture bandpass filter weights high frequency components of luminance
+ * signal (bits 0-1)
+ * 0=factor 0, 1=0.25, 2=0.5, 3=1 */
+#define SAA7191_LUMA_APER_MASK 0x03
+#define SAA7191_LUMA_APER_SHIFT 0
+#define SAA7191_LUMA_APER_3 0x03
+#define SAA7191_LUMA_APER_2 0x02
+#define SAA7191_LUMA_APER_1 0x01
+#define SAA7191_LUMA_APER_0 0x00
+
+/* Chrominance Gain Control Settings Register definitions */
+/* colour on: 0=automatic colour-killer enabled, 1=forced colour on */
#define SAA7191_GAIN_COLO 0x80
+/* chrominance gain control (AGC filter)
+ * 0=loop filter time constant slow, 1=medium, 2=fast, 3=actual gain */
+#define SAA7191_GAIN_LFIS_MASK 0x60
+#define SAA7191_GAIN_LFIS_SHIFT 5
+#define SAA7191_GAIN_LFIS_3 0x60
+#define SAA7191_GAIN_LFIS_2 0x40
+#define SAA7191_GAIN_LFIS_1 0x20
+#define SAA7191_GAIN_LFIS_0 0x00
/* Standard/Mode Control Register definitions */
/* tv/vtr mode bit: 0=TV mode (slow time constant),
* 1=VTR mode (fast time constant) */
#define SAA7191_STDC_VTRC 0x80
+/* SAA7191B-specific functions enable (RTCO, ODD and GPSW0 outputs)
+ * 0=outputs set to high-impedance (circuit equals SAA7191), 1=enabled */
+#define SAA7191_STDC_NFEN 0x08
+/* HREF generation: 0=like SAA7191, 1=HREF is 8xLLC2 clocks earlier */
+#define SAA7191_STDC_HRMV 0x04
+/* general purpose switch 0
+ * (not used with VINO afaik) */
+#define SAA7191_STDC_GPSW0 0x02
/* SECAM mode bit: 0=other standards, 1=SECAM */
#define SAA7191_STDC_SECS 0x01
-/* the bit fields above must be or'd with this value */
-#define SAA7191_STDC_VALUE 0x0c
/* I/O and Clock Control Register definitions */
/* horizontal clock PLL: 0=PLL closed,
* 1=PLL circuit open and horizontal freq fixed */
#define SAA7191_IOCK_HPLL 0x80
+/* colour-difference output enable (outputs UV0-UV7) */
+#define SAA7191_IOCK_OEDC 0x40
+/* H-sync output enable */
+#define SAA7191_IOCK_OEHS 0x20
+/* V-sync output enable */
+#define SAA7191_IOCK_OEVS 0x10
+/* luminance output enable (outputs Y0-Y7) */
+#define SAA7191_IOCK_OEDY 0x08
/* S-VHS bit (chrominance from CVBS or from chrominance input):
* 0=controlled by BYPS-bit, 1=from chrominance input */
#define SAA7191_IOCK_CHRS 0x04
@@ -83,11 +135,40 @@
/* field select: (if AUFD=0)
* 0=50Hz (625 lines), 1=60Hz (525 lines) */
#define SAA7191_CTL3_FSEL 0x40
-/* the bit fields above must be or'd with this value */
-#define SAA7191_CTL3_VALUE 0x19
+/* SECAM cross-colour reduction enable */
+#define SAA7191_CTL3_SXCR 0x20
+/* sync and clamping pulse enable (HCL and HSY outputs) */
+#define SAA7191_CTL3_SCEN 0x10
+/* output format: 0=4:1:1, 1=4:2:2 (4:2:2 for VINO) */
+#define SAA7191_CTL3_OFTS 0x08
+/* luminance delay compensation
+ * 0=0*2/LLC, 1=+1*2/LLC, 2=+2*2/LLC, 3=+3*2/LLC,
+ * 4=-4*2/LLC, 5=-3*2/LLC, 6=-2*2/LLC, 7=-1*2/LLC
+ * step size = 2/LLC = 67.8ns for 50Hz, 81.5ns for 60Hz */
+#define SAA7191_CTL3_YDEL_MASK 0x07
+#define SAA7191_CTL3_YDEL_SHIFT 0
+#define SAA7191_CTL3_YDEL2 0x04
+#define SAA7191_CTL3_YDEL1 0x02
+#define SAA7191_CTL3_YDEL0 0x01
+
+/* Miscellaneous Control #2 Register definitions */
+/* select HREF position
+ * 0=normal, HREF is matched to YUV output port,
+ * 1=HREF is matched to CVBS input port */
+#define SAA7191_CTL4_HRFS 0x04
+/* vertical noise reduction
+ * 0=normal, 1=searching window, 2=auto-deflection, 3=reduction bypassed */
+#define SAA7191_CTL4_VNOI_MASK 0x03
+#define SAA7191_CTL4_VNOI_SHIFT 0
+#define SAA7191_CTL4_VNOI_3 0x03
+#define SAA7191_CTL4_VNOI_2 0x02
+#define SAA7191_CTL4_VNOI_1 0x01
+#define SAA7191_CTL4_VNOI_0 0x00
/* Chrominance Gain Control Register definitions
- * (nominal value for UV CCIR level) */
+ * - for QAM-modulated input signals, effects output amplitude
+ * (SECAM gain fixed)
+ * (nominal values for UV CCIR level) */
#define SAA7191_CHCV_NTSC 0x2c
#define SAA7191_CHCV_PAL 0x59
@@ -99,16 +180,13 @@
#define SAA7191_NORM_PAL 1
#define SAA7191_NORM_NTSC 2
#define SAA7191_NORM_SECAM 3
-
-#define SAA7191_VALUE_ENABLED 1
-#define SAA7191_VALUE_DISABLED 0
-#define SAA7191_VALUE_UNCHANGED -1
+#define SAA7191_NORM_AUTO_EXT 4 /* extended auto-detection */
struct saa7191_status {
- /* 0=no signal, 1=signal active*/
+ /* 0=no signal, 1=signal detected */
int signal;
/* 0=50hz (pal) signal, 1=60hz (ntsc) signal */
- int ntsc;
+ int signal_60hz;
/* 0=no color detected, 1=color detected */
int color;
@@ -118,22 +196,60 @@ struct saa7191_status {
int norm;
};
-#define SAA7191_HUE_MIN 0x00
-#define SAA7191_HUE_MAX 0xff
-#define SAA7191_HUE_DEFAULT 0x80
+#define SAA7191_BANDPASS_MIN 0x00
+#define SAA7191_BANDPASS_MAX 0x03
+#define SAA7191_BANDPASS_DEFAULT 0x00
+
+#define SAA7191_BANDPASS_WEIGHT_MIN 0x00
+#define SAA7191_BANDPASS_WEIGHT_MAX 0x03
+#define SAA7191_BANDPASS_WEIGHT_DEFAULT 0x01
+
+#define SAA7191_CORING_MIN 0x00
+#define SAA7191_CORING_MAX 0x03
+#define SAA7191_CORING_DEFAULT 0x00
+
+#define SAA7191_HUE_MIN 0x00
+#define SAA7191_HUE_MAX 0xff
+#define SAA7191_HUE_DEFAULT 0x80
+
+#define SAA7191_VTRC_MIN 0x00
+#define SAA7191_VTRC_MAX 0x01
+#define SAA7191_VTRC_DEFAULT 0x00
+
+#define SAA7191_FORCE_COLOUR_MIN 0x00
+#define SAA7191_FORCE_COLOUR_MAX 0x01
+#define SAA7191_FORCE_COLOUR_DEFAULT 0x00
+
+#define SAA7191_CHROMA_GAIN_MIN 0x00
+#define SAA7191_CHROMA_GAIN_MAX 0x03
+#define SAA7191_CHROMA_GAIN_DEFAULT 0x00
+
+#define SAA7191_LUMA_DELAY_MIN -0x04
+#define SAA7191_LUMA_DELAY_MAX 0x03
+#define SAA7191_LUMA_DELAY_DEFAULT 0x01
+
+#define SAA7191_VNR_MIN 0x00
+#define SAA7191_VNR_MAX 0x03
+#define SAA7191_VNR_DEFAULT 0x00
-#define SAA7191_VTRC_MIN 0x00
-#define SAA7191_VTRC_MAX 0x01
-#define SAA7191_VTRC_DEFAULT 0x00
+#define SAA7191_CONTROL_BANDPASS 0
+#define SAA7191_CONTROL_BANDPASS_WEIGHT 1
+#define SAA7191_CONTROL_CORING 2
+#define SAA7191_CONTROL_FORCE_COLOUR 3 /* boolean */
+#define SAA7191_CONTROL_CHROMA_GAIN 4
+#define SAA7191_CONTROL_HUE 5
+#define SAA7191_CONTROL_VTRC 6 /* boolean */
+#define SAA7191_CONTROL_LUMA_DELAY 7
+#define SAA7191_CONTROL_VNR 8
struct saa7191_control {
- int hue;
- int vtrc;
+ u8 type;
+ s32 value;
};
#define DECODER_SAA7191_GET_STATUS _IOR('d', 195, struct saa7191_status)
#define DECODER_SAA7191_SET_NORM _IOW('d', 196, int)
-#define DECODER_SAA7191_GET_CONTROLS _IOR('d', 197, struct saa7191_control)
-#define DECODER_SAA7191_SET_CONTROLS _IOW('d', 198, struct saa7191_control)
+#define DECODER_SAA7191_GET_CONTROL _IOR('d', 197, struct saa7191_control)
+#define DECODER_SAA7191_SET_CONTROL _IOW('d', 198, struct saa7191_control)
#endif
diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c
index 255b6088ebf..d32737dd214 100644
--- a/drivers/media/video/tda7432.c
+++ b/drivers/media/video/tda7432.c
@@ -50,7 +50,6 @@
#include "bttv.h"
#include <media/audiochip.h>
-#include <media/id.h>
#ifndef VIDEO_AUDIO_BALANCE
# define VIDEO_AUDIO_BALANCE 32
@@ -310,9 +309,9 @@ static int tda7432_attach(struct i2c_adapter *adap, int addr, int kind)
memset(t,0,sizeof *t);
client = &t->c;
- memcpy(client,&client_template,sizeof(struct i2c_client));
- client->adapter = adap;
- client->addr = addr;
+ memcpy(client,&client_template,sizeof(struct i2c_client));
+ client->adapter = adap;
+ client->addr = addr;
i2c_set_clientdata(client, t);
do_tda7432_init(client);
@@ -472,7 +471,7 @@ static int tda7432_command(struct i2c_client *client,
}
}
- t->muted=(va->flags & VIDEO_AUDIO_MUTE);
+ t->muted=(va->flags & VIDEO_AUDIO_MUTE);
if (t->muted)
{
/* Mute & update balance*/
@@ -503,12 +502,12 @@ static int tda7432_command(struct i2c_client *client,
static struct i2c_driver driver = {
.owner = THIS_MODULE,
- .name = "i2c tda7432 driver",
+ .name = "i2c tda7432 driver",
.id = I2C_DRIVERID_TDA7432,
- .flags = I2C_DF_NOTIFY,
+ .flags = I2C_DF_NOTIFY,
.attach_adapter = tda7432_probe,
- .detach_client = tda7432_detach,
- .command = tda7432_command,
+ .detach_client = tda7432_detach,
+ .command = tda7432_command,
};
static struct i2c_client client_template =
diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c
index c65f0c7680a..61d94ddaff4 100644
--- a/drivers/media/video/tda8290.c
+++ b/drivers/media/video/tda8290.c
@@ -1,172 +1,406 @@
/*
- *
- * i2c tv tuner chip device driver
- * controls the philips tda8290+75 tuner chip combo.
- */
+
+ i2c tv tuner chip device driver
+ controls the philips tda8290+75 tuner chip combo.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
#include <linux/i2c.h>
#include <linux/videodev.h>
#include <linux/delay.h>
#include <media/tuner.h>
-#define I2C_ADDR_TDA8290 0x4b
-#define I2C_ADDR_TDA8275 0x61
-
/* ---------------------------------------------------------------------- */
-struct freq_entry {
- u16 freq;
- u8 value;
+struct tda827x_data {
+ u32 lomax;
+ u8 spd;
+ u8 bs;
+ u8 bp;
+ u8 cp;
+ u8 gc3;
+ u8 div1p5;
};
-static struct freq_entry band_table[] = {
- { 0x2DF4, 0x1C },
- { 0x2574, 0x14 },
- { 0x22B4, 0x0C },
- { 0x20D4, 0x0B },
- { 0x1E74, 0x3B },
- { 0x1C34, 0x33 },
- { 0x16F4, 0x5B },
- { 0x1454, 0x53 },
- { 0x12D4, 0x52 },
- { 0x1034, 0x4A },
- { 0x0EE4, 0x7A },
- { 0x0D34, 0x72 },
- { 0x0B54, 0x9A },
- { 0x0914, 0x91 },
- { 0x07F4, 0x89 },
- { 0x0774, 0xB9 },
- { 0x067B, 0xB1 },
- { 0x0634, 0xD9 },
- { 0x05A4, 0xD8 }, // FM radio
- { 0x0494, 0xD0 },
- { 0x03BC, 0xC8 },
- { 0x0394, 0xF8 }, // 57250000 Hz
- { 0x0000, 0xF0 }, // 0
+ /* Note lomax entry is lo / 62500 */
+
+static struct tda827x_data tda827x_analog[] = {
+ { .lomax = 992, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, /* 62 MHz */
+ { .lomax = 1056, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, /* 66 MHz */
+ { .lomax = 1216, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, /* 76 MHz */
+ { .lomax = 1344, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, /* 84 MHz */
+ { .lomax = 1488, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 93 MHz */
+ { .lomax = 1568, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 98 MHz */
+ { .lomax = 1744, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 109 MHz */
+ { .lomax = 1968, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 123 MHz */
+ { .lomax = 2128, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 133 MHz */
+ { .lomax = 2416, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 151 MHz */
+ { .lomax = 2464, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 154 MHz */
+ { .lomax = 2896, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 181 MHz */
+ { .lomax = 2960, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 185 MHz */
+ { .lomax = 3472, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 217 MHz */
+ { .lomax = 3904, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 244 MHz */
+ { .lomax = 4240, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 265 MHz */
+ { .lomax = 4832, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 302 MHz */
+ { .lomax = 5184, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 324 MHz */
+ { .lomax = 5920, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 370 MHz */
+ { .lomax = 7264, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 454 MHz */
+ { .lomax = 7888, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 493 MHz */
+ { .lomax = 8480, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 530 MHz */
+ { .lomax = 8864, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 554 MHz */
+ { .lomax = 9664, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 604 MHz */
+ { .lomax = 11088, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 696 MHz */
+ { .lomax = 11840, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, /* 740 MHz */
+ { .lomax = 13120, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 820 MHz */
+ { .lomax = 13840, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, /* 865 MHz */
+ { .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0} /* End */
};
-static struct freq_entry div_table[] = {
- { 0x1C34, 3 },
- { 0x0D34, 2 },
- { 0x067B, 1 },
- { 0x0000, 0 },
-};
+static void tda827x_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
+{
+ unsigned char tuner_reg[8];
+ unsigned char reg2[2];
+ u32 N;
+ int i;
+ struct tuner *t = i2c_get_clientdata(c);
+ struct i2c_msg msg = {.addr = t->tda827x_addr, .flags = 0};
-static struct freq_entry agc_table[] = {
- { 0x22B4, 0x8F },
- { 0x0B54, 0x9F },
- { 0x09A4, 0x8F },
- { 0x0554, 0x9F },
- { 0x0000, 0xBF },
-};
+ if (t->mode == V4L2_TUNER_RADIO)
+ freq = freq / 1000;
-static __u8 get_freq_entry( struct freq_entry* table, __u16 freq)
-{
- while(table->freq && table->freq > freq)
- table++;
- return table->value;
-}
+ N = freq + ifc;
+ i = 0;
+ while (tda827x_analog[i].lomax < N) {
+ if(tda827x_analog[i + 1].lomax == 0)
+ break;
+ i++;
+ }
+
+ N = N << tda827x_analog[i].spd;
+
+ tuner_reg[0] = 0;
+ tuner_reg[1] = (unsigned char)(N>>8);
+ tuner_reg[2] = (unsigned char) N;
+ tuner_reg[3] = 0x40;
+ tuner_reg[4] = 0x52 + (t->tda827x_lpsel << 5);
+ tuner_reg[5] = (tda827x_analog[i].spd << 6) + (tda827x_analog[i].div1p5 <<5) +
+ (tda827x_analog[i].bs <<3) + tda827x_analog[i].bp;
+ tuner_reg[6] = 0x8f + (tda827x_analog[i].gc3 << 4);
+ tuner_reg[7] = 0x8f;
+
+ msg.buf = tuner_reg;
+ msg.len = 8;
+ i2c_transfer(c->adapter, &msg, 1);
+
+ msg.buf= reg2;
+ msg.len = 2;
+ reg2[0] = 0x80;
+ reg2[1] = 0;
+ i2c_transfer(c->adapter, &msg, 1);
+
+ reg2[0] = 0x60;
+ reg2[1] = 0xbf;
+ i2c_transfer(c->adapter, &msg, 1);
+
+ reg2[0] = 0x30;
+ reg2[1] = tuner_reg[4] + 0x80;
+ i2c_transfer(c->adapter, &msg, 1);
+
+ msleep(1);
+ reg2[0] = 0x30;
+ reg2[1] = tuner_reg[4] + 4;
+ i2c_transfer(c->adapter, &msg, 1);
+
+ msleep(1);
+ reg2[0] = 0x30;
+ reg2[1] = tuner_reg[4];
+ i2c_transfer(c->adapter, &msg, 1);
-/* ---------------------------------------------------------------------- */
+ msleep(550);
+ reg2[0] = 0x30;
+ reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_analog[i].cp ;
+ i2c_transfer(c->adapter, &msg, 1);
-static unsigned char i2c_enable_bridge[2] = { 0x21, 0xC0 };
-static unsigned char i2c_disable_bridge[2] = { 0x21, 0x80 };
-static unsigned char i2c_init_tda8275[14] = { 0x00, 0x00, 0x00, 0x00,
- 0xfC, 0x04, 0xA3, 0x3F,
- 0x2A, 0x04, 0xFF, 0x00,
- 0x00, 0x40 };
-static unsigned char i2c_set_VS[2] = { 0x30, 0x6F };
-static unsigned char i2c_set_GP01_CF[2] = { 0x20, 0x0B };
-static unsigned char i2c_tda8290_reset[2] = { 0x00, 0x00 };
-static unsigned char i2c_tda8290_standby[2] = { 0x00, 0x02 };
-static unsigned char i2c_gainset_off[2] = { 0x28, 0x14 };
-static unsigned char i2c_gainset_on[2] = { 0x28, 0x54 };
-static unsigned char i2c_agc3_00[2] = { 0x80, 0x00 };
-static unsigned char i2c_agc2_BF[2] = { 0x60, 0xBF };
-static unsigned char i2c_cb1_D0[2] = { 0x30, 0xD0 };
-static unsigned char i2c_cb1_D2[2] = { 0x30, 0xD2 };
-static unsigned char i2c_cb1_56[2] = { 0x30, 0x56 };
-static unsigned char i2c_cb1_52[2] = { 0x30, 0x52 };
-static unsigned char i2c_cb1_50[2] = { 0x30, 0x50 };
-static unsigned char i2c_agc2_7F[2] = { 0x60, 0x7F };
-static unsigned char i2c_agc3_08[2] = { 0x80, 0x08 };
-
-static struct i2c_msg i2c_msg_init[] = {
- { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_init_tda8275), i2c_init_tda8275 },
- { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_disable_bridge), i2c_disable_bridge },
- { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_set_VS), i2c_set_VS },
- { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_set_GP01_CF), i2c_set_GP01_CF },
-};
+ reg2[0] = 0x60;
+ reg2[1] = 0x3f;
+ i2c_transfer(c->adapter, &msg, 1);
-static struct i2c_msg i2c_msg_prolog[] = {
-// { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_easy_mode), i2c_easy_mode },
- { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_gainset_off), i2c_gainset_off },
- { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_tda8290_reset), i2c_tda8290_reset },
- { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_enable_bridge), i2c_enable_bridge },
-};
+ reg2[0] = 0x80;
+ reg2[1] = 0x08; // Vsync en
+ i2c_transfer(c->adapter, &msg, 1);
+}
-static struct i2c_msg i2c_msg_config[] = {
-// { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_set_freq), i2c_set_freq },
- { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_agc3_00), i2c_agc3_00 },
- { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_agc2_BF), i2c_agc2_BF },
- { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_cb1_D2), i2c_cb1_D2 },
- { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_cb1_56), i2c_cb1_56 },
- { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_cb1_52), i2c_cb1_52 },
-};
+static void tda827x_agcf(struct i2c_client *c)
+{
+ struct tuner *t = i2c_get_clientdata(c);
+ unsigned char data[] = {0x80, 0x0c};
+ struct i2c_msg msg = {.addr = t->tda827x_addr, .buf = data,
+ .flags = 0, .len = 2};
+ i2c_transfer(c->adapter, &msg, 1);
+}
-static struct i2c_msg i2c_msg_epilog[] = {
- { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_cb1_50), i2c_cb1_50 },
- { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_agc2_7F), i2c_agc2_7F },
- { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_agc3_08), i2c_agc3_08 },
- { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_disable_bridge), i2c_disable_bridge },
- { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_gainset_on), i2c_gainset_on },
+/* ---------------------------------------------------------------------- */
+
+struct tda827xa_data {
+ u32 lomax;
+ u8 svco;
+ u8 spd;
+ u8 scr;
+ u8 sbs;
+ u8 gc3;
};
-static struct i2c_msg i2c_msg_standby[] = {
- { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_enable_bridge), i2c_enable_bridge },
- { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_cb1_D0), i2c_cb1_D0 },
- { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_disable_bridge), i2c_disable_bridge },
- { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_tda8290_standby), i2c_tda8290_standby },
+static struct tda827xa_data tda827xa_analog[] = {
+ { .lomax = 910, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3}, /* 56.875 MHz */
+ { .lomax = 1076, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, /* 67.25 MHz */
+ { .lomax = 1300, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, /* 81.25 MHz */
+ { .lomax = 1560, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, /* 97.5 MHz */
+ { .lomax = 1820, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1}, /* 113.75 MHz */
+ { .lomax = 2152, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, /* 134.5 MHz */
+ { .lomax = 2464, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, /* 154 MHz */
+ { .lomax = 2600, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, /* 162.5 MHz */
+ { .lomax = 2928, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, /* 183 MHz */
+ { .lomax = 3120, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, /* 195 MHz */
+ { .lomax = 3640, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 3}, /* 227.5 MHz */
+ { .lomax = 4304, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 3}, /* 269 MHz */
+ { .lomax = 5200, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, /* 325 MHz */
+ { .lomax = 6240, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3}, /* 390 MHz */
+ { .lomax = 7280, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3}, /* 455 MHz */
+ { .lomax = 8320, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, /* 520 MHz */
+ { .lomax = 8608, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, /* 538 MHz */
+ { .lomax = 8864, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, /* 554 MHz */
+ { .lomax = 9920, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, /* 620 MHz */
+ { .lomax = 10400, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, /* 650 MHz */
+ { .lomax = 11200, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, /* 700 MHz */
+ { .lomax = 12480, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, /* 780 MHz */
+ { .lomax = 13120, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, /* 820 MHz */
+ { .lomax = 13920, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, /* 870 MHz */
+ { .lomax = 14576, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0}, /* 911 MHz */
+ { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} /* End */
};
-static int tda8290_tune(struct i2c_client *c)
+static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
{
+ unsigned char tuner_reg[14];
+ unsigned char reg2[2];
+ u32 N;
+ int i;
struct tuner *t = i2c_get_clientdata(c);
- struct i2c_msg easy_mode =
- { I2C_ADDR_TDA8290, 0, 2, t->i2c_easy_mode };
- struct i2c_msg set_freq =
- { I2C_ADDR_TDA8275, 0, 8, t->i2c_set_freq };
+ struct i2c_msg msg = {.addr = t->tda827x_addr, .flags = 0};
- i2c_transfer(c->adapter, &easy_mode, 1);
- i2c_transfer(c->adapter, i2c_msg_prolog, ARRAY_SIZE(i2c_msg_prolog));
+ if (t->mode == V4L2_TUNER_RADIO)
+ freq = freq / 1000;
- i2c_transfer(c->adapter, &set_freq, 1);
- i2c_transfer(c->adapter, i2c_msg_config, ARRAY_SIZE(i2c_msg_config));
+ N = freq + ifc;
+ i = 0;
+ while (tda827xa_analog[i].lomax < N) {
+ if(tda827xa_analog[i + 1].lomax == 0)
+ break;
+ i++;
+ }
+
+ N = N << tda827xa_analog[i].spd;
+
+ tuner_reg[0] = 0;
+ tuner_reg[1] = (unsigned char)(N>>8);
+ tuner_reg[2] = (unsigned char) N;
+ tuner_reg[3] = 0;
+ tuner_reg[4] = 0x16;
+ tuner_reg[5] = (tda827xa_analog[i].spd << 5) + (tda827xa_analog[i].svco << 3) +
+ tda827xa_analog[i].sbs;
+ tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4);
+ tuner_reg[7] = 0x0c;
+ tuner_reg[8] = 4;
+ tuner_reg[9] = 0x20;
+ tuner_reg[10] = 0xff;
+ tuner_reg[11] = 0xe0;
+ tuner_reg[12] = 0;
+ tuner_reg[13] = 0x39 + (t->tda827x_lpsel << 1);
+
+ msg.buf = tuner_reg;
+ msg.len = 14;
+ i2c_transfer(c->adapter, &msg, 1);
+
+ msg.buf= reg2;
+ msg.len = 2;
+ reg2[0] = 0x60;
+ reg2[1] = 0x3c;
+ i2c_transfer(c->adapter, &msg, 1);
+
+ reg2[0] = 0xa0;
+ reg2[1] = 0xc0;
+ i2c_transfer(c->adapter, &msg, 1);
+
+ msleep(2);
+ reg2[0] = 0x30;
+ reg2[1] = 0x10 + tda827xa_analog[i].scr;
+ i2c_transfer(c->adapter, &msg, 1);
msleep(550);
- i2c_transfer(c->adapter, i2c_msg_epilog, ARRAY_SIZE(i2c_msg_epilog));
- return 0;
+ reg2[0] = 0x50;
+ reg2[1] = 0x8f + (tda827xa_analog[i].gc3 << 4);
+ i2c_transfer(c->adapter, &msg, 1);
+
+ reg2[0] = 0x80;
+ reg2[1] = 0x28;
+ i2c_transfer(c->adapter, &msg, 1);
+
+ reg2[0] = 0xb0;
+ reg2[1] = 0x01;
+ i2c_transfer(c->adapter, &msg, 1);
+
+ reg2[0] = 0xc0;
+ reg2[1] = 0x19 + (t->tda827x_lpsel << 1);
+ i2c_transfer(c->adapter, &msg, 1);
}
-static void set_frequency(struct tuner *t, u16 ifc, unsigned int freq)
+static void tda827xa_agcf(struct i2c_client *c)
{
- u32 N;
+ struct tuner *t = i2c_get_clientdata(c);
+ unsigned char data[] = {0x80, 0x2c};
+ struct i2c_msg msg = {.addr = t->tda827x_addr, .buf = data,
+ .flags = 0, .len = 2};
+ i2c_transfer(c->adapter, &msg, 1);
+}
- if (t->mode == V4L2_TUNER_RADIO)
- freq = freq / 1000;
+/*---------------------------------------------------------------------*/
- N = (((freq<<3)+ifc)&0x3fffc);
-
- N = N >> get_freq_entry(div_table, freq);
- t->i2c_set_freq[0] = 0;
- t->i2c_set_freq[1] = (unsigned char)(N>>8);
- t->i2c_set_freq[2] = (unsigned char) N;
- t->i2c_set_freq[3] = 0x40;
- t->i2c_set_freq[4] = 0x52;
- t->i2c_set_freq[5] = get_freq_entry(band_table, freq);
- t->i2c_set_freq[6] = get_freq_entry(agc_table, freq);
- t->i2c_set_freq[7] = 0x8f;
+static void tda8290_i2c_bridge(struct i2c_client *c, int close)
+{
+ unsigned char enable[2] = { 0x21, 0xC0 };
+ unsigned char disable[2] = { 0x21, 0x80 };
+ unsigned char *msg;
+ if(close) {
+ msg = enable;
+ i2c_master_send(c, msg, 2);
+ /* let the bridge stabilize */
+ msleep(20);
+ } else {
+ msg = disable;
+ i2c_master_send(c, msg, 2);
+ }
}
+/*---------------------------------------------------------------------*/
+
+static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
+{
+ struct tuner *t = i2c_get_clientdata(c);
+ unsigned char soft_reset[] = { 0x00, 0x00 };
+ unsigned char easy_mode[] = { 0x01, t->tda8290_easy_mode };
+ unsigned char expert_mode[] = { 0x01, 0x80 };
+ unsigned char gainset_off[] = { 0x28, 0x14 };
+ unsigned char if_agc_spd[] = { 0x0f, 0x88 };
+ unsigned char adc_head_6[] = { 0x05, 0x04 };
+ unsigned char adc_head_9[] = { 0x05, 0x02 };
+ unsigned char adc_head_12[] = { 0x05, 0x01 };
+ unsigned char pll_bw_nom[] = { 0x0d, 0x47 };
+ unsigned char pll_bw_low[] = { 0x0d, 0x27 };
+ unsigned char gainset_2[] = { 0x28, 0x64 };
+ unsigned char agc_rst_on[] = { 0x0e, 0x0b };
+ unsigned char agc_rst_off[] = { 0x0e, 0x09 };
+ unsigned char if_agc_set[] = { 0x0f, 0x81 };
+ unsigned char addr_adc_sat = 0x1a;
+ unsigned char addr_agc_stat = 0x1d;
+ unsigned char addr_pll_stat = 0x1b;
+ unsigned char adc_sat, agc_stat,
+ pll_stat;
+
+ i2c_master_send(c, easy_mode, 2);
+ i2c_master_send(c, soft_reset, 2);
+ msleep(1);
+
+ expert_mode[1] = t->tda8290_easy_mode + 0x80;
+ i2c_master_send(c, expert_mode, 2);
+ i2c_master_send(c, gainset_off, 2);
+ i2c_master_send(c, if_agc_spd, 2);
+ if (t->tda8290_easy_mode & 0x60)
+ i2c_master_send(c, adc_head_9, 2);
+ else
+ i2c_master_send(c, adc_head_6, 2);
+ i2c_master_send(c, pll_bw_nom, 2);
+
+ tda8290_i2c_bridge(c, 1);
+ if (t->tda827x_ver != 0)
+ tda827xa_tune(c, ifc, freq);
+ else
+ tda827x_tune(c, ifc, freq);
+ /* adjust headroom resp. gain */
+ i2c_master_send(c, &addr_adc_sat, 1);
+ i2c_master_recv(c, &adc_sat, 1);
+ i2c_master_send(c, &addr_agc_stat, 1);
+ i2c_master_recv(c, &agc_stat, 1);
+ i2c_master_send(c, &addr_pll_stat, 1);
+ i2c_master_recv(c, &pll_stat, 1);
+ if (pll_stat & 0x80)
+ tuner_dbg("tda8290 is locked, AGC: %d\n", agc_stat);
+ else
+ tuner_dbg("tda8290 not locked, no signal?\n");
+ if ((agc_stat > 115) || (!(pll_stat & 0x80) && (adc_sat < 20))) {
+ tuner_dbg("adjust gain, step 1. Agc: %d, ADC stat: %d, lock: %d\n",
+ agc_stat, adc_sat, pll_stat & 0x80);
+ i2c_master_send(c, gainset_2, 2);
+ msleep(100);
+ i2c_master_send(c, &addr_agc_stat, 1);
+ i2c_master_recv(c, &agc_stat, 1);
+ i2c_master_send(c, &addr_pll_stat, 1);
+ i2c_master_recv(c, &pll_stat, 1);
+ if ((agc_stat > 115) || !(pll_stat & 0x80)) {
+ tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n",
+ agc_stat, pll_stat & 0x80);
+ if (t->tda827x_ver != 0)
+ tda827xa_agcf(c);
+ else
+ tda827x_agcf(c);
+ msleep(100);
+ i2c_master_send(c, &addr_agc_stat, 1);
+ i2c_master_recv(c, &agc_stat, 1);
+ i2c_master_send(c, &addr_pll_stat, 1);
+ i2c_master_recv(c, &pll_stat, 1);
+ if((agc_stat > 115) || !(pll_stat & 0x80)) {
+ tuner_dbg("adjust gain, step 3. Agc: %d\n", agc_stat);
+ i2c_master_send(c, adc_head_12, 2);
+ i2c_master_send(c, pll_bw_low, 2);
+ msleep(100);
+ }
+ }
+ }
+
+ /* l/ l' deadlock? */
+ if(t->tda8290_easy_mode & 0x60) {
+ i2c_master_send(c, &addr_adc_sat, 1);
+ i2c_master_recv(c, &adc_sat, 1);
+ i2c_master_send(c, &addr_pll_stat, 1);
+ i2c_master_recv(c, &pll_stat, 1);
+ if ((adc_sat > 20) || !(pll_stat & 0x80)) {
+ tuner_dbg("trying to resolve SECAM L deadlock\n");
+ i2c_master_send(c, agc_rst_on, 2);
+ msleep(40);
+ i2c_master_send(c, agc_rst_off, 2);
+ }
+ }
+
+ tda8290_i2c_bridge(c, 0);
+ i2c_master_send(c, if_agc_set, 2);
+ return 0;
+}
+
+
+/*---------------------------------------------------------------------*/
+
#define V4L2_STD_MN (V4L2_STD_PAL_M|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc|V4L2_STD_NTSC)
#define V4L2_STD_B (V4L2_STD_PAL_B|V4L2_STD_PAL_B1|V4L2_STD_SECAM_B)
#define V4L2_STD_GH (V4L2_STD_PAL_G|V4L2_STD_PAL_H|V4L2_STD_SECAM_G|V4L2_STD_SECAM_H)
@@ -174,20 +408,41 @@ static void set_frequency(struct tuner *t, u16 ifc, unsigned int freq)
static void set_audio(struct tuner *t)
{
- t->i2c_easy_mode[0] = 0x01;
-
- if (t->std & V4L2_STD_MN)
- t->i2c_easy_mode[1] = 0x01;
- else if (t->std & V4L2_STD_B)
- t->i2c_easy_mode[1] = 0x02;
- else if (t->std & V4L2_STD_GH)
- t->i2c_easy_mode[1] = 0x04;
- else if (t->std & V4L2_STD_PAL_I)
- t->i2c_easy_mode[1] = 0x08;
- else if (t->std & V4L2_STD_DK)
- t->i2c_easy_mode[1] = 0x10;
- else if (t->std & V4L2_STD_SECAM_L)
- t->i2c_easy_mode[1] = 0x20;
+ char* mode;
+
+ t->tda827x_lpsel = 0;
+ mode = "xx";
+ if (t->std & V4L2_STD_MN) {
+ t->sgIF = 92;
+ t->tda8290_easy_mode = 0x01;
+ t->tda827x_lpsel = 1;
+ mode = "MN";
+ } else if (t->std & V4L2_STD_B) {
+ t->sgIF = 108;
+ t->tda8290_easy_mode = 0x02;
+ mode = "B";
+ } else if (t->std & V4L2_STD_GH) {
+ t->sgIF = 124;
+ t->tda8290_easy_mode = 0x04;
+ mode = "GH";
+ } else if (t->std & V4L2_STD_PAL_I) {
+ t->sgIF = 124;
+ t->tda8290_easy_mode = 0x08;
+ mode = "I";
+ } else if (t->std & V4L2_STD_DK) {
+ t->sgIF = 124;
+ t->tda8290_easy_mode = 0x10;
+ mode = "DK";
+ } else if (t->std & V4L2_STD_SECAM_L) {
+ t->sgIF = 124;
+ t->tda8290_easy_mode = 0x20;
+ mode = "L";
+ } else if (t->std & V4L2_STD_SECAM_LC) {
+ t->sgIF = 20;
+ t->tda8290_easy_mode = 0x40;
+ mode = "LC";
+ }
+ tuner_dbg("setting tda8290 to system %s\n", mode);
}
static void set_tv_freq(struct i2c_client *c, unsigned int freq)
@@ -195,15 +450,13 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq)
struct tuner *t = i2c_get_clientdata(c);
set_audio(t);
- set_frequency(t, 864, freq);
- tda8290_tune(c);
+ tda8290_tune(c, t->sgIF, freq);
}
static void set_radio_freq(struct i2c_client *c, unsigned int freq)
{
- struct tuner *t = i2c_get_clientdata(c);
- set_frequency(t, 704, freq);
- tda8290_tune(c);
+ /* if frequency is 5.5 MHz */
+ tda8290_tune(c, 88, freq);
}
static int has_signal(struct i2c_client *c)
@@ -216,27 +469,145 @@ static int has_signal(struct i2c_client *c)
return (afc & 0x80)? 65535:0;
}
+/*---------------------------------------------------------------------*/
+
static void standby(struct i2c_client *c)
{
- i2c_transfer(c->adapter, i2c_msg_standby, ARRAY_SIZE(i2c_msg_standby));
+ struct tuner *t = i2c_get_clientdata(c);
+ unsigned char cb1[] = { 0x30, 0xD0 };
+ unsigned char tda8290_standby[] = { 0x00, 0x02 };
+ struct i2c_msg msg = {.addr = t->tda827x_addr, .flags=0, .buf=cb1, .len = 2};
+
+ tda8290_i2c_bridge(c, 1);
+ if (t->tda827x_ver != 0)
+ cb1[1] = 0x90;
+ i2c_transfer(c->adapter, &msg, 1);
+ tda8290_i2c_bridge(c, 0);
+ i2c_master_send(c, tda8290_standby, 2);
}
-int tda8290_init(struct i2c_client *c)
+
+static void tda8290_init_if(struct i2c_client *c)
+{
+ unsigned char set_VS[] = { 0x30, 0x6F };
+ unsigned char set_GP01_CF[] = { 0x20, 0x0B };
+
+ i2c_master_send(c, set_VS, 2);
+ i2c_master_send(c, set_GP01_CF, 2);
+}
+
+static void tda8290_init_tuner(struct i2c_client *c)
{
struct tuner *t = i2c_get_clientdata(c);
+ unsigned char tda8275_init[] = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf,
+ 0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 };
+ unsigned char tda8275a_init[] = { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b,
+ 0x0c, 0x04, 0x20, 0xFF, 0x00, 0x00, 0x4b };
+ struct i2c_msg msg = {.addr = t->tda827x_addr, .flags=0,
+ .buf=tda8275_init, .len = 14};
+ if (t->tda827x_ver != 0)
+ msg.buf = tda8275a_init;
+
+ tda8290_i2c_bridge(c, 1);
+ i2c_transfer(c->adapter, &msg, 1);
+ tda8290_i2c_bridge(c, 0);
+}
- strlcpy(c->name, "tda8290+75", sizeof(c->name));
+/*---------------------------------------------------------------------*/
+
+int tda8290_init(struct i2c_client *c)
+{
+ struct tuner *t = i2c_get_clientdata(c);
+ u8 data;
+ int i, ret, tuners_found;
+ u32 tuner_addrs;
+ struct i2c_msg msg = {.flags=I2C_M_RD, .buf=&data, .len = 1};
+
+ tda8290_i2c_bridge(c, 1);
+ /* probe for tuner chip */
+ tuners_found = 0;
+ tuner_addrs = 0;
+ for (i=0x60; i<= 0x63; i++) {
+ msg.addr = i;
+ ret = i2c_transfer(c->adapter, &msg, 1);
+ if (ret == 1) {
+ tuners_found++;
+ tuner_addrs = (tuner_addrs << 8) + i;
+ }
+ }
+ /* if there is more than one tuner, we expect the right one is
+ behind the bridge and we choose the highest address that doesn't
+ give a response now
+ */
+ tda8290_i2c_bridge(c, 0);
+ if(tuners_found > 1)
+ for (i = 0; i < tuners_found; i++) {
+ msg.addr = tuner_addrs & 0xff;
+ ret = i2c_transfer(c->adapter, &msg, 1);
+ if(ret == 1)
+ tuner_addrs = tuner_addrs >> 8;
+ else
+ break;
+ }
+ if (tuner_addrs == 0) {
+ tuner_addrs = 0x61;
+ tuner_info ("could not clearly identify tuner address, defaulting to %x\n",
+ tuner_addrs);
+ } else {
+ tuner_addrs = tuner_addrs & 0xff;
+ tuner_info ("setting tuner address to %x\n", tuner_addrs);
+ }
+ t->tda827x_addr = tuner_addrs;
+ msg.addr = tuner_addrs;
+
+ tda8290_i2c_bridge(c, 1);
+ ret = i2c_transfer(c->adapter, &msg, 1);
+ if( ret != 1)
+ tuner_warn ("TDA827x access failed!\n");
+ if ((data & 0x3c) == 0) {
+ strlcpy(c->name, "tda8290+75", sizeof(c->name));
+ t->tda827x_ver = 0;
+ } else {
+ strlcpy(c->name, "tda8290+75a", sizeof(c->name));
+ t->tda827x_ver = 2;
+ }
tuner_info("tuner: type set to %s\n", c->name);
+
t->tv_freq = set_tv_freq;
t->radio_freq = set_radio_freq;
t->has_signal = has_signal;
t->standby = standby;
+ t->tda827x_lpsel = 0;
- i2c_master_send(c, i2c_enable_bridge, ARRAY_SIZE(i2c_enable_bridge));
- i2c_transfer(c->adapter, i2c_msg_init, ARRAY_SIZE(i2c_msg_init));
+ tda8290_init_tuner(c);
+ tda8290_init_if(c);
return 0;
}
+int tda8290_probe(struct i2c_client *c)
+{
+ unsigned char soft_reset[] = { 0x00, 0x00 };
+ unsigned char easy_mode_b[] = { 0x01, 0x02 };
+ unsigned char easy_mode_g[] = { 0x01, 0x04 };
+ unsigned char addr_dto_lsb = 0x07;
+ unsigned char data;
+
+ i2c_master_send(c, easy_mode_b, 2);
+ i2c_master_send(c, soft_reset, 2);
+ i2c_master_send(c, &addr_dto_lsb, 1);
+ i2c_master_recv(c, &data, 1);
+ if (data == 0) {
+ i2c_master_send(c, easy_mode_g, 2);
+ i2c_master_send(c, soft_reset, 2);
+ i2c_master_send(c, &addr_dto_lsb, 1);
+ i2c_master_recv(c, &data, 1);
+ if (data == 0x7b) {
+ return 0;
+ }
+ }
+ return -1;
+}
+
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* ---------------------------------------------------------------------------
diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c
index 7e3dcdb262b..a5e37dc91f3 100644
--- a/drivers/media/video/tda9875.c
+++ b/drivers/media/video/tda9875.c
@@ -32,7 +32,6 @@
#include "bttv.h"
#include <media/audiochip.h>
-#include <media/id.h>
static int debug; /* insmod parameter */
module_param(debug, int, S_IRUGO | S_IWUSR);
@@ -126,20 +125,20 @@ static int tda9875_write(struct i2c_client *client, int subaddr, unsigned char v
static int i2c_read_register(struct i2c_adapter *adap, int addr, int reg)
{
- unsigned char write[1];
- unsigned char read[1];
- struct i2c_msg msgs[2] = {
- { addr, 0, 1, write },
- { addr, I2C_M_RD, 1, read }
- };
- write[0] = reg;
-
- if (2 != i2c_transfer(adap,msgs,2)) {
- printk(KERN_WARNING "tda9875: I/O error (read2)\n");
- return -1;
- }
- dprintk("tda9875: chip_read2: reg%d=0x%x\n",reg,read[0]);
- return read[0];
+ unsigned char write[1];
+ unsigned char read[1];
+ struct i2c_msg msgs[2] = {
+ { addr, 0, 1, write },
+ { addr, I2C_M_RD, 1, read }
+ };
+ write[0] = reg;
+
+ if (2 != i2c_transfer(adap,msgs,2)) {
+ printk(KERN_WARNING "tda9875: I/O error (read2)\n");
+ return -1;
+ }
+ dprintk("tda9875: chip_read2: reg%d=0x%x\n",reg,read[0]);
+ return read[0];
}
static void tda9875_set(struct i2c_client *client)
@@ -184,7 +183,7 @@ static void do_tda9875_init(struct i2c_client *client)
tda9875_write(client, TDA9875_DACOS, 0x02 ); /* sig DAC i/o(in:nicam)*/
tda9875_write(client, TDA9875_ADCIS, 0x6f ); /* sig ADC input(in:mono)*/
tda9875_write(client, TDA9875_LOSR, 0x00 ); /* line out (in:mono)*/
- tda9875_write(client, TDA9875_AER, 0x00 ); /*06 Effect (AVL+PSEUDO) */
+ tda9875_write(client, TDA9875_AER, 0x00 ); /*06 Effect (AVL+PSEUDO) */
tda9875_write(client, TDA9875_MCS, 0x44 ); /* Main ch select (DAC) */
tda9875_write(client, TDA9875_MVL, 0x03 ); /* Vol Main left 10dB */
tda9875_write(client, TDA9875_MVR, 0x03 ); /* Vol Main right 10dB*/
@@ -200,7 +199,7 @@ static void do_tda9875_init(struct i2c_client *client)
t->mode=AUDIO_UNMUTE;
t->lvol=t->rvol =0; /* 0dB */
- t->bass=0; /* 0dB */
+ t->bass=0; /* 0dB */
t->treble=0; /* 0dB */
tda9875_set(client);
@@ -239,9 +238,9 @@ static int tda9875_attach(struct i2c_adapter *adap, int addr, int kind)
memset(t,0,sizeof *t);
client = &t->c;
- memcpy(client,&client_template,sizeof(struct i2c_client));
- client->adapter = adap;
- client->addr = addr;
+ memcpy(client,&client_template,sizeof(struct i2c_client));
+ client->adapter = adap;
+ client->addr = addr;
i2c_set_clientdata(client, t);
if(!tda9875_checkit(adap,addr)) {
@@ -287,7 +286,7 @@ static int tda9875_command(struct i2c_client *client,
dprintk("In tda9875_command...\n");
switch (cmd) {
- /* --- v4l ioctls --- */
+ /* --- v4l ioctls --- */
/* take care: bttv does userspace copying, we'll get a
kernel pointer here... */
case VIDIOCGAUDIO:
@@ -355,7 +354,7 @@ static int tda9875_command(struct i2c_client *client,
//printk("tda9875 bal:%04x vol:%04x bass:%04x treble:%04x\n",va->balance,va->volume,va->bass,va->treble);
- tda9875_set(client);
+ tda9875_set(client);
break;
@@ -374,18 +373,18 @@ static int tda9875_command(struct i2c_client *client,
static struct i2c_driver driver = {
.owner = THIS_MODULE,
- .name = "i2c tda9875 driver",
- .id = I2C_DRIVERID_TDA9875,
- .flags = I2C_DF_NOTIFY,
+ .name = "i2c tda9875 driver",
+ .id = I2C_DRIVERID_TDA9875,
+ .flags = I2C_DF_NOTIFY,
.attach_adapter = tda9875_probe,
- .detach_client = tda9875_detach,
- .command = tda9875_command,
+ .detach_client = tda9875_detach,
+ .command = tda9875_command,
};
static struct i2c_client client_template =
{
- .name = "tda9875",
- .driver = &driver,
+ .name = "tda9875",
+ .driver = &driver,
};
static int __init tda9875_init(void)
diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c
index 94053f149dd..4249127c0a1 100644
--- a/drivers/media/video/tda9887.c
+++ b/drivers/media/video/tda9887.c
@@ -11,7 +11,6 @@
#include <media/audiochip.h>
#include <media/tuner.h>
-#include <media/id.h>
/* Chips:
TDA9885 (PAL, NTSC)
@@ -44,8 +43,13 @@ MODULE_LICENSE("GPL");
/* ---------------------------------------------------------------------- */
#define UNSET (-1U)
-#define PREFIX "tda9885/6/7: "
-#define dprintk if (debug) printk
+#define tda9887_info(fmt, arg...) do {\
+ printk(KERN_INFO "%s %d-%04x: " fmt, t->client.name, \
+ i2c_adapter_id(t->client.adapter), t->client.addr , ##arg); } while (0)
+#define tda9887_dbg(fmt, arg...) do {\
+ if (debug) \
+ printk(KERN_INFO "%s %d-%04x: " fmt, t->client.name, \
+ i2c_adapter_id(t->client.adapter), t->client.addr , ##arg); } while (0)
struct tda9887 {
struct i2c_client client;
@@ -55,6 +59,7 @@ struct tda9887 {
unsigned int pinnacle_id;
unsigned int using_v4l2;
unsigned int radio_mode;
+ unsigned char data[4];
};
struct tvnorm {
@@ -180,7 +185,8 @@ static struct tvnorm tvnorms[] = {
.name = "SECAM-L",
.b = ( cPositiveAmTV |
cQSS ),
- .e = ( cAudioIF_6_5 |
+ .e = ( cGating_36 |
+ cAudioIF_6_5 |
cVideoIF_38_90 ),
},{
.std = V4L2_STD_SECAM_DK,
@@ -236,7 +242,7 @@ static struct tvnorm radio_mono = {
/* ---------------------------------------------------------------------- */
-static void dump_read_message(unsigned char *buf)
+static void dump_read_message(struct tda9887 *t, unsigned char *buf)
{
static char *afc[16] = {
"- 12.5 kHz",
@@ -256,15 +262,15 @@ static void dump_read_message(unsigned char *buf)
"+ 37.5 kHz",
"+ 12.5 kHz",
};
- printk(PREFIX "read: 0x%2x\n", buf[0]);
- printk(" after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no");
- printk(" afc : %s\n", afc[(buf[0] >> 1) & 0x0f]);
- printk(" fmif level : %s\n", (buf[0] & 0x20) ? "high" : "low");
- printk(" afc window : %s\n", (buf[0] & 0x40) ? "in" : "out");
- printk(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low");
+ tda9887_info("read: 0x%2x\n", buf[0]);
+ tda9887_info(" after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no");
+ tda9887_info(" afc : %s\n", afc[(buf[0] >> 1) & 0x0f]);
+ tda9887_info(" fmif level : %s\n", (buf[0] & 0x20) ? "high" : "low");
+ tda9887_info(" afc window : %s\n", (buf[0] & 0x40) ? "in" : "out");
+ tda9887_info(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low");
}
-static void dump_write_message(unsigned char *buf)
+static void dump_write_message(struct tda9887 *t, unsigned char *buf)
{
static char *sound[4] = {
"AM/TV",
@@ -304,58 +310,58 @@ static void dump_write_message(unsigned char *buf)
"44 MHz",
};
- printk(PREFIX "write: byte B 0x%02x\n",buf[1]);
- printk(" B0 video mode : %s\n",
+ tda9887_info("write: byte B 0x%02x\n",buf[1]);
+ tda9887_info(" B0 video mode : %s\n",
(buf[1] & 0x01) ? "video trap" : "sound trap");
- printk(" B1 auto mute fm : %s\n",
+ tda9887_info(" B1 auto mute fm : %s\n",
(buf[1] & 0x02) ? "yes" : "no");
- printk(" B2 carrier mode : %s\n",
+ tda9887_info(" B2 carrier mode : %s\n",
(buf[1] & 0x04) ? "QSS" : "Intercarrier");
- printk(" B3-4 tv sound/radio : %s\n",
+ tda9887_info(" B3-4 tv sound/radio : %s\n",
sound[(buf[1] & 0x18) >> 3]);
- printk(" B5 force mute audio: %s\n",
+ tda9887_info(" B5 force mute audio: %s\n",
(buf[1] & 0x20) ? "yes" : "no");
- printk(" B6 output port 1 : %s\n",
+ tda9887_info(" B6 output port 1 : %s\n",
(buf[1] & 0x40) ? "high (inactive)" : "low (active)");
- printk(" B7 output port 2 : %s\n",
+ tda9887_info(" B7 output port 2 : %s\n",
(buf[1] & 0x80) ? "high (inactive)" : "low (active)");
- printk(PREFIX "write: byte C 0x%02x\n",buf[2]);
- printk(" C0-4 top adjustment : %s dB\n", adjust[buf[2] & 0x1f]);
- printk(" C5-6 de-emphasis : %s\n", deemph[(buf[2] & 0x60) >> 5]);
- printk(" C7 audio gain : %s\n",
+ tda9887_info("write: byte C 0x%02x\n",buf[2]);
+ tda9887_info(" C0-4 top adjustment : %s dB\n", adjust[buf[2] & 0x1f]);
+ tda9887_info(" C5-6 de-emphasis : %s\n", deemph[(buf[2] & 0x60) >> 5]);
+ tda9887_info(" C7 audio gain : %s\n",
(buf[2] & 0x80) ? "-6" : "0");
- printk(PREFIX "write: byte E 0x%02x\n",buf[3]);
- printk(" E0-1 sound carrier : %s\n",
+ tda9887_info("write: byte E 0x%02x\n",buf[3]);
+ tda9887_info(" E0-1 sound carrier : %s\n",
carrier[(buf[3] & 0x03)]);
- printk(" E6 l pll ganting : %s\n",
+ tda9887_info(" E6 l pll gating : %s\n",
(buf[3] & 0x40) ? "36" : "13");
if (buf[1] & 0x08) {
/* radio */
- printk(" E2-4 video if : %s\n",
+ tda9887_info(" E2-4 video if : %s\n",
rif[(buf[3] & 0x0c) >> 2]);
- printk(" E7 vif agc output : %s\n",
+ tda9887_info(" E7 vif agc output : %s\n",
(buf[3] & 0x80)
? ((buf[3] & 0x10) ? "fm-agc radio" : "sif-agc radio")
: "fm radio carrier afc");
} else {
/* video */
- printk(" E2-4 video if : %s\n",
+ tda9887_info(" E2-4 video if : %s\n",
vif[(buf[3] & 0x1c) >> 2]);
- printk(" E5 tuner gain : %s\n",
+ tda9887_info(" E5 tuner gain : %s\n",
(buf[3] & 0x80)
? ((buf[3] & 0x20) ? "external" : "normal")
: ((buf[3] & 0x20) ? "minimum" : "normal"));
- printk(" E7 vif agc output : %s\n",
+ tda9887_info(" E7 vif agc output : %s\n",
(buf[3] & 0x80)
? ((buf[3] & 0x20)
? "pin3 port, pin22 vif agc out"
: "pin22 port, pin3 vif acg ext in")
: "pin3+pin22 port");
}
- printk("--\n");
+ tda9887_info("--\n");
}
/* ---------------------------------------------------------------------- */
@@ -379,11 +385,11 @@ static int tda9887_set_tvnorm(struct tda9887 *t, char *buf)
}
}
if (NULL == norm) {
- dprintk(PREFIX "Unsupported tvnorm entry - audio muted\n");
+ tda9887_dbg("Unsupported tvnorm entry - audio muted\n");
return -1;
}
- dprintk(PREFIX "configure for: %s\n",norm->name);
+ tda9887_dbg("configure for: %s\n",norm->name);
buf[1] = norm->b;
buf[2] = norm->c;
buf[3] = norm->e;
@@ -458,6 +464,8 @@ static int tda9887_set_config(struct tda9887 *t, char *buf)
break;
}
}
+ if ((t->config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC))
+ buf[1] &= ~cQSS;
return 0;
}
@@ -475,11 +483,11 @@ static int tda9887_set_pinnacle(struct tda9887 *t, char *buf)
}
}
if (t->std & V4L2_STD_525_60) {
- if ((5 == t->pinnacle_id) || (6 == t->pinnacle_id)) {
+ if ((5 == t->pinnacle_id) || (6 == t->pinnacle_id)) {
bCarrierMode = cIntercarrier;
} else {
bCarrierMode = cQSS;
- }
+ }
}
if (bCarrierMode != UNSET) {
@@ -505,26 +513,26 @@ static int tda9887_fixup_std(struct tda9887 *t)
case 'B':
case 'g':
case 'G':
- dprintk(PREFIX "insmod fixup: PAL => PAL-BG\n");
+ tda9887_dbg("insmod fixup: PAL => PAL-BG\n");
t->std = V4L2_STD_PAL_BG;
break;
case 'i':
case 'I':
- dprintk(PREFIX "insmod fixup: PAL => PAL-I\n");
+ tda9887_dbg("insmod fixup: PAL => PAL-I\n");
t->std = V4L2_STD_PAL_I;
break;
case 'd':
case 'D':
case 'k':
case 'K':
- dprintk(PREFIX "insmod fixup: PAL => PAL-DK\n");
+ tda9887_dbg("insmod fixup: PAL => PAL-DK\n");
t->std = V4L2_STD_PAL_DK;
break;
case '-':
/* default parameter, do nothing */
break;
default:
- printk(PREFIX "pal= argument not recognised\n");
+ tda9887_info("pal= argument not recognised\n");
break;
}
}
@@ -534,19 +542,19 @@ static int tda9887_fixup_std(struct tda9887 *t)
case 'D':
case 'k':
case 'K':
- dprintk(PREFIX "insmod fixup: SECAM => SECAM-DK\n");
+ tda9887_dbg("insmod fixup: SECAM => SECAM-DK\n");
t->std = V4L2_STD_SECAM_DK;
break;
case 'l':
case 'L':
- dprintk(PREFIX "insmod fixup: SECAM => SECAM-L\n");
+ tda9887_dbg("insmod fixup: SECAM => SECAM-L\n");
t->std = V4L2_STD_SECAM_L;
break;
case '-':
/* default parameter, do nothing */
break;
default:
- printk(PREFIX "secam= argument not recognised\n");
+ tda9887_info("secam= argument not recognised\n");
break;
}
}
@@ -559,41 +567,40 @@ static int tda9887_status(struct tda9887 *t)
int rc;
memset(buf,0,sizeof(buf));
- if (1 != (rc = i2c_master_recv(&t->client,buf,1)))
- printk(PREFIX "i2c i/o error: rc == %d (should be 1)\n",rc);
- dump_read_message(buf);
+ if (1 != (rc = i2c_master_recv(&t->client,buf,1)))
+ tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc);
+ dump_read_message(t, buf);
return 0;
}
static int tda9887_configure(struct tda9887 *t)
{
- unsigned char buf[4];
int rc;
- memset(buf,0,sizeof(buf));
- tda9887_set_tvnorm(t,buf);
+ memset(t->data,0,sizeof(t->data));
+ tda9887_set_tvnorm(t,t->data);
- buf[1] |= cOutputPort1Inactive;
- buf[1] |= cOutputPort2Inactive;
+ t->data[1] |= cOutputPort1Inactive;
+ t->data[1] |= cOutputPort2Inactive;
if (UNSET != t->pinnacle_id) {
- tda9887_set_pinnacle(t,buf);
+ tda9887_set_pinnacle(t,t->data);
}
- tda9887_set_config(t,buf);
- tda9887_set_insmod(t,buf);
+ tda9887_set_config(t,t->data);
+ tda9887_set_insmod(t,t->data);
if (t->mode == T_STANDBY) {
- buf[1] |= cForcedMuteAudioON;
+ t->data[1] |= cForcedMuteAudioON;
}
- dprintk(PREFIX "writing: b=0x%02x c=0x%02x e=0x%02x\n",
- buf[1],buf[2],buf[3]);
+ tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
+ t->data[1],t->data[2],t->data[3]);
if (debug > 1)
- dump_write_message(buf);
+ dump_write_message(t, t->data);
- if (4 != (rc = i2c_master_send(&t->client,buf,4)))
- printk(PREFIX "i2c i/o error: rc == %d (should be 4)\n",rc);
+ if (4 != (rc = i2c_master_send(&t->client,t->data,4)))
+ tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc);
if (debug > 2) {
msleep_interruptible(1000);
@@ -608,13 +615,11 @@ static int tda9887_attach(struct i2c_adapter *adap, int addr, int kind)
{
struct tda9887 *t;
- client_template.adapter = adap;
- client_template.addr = addr;
-
- printk(PREFIX "chip found @ 0x%x\n", addr<<1);
+ client_template.adapter = adap;
+ client_template.addr = addr;
- if (NULL == (t = kmalloc(sizeof(*t), GFP_KERNEL)))
- return -ENOMEM;
+ if (NULL == (t = kmalloc(sizeof(*t), GFP_KERNEL)))
+ return -ENOMEM;
memset(t,0,sizeof(*t));
t->client = client_template;
@@ -622,6 +627,8 @@ static int tda9887_attach(struct i2c_adapter *adap, int addr, int kind)
t->pinnacle_id = UNSET;
t->radio_mode = V4L2_TUNER_MODE_STEREO;
+ tda9887_info("chip found @ 0x%x (%s)\n", addr<<1, adap->name);
+
i2c_set_clientdata(&t->client, t);
i2c_attach_client(&t->client);
@@ -655,18 +662,18 @@ static int tda9887_detach(struct i2c_client *client)
}
#define SWITCH_V4L2 if (!t->using_v4l2 && debug) \
- printk(PREFIX "switching to v4l2\n"); \
- t->using_v4l2 = 1;
+ tda9887_info("switching to v4l2\n"); \
+ t->using_v4l2 = 1;
#define CHECK_V4L2 if (t->using_v4l2) { if (debug) \
- printk(PREFIX "ignore v4l1 call\n"); \
- return 0; }
+ tda9887_info("ignore v4l1 call\n"); \
+ return 0; }
static int
tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct tda9887 *t = i2c_get_clientdata(client);
- switch (cmd) {
+ switch (cmd) {
/* --- configuration --- */
case AUDC_SET_RADIO:
@@ -777,6 +784,11 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg)
}
break;
}
+ case VIDIOC_LOG_STATUS:
+ {
+ tda9887_info("Data bytes: b=%02x c=%02x e=%02x\n", t->data[1], t->data[2], t->data[3]);
+ break;
+ }
default:
/* nothing */
break;
@@ -786,7 +798,10 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg)
static int tda9887_suspend(struct device * dev, pm_message_t state)
{
- dprintk("tda9887: suspend\n");
+ struct i2c_client *c = container_of(dev, struct i2c_client, dev);
+ struct tda9887 *t = i2c_get_clientdata(c);
+
+ tda9887_dbg("suspend\n");
return 0;
}
@@ -795,7 +810,7 @@ static int tda9887_resume(struct device * dev)
struct i2c_client *c = container_of(dev, struct i2c_client, dev);
struct tda9887 *t = i2c_get_clientdata(c);
- dprintk("tda9887: resume\n");
+ tda9887_dbg("resume\n");
tda9887_configure(t);
return 0;
}
diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c
index 38bf5094379..a9375ef05de 100644
--- a/drivers/media/video/tea5767.c
+++ b/drivers/media/video/tea5767.c
@@ -117,10 +117,10 @@
#define TEA5767_RESERVED_MASK 0xff
enum tea5767_xtal_freq {
- TEA5767_LOW_LO_32768 = 0,
- TEA5767_HIGH_LO_32768 = 1,
- TEA5767_LOW_LO_13MHz = 2,
- TEA5767_HIGH_LO_13MHz = 3,
+ TEA5767_LOW_LO_32768 = 0,
+ TEA5767_HIGH_LO_32768 = 1,
+ TEA5767_LOW_LO_13MHz = 2,
+ TEA5767_HIGH_LO_13MHz = 3,
};
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index ad85bef1c3d..e58abdfcaab 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -28,7 +28,7 @@
/* standard i2c insmod options */
static unsigned short normal_i2c[] = {
- 0x4b, /* tda8290 */
+ 0x42, 0x43, 0x4a, 0x4b, /* tda8290 */
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
I2C_CLIENT_END
@@ -189,6 +189,13 @@ static void set_type(struct i2c_client *c, unsigned int type,
i2c_master_send(c, buffer, 4);
default_tuner_init(c);
break;
+ case TUNER_PHILIPS_TD1316:
+ buffer[0] = 0x0b;
+ buffer[1] = 0xdc;
+ buffer[2] = 0x86;
+ buffer[3] = 0xa4;
+ i2c_master_send(c,buffer,4);
+ default_tuner_init(c);
default:
default_tuner_init(c);
break;
@@ -215,9 +222,9 @@ static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup)
{
struct tuner *t = i2c_get_clientdata(c);
- if ((tun_setup->addr == ADDR_UNSET &&
+ if ( t->type == UNSET && ((tun_setup->addr == ADDR_UNSET &&
(t->mode_mask & tun_setup->mode_mask)) ||
- tun_setup->addr == c->addr) {
+ tun_setup->addr == c->addr)) {
set_type(c, tun_setup->type, tun_setup->mode_mask);
}
}
@@ -244,7 +251,7 @@ static inline int check_mode(struct tuner *t, char *cmd)
static char pal[] = "-";
module_param_string(pal, pal, sizeof(pal), 0644);
-static char secam[] = "-";
+static char secam[] = "--";
module_param_string(secam, secam, sizeof(secam), 0644);
/* get more precise norm info from insmod option */
@@ -300,8 +307,13 @@ static int tuner_fixup_std(struct tuner *t)
break;
case 'l':
case 'L':
- tuner_dbg ("insmod fixup: SECAM => SECAM-L\n");
- t->std = V4L2_STD_SECAM_L;
+ if ((secam[1]=='C')||(secam[1]=='c')) {
+ tuner_dbg ("insmod fixup: SECAM => SECAM-L'\n");
+ t->std = V4L2_STD_SECAM_LC;
+ } else {
+ tuner_dbg ("insmod fixup: SECAM => SECAM-L\n");
+ t->std = V4L2_STD_SECAM_L;
+ }
break;
case '-':
/* default parameter, do nothing */
@@ -341,23 +353,33 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
t->audmode = V4L2_TUNER_MODE_STEREO;
t->mode_mask = T_UNINITIALIZED;
-
- tuner_info("chip found @ 0x%x (%s)\n", addr << 1, adap->name);
-
if (show_i2c) {
unsigned char buffer[16];
int i,rc;
memset(buffer, 0, sizeof(buffer));
rc = i2c_master_recv(&t->i2c, buffer, sizeof(buffer));
- printk("tuner-%04x I2C RECV = ",addr);
+ tuner_info("I2C RECV = ");
for (i=0;i<rc;i++)
printk("%02x ",buffer[i]);
printk("\n");
}
/* TEA5767 autodetection code - only for addr = 0xc0 */
if (!no_autodetect) {
- if (addr == 0x60) {
+ switch (addr) {
+ case 0x42:
+ case 0x43:
+ case 0x4a:
+ case 0x4b:
+ /* If chip is not tda8290, don't register.
+ since it can be tda9887*/
+ if (tda8290_probe(&t->i2c) != 0) {
+ tuner_dbg("chip at addr %x is not a tda8290\n", addr);
+ kfree(t);
+ return 0;
+ }
+ break;
+ case 0x60:
if (tea5767_autodetection(&t->i2c) != EINVAL) {
t->type = TUNER_TEA5767;
t->mode_mask = T_RADIO;
@@ -365,10 +387,9 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
t->freq = 87.5 * 16; /* Sets freq to FM range */
default_mode_mask &= ~T_RADIO;
- i2c_attach_client (&t->i2c);
- set_type(&t->i2c,t->type, t->mode_mask);
- return 0;
+ goto register_client;
}
+ break;
}
}
@@ -381,6 +402,8 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
}
/* Should be just before return */
+register_client:
+ tuner_info("chip found @ 0x%x (%s)\n", addr << 1, adap->name);
i2c_attach_client (&t->i2c);
set_type (&t->i2c,t->type, t->mode_mask);
return 0;
@@ -425,23 +448,23 @@ static int tuner_detach(struct i2c_client *client)
static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd)
{
- if (mode == t->mode)
- return 0;
-
- t->mode = mode;
-
- if (check_mode(t, cmd) == EINVAL) {
- t->mode = T_STANDBY;
- if (t->standby)
- t->standby (client);
- return EINVAL;
- }
- return 0;
+ if (mode == t->mode)
+ return 0;
+
+ t->mode = mode;
+
+ if (check_mode(t, cmd) == EINVAL) {
+ t->mode = T_STANDBY;
+ if (t->standby)
+ t->standby (client);
+ return EINVAL;
+ }
+ return 0;
}
#define switch_v4l2() if (!t->using_v4l2) \
- tuner_dbg("switching to v4l2\n"); \
- t->using_v4l2 = 1;
+ tuner_dbg("switching to v4l2\n"); \
+ t->using_v4l2 = 1;
static inline int check_v4l2(struct tuner *t)
{
@@ -479,8 +502,6 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
break;
}
case AUDC_CONFIG_PINNACLE:
- if (check_mode(t, "AUDC_CONFIG_PINNACLE") == EINVAL)
- return 0;
switch (*iarg) {
case 2:
tuner_dbg("pinnacle pal\n");
@@ -616,7 +637,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
switch_v4l2();
if (V4L2_TUNER_RADIO == f->type &&
V4L2_TUNER_RADIO != t->mode) {
- if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY")
+ if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY")
== EINVAL)
return 0;
}
@@ -688,7 +709,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
break;
}
default:
- tuner_dbg("Unimplemented IOCTL 0x%08x(dir=%d,tp=0x%02x,nr=%d,sz=%d)\n",
+ tuner_dbg("Unimplemented IOCTL 0x%08x(dir=%d,tp='%c',nr=%d,sz=%d)\n",
cmd, _IOC_DIR(cmd), _IOC_TYPE(cmd),
_IOC_NR(cmd), _IOC_SIZE(cmd));
break;
diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c
index 8edd73abe1d..e0c9fdb9914 100644
--- a/drivers/media/video/tuner-simple.c
+++ b/drivers/media/video/tuner-simple.c
@@ -102,7 +102,7 @@ struct tunertype
*/
static struct tunertype tuners[] = {
/* 0-9 */
- { "Temic PAL (4002 FH5)", TEMIC, PAL,
+ { "Temic PAL (4002 FH5)", TEMIC, PAL,
16*140.25,16*463.25,0x02,0x04,0x01,0x8e,623},
{ "Philips PAL_I (FI1246 and compatibles)", Philips, PAL_I,
16*140.25,16*463.25,0xa0,0x90,0x30,0x8e,623},
@@ -118,41 +118,41 @@ static struct tunertype tuners[] = {
16*157.25,16*463.25,0x02,0x04,0x01,0x8e,732},
{ "Temic PAL_I (4062 FY5)", TEMIC, PAL_I,
16*170.00,16*450.00,0x02,0x04,0x01,0x8e,623},
- { "Temic NTSC (4036 FY5)", TEMIC, NTSC,
+ { "Temic NTSC (4036 FY5)", TEMIC, NTSC,
16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,732},
- { "Alps HSBH1", TEMIC, NTSC,
+ { "Alps HSBH1", TEMIC, NTSC,
16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732},
/* 10-19 */
- { "Alps TSBE1", TEMIC, PAL,
+ { "Alps TSBE1", TEMIC, PAL,
16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732},
- { "Alps TSBB5", Alps, PAL_I, /* tested (UK UHF) with Modulartech MM205 */
+ { "Alps TSBB5", Alps, PAL_I, /* tested (UK UHF) with Modulartech MM205 */
16*133.25,16*351.25,0x01,0x02,0x08,0x8e,632},
- { "Alps TSBE5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */
+ { "Alps TSBE5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */
16*133.25,16*351.25,0x01,0x02,0x08,0x8e,622},
- { "Alps TSBC5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */
+ { "Alps TSBC5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */
16*133.25,16*351.25,0x01,0x02,0x08,0x8e,608},
{ "Temic PAL_BG (4006FH5)", TEMIC, PAL,
16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
- { "Alps TSCH6", Alps, NTSC,
- 16*137.25,16*385.25,0x14,0x12,0x11,0x8e,732},
- { "Temic PAL_DK (4016 FY5)", TEMIC, PAL,
- 16*168.25,16*456.25,0xa0,0x90,0x30,0x8e,623},
- { "Philips NTSC_M (MK2)", Philips, NTSC,
- 16*160.00,16*454.00,0xa0,0x90,0x30,0x8e,732},
- { "Temic PAL_I (4066 FY5)", TEMIC, PAL_I,
- 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
- { "Temic PAL* auto (4006 FN5)", TEMIC, PAL,
- 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
+ { "Alps TSCH6", Alps, NTSC,
+ 16*137.25,16*385.25,0x14,0x12,0x11,0x8e,732},
+ { "Temic PAL_DK (4016 FY5)", TEMIC, PAL,
+ 16*168.25,16*456.25,0xa0,0x90,0x30,0x8e,623},
+ { "Philips NTSC_M (MK2)", Philips, NTSC,
+ 16*160.00,16*454.00,0xa0,0x90,0x30,0x8e,732},
+ { "Temic PAL_I (4066 FY5)", TEMIC, PAL_I,
+ 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
+ { "Temic PAL* auto (4006 FN5)", TEMIC, PAL,
+ 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
/* 20-29 */
- { "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)", TEMIC, PAL,
- 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
- { "Temic NTSC (4039 FR5)", TEMIC, NTSC,
- 16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732},
- { "Temic PAL/SECAM multi (4046 FM5)", TEMIC, PAL,
- 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
- { "Philips PAL_DK (FI1256 and compatibles)", Philips, PAL,
+ { "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)", TEMIC, PAL,
+ 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
+ { "Temic NTSC (4039 FR5)", TEMIC, NTSC,
+ 16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732},
+ { "Temic PAL/SECAM multi (4046 FM5)", TEMIC, PAL,
+ 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
+ { "Philips PAL_DK (FI1256 and compatibles)", Philips, PAL,
16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
{ "Philips PAL/SECAM multi (FQ1216ME)", Philips, PAL,
16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
@@ -173,21 +173,21 @@ static struct tunertype tuners[] = {
{ "SHARP NTSC_JP (2U5JF5540)", SHARP, NTSC, /* 940=16*58.75 NTSC@Japan */
16*137.25,16*317.25,0x01,0x02,0x08,0x8e,940 },
{ "Samsung PAL TCPM9091PD27", Samsung, PAL, /* from sourceforge v3tv */
- 16*169,16*464,0xA0,0x90,0x30,0x8e,623},
+ 16*169,16*464,0xA0,0x90,0x30,0x8e,623},
{ "MT20xx universal", Microtune, PAL|NTSC,
/* see mt20xx.c for details */ },
{ "Temic PAL_BG (4106 FH5)", TEMIC, PAL,
- 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
+ 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
{ "Temic PAL_DK/SECAM_L (4012 FY5)", TEMIC, PAL,
- 16*140.25, 16*463.25, 0x02,0x04,0x01,0x8e,623},
+ 16*140.25, 16*463.25, 0x02,0x04,0x01,0x8e,623},
{ "Temic NTSC (4136 FY5)", TEMIC, NTSC,
- 16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732},
- { "LG PAL (newer TAPC series)", LGINNOTEK, PAL,
- 16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,623},
+ 16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732},
+ { "LG PAL (newer TAPC series)", LGINNOTEK, PAL,
+ 16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,623},
{ "Philips PAL/SECAM multi (FM1216ME MK3)", Philips, PAL,
- 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,623 },
+ 16*158.00,16*442.00,0x01,0x02,0x04,0x8e,623 },
{ "LG NTSC (newer TAPC series)", LGINNOTEK, NTSC,
- 16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,732},
+ 16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,732},
/* 40-49 */
{ "HITACHI V7-J180AT", HITACHI, NTSC,
@@ -196,24 +196,24 @@ static struct tunertype tuners[] = {
16*140.25,16*463.25,0x01,0xc2,0xcf,0x8e,623},
{ "Philips 1236D ATSC/NTSC daul in", Philips, ATSC,
16*157.25,16*454.00,0xa0,0x90,0x30,0x8e,732},
- { "Philips NTSC MK3 (FM1236MK3 or FM1236/F)", Philips, NTSC,
- 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732},
- { "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)", Philips, NTSC,
- 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732},
+ { "Philips NTSC MK3 (FM1236MK3 or FM1236/F)", Philips, NTSC,
+ 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732},
+ { "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)", Philips, NTSC,
+ 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732},
{ "Microtune 4049 FM5", Microtune, PAL,
16*141.00,16*464.00,0xa0,0x90,0x30,0x8e,623},
{ "Panasonic VP27s/ENGE4324D", Panasonic, NTSC,
16*160.00,16*454.00,0x01,0x02,0x08,0xce,940},
- { "LG NTSC (TAPE series)", LGINNOTEK, NTSC,
- 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 },
- { "Tenna TNF 8831 BGFF)", Philips, PAL,
- 16*161.25,16*463.25,0xa0,0x90,0x30,0x8e,623},
+ { "LG NTSC (TAPE series)", LGINNOTEK, NTSC,
+ 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 },
+ { "Tenna TNF 8831 BGFF)", Philips, PAL,
+ 16*161.25,16*463.25,0xa0,0x90,0x30,0x8e,623},
{ "Microtune 4042 FI5 ATSC/NTSC dual in", Microtune, NTSC,
16*162.00,16*457.00,0xa2,0x94,0x31,0x8e,732},
/* 50-59 */
- { "TCL 2002N", TCL, NTSC,
- 16*172.00,16*448.00,0x01,0x02,0x08,0x8e,732},
+ { "TCL 2002N", TCL, NTSC,
+ 16*172.00,16*448.00,0x01,0x02,0x08,0x8e,732},
{ "Philips PAL/SECAM_D (FM 1256 I-H3)", Philips, PAL,
16*160.00,16*442.00,0x01,0x02,0x04,0x8e,623 },
{ "Thomson DDT 7610 (ATSC/NTSC)", THOMSON, ATSC,
@@ -222,8 +222,8 @@ static struct tunertype tuners[] = {
16*160.00,16*454.00,0x41,0x42,0x04,0x8e,940}, /* UHF band untested */
{ "tda8290+75", Philips, PAL|NTSC,
/* see tda8290.c for details */ },
- { "LG PAL (TAPE series)", LGINNOTEK, PAL,
- 16*170.00, 16*450.00, 0x01,0x02,0x08,0xce,623},
+ { "TCL 2002MB", TCL, PAL,
+ 16*170.00, 16*450.00, 0x01,0x02,0x08,0xce,623},
{ "Philips PAL/SECAM multi (FQ1216AME MK4)", Philips, PAL,
16*160.00,16*442.00,0x01,0x02,0x04,0xce,623 },
{ "Philips FQ1236A MK4", Philips, NTSC,
@@ -233,21 +233,27 @@ static struct tunertype tuners[] = {
{ "Ymec TVision TVF-5533MF", Philips, NTSC,
16*160.00,16*454.00,0x01,0x02,0x04,0x8e,732},
- /* 60-66 */
+ /* 60-69 */
{ "Thomson DDT 7611 (ATSC/NTSC)", THOMSON, ATSC,
16*157.25,16*454.00,0x39,0x3a,0x3c,0x8e,732},
{ "Tena TNF9533-D/IF/TNF9533-B/DF", Philips, PAL,
- 16*160.25,16*464.25,0x01,0x02,0x04,0x8e,623},
+ 16*160.25,16*464.25,0x01,0x02,0x04,0x8e,623},
{ "Philips TEA5767HN FM Radio", Philips, RADIO,
- /* see tea5767.c for details */},
+ /* see tea5767.c for details */},
{ "Philips FMD1216ME MK3 Hybrid Tuner", Philips, PAL,
16*160.00,16*442.00,0x51,0x52,0x54,0x86,623 },
{ "LG TDVS-H062F/TUA6034", LGINNOTEK, ATSC,
16*160.00,16*455.00,0x01,0x02,0x04,0x8e,732},
{ "Ymec TVF66T5-B/DFF", Philips, PAL,
- 16*160.25,16*464.25,0x01,0x02,0x08,0x8e,623},
- { "LG NTSC (TALN mini series)", LGINNOTEK, NTSC,
+ 16*160.25,16*464.25,0x01,0x02,0x08,0x8e,623},
+ { "LG NTSC (TALN mini series)", LGINNOTEK, NTSC,
16*137.25,16*373.25,0x01,0x02,0x08,0x8e,732 },
+ { "Philips TD1316 Hybrid Tuner", Philips, PAL,
+ 16*160.00,16*442.00,0xa1,0xa2,0xa4,0xc8,623 },
+ { "Philips TUV1236D ATSC/NTSC dual in", Philips, ATSC,
+ 16*157.25,16*454.00,0x01,0x02,0x04,0xce,732 },
+ { "Tena TNF 5335 MF", Philips, NTSC,
+ 16*157.25,16*454.00,0x01,0x02,0x04,0x8e,732 },
};
unsigned const int tuner_count = ARRAY_SIZE(tuners);
@@ -277,7 +283,7 @@ static int tuner_stereo(struct i2c_client *c)
status = tuner_getstatus (c);
switch (t->type) {
- case TUNER_PHILIPS_FM1216ME_MK3:
+ case TUNER_PHILIPS_FM1216ME_MK3:
case TUNER_PHILIPS_FM1236_MK3:
case TUNER_PHILIPS_FM1256_IH3:
stereo = ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
@@ -295,10 +301,10 @@ static int tuner_stereo(struct i2c_client *c)
static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
{
struct tuner *t = i2c_get_clientdata(c);
- u8 config;
+ u8 config, tuneraddr;
u16 div;
struct tunertype *tun;
- unsigned char buffer[4];
+ unsigned char buffer[4];
int rc;
tun = &tuners[t->type];
@@ -373,6 +379,31 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
/* Set the charge pump for fast tuning */
tun->config |= TUNER_CHARGE_PUMP;
break;
+
+ case TUNER_PHILIPS_TUV1236D:
+ /* 0x40 -> ATSC antenna input 1 */
+ /* 0x48 -> ATSC antenna input 2 */
+ /* 0x00 -> NTSC antenna input 1 */
+ /* 0x08 -> NTSC antenna input 2 */
+ buffer[0] = 0x14;
+ buffer[1] = 0x00;
+ buffer[2] = 0x17;
+ buffer[3] = 0x00;
+ config &= ~0x40;
+ if (t->std & V4L2_STD_ATSC) {
+ config |= 0x40;
+ buffer[1] = 0x04;
+ }
+ /* set to the correct mode (analog or digital) */
+ tuneraddr = c->addr;
+ c->addr = 0x0a;
+ if (2 != (rc = i2c_master_send(c,&buffer[0],2)))
+ tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc);
+ if (2 != (rc = i2c_master_send(c,&buffer[2],2)))
+ tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc);
+ c->addr = tuneraddr;
+ /* FIXME: input */
+ break;
}
/*
@@ -404,7 +435,7 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
buffer[0],buffer[1],buffer[2],buffer[3]);
- if (4 != (rc = i2c_master_send(c,buffer,4)))
+ if (4 != (rc = i2c_master_send(c,buffer,4)))
tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
if (t->type == TUNER_MICROTUNE_4042FI5) {
@@ -443,7 +474,7 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
{
struct tunertype *tun;
struct tuner *t = i2c_get_clientdata(c);
- unsigned char buffer[4];
+ unsigned char buffer[4];
unsigned div;
int rc;
@@ -476,13 +507,13 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
buffer[3] = 0xa4;
break;
}
- buffer[0] = (div>>8) & 0x7f;
- buffer[1] = div & 0xff;
+ buffer[0] = (div>>8) & 0x7f;
+ buffer[1] = div & 0xff;
tuner_dbg("radio 0x%02x 0x%02x 0x%02x 0x%02x\n",
buffer[0],buffer[1],buffer[2],buffer[3]);
- if (4 != (rc = i2c_master_send(c,buffer,4)))
+ if (4 != (rc = i2c_master_send(c,buffer,4)))
tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
}
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index 1c31ef52f86..c31bf28b73f 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -31,7 +31,6 @@
#include <linux/smp_lock.h>
#include <media/audiochip.h>
-#include <media/id.h>
#include "tvaudio.h"
@@ -458,8 +457,8 @@ static void tda9840_setmode(struct CHIPSTATE *chip, int mode)
#define TDA9855_LOUD 1<<5 /* Loudness, 1==off */
#define TDA9855_SUR 1<<3 /* Surround / Subwoofer 1==.5(L-R) 0==.5(L+R) */
/* Bits 0 to 3 select various combinations
- * of line in and line out, only the
- * interesting ones are defined */
+ * of line in and line out, only the
+ * interesting ones are defined */
#define TDA9855_EXT 1<<2 /* Selects inputs LIR and LIL. Pins 41 & 12 */
#define TDA9855_INT 0 /* Selects inputs LOR and LOL. (internal) */
@@ -1028,7 +1027,7 @@ static int tda9874a_initialize(struct CHIPSTATE *chip)
#define TEA6300_TR 0x03 /* treble */
#define TEA6300_FA 0x04 /* fader control */
#define TEA6300_S 0x05 /* switch register */
- /* values for those registers: */
+ /* values for those registers: */
#define TEA6300_S_SA 0x01 /* stereo A input */
#define TEA6300_S_SB 0x02 /* stereo B */
#define TEA6300_S_SC 0x04 /* stereo C */
@@ -1042,7 +1041,7 @@ static int tda9874a_initialize(struct CHIPSTATE *chip)
#define TEA6320_BA 0x05 /* bass (0-4) */
#define TEA6320_TR 0x06 /* treble (0-4) */
#define TEA6320_S 0x07 /* switch register */
- /* values for those registers: */
+ /* values for those registers: */
#define TEA6320_S_SA 0x07 /* stereo A input */
#define TEA6320_S_SB 0x06 /* stereo B */
#define TEA6320_S_SC 0x05 /* stereo C */
@@ -1082,7 +1081,7 @@ static int tea6320_initialize(struct CHIPSTATE * chip)
#define TDA8425_BA 0x02 /* bass */
#define TDA8425_TR 0x03 /* treble */
#define TDA8425_S1 0x08 /* switch functions */
- /* values for those registers: */
+ /* values for those registers: */
#define TDA8425_S1_OFF 0xEE /* audio off (mute on) */
#define TDA8425_S1_CH1 0xCE /* audio channel 1 (mute off) - "linear stereo" mode */
#define TDA8425_S1_CH2 0xCF /* audio channel 2 (mute off) - "linear stereo" mode */
@@ -1148,7 +1147,7 @@ static void tda8425_setmode(struct CHIPSTATE *chip, int mode)
/* bit definition of the RESET register, I2C data. */
#define PIC16C54_MISC_RESET_REMOTE_CTL 0x01 /* bit 0, Reset to receive the key */
- /* code of remote controller */
+ /* code of remote controller */
#define PIC16C54_MISC_MTS_MAIN 0x02 /* bit 1 */
#define PIC16C54_MISC_MTS_SAP 0x04 /* bit 2 */
#define PIC16C54_MISC_MTS_BOTH 0x08 /* bit 3 */
@@ -1281,7 +1280,7 @@ static struct CHIPDESC chiplist[] = {
.setmode = tda9840_setmode,
.checkmode = generic_checkmode,
- .init = { 2, { TDA9840_TEST, TDA9840_TEST_INT1SN
+ .init = { 2, { TDA9840_TEST, TDA9840_TEST_INT1SN
/* ,TDA9840_SW, TDA9840_MONO */} }
},
{
@@ -1438,7 +1437,7 @@ static struct CHIPDESC chiplist[] = {
},
{
.name = "pic16c54 (PV951)",
- .id = I2C_DRIVERID_PIC16C54_PV951,
+ .id = I2C_DRIVERID_PIC16C54_PV9,
.insmodopt = &pic16c54,
.addr_lo = I2C_PIC16C54 >> 1,
.addr_hi = I2C_PIC16C54>> 1,
@@ -1467,7 +1466,7 @@ static struct CHIPDESC chiplist[] = {
.setmode = ta8874z_setmode,
.checkmode = generic_checkmode,
- .init = {2, { TA8874Z_MONO_SET, TA8874Z_SEPARATION_DEFAULT}},
+ .init = {2, { TA8874Z_MONO_SET, TA8874Z_SEPARATION_DEFAULT}},
},
{ .name = NULL } /* EOF */
};
@@ -1486,8 +1485,8 @@ static int chip_attach(struct i2c_adapter *adap, int addr, int kind)
return -ENOMEM;
memset(chip,0,sizeof(*chip));
memcpy(&chip->c,&client_template,sizeof(struct i2c_client));
- chip->c.adapter = adap;
- chip->c.addr = addr;
+ chip->c.adapter = adap;
+ chip->c.addr = addr;
i2c_set_clientdata(&chip->c, chip);
/* find description for the chip */
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
index 5344d559219..72e8741e8b5 100644
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/video/tveeprom.c
@@ -6,12 +6,12 @@
* which are:
Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
- & Marcus Metzler (mocm@thp.uni-koeln.de)
+ & Marcus Metzler (mocm@thp.uni-koeln.de)
(c) 1999-2001 Gerd Knorr <kraxel@goldbach.in-berlin.de>
* Adjustments to fit a more general model and all bugs:
- Copyright (C) 2003 John Klar <linpvr at projectplasma.com>
+ Copyright (C) 2003 John Klar <linpvr at projectplasma.com>
* 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
@@ -40,6 +40,7 @@
#include <media/tuner.h>
#include <media/tveeprom.h>
+#include <media/audiochip.h>
MODULE_DESCRIPTION("i2c Hauppauge eeprom decoder driver");
MODULE_AUTHOR("John Klar");
@@ -53,14 +54,14 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
#define tveeprom_info(fmt, arg...) do {\
printk(KERN_INFO "tveeprom %d-%04x: " fmt, \
- c->adapter->nr, c->addr , ##arg); } while (0)
+ c->adapter->nr, c->addr , ##arg); } while (0)
#define tveeprom_warn(fmt, arg...) do {\
printk(KERN_WARNING "tveeprom %d-%04x: " fmt, \
- c->adapter->nr, c->addr , ##arg); } while (0)
+ c->adapter->nr, c->addr , ##arg); } while (0)
#define tveeprom_dbg(fmt, arg...) do {\
if (debug) \
- printk(KERN_INFO "tveeprom %d-%04x: " fmt, \
- c->adapter->nr, c->addr , ##arg); } while (0)
+ printk(KERN_INFO "tveeprom %d-%04x: " fmt, \
+ c->adapter->nr, c->addr , ##arg); } while (0)
/* ----------------------------------------------------------------------- */
@@ -134,8 +135,8 @@ hauppauge_tuner[] =
{ TUNER_TEMIC_4039FR5_NTSC, "Temic 4039FR5" },
{ TUNER_PHILIPS_FQ1216ME, "Philips FQ1216 ME" },
{ TUNER_TEMIC_4066FY5_PAL_I, "Temic 4066FY5" },
- { TUNER_PHILIPS_NTSC, "Philips TD1536" },
- { TUNER_PHILIPS_NTSC, "Philips TD1536D" },
+ { TUNER_PHILIPS_NTSC, "Philips TD1536" },
+ { TUNER_PHILIPS_NTSC, "Philips TD1536D" },
{ TUNER_PHILIPS_NTSC, "Philips FMR1236" }, /* mono radio */
{ TUNER_ABSENT, "Philips FI1256MP" },
/* 40-49 */
@@ -189,7 +190,7 @@ hauppauge_tuner[] =
{ TUNER_LG_PAL_NEW_TAPC, "TCL 2002MB 3"},
{ TUNER_LG_PAL_NEW_TAPC, "TCL 2002MI 3"},
{ TUNER_TCL_2002N, "TCL 2002N 6A"},
- { TUNER_ABSENT, "Philips FQ1236 MK3"},
+ { TUNER_PHILIPS_FM1236_MK3, "Philips FQ1236 MK3"},
{ TUNER_ABSENT, "Samsung TCPN 2121P30A"},
{ TUNER_ABSENT, "Samsung TCPE 4121P30A"},
{ TUNER_PHILIPS_FM1216ME_MK3, "TCL MFPE05 2"},
@@ -200,95 +201,137 @@ hauppauge_tuner[] =
{ TUNER_ABSENT, "Philips FQ1286A MK4"},
{ TUNER_ABSENT, "Philips FQ1216ME MK5"},
{ TUNER_ABSENT, "Philips FQ1236 MK5"},
- { TUNER_ABSENT, "Unspecified"},
- { TUNER_LG_PAL_TAPE, "LG PAL (TAPE Series)"},
- { TUNER_ABSENT, "Unspecified"},
- { TUNER_TCL_2002N, "TCL 2002N 5H"},
- /* 100-103 */
- { TUNER_ABSENT, "Unspecified"},
- { TUNER_TEA5767, "Philips TEA5767HN FM Radio"},
- { TUNER_ABSENT, "Unspecified"},
- { TUNER_PHILIPS_FM1236_MK3, "TCL MFNM05 4"},
+ { TUNER_ABSENT, "Samsung TCPG_6121P30A"},
+ { TUNER_TCL_2002MB, "TCL 2002MB_3H"},
+ { TUNER_ABSENT, "TCL 2002MI_3H"},
+ { TUNER_TCL_2002N, "TCL 2002N 5H"},
+ /* 100-109 */
+ { TUNER_ABSENT, "Philips FMD1216ME"},
+ { TUNER_TEA5767, "Philips TEA5768HL FM Radio"},
+ { TUNER_ABSENT, "Panasonic ENV57H12D5"},
+ { TUNER_ABSENT, "TCL MFNM05-4"},
+ { TUNER_ABSENT, "TCL MNM05-4"},
+ { TUNER_PHILIPS_FM1216ME_MK3, "TCL MPE05-2"},
+ { TUNER_ABSENT, "TCL MQNM05-4"},
+ { TUNER_ABSENT, "LG TAPC-W701D"},
+ { TUNER_ABSENT, "TCL 9886P-WM"},
+ { TUNER_ABSENT, "TCL 1676NM-WM"},
};
-/* This list is supplied by Hauppauge. Thanks! */
-static const char *audioIC[] = {
- /* 0-4 */
- "None", "TEA6300", "TEA6320", "TDA9850", "MSP3400C",
- /* 5-9 */
- "MSP3410D", "MSP3415", "MSP3430", "MSP3438", "CS5331",
- /* 10-14 */
- "MSP3435", "MSP3440", "MSP3445", "MSP3411", "MSP3416",
- /* 15-19 */
- "MSP3425", "MSP3451", "MSP3418", "Type 0x12", "OKI7716",
- /* 20-24 */
- "MSP4410", "MSP4420", "MSP4440", "MSP4450", "MSP4408",
- /* 25-29 */
- "MSP4418", "MSP4428", "MSP4448", "MSP4458", "Type 0x1d",
- /* 30-34 */
- "CX880", "CX881", "CX883", "CX882", "CX25840",
- /* 35-38 */
- "CX25841", "CX25842", "CX25843", "CX23418",
+static struct HAUPPAUGE_AUDIOIC
+{
+ enum audiochip id;
+ char *name;
+}
+audioIC[] =
+{
+ /* 0-4 */
+ {AUDIO_CHIP_NONE, "None"},
+ {AUDIO_CHIP_TEA6300, "TEA6300"},
+ {AUDIO_CHIP_TEA6300, "TEA6320"},
+ {AUDIO_CHIP_TDA985X, "TDA9850"},
+ {AUDIO_CHIP_MSP34XX, "MSP3400C"},
+ /* 5-9 */
+ {AUDIO_CHIP_MSP34XX, "MSP3410D"},
+ {AUDIO_CHIP_MSP34XX, "MSP3415"},
+ {AUDIO_CHIP_MSP34XX, "MSP3430"},
+ {AUDIO_CHIP_UNKNOWN, "MSP3438"},
+ {AUDIO_CHIP_UNKNOWN, "CS5331"},
+ /* 10-14 */
+ {AUDIO_CHIP_MSP34XX, "MSP3435"},
+ {AUDIO_CHIP_MSP34XX, "MSP3440"},
+ {AUDIO_CHIP_MSP34XX, "MSP3445"},
+ {AUDIO_CHIP_UNKNOWN, "MSP3411"},
+ {AUDIO_CHIP_UNKNOWN, "MSP3416"},
+ /* 15-19 */
+ {AUDIO_CHIP_MSP34XX, "MSP3425"},
+ {AUDIO_CHIP_UNKNOWN, "MSP3451"},
+ {AUDIO_CHIP_UNKNOWN, "MSP3418"},
+ {AUDIO_CHIP_UNKNOWN, "Type 0x12"},
+ {AUDIO_CHIP_UNKNOWN, "OKI7716"},
+ /* 20-24 */
+ {AUDIO_CHIP_UNKNOWN, "MSP4410"},
+ {AUDIO_CHIP_UNKNOWN, "MSP4420"},
+ {AUDIO_CHIP_UNKNOWN, "MSP4440"},
+ {AUDIO_CHIP_UNKNOWN, "MSP4450"},
+ {AUDIO_CHIP_UNKNOWN, "MSP4408"},
+ /* 25-29 */
+ {AUDIO_CHIP_UNKNOWN, "MSP4418"},
+ {AUDIO_CHIP_UNKNOWN, "MSP4428"},
+ {AUDIO_CHIP_UNKNOWN, "MSP4448"},
+ {AUDIO_CHIP_UNKNOWN, "MSP4458"},
+ {AUDIO_CHIP_UNKNOWN, "Type 0x1d"},
+ /* 30-34 */
+ {AUDIO_CHIP_INTERNAL, "CX880"},
+ {AUDIO_CHIP_INTERNAL, "CX881"},
+ {AUDIO_CHIP_INTERNAL, "CX883"},
+ {AUDIO_CHIP_INTERNAL, "CX882"},
+ {AUDIO_CHIP_INTERNAL, "CX25840"},
+ /* 35-38 */
+ {AUDIO_CHIP_INTERNAL, "CX25841"},
+ {AUDIO_CHIP_INTERNAL, "CX25842"},
+ {AUDIO_CHIP_INTERNAL, "CX25843"},
+ {AUDIO_CHIP_INTERNAL, "CX23418"},
};
/* This list is supplied by Hauppauge. Thanks! */
static const char *decoderIC[] = {
- /* 0-4 */
- "None", "BT815", "BT817", "BT819", "BT815A",
- /* 5-9 */
- "BT817A", "BT819A", "BT827", "BT829", "BT848",
- /* 10-14 */
- "BT848A", "BT849A", "BT829A", "BT827A", "BT878",
- /* 15-19 */
- "BT879", "BT880", "VPX3226E", "SAA7114", "SAA7115",
- /* 20-24 */
- "CX880", "CX881", "CX883", "SAA7111", "SAA7113",
- /* 25-29 */
- "CX882", "TVP5150A", "CX25840", "CX25841", "CX25842",
- /* 30-31 */
- "CX25843", "CX23418",
+ /* 0-4 */
+ "None", "BT815", "BT817", "BT819", "BT815A",
+ /* 5-9 */
+ "BT817A", "BT819A", "BT827", "BT829", "BT848",
+ /* 10-14 */
+ "BT848A", "BT849A", "BT829A", "BT827A", "BT878",
+ /* 15-19 */
+ "BT879", "BT880", "VPX3226E", "SAA7114", "SAA7115",
+ /* 20-24 */
+ "CX880", "CX881", "CX883", "SAA7111", "SAA7113",
+ /* 25-29 */
+ "CX882", "TVP5150A", "CX25840", "CX25841", "CX25842",
+ /* 30-31 */
+ "CX25843", "CX23418",
};
static int hasRadioTuner(int tunerType)
{
- switch (tunerType) {
- case 18: //PNPEnv_TUNER_FR1236_MK2:
- case 23: //PNPEnv_TUNER_FM1236:
- case 38: //PNPEnv_TUNER_FMR1236:
- case 16: //PNPEnv_TUNER_FR1216_MK2:
- case 19: //PNPEnv_TUNER_FR1246_MK2:
- case 21: //PNPEnv_TUNER_FM1216:
- case 24: //PNPEnv_TUNER_FM1246:
- case 17: //PNPEnv_TUNER_FR1216MF_MK2:
- case 22: //PNPEnv_TUNER_FM1216MF:
- case 20: //PNPEnv_TUNER_FR1256_MK2:
- case 25: //PNPEnv_TUNER_FM1256:
- case 33: //PNPEnv_TUNER_4039FR5:
- case 42: //PNPEnv_TUNER_4009FR5:
- case 52: //PNPEnv_TUNER_4049FM5:
- case 54: //PNPEnv_TUNER_4049FM5_AltI2C:
- case 44: //PNPEnv_TUNER_4009FN5:
- case 31: //PNPEnv_TUNER_TCPB9085P:
- case 30: //PNPEnv_TUNER_TCPN9085D:
- case 46: //PNPEnv_TUNER_TP18NSR01F:
- case 47: //PNPEnv_TUNER_TP18PSB01D:
- case 49: //PNPEnv_TUNER_TAPC_I001D:
- case 60: //PNPEnv_TUNER_TAPE_S001D_MK3:
- case 57: //PNPEnv_TUNER_FM1216ME_MK3:
- case 59: //PNPEnv_TUNER_FM1216MP_MK3:
- case 58: //PNPEnv_TUNER_FM1236_MK3:
- case 68: //PNPEnv_TUNER_TAPE_H001F_MK3:
- case 61: //PNPEnv_TUNER_TAPE_M001D_MK3:
- case 78: //PNPEnv_TUNER_TDA8275C1_8290_FM:
- case 89: //PNPEnv_TUNER_TCL_MFPE05_2:
- case 92: //PNPEnv_TUNER_PHILIPS_FQ1236A_MK4:
- return 1;
- }
- return 0;
+ switch (tunerType) {
+ case 18: //PNPEnv_TUNER_FR1236_MK2:
+ case 23: //PNPEnv_TUNER_FM1236:
+ case 38: //PNPEnv_TUNER_FMR1236:
+ case 16: //PNPEnv_TUNER_FR1216_MK2:
+ case 19: //PNPEnv_TUNER_FR1246_MK2:
+ case 21: //PNPEnv_TUNER_FM1216:
+ case 24: //PNPEnv_TUNER_FM1246:
+ case 17: //PNPEnv_TUNER_FR1216MF_MK2:
+ case 22: //PNPEnv_TUNER_FM1216MF:
+ case 20: //PNPEnv_TUNER_FR1256_MK2:
+ case 25: //PNPEnv_TUNER_FM1256:
+ case 33: //PNPEnv_TUNER_4039FR5:
+ case 42: //PNPEnv_TUNER_4009FR5:
+ case 52: //PNPEnv_TUNER_4049FM5:
+ case 54: //PNPEnv_TUNER_4049FM5_AltI2C:
+ case 44: //PNPEnv_TUNER_4009FN5:
+ case 31: //PNPEnv_TUNER_TCPB9085P:
+ case 30: //PNPEnv_TUNER_TCPN9085D:
+ case 46: //PNPEnv_TUNER_TP18NSR01F:
+ case 47: //PNPEnv_TUNER_TP18PSB01D:
+ case 49: //PNPEnv_TUNER_TAPC_I001D:
+ case 60: //PNPEnv_TUNER_TAPE_S001D_MK3:
+ case 57: //PNPEnv_TUNER_FM1216ME_MK3:
+ case 59: //PNPEnv_TUNER_FM1216MP_MK3:
+ case 58: //PNPEnv_TUNER_FM1236_MK3:
+ case 68: //PNPEnv_TUNER_TAPE_H001F_MK3:
+ case 61: //PNPEnv_TUNER_TAPE_M001D_MK3:
+ case 78: //PNPEnv_TUNER_TDA8275C1_8290_FM:
+ case 89: //PNPEnv_TUNER_TCL_MFPE05_2:
+ case 92: //PNPEnv_TUNER_PHILIPS_FQ1236A_MK4:
+ return 1;
+ }
+ return 0;
}
void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
- unsigned char *eeprom_data)
+ unsigned char *eeprom_data)
{
/* ----------------------------------------------
** The hauppauge eeprom format is tagged
@@ -312,19 +355,27 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
** # of inputs/outputs ???
*/
- int i, j, len, done, beenhere, tag;
+ int i, j, len, done, beenhere, tag,start;
- int tuner1 = 0, t_format1 = 0;
+ int tuner1 = 0, t_format1 = 0, audioic=-1;
char *t_name1 = NULL;
- const char *t_fmt_name1[8] = { " none", "", "", "", "", "", "", "" };
+ const char *t_fmt_name1[8] = { " none", "", "", "", "", "", "", "" };
- int tuner2 = 0, t_format2 = 0;
+ int tuner2 = 0, t_format2 = 0;
char *t_name2 = NULL;
- const char *t_fmt_name2[8] = { " none", "", "", "", "", "", "", "" };
+ const char *t_fmt_name2[8] = { " none", "", "", "", "", "", "", "" };
- memset(tvee, 0, sizeof(*tvee));
+ memset(tvee, 0, sizeof(*tvee));
done = len = beenhere = 0;
- for (i = 0; !done && i < 256; i += len) {
+
+ /* Hack for processing eeprom for em28xx */
+ if ((eeprom_data[0]==0x1a)&&(eeprom_data[1]==0xeb)&&
+ (eeprom_data[2]==0x67)&&(eeprom_data[3]==0x95))
+ start=0xa0;
+ else
+ start=0;
+
+ for (i = start; !done && i < 256; i += len) {
if (eeprom_data[i] == 0x84) {
len = eeprom_data[i + 1] + (eeprom_data[i + 2] << 8);
i += 3;
@@ -338,28 +389,28 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
++i;
} else {
tveeprom_warn("Encountered bad packet header [%02x]. "
- "Corrupt or not a Hauppauge eeprom.\n", eeprom_data[i]);
+ "Corrupt or not a Hauppauge eeprom.\n", eeprom_data[i]);
return;
}
- if (debug) {
- tveeprom_info("Tag [%02x] + %d bytes:", eeprom_data[i], len - 1);
- for(j = 1; j < len; j++) {
- printk(" %02x", eeprom_data[i + j]);
- }
- printk("\n");
- }
+ if (debug) {
+ tveeprom_info("Tag [%02x] + %d bytes:", eeprom_data[i], len - 1);
+ for(j = 1; j < len; j++) {
+ printk(" %02x", eeprom_data[i + j]);
+ }
+ printk("\n");
+ }
/* process by tag */
tag = eeprom_data[i];
switch (tag) {
case 0x00:
- /* tag: 'Comprehensive' */
+ /* tag: 'Comprehensive' */
tuner1 = eeprom_data[i+6];
t_format1 = eeprom_data[i+5];
tvee->has_radio = eeprom_data[i+len-1];
- /* old style tag, don't know how to detect
- IR presence, mark as unknown. */
+ /* old style tag, don't know how to detect
+ IR presence, mark as unknown. */
tvee->has_ir = 2;
tvee->model =
eeprom_data[i+8] +
@@ -370,7 +421,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
break;
case 0x01:
- /* tag: 'SerialID' */
+ /* tag: 'SerialID' */
tvee->serial_number =
eeprom_data[i+6] +
(eeprom_data[i+7] << 8) +
@@ -378,17 +429,21 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
break;
case 0x02:
- /* tag 'AudioInfo'
- Note mask with 0x7F, high bit used on some older models
- to indicate 4052 mux was removed in favor of using MSP
- inputs directly. */
- tvee->audio_processor = eeprom_data[i+2] & 0x7f;
+ /* tag 'AudioInfo'
+ Note mask with 0x7F, high bit used on some older models
+ to indicate 4052 mux was removed in favor of using MSP
+ inputs directly. */
+ audioic = eeprom_data[i+2] & 0x7f;
+ if (audioic < sizeof(audioIC)/sizeof(*audioIC))
+ tvee->audio_processor = audioIC[audioic].id;
+ else
+ tvee->audio_processor = AUDIO_CHIP_UNKNOWN;
break;
- /* case 0x03: tag 'EEInfo' */
+ /* case 0x03: tag 'EEInfo' */
case 0x04:
- /* tag 'SerialID2' */
+ /* tag 'SerialID2' */
tvee->serial_number =
eeprom_data[i+5] +
(eeprom_data[i+6] << 8) +
@@ -396,15 +451,20 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
break;
case 0x05:
- /* tag 'Audio2'
- Note mask with 0x7F, high bit used on some older models
- to indicate 4052 mux was removed in favor of using MSP
- inputs directly. */
- tvee->audio_processor = eeprom_data[i+1] & 0x7f;
+ /* tag 'Audio2'
+ Note mask with 0x7F, high bit used on some older models
+ to indicate 4052 mux was removed in favor of using MSP
+ inputs directly. */
+ audioic = eeprom_data[i+1] & 0x7f;
+ if (audioic < sizeof(audioIC)/sizeof(*audioIC))
+ tvee->audio_processor = audioIC[audioic].id;
+ else
+ tvee->audio_processor = AUDIO_CHIP_UNKNOWN;
+
break;
case 0x06:
- /* tag 'ModelRev' */
+ /* tag 'ModelRev' */
tvee->model =
eeprom_data[i+1] +
(eeprom_data[i+2] << 8);
@@ -414,55 +474,55 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
break;
case 0x07:
- /* tag 'Details': according to Hauppauge not interesting
- on any PCI-era or later boards. */
+ /* tag 'Details': according to Hauppauge not interesting
+ on any PCI-era or later boards. */
break;
- /* there is no tag 0x08 defined */
+ /* there is no tag 0x08 defined */
case 0x09:
- /* tag 'Video' */
+ /* tag 'Video' */
tvee->decoder_processor = eeprom_data[i + 1];
break;
case 0x0a:
- /* tag 'Tuner' */
+ /* tag 'Tuner' */
if (beenhere == 0) {
tuner1 = eeprom_data[i+2];
t_format1 = eeprom_data[i+1];
beenhere = 1;
} else {
- /* a second (radio) tuner may be present */
+ /* a second (radio) tuner may be present */
tuner2 = eeprom_data[i+2];
t_format2 = eeprom_data[i+1];
- if (t_format2 == 0) { /* not a TV tuner? */
- tvee->has_radio = 1; /* must be radio */
- }
- }
+ if (t_format2 == 0) { /* not a TV tuner? */
+ tvee->has_radio = 1; /* must be radio */
+ }
+ }
break;
- case 0x0b:
- /* tag 'Inputs': according to Hauppauge this is specific
- to each driver family, so no good assumptions can be
- made. */
- break;
+ case 0x0b:
+ /* tag 'Inputs': according to Hauppauge this is specific
+ to each driver family, so no good assumptions can be
+ made. */
+ break;
- /* case 0x0c: tag 'Balun' */
- /* case 0x0d: tag 'Teletext' */
+ /* case 0x0c: tag 'Balun' */
+ /* case 0x0d: tag 'Teletext' */
case 0x0e:
- /* tag: 'Radio' */
+ /* tag: 'Radio' */
tvee->has_radio = eeprom_data[i+1];
break;
- case 0x0f:
- /* tag 'IRInfo' */
- tvee->has_ir = eeprom_data[i+1];
- break;
+ case 0x0f:
+ /* tag 'IRInfo' */
+ tvee->has_ir = eeprom_data[i+1];
+ break;
- /* case 0x10: tag 'VBIInfo' */
- /* case 0x11: tag 'QCInfo' */
- /* case 0x12: tag 'InfoBits' */
+ /* case 0x10: tag 'VBIInfo' */
+ /* case 0x11: tag 'QCInfo' */
+ /* case 0x12: tag 'InfoBits' */
default:
tveeprom_dbg("Not sure what to do with tag [%02x]\n", tag);
@@ -483,11 +543,11 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
tvee->rev_str[4] = 0;
}
- if (hasRadioTuner(tuner1) && !tvee->has_radio) {
- tveeprom_info("The eeprom says no radio is present, but the tuner type\n");
- tveeprom_info("indicates otherwise. I will assume that radio is present.\n");
- tvee->has_radio = 1;
- }
+ if (hasRadioTuner(tuner1) && !tvee->has_radio) {
+ tveeprom_info("The eeprom says no radio is present, but the tuner type\n");
+ tveeprom_info("indicates otherwise. I will assume that radio is present.\n");
+ tvee->has_radio = 1;
+ }
if (tuner1 < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) {
tvee->tuner_type = hauppauge_tuner[tuner1].id;
@@ -510,45 +570,53 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
tvee->tuner_formats |= hauppauge_tuner_fmt[i].id;
t_fmt_name1[j++] = hauppauge_tuner_fmt[i].name;
}
- if (t_format2 & (1 << i)) {
- tvee->tuner2_formats |= hauppauge_tuner_fmt[i].id;
- t_fmt_name2[j++] = hauppauge_tuner_fmt[i].name;
- }
+ if (t_format2 & (1 << i)) {
+ tvee->tuner2_formats |= hauppauge_tuner_fmt[i].id;
+ t_fmt_name2[j++] = hauppauge_tuner_fmt[i].name;
+ }
}
tveeprom_info("Hauppauge model %d, rev %s, serial# %d\n",
- tvee->model, tvee->rev_str, tvee->serial_number);
+ tvee->model, tvee->rev_str, tvee->serial_number);
tveeprom_info("tuner model is %s (idx %d, type %d)\n",
- t_name1, tuner1, tvee->tuner_type);
+ t_name1, tuner1, tvee->tuner_type);
tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n",
- t_fmt_name1[0], t_fmt_name1[1], t_fmt_name1[2], t_fmt_name1[3],
- t_fmt_name1[4], t_fmt_name1[5], t_fmt_name1[6], t_fmt_name1[7],
- t_format1);
- if (tuner2) {
- tveeprom_info("second tuner model is %s (idx %d, type %d)\n",
- t_name2, tuner2, tvee->tuner2_type);
- }
- if (t_format2) {
- tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n",
- t_fmt_name2[0], t_fmt_name2[1], t_fmt_name2[2], t_fmt_name2[3],
- t_fmt_name2[4], t_fmt_name2[5], t_fmt_name2[6], t_fmt_name2[7],
- t_format2);
- }
- tveeprom_info("audio processor is %s (idx %d)\n",
- STRM(audioIC, tvee->audio_processor),
- tvee->audio_processor);
- if (tvee->decoder_processor) {
- tveeprom_info("decoder processor is %s (idx %d)\n",
- STRM(decoderIC, tvee->decoder_processor),
- tvee->decoder_processor);
- }
- if (tvee->has_ir == 2)
- tveeprom_info("has %sradio\n",
- tvee->has_radio ? "" : "no ");
- else
- tveeprom_info("has %sradio, has %sIR remote\n",
- tvee->has_radio ? "" : "no ",
- tvee->has_ir ? "" : "no ");
+ t_fmt_name1[0], t_fmt_name1[1], t_fmt_name1[2], t_fmt_name1[3],
+ t_fmt_name1[4], t_fmt_name1[5], t_fmt_name1[6], t_fmt_name1[7],
+ t_format1);
+ if (tuner2) {
+ tveeprom_info("second tuner model is %s (idx %d, type %d)\n",
+ t_name2, tuner2, tvee->tuner2_type);
+ }
+ if (t_format2) {
+ tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n",
+ t_fmt_name2[0], t_fmt_name2[1], t_fmt_name2[2], t_fmt_name2[3],
+ t_fmt_name2[4], t_fmt_name2[5], t_fmt_name2[6], t_fmt_name2[7],
+ t_format2);
+ }
+ if (audioic<0) {
+ tveeprom_info("audio processor is unknown (no idx)\n");
+ tvee->audio_processor=AUDIO_CHIP_UNKNOWN;
+ } else {
+ if (audioic < sizeof(audioIC)/sizeof(*audioIC))
+ tveeprom_info("audio processor is %s (idx %d)\n",
+ audioIC[audioic].name,audioic);
+ else
+ tveeprom_info("audio processor is unknown (idx %d)\n",
+ audioic);
+ }
+ if (tvee->decoder_processor) {
+ tveeprom_info("decoder processor is %s (idx %d)\n",
+ STRM(decoderIC, tvee->decoder_processor),
+ tvee->decoder_processor);
+ }
+ if (tvee->has_ir == 2)
+ tveeprom_info("has %sradio\n",
+ tvee->has_radio ? "" : "no ");
+ else
+ tveeprom_info("has %sradio, has %sIR remote\n",
+ tvee->has_radio ? "" : "no ",
+ tvee->has_ir ? "" : "no ");
}
EXPORT_SYMBOL(tveeprom_hauppauge_analog);
@@ -569,18 +637,18 @@ int tveeprom_read(struct i2c_client *c, unsigned char *eedata, int len)
tveeprom_warn("i2c eeprom read error (err=%d)\n", err);
return -1;
}
- if (debug) {
- int i;
-
- tveeprom_info("full 256-byte eeprom dump:\n");
- for (i = 0; i < len; i++) {
- if (0 == (i % 16))
- tveeprom_info("%02x:", i);
- printk(" %02x", eedata[i]);
- if (15 == (i % 16))
- printk("\n");
- }
- }
+ if (debug) {
+ int i;
+
+ tveeprom_info("full 256-byte eeprom dump:\n");
+ for (i = 0; i < len; i++) {
+ if (0 == (i % 16))
+ tveeprom_info("%02x:", i);
+ printk(" %02x", eedata[i]);
+ if (15 == (i % 16))
+ printk("\n");
+ }
+ }
return 0;
}
EXPORT_SYMBOL(tveeprom_read);
@@ -590,10 +658,6 @@ EXPORT_SYMBOL(tveeprom_read);
/* run, just call the exported tveeprom_* directly, there is no point in */
/* using the indirect way via i2c_driver->command() */
-#ifndef I2C_DRIVERID_TVEEPROM
-# define I2C_DRIVERID_TVEEPROM I2C_DRIVERID_EXP2
-#endif
-
static unsigned short normal_i2c[] = {
0xa0 >> 1,
I2C_CLIENT_END,
diff --git a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c
index d86e08ebddf..8318bd1aad0 100644
--- a/drivers/media/video/tvmixer.c
+++ b/drivers/media/video/tvmixer.c
@@ -79,7 +79,7 @@ static int tvmixer_ioctl(struct inode *inode, struct file *file, unsigned int cm
{
struct video_audio va;
int left,right,ret,val = 0;
- struct TVMIXER *mix = file->private_data;
+ struct TVMIXER *mix = file->private_data;
struct i2c_client *client = mix->dev;
void __user *argp = (void __user *)arg;
int __user *p = argp;
@@ -87,25 +87,25 @@ static int tvmixer_ioctl(struct inode *inode, struct file *file, unsigned int cm
if (NULL == client)
return -ENODEV;
- if (cmd == SOUND_MIXER_INFO) {
- mixer_info info;
- strlcpy(info.id, "tv card", sizeof(info.id));
- strlcpy(info.name, client->name, sizeof(info.name));
- info.modify_counter = 42 /* FIXME */;
- if (copy_to_user(argp, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == SOUND_OLD_MIXER_INFO) {
- _old_mixer_info info;
- strlcpy(info.id, "tv card", sizeof(info.id));
- strlcpy(info.name, client->name, sizeof(info.name));
- if (copy_to_user(argp, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == OSS_GETVERSION)
- return put_user(SOUND_VERSION, p);
+ if (cmd == SOUND_MIXER_INFO) {
+ mixer_info info;
+ strlcpy(info.id, "tv card", sizeof(info.id));
+ strlcpy(info.name, client->name, sizeof(info.name));
+ info.modify_counter = 42 /* FIXME */;
+ if (copy_to_user(argp, &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
+ }
+ if (cmd == SOUND_OLD_MIXER_INFO) {
+ _old_mixer_info info;
+ strlcpy(info.id, "tv card", sizeof(info.id));
+ strlcpy(info.name, client->name, sizeof(info.name));
+ if (copy_to_user(argp, &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
+ }
+ if (cmd == OSS_GETVERSION)
+ return put_user(SOUND_VERSION, p);
if (_SIOC_DIR(cmd) & _SIOC_WRITE)
if (get_user(val, p))
@@ -181,8 +181,8 @@ static int tvmixer_ioctl(struct inode *inode, struct file *file, unsigned int cm
static int tvmixer_open(struct inode *inode, struct file *file)
{
- int i, minor = iminor(inode);
- struct TVMIXER *mix = NULL;
+ int i, minor = iminor(inode);
+ struct TVMIXER *mix = NULL;
struct i2c_client *client = NULL;
for (i = 0; i < DEV_MAX; i++) {
@@ -204,7 +204,7 @@ static int tvmixer_open(struct inode *inode, struct file *file)
#endif
if (client->adapter->owner)
try_module_get(client->adapter->owner);
- return 0;
+ return 0;
}
static int tvmixer_release(struct inode *inode, struct file *file)
@@ -231,15 +231,15 @@ static struct i2c_driver driver = {
.owner = THIS_MODULE,
#endif
.name = "tv card mixer driver",
- .id = I2C_DRIVERID_TVMIXER,
+ .id = I2C_DRIVERID_TVMIXER,
#ifdef I2C_DF_DUMMY
.flags = I2C_DF_DUMMY,
#else
.flags = I2C_DF_NOTIFY,
- .detach_adapter = tvmixer_adapters,
+ .detach_adapter = tvmixer_adapters,
#endif
- .attach_adapter = tvmixer_adapters,
- .detach_client = tvmixer_clients,
+ .attach_adapter = tvmixer_adapters,
+ .detach_client = tvmixer_clients,
};
static struct file_operations tvmixer_fops = {
diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c
new file mode 100644
index 00000000000..81e6d4494e7
--- /dev/null
+++ b/drivers/media/video/tvp5150.c
@@ -0,0 +1,829 @@
+/*
+ * tvp5150 - Texas Instruments TVP5150A(M) video decoder driver
+ *
+ * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@brturbo.com.br)
+ * This code is placed under the terms of the GNU General Public License
+ */
+
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <linux/delay.h>
+#include <linux/video_decoder.h>
+
+#include "tvp5150_reg.h"
+
+MODULE_DESCRIPTION("Texas Instruments TVP5150A video decoder driver"); /* standard i2c insmod options */
+MODULE_AUTHOR("Mauro Carvalho Chehab");
+MODULE_LICENSE("GPL");
+
+static unsigned short normal_i2c[] = {
+ 0xb8 >> 1,
+ 0xba >> 1,
+ I2C_CLIENT_END
+};
+
+I2C_CLIENT_INSMOD;
+
+static int debug = 0;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+#define dprintk(num, format, args...) \
+ do { \
+ if (debug >= num) \
+ printk(format , ##args); \
+ } while (0)
+
+/* supported controls */
+static struct v4l2_queryctrl tvp5150_qctrl[] = {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 0,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 0x1,
+ .default_value = 0x10,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 0x1,
+ .default_value = 0x10,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_HUE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hue",
+ .minimum = -128,
+ .maximum = 127,
+ .step = 0x1,
+ .default_value = 0x10,
+ .flags = 0,
+ }
+};
+
+struct tvp5150 {
+ struct i2c_client *client;
+
+ int norm;
+ int input;
+ int enable;
+ int bright;
+ int contrast;
+ int hue;
+ int sat;
+};
+
+static inline int tvp5150_read(struct i2c_client *c, unsigned char addr)
+{
+ unsigned char buffer[1];
+ int rc;
+
+ buffer[0] = addr;
+ if (1 != (rc = i2c_master_send(c, buffer, 1)))
+ dprintk(0, "i2c i/o error: rc == %d (should be 1)\n", rc);
+
+ msleep(10);
+
+ if (1 != (rc = i2c_master_recv(c, buffer, 1)))
+ dprintk(0, "i2c i/o error: rc == %d (should be 1)\n", rc);
+
+ return (buffer[0]);
+}
+
+static inline void tvp5150_write(struct i2c_client *c, unsigned char addr,
+ unsigned char value)
+{
+ unsigned char buffer[2];
+ int rc;
+/* struct tvp5150 *core = i2c_get_clientdata(c); */
+
+ buffer[0] = addr;
+ buffer[1] = value;
+ dprintk(1, "tvp5150: writing 0x%02x 0x%02x\n", buffer[0], buffer[1]);
+ if (2 != (rc = i2c_master_send(c, buffer, 2)))
+ dprintk(0, "i2c i/o error: rc == %d (should be 2)\n", rc);
+}
+
+static void dump_reg(struct i2c_client *c)
+{
+ printk("tvp5150: Video input source selection #1 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VD_IN_SRC_SEL_1));
+ printk("tvp5150: Analog channel controls = 0x%02x\n",
+ tvp5150_read(c, TVP5150_ANAL_CHL_CTL));
+ printk("tvp5150: Operation mode controls = 0x%02x\n",
+ tvp5150_read(c, TVP5150_OP_MODE_CTL));
+ printk("tvp5150: Miscellaneous controls = 0x%02x\n",
+ tvp5150_read(c, TVP5150_MISC_CTL));
+ printk("tvp5150: Autoswitch mask: TVP5150A / TVP5150AM = 0x%02x\n",
+ tvp5150_read(c, TVP5150_AUTOSW_MSK));
+ printk("tvp5150: Color killer threshold control = 0x%02x\n",
+ tvp5150_read(c, TVP5150_COLOR_KIL_THSH_CTL));
+ printk("tvp5150: Luminance processing control #1 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LUMA_PROC_CTL_1));
+ printk("tvp5150: Luminance processing control #2 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LUMA_PROC_CTL_2));
+ printk("tvp5150: Brightness control = 0x%02x\n",
+ tvp5150_read(c, TVP5150_BRIGHT_CTL));
+ printk("tvp5150: Color saturation control = 0x%02x\n",
+ tvp5150_read(c, TVP5150_SATURATION_CTL));
+ printk("tvp5150: Hue control = 0x%02x\n",
+ tvp5150_read(c, TVP5150_HUE_CTL));
+ printk("tvp5150: Contrast control = 0x%02x\n",
+ tvp5150_read(c, TVP5150_CONTRAST_CTL));
+ printk("tvp5150: Outputs and data rates select = 0x%02x\n",
+ tvp5150_read(c, TVP5150_DATA_RATE_SEL));
+ printk("tvp5150: Luminance processing control #3 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LUMA_PROC_CTL_3));
+ printk("tvp5150: Configuration shared pins = 0x%02x\n",
+ tvp5150_read(c, TVP5150_CONF_SHARED_PIN));
+ printk("tvp5150: Active video cropping start MSB = 0x%02x\n",
+ tvp5150_read(c, TVP5150_ACT_VD_CROP_ST_MSB));
+ printk("tvp5150: Active video cropping start LSB = 0x%02x\n",
+ tvp5150_read(c, TVP5150_ACT_VD_CROP_ST_LSB));
+ printk("tvp5150: Active video cropping stop MSB = 0x%02x\n",
+ tvp5150_read(c, TVP5150_ACT_VD_CROP_STP_MSB));
+ printk("tvp5150: Active video cropping stop LSB = 0x%02x\n",
+ tvp5150_read(c, TVP5150_ACT_VD_CROP_STP_LSB));
+ printk("tvp5150: Genlock/RTC = 0x%02x\n",
+ tvp5150_read(c, TVP5150_GENLOCK));
+ printk("tvp5150: Horizontal sync start = 0x%02x\n",
+ tvp5150_read(c, TVP5150_HORIZ_SYNC_START));
+ printk("tvp5150: Vertical blanking start = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VERT_BLANKING_START));
+ printk("tvp5150: Vertical blanking stop = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VERT_BLANKING_STOP));
+ printk("tvp5150: Chrominance processing control #1 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_CHROMA_PROC_CTL_1));
+ printk("tvp5150: Chrominance processing control #2 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_CHROMA_PROC_CTL_2));
+ printk("tvp5150: Interrupt reset register B = 0x%02x\n",
+ tvp5150_read(c, TVP5150_INT_RESET_REG_B));
+ printk("tvp5150: Interrupt enable register B = 0x%02x\n",
+ tvp5150_read(c, TVP5150_INT_ENABLE_REG_B));
+ printk("tvp5150: Interrupt configuration register B = 0x%02x\n",
+ tvp5150_read(c, TVP5150_INTT_CONFIG_REG_B));
+ printk("tvp5150: Video standard = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VIDEO_STD));
+ printk("tvp5150: Cb gain factor = 0x%02x\n",
+ tvp5150_read(c, TVP5150_CB_GAIN_FACT));
+ printk("tvp5150: Cr gain factor = 0x%02x\n",
+ tvp5150_read(c, TVP5150_CR_GAIN_FACTOR));
+ printk("tvp5150: Macrovision on counter = 0x%02x\n",
+ tvp5150_read(c, TVP5150_MACROVISION_ON_CTR));
+ printk("tvp5150: Macrovision off counter = 0x%02x\n",
+ tvp5150_read(c, TVP5150_MACROVISION_OFF_CTR));
+ printk("tvp5150: revision select (TVP5150AM1 only) = 0x%02x\n",
+ tvp5150_read(c, TVP5150_REV_SELECT));
+ printk("tvp5150: MSB of device ID = 0x%02x\n",
+ tvp5150_read(c, TVP5150_MSB_DEV_ID));
+ printk("tvp5150: LSB of device ID = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LSB_DEV_ID));
+ printk("tvp5150: ROM major version = 0x%02x\n",
+ tvp5150_read(c, TVP5150_ROM_MAJOR_VER));
+ printk("tvp5150: ROM minor version = 0x%02x\n",
+ tvp5150_read(c, TVP5150_ROM_MINOR_VER));
+ printk("tvp5150: Vertical line count MSB = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VERT_LN_COUNT_MSB));
+ printk("tvp5150: Vertical line count LSB = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VERT_LN_COUNT_LSB));
+ printk("tvp5150: Interrupt status register B = 0x%02x\n",
+ tvp5150_read(c, TVP5150_INT_STATUS_REG_B));
+ printk("tvp5150: Interrupt active register B = 0x%02x\n",
+ tvp5150_read(c, TVP5150_INT_ACTIVE_REG_B));
+ printk("tvp5150: Status register #1 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_STATUS_REG_1));
+ printk("tvp5150: Status register #2 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_STATUS_REG_2));
+ printk("tvp5150: Status register #3 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_STATUS_REG_3));
+ printk("tvp5150: Status register #4 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_STATUS_REG_4));
+ printk("tvp5150: Status register #5 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_STATUS_REG_5));
+ printk("tvp5150: Closed caption data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_CC_DATA_REG1));
+ printk("tvp5150: Closed caption data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_CC_DATA_REG2));
+ printk("tvp5150: Closed caption data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_CC_DATA_REG3));
+ printk("tvp5150: Closed caption data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_CC_DATA_REG4));
+ printk("tvp5150: WSS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_WSS_DATA_REG1));
+ printk("tvp5150: WSS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_WSS_DATA_REG2));
+ printk("tvp5150: WSS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_WSS_DATA_REG3));
+ printk("tvp5150: WSS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_WSS_DATA_REG4));
+ printk("tvp5150: WSS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_WSS_DATA_REG5));
+ printk("tvp5150: WSS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_WSS_DATA_REG6));
+ printk("tvp5150: VPS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VPS_DATA_REG1));
+ printk("tvp5150: VPS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VPS_DATA_REG2));
+ printk("tvp5150: VPS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VPS_DATA_REG3));
+ printk("tvp5150: VPS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VPS_DATA_REG4));
+ printk("tvp5150: VPS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VPS_DATA_REG5));
+ printk("tvp5150: VPS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VPS_DATA_REG6));
+ printk("tvp5150: VPS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VPS_DATA_REG7));
+ printk("tvp5150: VPS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VPS_DATA_REG8));
+ printk("tvp5150: VPS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VPS_DATA_REG9));
+ printk("tvp5150: VPS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VPS_DATA_REG10));
+ printk("tvp5150: VPS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VPS_DATA_REG11));
+ printk("tvp5150: VPS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VPS_DATA_REG12));
+ printk("tvp5150: VPS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VPS_DATA_REG13));
+ printk("tvp5150: VITC data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VITC_DATA_REG1));
+ printk("tvp5150: VITC data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VITC_DATA_REG2));
+ printk("tvp5150: VITC data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VITC_DATA_REG3));
+ printk("tvp5150: VITC data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VITC_DATA_REG4));
+ printk("tvp5150: VITC data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VITC_DATA_REG5));
+ printk("tvp5150: VITC data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VITC_DATA_REG6));
+ printk("tvp5150: VITC data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VITC_DATA_REG7));
+ printk("tvp5150: VITC data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VITC_DATA_REG8));
+ printk("tvp5150: VITC data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VITC_DATA_REG9));
+ printk("tvp5150: VBI FIFO read data = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VBI_FIFO_READ_DATA));
+ printk("tvp5150: Teletext filter 1 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_TELETEXT_FIL_1_1));
+ printk("tvp5150: Teletext filter 1 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_TELETEXT_FIL_1_2));
+ printk("tvp5150: Teletext filter 1 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_TELETEXT_FIL_1_3));
+ printk("tvp5150: Teletext filter 1 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_TELETEXT_FIL_1_4));
+ printk("tvp5150: Teletext filter 1 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_TELETEXT_FIL_1_5));
+ printk("tvp5150: Teletext filter 2 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_TELETEXT_FIL_2_1));
+ printk("tvp5150: Teletext filter 2 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_TELETEXT_FIL_2_2));
+ printk("tvp5150: Teletext filter 2 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_TELETEXT_FIL_2_3));
+ printk("tvp5150: Teletext filter 2 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_TELETEXT_FIL_2_4));
+ printk("tvp5150: Teletext filter 2 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_TELETEXT_FIL_2_5));
+ printk("tvp5150: Teletext filter enable = 0x%02x\n",
+ tvp5150_read(c, TVP5150_TELETEXT_FIL_ENA));
+ printk("tvp5150: Interrupt status register A = 0x%02x\n",
+ tvp5150_read(c, TVP5150_INT_STATUS_REG_A));
+ printk("tvp5150: Interrupt enable register A = 0x%02x\n",
+ tvp5150_read(c, TVP5150_INT_ENABLE_REG_A));
+ printk("tvp5150: Interrupt configuration = 0x%02x\n",
+ tvp5150_read(c, TVP5150_INT_CONF));
+ printk("tvp5150: VDP configuration RAM data = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VDP_CONF_RAM_DATA));
+ printk("tvp5150: Configuration RAM address low byte = 0x%02x\n",
+ tvp5150_read(c, TVP5150_CONF_RAM_ADDR_LOW));
+ printk("tvp5150: Configuration RAM address high byte = 0x%02x\n",
+ tvp5150_read(c, TVP5150_CONF_RAM_ADDR_HIGH));
+ printk("tvp5150: VDP status register = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VDP_STATUS_REG));
+ printk("tvp5150: FIFO word count = 0x%02x\n",
+ tvp5150_read(c, TVP5150_FIFO_WORD_COUNT));
+ printk("tvp5150: FIFO interrupt threshold = 0x%02x\n",
+ tvp5150_read(c, TVP5150_FIFO_INT_THRESHOLD));
+ printk("tvp5150: FIFO reset = 0x%02x\n",
+ tvp5150_read(c, TVP5150_FIFO_RESET));
+ printk("tvp5150: Line number interrupt = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_NUMBER_INT));
+ printk("tvp5150: Pixel alignment register low byte = 0x%02x\n",
+ tvp5150_read(c, TVP5150_PIX_ALIGN_REG_LOW));
+ printk("tvp5150: Pixel alignment register high byte = 0x%02x\n",
+ tvp5150_read(c, TVP5150_PIX_ALIGN_REG_HIGH));
+ printk("tvp5150: FIFO output control = 0x%02x\n",
+ tvp5150_read(c, TVP5150_FIFO_OUT_CTRL));
+ printk("tvp5150: Full field enable 1 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_FULL_FIELD_ENA_1));
+ printk("tvp5150: Full field enable 2 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_FULL_FIELD_ENA_2));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_1));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_2));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_3));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_4));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_5));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_6));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_7));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_8));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_9));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_10));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_11));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_12));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_13));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_14));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_15));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_16));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_17));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_18));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_19));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_20));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_21));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_22));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_23));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_24));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_25));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_27));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_28));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_29));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_30));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_31));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_32));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_33));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_34));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_35));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_36));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_37));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_38));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_39));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_40));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_41));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_42));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_43));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_44));
+ printk("tvp5150: Full field mode register = 0x%02x\n",
+ tvp5150_read(c, TVP5150_FULL_FIELD_MODE_REG));
+}
+
+/****************************************************************************
+ Basic functions
+ ****************************************************************************/
+enum tvp5150_input {
+ TVP5150_ANALOG_CH0 = 0,
+ TVP5150_SVIDEO = 1,
+ TVP5150_ANALOG_CH1 = 2,
+ TVP5150_BLACK_SCREEN = 8
+};
+
+static inline void tvp5150_selmux(struct i2c_client *c,
+ enum tvp5150_input input)
+{
+ struct tvp5150 *decoder = i2c_get_clientdata(c);
+
+ if (!decoder->enable)
+ input |= TVP5150_BLACK_SCREEN;
+
+ tvp5150_write(c, TVP5150_VD_IN_SRC_SEL_1, input);
+};
+
+static inline void tvp5150_reset(struct i2c_client *c)
+{
+ struct tvp5150 *decoder = i2c_get_clientdata(c);
+
+ tvp5150_write(c, TVP5150_CONF_SHARED_PIN, 2);
+
+ /* Automatic offset and AGC enabled */
+ tvp5150_write(c, TVP5150_ANAL_CHL_CTL, 0x15);
+
+ /* Normal Operation */
+// tvp5150_write(c, TVP5150_OP_MODE_CTL, 0x00);
+
+ /* Activate YCrCb output 0x9 or 0xd ? */
+ tvp5150_write(c, TVP5150_MISC_CTL, 0x6f);
+
+ /* Activates video std autodetection for all standards */
+ tvp5150_write(c, TVP5150_AUTOSW_MSK, 0x0);
+
+ /* Default format: 0x47, 4:2:2: 0x40 */
+ tvp5150_write(c, TVP5150_DATA_RATE_SEL, 0x47);
+
+ tvp5150_selmux(c, decoder->input);
+
+ tvp5150_write(c, TVP5150_CHROMA_PROC_CTL_1, 0x0c);
+ tvp5150_write(c, TVP5150_CHROMA_PROC_CTL_2, 0x54);
+
+ tvp5150_write(c, 0x27, 0x20); /* ?????????? */
+
+ tvp5150_write(c, TVP5150_VIDEO_STD, 0x0); /* Auto switch */
+
+ tvp5150_write(c, TVP5150_BRIGHT_CTL, decoder->bright >> 8);
+ tvp5150_write(c, TVP5150_CONTRAST_CTL, decoder->contrast >> 8);
+ tvp5150_write(c, TVP5150_SATURATION_CTL, decoder->contrast >> 8);
+ tvp5150_write(c, TVP5150_HUE_CTL, (decoder->hue - 32768) >> 8);
+};
+
+static int tvp5150_get_ctrl(struct i2c_client *c, struct v4l2_control *ctrl)
+{
+/* struct tvp5150 *decoder = i2c_get_clientdata(c); */
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ctrl->value = tvp5150_read(c, TVP5150_BRIGHT_CTL);
+ return 0;
+ case V4L2_CID_CONTRAST:
+ ctrl->value = tvp5150_read(c, TVP5150_CONTRAST_CTL);
+ return 0;
+ case V4L2_CID_SATURATION:
+ ctrl->value = tvp5150_read(c, TVP5150_SATURATION_CTL);
+ return 0;
+ case V4L2_CID_HUE:
+ ctrl->value = tvp5150_read(c, TVP5150_HUE_CTL);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int tvp5150_set_ctrl(struct i2c_client *c, struct v4l2_control *ctrl)
+{
+/* struct tvp5150 *decoder = i2c_get_clientdata(c); */
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ tvp5150_write(c, TVP5150_BRIGHT_CTL, ctrl->value);
+ return 0;
+ case V4L2_CID_CONTRAST:
+ tvp5150_write(c, TVP5150_CONTRAST_CTL, ctrl->value);
+ return 0;
+ case V4L2_CID_SATURATION:
+ tvp5150_write(c, TVP5150_SATURATION_CTL, ctrl->value);
+ return 0;
+ case V4L2_CID_HUE:
+ tvp5150_write(c, TVP5150_HUE_CTL, ctrl->value);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+/****************************************************************************
+ I2C Command
+ ****************************************************************************/
+static int tvp5150_command(struct i2c_client *client,
+ unsigned int cmd, void *arg)
+{
+ struct tvp5150 *decoder = i2c_get_clientdata(client);
+
+ switch (cmd) {
+
+ case 0:
+ case DECODER_INIT:
+ tvp5150_reset(client);
+ break;
+
+ case DECODER_DUMP:
+ dump_reg(client);
+ break;
+
+ case DECODER_GET_CAPABILITIES:
+ {
+ struct video_decoder_capability *cap = arg;
+
+ cap->flags = VIDEO_DECODER_PAL |
+ VIDEO_DECODER_NTSC |
+ VIDEO_DECODER_SECAM |
+ VIDEO_DECODER_AUTO | VIDEO_DECODER_CCIR;
+ cap->inputs = 3;
+ cap->outputs = 1;
+ break;
+ }
+ case DECODER_GET_STATUS:
+ {
+ break;
+ }
+
+ case DECODER_SET_GPIO:
+ break;
+
+ case DECODER_SET_VBI_BYPASS:
+ break;
+
+ case DECODER_SET_NORM:
+ {
+ int *iarg = arg;
+
+ switch (*iarg) {
+
+ case VIDEO_MODE_NTSC:
+ break;
+
+ case VIDEO_MODE_PAL:
+ break;
+
+ case VIDEO_MODE_SECAM:
+ break;
+
+ case VIDEO_MODE_AUTO:
+ break;
+
+ default:
+ return -EINVAL;
+
+ }
+ decoder->norm = *iarg;
+ break;
+ }
+ case DECODER_SET_INPUT:
+ {
+ int *iarg = arg;
+ if (*iarg < 0 || *iarg > 3) {
+ return -EINVAL;
+ }
+
+ decoder->input = *iarg;
+ tvp5150_selmux(client, decoder->input);
+
+ break;
+ }
+ case DECODER_SET_OUTPUT:
+ {
+ int *iarg = arg;
+
+ /* not much choice of outputs */
+ if (*iarg != 0) {
+ return -EINVAL;
+ }
+ break;
+ }
+ case DECODER_ENABLE_OUTPUT:
+ {
+ int *iarg = arg;
+
+ decoder->enable = (*iarg != 0);
+
+ tvp5150_selmux(client, decoder->input);
+
+ break;
+ }
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *qc = arg;
+ u8 i, n;
+
+ dprintk(1, KERN_DEBUG "VIDIOC_QUERYCTRL");
+
+ n = sizeof(tvp5150_qctrl) / sizeof(tvp5150_qctrl[0]);
+ for (i = 0; i < n; i++)
+ if (qc->id && qc->id == tvp5150_qctrl[i].id) {
+ memcpy(qc, &(tvp5150_qctrl[i]),
+ sizeof(*qc));
+ return 0;
+ }
+
+ return -EINVAL;
+ }
+ case VIDIOC_G_CTRL:
+ {
+ struct v4l2_control *ctrl = arg;
+ dprintk(1, KERN_DEBUG "VIDIOC_G_CTRL");
+
+ return tvp5150_get_ctrl(client, ctrl);
+ }
+ case VIDIOC_S_CTRL_OLD: /* ??? */
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *ctrl = arg;
+ u8 i, n;
+ dprintk(1, KERN_DEBUG "VIDIOC_S_CTRL");
+ n = sizeof(tvp5150_qctrl) / sizeof(tvp5150_qctrl[0]);
+ for (i = 0; i < n; i++)
+ if (ctrl->id == tvp5150_qctrl[i].id) {
+ if (ctrl->value <
+ tvp5150_qctrl[i].minimum
+ || ctrl->value >
+ tvp5150_qctrl[i].maximum)
+ return -ERANGE;
+ dprintk(1,
+ KERN_DEBUG
+ "VIDIOC_S_CTRL: id=%d, value=%d",
+ ctrl->id, ctrl->value);
+ return tvp5150_set_ctrl(client, ctrl);
+ }
+ return -EINVAL;
+ }
+
+ case DECODER_SET_PICTURE:
+ {
+ struct video_picture *pic = arg;
+ if (decoder->bright != pic->brightness) {
+ /* We want 0 to 255 we get 0-65535 */
+ decoder->bright = pic->brightness;
+ tvp5150_write(client, TVP5150_BRIGHT_CTL,
+ decoder->bright >> 8);
+ }
+ if (decoder->contrast != pic->contrast) {
+ /* We want 0 to 255 we get 0-65535 */
+ decoder->contrast = pic->contrast;
+ tvp5150_write(client, TVP5150_CONTRAST_CTL,
+ decoder->contrast >> 8);
+ }
+ if (decoder->sat != pic->colour) {
+ /* We want 0 to 255 we get 0-65535 */
+ decoder->sat = pic->colour;
+ tvp5150_write(client, TVP5150_SATURATION_CTL,
+ decoder->contrast >> 8);
+ }
+ if (decoder->hue != pic->hue) {
+ /* We want -128 to 127 we get 0-65535 */
+ decoder->hue = pic->hue;
+ tvp5150_write(client, TVP5150_HUE_CTL,
+ (decoder->hue - 32768) >> 8);
+ }
+ break;
+ }
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+ I2C Client & Driver
+ ****************************************************************************/
+static struct i2c_driver driver;
+
+static struct i2c_client client_template = {
+ .name = "(unset)",
+ .flags = I2C_CLIENT_ALLOW_USE,
+ .driver = &driver,
+};
+
+static int tvp5150_detect_client(struct i2c_adapter *adapter,
+ int address, int kind)
+{
+ struct i2c_client *client;
+ struct tvp5150 *core;
+ int rv;
+
+ dprintk(1,
+ KERN_INFO
+ "tvp5150.c: detecting tvp5150 client on address 0x%x\n",
+ address << 1);
+
+ client_template.adapter = adapter;
+ client_template.addr = address;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality
+ (adapter,
+ I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
+ return 0;
+
+ client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (client == 0)
+ return -ENOMEM;
+ memcpy(client, &client_template, sizeof(struct i2c_client));
+
+ core = kmalloc(sizeof(struct tvp5150), GFP_KERNEL);
+ if (core == 0) {
+ kfree(client);
+ return -ENOMEM;
+ }
+ memset(core, 0, sizeof(struct tvp5150));
+ i2c_set_clientdata(client, core);
+
+ rv = i2c_attach_client(client);
+
+ core->norm = VIDEO_MODE_AUTO;
+ core->input = 2;
+ core->enable = 1;
+ core->bright = 32768;
+ core->contrast = 32768;
+ core->hue = 32768;
+ core->sat = 32768;
+
+ if (rv) {
+ kfree(client);
+ kfree(core);
+ return rv;
+ }
+
+ if (debug > 1)
+ dump_reg(client);
+
+ return 0;
+}
+
+static int tvp5150_attach_adapter(struct i2c_adapter *adapter)
+{
+ dprintk(1,
+ KERN_INFO
+ "tvp5150.c: starting probe for adapter %s (0x%x)\n",
+ adapter->name, adapter->id);
+ return i2c_probe(adapter, &addr_data, &tvp5150_detect_client);
+}
+
+static int tvp5150_detach_client(struct i2c_client *client)
+{
+ struct tvp5150 *decoder = i2c_get_clientdata(client);
+ int err;
+
+ err = i2c_detach_client(client);
+ if (err) {
+ return err;
+ }
+
+ kfree(decoder);
+ kfree(client);
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_driver driver = {
+ .owner = THIS_MODULE,
+ .name = "tvp5150",
+
+ /* FIXME */
+ .id = I2C_DRIVERID_SAA7110,
+ .flags = I2C_DF_NOTIFY,
+
+ .attach_adapter = tvp5150_attach_adapter,
+ .detach_client = tvp5150_detach_client,
+
+ .command = tvp5150_command,
+};
+
+static int __init tvp5150_init(void)
+{
+ return i2c_add_driver(&driver);
+}
+
+static void __exit tvp5150_exit(void)
+{
+ i2c_del_driver(&driver);
+}
+
+module_init(tvp5150_init);
+module_exit(tvp5150_exit);
diff --git a/drivers/media/video/tvp5150_reg.h b/drivers/media/video/tvp5150_reg.h
new file mode 100644
index 00000000000..cd45c1ded78
--- /dev/null
+++ b/drivers/media/video/tvp5150_reg.h
@@ -0,0 +1,173 @@
+#define TVP5150_VD_IN_SRC_SEL_1 0x00 /* Video input source selection #1 */
+#define TVP5150_ANAL_CHL_CTL 0x01 /* Analog channel controls */
+#define TVP5150_OP_MODE_CTL 0x02 /* Operation mode controls */
+#define TVP5150_MISC_CTL 0x03 /* Miscellaneous controls */
+#define TVP5150_AUTOSW_MSK 0x04 /* Autoswitch mask: TVP5150A / TVP5150AM */
+
+/* Reserved 05h */
+
+#define TVP5150_COLOR_KIL_THSH_CTL 0x06 /* Color killer threshold control */
+#define TVP5150_LUMA_PROC_CTL_1 0x07 /* Luminance processing control #1 */
+#define TVP5150_LUMA_PROC_CTL_2 0x08 /* Luminance processing control #2 */
+#define TVP5150_BRIGHT_CTL 0x09 /* Brightness control */
+#define TVP5150_SATURATION_CTL 0x0a /* Color saturation control */
+#define TVP5150_HUE_CTL 0x0b /* Hue control */
+#define TVP5150_CONTRAST_CTL 0x0c /* Contrast control */
+#define TVP5150_DATA_RATE_SEL 0x0d /* Outputs and data rates select */
+#define TVP5150_LUMA_PROC_CTL_3 0x0e /* Luminance processing control #3 */
+#define TVP5150_CONF_SHARED_PIN 0x0f /* Configuration shared pins */
+
+/* Reserved 10h */
+
+#define TVP5150_ACT_VD_CROP_ST_MSB 0x11 /* Active video cropping start MSB */
+#define TVP5150_ACT_VD_CROP_ST_LSB 0x12 /* Active video cropping start LSB */
+#define TVP5150_ACT_VD_CROP_STP_MSB 0x13 /* Active video cropping stop MSB */
+#define TVP5150_ACT_VD_CROP_STP_LSB 0x14 /* Active video cropping stop LSB */
+#define TVP5150_GENLOCK 0x15 /* Genlock/RTC */
+#define TVP5150_HORIZ_SYNC_START 0x16 /* Horizontal sync start */
+
+/* Reserved 17h */
+
+#define TVP5150_VERT_BLANKING_START 0x18 /* Vertical blanking start */
+#define TVP5150_VERT_BLANKING_STOP 0x19 /* Vertical blanking stop */
+#define TVP5150_CHROMA_PROC_CTL_1 0x1a /* Chrominance processing control #1 */
+#define TVP5150_CHROMA_PROC_CTL_2 0x1b /* Chrominance processing control #2 */
+#define TVP5150_INT_RESET_REG_B 0x1c /* Interrupt reset register B */
+#define TVP5150_INT_ENABLE_REG_B 0x1d /* Interrupt enable register B */
+#define TVP5150_INTT_CONFIG_REG_B 0x1e /* Interrupt configuration register B */
+
+/* Reserved 1Fh-27h */
+
+#define TVP5150_VIDEO_STD 0x28 /* Video standard */
+
+/* Reserved 29h-2bh */
+
+#define TVP5150_CB_GAIN_FACT 0x2c /* Cb gain factor */
+#define TVP5150_CR_GAIN_FACTOR 0x2d /* Cr gain factor */
+#define TVP5150_MACROVISION_ON_CTR 0x2e /* Macrovision on counter */
+#define TVP5150_MACROVISION_OFF_CTR 0x2f /* Macrovision off counter */
+#define TVP5150_REV_SELECT 0x30 /* revision select (TVP5150AM1 only) */
+
+/* Reserved 31h-7Fh */
+
+#define TVP5150_MSB_DEV_ID 0x80 /* MSB of device ID */
+#define TVP5150_LSB_DEV_ID 0x81 /* LSB of device ID */
+#define TVP5150_ROM_MAJOR_VER 0x82 /* ROM major version */
+#define TVP5150_ROM_MINOR_VER 0x83 /* ROM minor version */
+#define TVP5150_VERT_LN_COUNT_MSB 0x84 /* Vertical line count MSB */
+#define TVP5150_VERT_LN_COUNT_LSB 0x85 /* Vertical line count LSB */
+#define TVP5150_INT_STATUS_REG_B 0x86 /* Interrupt status register B */
+#define TVP5150_INT_ACTIVE_REG_B 0x87 /* Interrupt active register B */
+#define TVP5150_STATUS_REG_1 0x88 /* Status register #1 */
+#define TVP5150_STATUS_REG_2 0x89 /* Status register #2 */
+#define TVP5150_STATUS_REG_3 0x8a /* Status register #3 */
+#define TVP5150_STATUS_REG_4 0x8b /* Status register #4 */
+#define TVP5150_STATUS_REG_5 0x8c /* Status register #5 */
+/* Reserved 8Dh-8Fh */
+#define TVP5150_CC_DATA_REG1 0x90 /* Closed caption data registers */
+#define TVP5150_CC_DATA_REG2 0x91 /* Closed caption data registers */
+#define TVP5150_CC_DATA_REG3 0x92 /* Closed caption data registers */
+#define TVP5150_CC_DATA_REG4 0x93 /* Closed caption data registers */
+#define TVP5150_WSS_DATA_REG1 0X94 /* WSS data registers */
+#define TVP5150_WSS_DATA_REG2 0X95 /* WSS data registers */
+#define TVP5150_WSS_DATA_REG3 0X96 /* WSS data registers */
+#define TVP5150_WSS_DATA_REG4 0X97 /* WSS data registers */
+#define TVP5150_WSS_DATA_REG5 0X98 /* WSS data registers */
+#define TVP5150_WSS_DATA_REG6 0X99 /* WSS data registers */
+#define TVP5150_VPS_DATA_REG1 0x9a /* VPS data registers */
+#define TVP5150_VPS_DATA_REG2 0x9b /* VPS data registers */
+#define TVP5150_VPS_DATA_REG3 0x9c /* VPS data registers */
+#define TVP5150_VPS_DATA_REG4 0x9d /* VPS data registers */
+#define TVP5150_VPS_DATA_REG5 0x9e /* VPS data registers */
+#define TVP5150_VPS_DATA_REG6 0x9f /* VPS data registers */
+#define TVP5150_VPS_DATA_REG7 0xa0 /* VPS data registers */
+#define TVP5150_VPS_DATA_REG8 0xa1 /* VPS data registers */
+#define TVP5150_VPS_DATA_REG9 0xa2 /* VPS data registers */
+#define TVP5150_VPS_DATA_REG10 0xa3 /* VPS data registers */
+#define TVP5150_VPS_DATA_REG11 0xa4 /* VPS data registers */
+#define TVP5150_VPS_DATA_REG12 0xa5 /* VPS data registers */
+#define TVP5150_VPS_DATA_REG13 0xa6 /* VPS data registers */
+#define TVP5150_VITC_DATA_REG1 0xa7 /* VITC data registers */
+#define TVP5150_VITC_DATA_REG2 0xa8 /* VITC data registers */
+#define TVP5150_VITC_DATA_REG3 0xa9 /* VITC data registers */
+#define TVP5150_VITC_DATA_REG4 0xaa /* VITC data registers */
+#define TVP5150_VITC_DATA_REG5 0xab /* VITC data registers */
+#define TVP5150_VITC_DATA_REG6 0xac /* VITC data registers */
+#define TVP5150_VITC_DATA_REG7 0xad /* VITC data registers */
+#define TVP5150_VITC_DATA_REG8 0xae /* VITC data registers */
+#define TVP5150_VITC_DATA_REG9 0xaf /* VITC data registers */
+#define TVP5150_VBI_FIFO_READ_DATA 0xb0 /* VBI FIFO read data */
+#define TVP5150_TELETEXT_FIL_1_1 0xb1 /* Teletext filter 1 */
+#define TVP5150_TELETEXT_FIL_1_2 0xb2 /* Teletext filter 1 */
+#define TVP5150_TELETEXT_FIL_1_3 0xb3 /* Teletext filter 1 */
+#define TVP5150_TELETEXT_FIL_1_4 0xb4 /* Teletext filter 1 */
+#define TVP5150_TELETEXT_FIL_1_5 0xb5 /* Teletext filter 1 */
+#define TVP5150_TELETEXT_FIL_2_1 0xb6 /* Teletext filter 2 */
+#define TVP5150_TELETEXT_FIL_2_2 0xb7 /* Teletext filter 2 */
+#define TVP5150_TELETEXT_FIL_2_3 0xb8 /* Teletext filter 2 */
+#define TVP5150_TELETEXT_FIL_2_4 0xb9 /* Teletext filter 2 */
+#define TVP5150_TELETEXT_FIL_2_5 0xba /* Teletext filter 2 */
+#define TVP5150_TELETEXT_FIL_ENA 0xbb /* Teletext filter enable */
+/* Reserved BCh-BFh */
+#define TVP5150_INT_STATUS_REG_A 0xc0 /* Interrupt status register A */
+#define TVP5150_INT_ENABLE_REG_A 0xc1 /* Interrupt enable register A */
+#define TVP5150_INT_CONF 0xc2 /* Interrupt configuration */
+#define TVP5150_VDP_CONF_RAM_DATA 0xc3 /* VDP configuration RAM data */
+#define TVP5150_CONF_RAM_ADDR_LOW 0xc4 /* Configuration RAM address low byte */
+#define TVP5150_CONF_RAM_ADDR_HIGH 0xc5 /* Configuration RAM address high byte */
+#define TVP5150_VDP_STATUS_REG 0xc6 /* VDP status register */
+#define TVP5150_FIFO_WORD_COUNT 0xc7 /* FIFO word count */
+#define TVP5150_FIFO_INT_THRESHOLD 0xc8 /* FIFO interrupt threshold */
+#define TVP5150_FIFO_RESET 0xc9 /* FIFO reset */
+#define TVP5150_LINE_NUMBER_INT 0xca /* Line number interrupt */
+#define TVP5150_PIX_ALIGN_REG_LOW 0xcb /* Pixel alignment register low byte */
+#define TVP5150_PIX_ALIGN_REG_HIGH 0xcc /* Pixel alignment register high byte */
+#define TVP5150_FIFO_OUT_CTRL 0xcd /* FIFO output control */
+/* Reserved CEh */
+#define TVP5150_FULL_FIELD_ENA_1 0xcf /* Full field enable 1 */
+#define TVP5150_FULL_FIELD_ENA_2 0xd0 /* Full field enable 2 */
+#define TVP5150_LINE_MODE_REG_1 0xd1 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_2 0xd2 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_3 0xd3 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_4 0xd4 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_5 0xd5 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_6 0xd6 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_7 0xd7 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_8 0xd8 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_9 0xd9 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_10 0xda /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_11 0xdb /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_12 0xdc /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_13 0xdd /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_14 0xde /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_15 0xdf /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_16 0xe0 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_17 0xe1 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_18 0xe2 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_19 0xe3 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_20 0xe4 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_21 0xe5 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_22 0xe6 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_23 0xe7 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_24 0xe8 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_25 0xe9 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_27 0xea /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_28 0xeb /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_29 0xec /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_30 0xed /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_31 0xee /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_32 0xef /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_33 0xf0 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_34 0xf1 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_35 0xf2 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_36 0xf3 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_37 0xf4 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_38 0xf5 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_39 0xf6 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_40 0xf7 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_41 0xf8 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_42 0xf9 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_43 0xfa /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_44 0xfb /* Line mode registers */
+#define TVP5150_FULL_FIELD_MODE_REG 0xfc /* Full field mode register */
+/* Reserved FDh-FFh */
diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c
index 59bb71381a1..4134549d11a 100644
--- a/drivers/media/video/v4l1-compat.c
+++ b/drivers/media/video/v4l1-compat.c
@@ -708,7 +708,7 @@ v4l_compat_translate_ioctl(struct inode *inode,
}
case VIDIOCGFREQ: /* get frequency */
{
- int *freq = arg;
+ unsigned long *freq = arg;
freq2.tuner = 0;
err = drv(inode, file, VIDIOC_G_FREQUENCY, &freq2);
@@ -720,7 +720,7 @@ v4l_compat_translate_ioctl(struct inode *inode,
}
case VIDIOCSFREQ: /* set frequency */
{
- int *freq = arg;
+ unsigned long *freq = arg;
freq2.tuner = 0;
drv(inode, file, VIDIOC_G_FREQUENCY, &freq2);
@@ -960,7 +960,7 @@ v4l_compat_translate_ioctl(struct inode *inode,
fmt->start[1] = fmt2->fmt.vbi.start[1];
fmt->count[1] = fmt2->fmt.vbi.count[1];
fmt->flags = fmt2->fmt.vbi.flags & 0x03;
- break;
+ break;
}
case VIDIOCSVBIFMT:
{
@@ -1006,10 +1006,8 @@ v4l_compat_translate_ioctl(struct inode *inode,
break;
}
- if (cap2)
- kfree(cap2);
- if (fmt2)
- kfree(fmt2);
+ kfree(cap2);
+ kfree(fmt2);
return err;
}
diff --git a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c
index 574b8e36f3c..acfd3a103f3 100644
--- a/drivers/media/video/video-buf.c
+++ b/drivers/media/video/video-buf.c
@@ -147,7 +147,7 @@ int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction,
data,size,dma->nr_pages);
down_read(&current->mm->mmap_sem);
- err = get_user_pages(current,current->mm,
+ err = get_user_pages(current,current->mm,
data & PAGE_MASK, dma->nr_pages,
rw == READ, 1, /* force */
dma->pages, NULL);
@@ -750,9 +750,9 @@ videobuf_read_zerocopy(struct videobuf_queue *q, char __user *data,
{
enum v4l2_field field;
unsigned long flags;
- int retval;
+ int retval;
- /* setup stuff */
+ /* setup stuff */
retval = -ENOMEM;
q->read_buf = videobuf_alloc(q->msize);
if (NULL == q->read_buf)
@@ -760,18 +760,18 @@ videobuf_read_zerocopy(struct videobuf_queue *q, char __user *data,
q->read_buf->memory = V4L2_MEMORY_USERPTR;
q->read_buf->baddr = (unsigned long)data;
- q->read_buf->bsize = count;
+ q->read_buf->bsize = count;
field = videobuf_next_field(q);
retval = q->ops->buf_prepare(q,q->read_buf,field);
if (0 != retval)
goto done;
- /* start capture & wait */
+ /* start capture & wait */
spin_lock_irqsave(q->irqlock,flags);
q->ops->buf_queue(q,q->read_buf);
spin_unlock_irqrestore(q->irqlock,flags);
- retval = videobuf_waiton(q->read_buf,0,0);
- if (0 == retval) {
+ retval = videobuf_waiton(q->read_buf,0,0);
+ if (0 == retval) {
videobuf_dma_pci_sync(q->pci,&q->read_buf->dma);
if (STATE_ERROR == q->read_buf->state)
retval = -EIO;
@@ -828,7 +828,7 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
}
/* wait until capture is done */
- retval = videobuf_waiton(q->read_buf, nonblocking, 1);
+ retval = videobuf_waiton(q->read_buf, nonblocking, 1);
if (0 != retval)
goto done;
videobuf_dma_pci_sync(q->pci,&q->read_buf->dma);
@@ -1096,7 +1096,7 @@ videobuf_vm_nopage(struct vm_area_struct *vma, unsigned long vaddr,
dprintk(3,"nopage: fault @ %08lx [vma %08lx-%08lx]\n",
vaddr,vma->vm_start,vma->vm_end);
- if (vaddr > vma->vm_end)
+ if (vaddr > vma->vm_end)
return NOPAGE_SIGBUS;
page = alloc_page(GFP_USER);
if (!page)
diff --git a/drivers/media/video/videocodec.c b/drivers/media/video/videocodec.c
index c9d5f1a873c..839db622040 100644
--- a/drivers/media/video/videocodec.c
+++ b/drivers/media/video/videocodec.c
@@ -353,8 +353,7 @@ videocodec_build_table (void)
dprintk(3, "videocodec_build table: %d entries, %d bytes\n", i,
size);
- if (videocodec_buf)
- kfree(videocodec_buf);
+ kfree(videocodec_buf);
videocodec_buf = (char *) kmalloc(size, GFP_KERNEL);
i = 0;
@@ -471,8 +470,7 @@ videocodec_exit (void)
{
#ifdef CONFIG_PROC_FS
remove_proc_entry("videocodecs", NULL);
- if (videocodec_buf)
- kfree(videocodec_buf);
+ kfree(videocodec_buf);
#endif
}
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
index 06df15f75de..83c49f9610d 100644
--- a/drivers/media/video/videodev.c
+++ b/drivers/media/video/videodev.c
@@ -215,8 +215,7 @@ video_usercopy(struct inode *inode, struct file *file,
}
out:
- if (mbuf)
- kfree(mbuf);
+ kfree(mbuf);
return err;
}
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
index ed4394e854a..71b28e9e085 100644
--- a/drivers/media/video/vino.c
+++ b/drivers/media/video/vino.c
@@ -12,15 +12,11 @@
/*
* TODO:
- * - remove "hacks" from memory allocation code and implement nopage()
+ * - remove "mark pages reserved-hacks" from memory allocation code
+ * and implement nopage()
* - check decimation, calculating and reporting image size when
* using decimation
- * - check vino_acquire_input(), vino_set_input() and channel
- * ownership handling
- * - report VINO error-interrupts via ioctls ?
- * - implement picture controls (all implemented?)
- * - use macros for boolean values (?)
- * - implement user mode buffers and overlay (?)
+ * - implement read(), user mode buffers and overlay (?)
*/
#include <linux/init.h>
@@ -60,18 +56,16 @@
* debug info.
* Note that the debug output also slows down the driver significantly */
// #define VINO_DEBUG
+// #define VINO_DEBUG_INT
-#define VINO_MODULE_VERSION "0.0.3"
-#define VINO_VERSION_CODE KERNEL_VERSION(0, 0, 3)
+#define VINO_MODULE_VERSION "0.0.5"
+#define VINO_VERSION_CODE KERNEL_VERSION(0, 0, 5)
MODULE_DESCRIPTION("SGI VINO Video4Linux2 driver");
MODULE_VERSION(VINO_MODULE_VERSION);
MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>");
MODULE_LICENSE("GPL");
-#define mem_map_reserve(p) set_bit(PG_reserved, &((p)->flags))
-#define mem_map_unreserve(p) clear_bit(PG_reserved, &((p)->flags))
-
#ifdef VINO_DEBUG
#define dprintk(x...) printk("VINO: " x);
#else
@@ -91,15 +85,16 @@ MODULE_LICENSE("GPL");
#define VINO_MIN_HEIGHT 32
#define VINO_CLIPPING_START_ODD_D1 1
-#define VINO_CLIPPING_START_ODD_PAL 1
-#define VINO_CLIPPING_START_ODD_NTSC 1
+#define VINO_CLIPPING_START_ODD_PAL 15
+#define VINO_CLIPPING_START_ODD_NTSC 12
#define VINO_CLIPPING_START_EVEN_D1 2
-#define VINO_CLIPPING_START_EVEN_PAL 2
-#define VINO_CLIPPING_START_EVEN_NTSC 2
+#define VINO_CLIPPING_START_EVEN_PAL 15
+#define VINO_CLIPPING_START_EVEN_NTSC 12
#define VINO_INPUT_CHANNEL_COUNT 3
+/* the number is the index for vino_inputs */
#define VINO_INPUT_NONE -1
#define VINO_INPUT_COMPOSITE 0
#define VINO_INPUT_SVIDEO 1
@@ -107,15 +102,13 @@ MODULE_LICENSE("GPL");
#define VINO_PAGE_RATIO (PAGE_SIZE / VINO_PAGE_SIZE)
-#define VINO_FIFO_THRESHOLD_DEFAULT 512
+#define VINO_FIFO_THRESHOLD_DEFAULT 16
-/*#define VINO_FRAMEBUFFER_SIZE (VINO_PAL_WIDTH * VINO_PAL_HEIGHT * 4 \
- + 2 * PAGE_SIZE)*/
#define VINO_FRAMEBUFFER_SIZE ((VINO_PAL_WIDTH \
* VINO_PAL_HEIGHT * 4 \
+ 3 * PAGE_SIZE) & ~(PAGE_SIZE - 1))
-#define VINO_FRAMEBUFFER_MAX_COUNT 8
+#define VINO_FRAMEBUFFER_COUNT_MAX 8
#define VINO_FRAMEBUFFER_UNUSED 0
#define VINO_FRAMEBUFFER_IN_USE 1
@@ -131,24 +124,27 @@ MODULE_LICENSE("GPL");
#define VINO_DUMMY_DESC_COUNT 4
#define VINO_DESC_FETCH_DELAY 5 /* microseconds */
+#define VINO_MAX_FRAME_SKIP_COUNT 128
+
/* the number is the index for vino_data_formats */
#define VINO_DATA_FMT_NONE -1
#define VINO_DATA_FMT_GREY 0
#define VINO_DATA_FMT_RGB332 1
#define VINO_DATA_FMT_RGB32 2
#define VINO_DATA_FMT_YUV 3
-//#define VINO_DATA_FMT_RGB24 4
#define VINO_DATA_FMT_COUNT 4
+/* the number is the index for vino_data_norms */
#define VINO_DATA_NORM_NONE -1
#define VINO_DATA_NORM_NTSC 0
#define VINO_DATA_NORM_PAL 1
#define VINO_DATA_NORM_SECAM 2
#define VINO_DATA_NORM_D1 3
-/* The following is a special entry that can be used to
+/* The following are special entries that can be used to
* autodetect the norm. */
-#define VINO_DATA_NORM_AUTO 0xff
+#define VINO_DATA_NORM_AUTO 0xfe
+#define VINO_DATA_NORM_AUTO_EXT 0xff
#define VINO_DATA_NORM_COUNT 4
@@ -232,7 +228,7 @@ struct vino_framebuffer_fifo {
unsigned int head;
unsigned int tail;
- unsigned int data[VINO_FRAMEBUFFER_MAX_COUNT];
+ unsigned int data[VINO_FRAMEBUFFER_COUNT_MAX];
};
struct vino_framebuffer_queue {
@@ -246,13 +242,20 @@ struct vino_framebuffer_queue {
struct vino_framebuffer_fifo in;
struct vino_framebuffer_fifo out;
- struct vino_framebuffer *buffer[VINO_FRAMEBUFFER_MAX_COUNT];
+ struct vino_framebuffer *buffer[VINO_FRAMEBUFFER_COUNT_MAX];
spinlock_t queue_lock;
struct semaphore queue_sem;
wait_queue_head_t frame_wait_queue;
};
+struct vino_interrupt_data {
+ struct timeval timestamp;
+ unsigned int frame_counter;
+ unsigned int skip_count;
+ unsigned int skip;
+};
+
struct vino_channel_settings {
unsigned int channel;
@@ -285,6 +288,8 @@ struct vino_channel_settings {
unsigned int users;
+ struct vino_interrupt_data int_data;
+
/* V4L support */
struct video_device *v4l_device;
};
@@ -315,7 +320,7 @@ struct vino_settings {
/* Module parameters */
/*
- * Using vino_pixel_conversion the ARGB32-format pixels supplied
+ * Using vino_pixel_conversion the ABGR32-format pixels supplied
* by the VINO chip can be converted to more common formats
* like RGBA32 (or probably RGB24 in the future). This way we
* can give out data that can be specified correctly with
@@ -329,7 +334,9 @@ struct vino_settings {
* Use non-zero value to enable conversion.
*/
static int vino_pixel_conversion = 0;
+
module_param_named(pixelconv, vino_pixel_conversion, int, 0);
+
MODULE_PARM_DESC(pixelconv,
"enable pixel conversion (non-zero value enables)");
@@ -345,15 +352,22 @@ static const char *vino_bus_name = "GIO64 bus";
static const char *vino_v4l_device_name_a = "SGI VINO Channel A";
static const char *vino_v4l_device_name_b = "SGI VINO Channel B";
+static void vino_capture_tasklet(unsigned long channel);
+
+DECLARE_TASKLET(vino_tasklet_a, vino_capture_tasklet, VINO_CHANNEL_A);
+DECLARE_TASKLET(vino_tasklet_b, vino_capture_tasklet, VINO_CHANNEL_B);
+
static const struct vino_input vino_inputs[] = {
{
.name = "Composite",
- .std = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM,
+ .std = V4L2_STD_NTSC | V4L2_STD_PAL
+ | V4L2_STD_SECAM,
},{
.name = "S-Video",
- .std = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM,
+ .std = V4L2_STD_NTSC | V4L2_STD_PAL
+ | V4L2_STD_SECAM,
},{
- .name = "D1 (IndyCam)",
+ .name = "D1/IndyCam",
.std = V4L2_STD_NTSC,
}
};
@@ -376,15 +390,10 @@ static const struct vino_data_format vino_data_formats[] = {
.colorspace = V4L2_COLORSPACE_SRGB,
},{
.description = "YUV 4:2:2",
- .bpp = 4,
+ .bpp = 2,
.pixelformat = V4L2_PIX_FMT_YUYV, // XXX: swapped?
.colorspace = V4L2_COLORSPACE_SMPTE170M,
- }/*,{
- .description = "24-bit RGB",
- .bpp = 3,
- .pixelformat = V4L2_PIX_FMT_RGB24,
- .colorspace = V4L2_COLORSPACE_SRGB,
- }*/
+ }
};
static const struct vino_data_norm vino_data_norms[] = {
@@ -397,18 +406,18 @@ static const struct vino_data_norm vino_data_norms[] = {
.width = VINO_NTSC_WIDTH,
.height = VINO_NTSC_HEIGHT,
.odd = {
- .top = VINO_CLIPPING_START_ODD_NTSC,
- .left = 0,
+ .top = VINO_CLIPPING_START_ODD_NTSC,
+ .left = 0,
.bottom = VINO_CLIPPING_START_ODD_NTSC
+ VINO_NTSC_HEIGHT / 2 - 1,
- .right = VINO_NTSC_WIDTH,
+ .right = VINO_NTSC_WIDTH,
},
.even = {
- .top = VINO_CLIPPING_START_EVEN_NTSC,
- .left = 0,
+ .top = VINO_CLIPPING_START_EVEN_NTSC,
+ .left = 0,
.bottom = VINO_CLIPPING_START_EVEN_NTSC
+ VINO_NTSC_HEIGHT / 2 - 1,
- .right = VINO_NTSC_WIDTH,
+ .right = VINO_NTSC_WIDTH,
},
},{
.description = "PAL",
@@ -419,18 +428,18 @@ static const struct vino_data_norm vino_data_norms[] = {
.width = VINO_PAL_WIDTH,
.height = VINO_PAL_HEIGHT,
.odd = {
- .top = VINO_CLIPPING_START_ODD_PAL,
- .left = 0,
+ .top = VINO_CLIPPING_START_ODD_PAL,
+ .left = 0,
.bottom = VINO_CLIPPING_START_ODD_PAL
+ VINO_PAL_HEIGHT / 2 - 1,
- .right = VINO_PAL_WIDTH,
+ .right = VINO_PAL_WIDTH,
},
.even = {
- .top = VINO_CLIPPING_START_EVEN_PAL,
- .left = 0,
+ .top = VINO_CLIPPING_START_EVEN_PAL,
+ .left = 0,
.bottom = VINO_CLIPPING_START_EVEN_PAL
+ VINO_PAL_HEIGHT / 2 - 1,
- .right = VINO_PAL_WIDTH,
+ .right = VINO_PAL_WIDTH,
},
},{
.description = "SECAM",
@@ -441,21 +450,21 @@ static const struct vino_data_norm vino_data_norms[] = {
.width = VINO_PAL_WIDTH,
.height = VINO_PAL_HEIGHT,
.odd = {
- .top = VINO_CLIPPING_START_ODD_PAL,
- .left = 0,
+ .top = VINO_CLIPPING_START_ODD_PAL,
+ .left = 0,
.bottom = VINO_CLIPPING_START_ODD_PAL
+ VINO_PAL_HEIGHT / 2 - 1,
- .right = VINO_PAL_WIDTH,
+ .right = VINO_PAL_WIDTH,
},
.even = {
- .top = VINO_CLIPPING_START_EVEN_PAL,
- .left = 0,
+ .top = VINO_CLIPPING_START_EVEN_PAL,
+ .left = 0,
.bottom = VINO_CLIPPING_START_EVEN_PAL
+ VINO_PAL_HEIGHT / 2 - 1,
- .right = VINO_PAL_WIDTH,
+ .right = VINO_PAL_WIDTH,
},
},{
- .description = "NTSC (D1 input)",
+ .description = "NTSC/D1",
.std = V4L2_STD_NTSC,
.fps_min = 6,
.fps_max = 30,
@@ -463,18 +472,18 @@ static const struct vino_data_norm vino_data_norms[] = {
.width = VINO_NTSC_WIDTH,
.height = VINO_NTSC_HEIGHT,
.odd = {
- .top = VINO_CLIPPING_START_ODD_D1,
- .left = 0,
+ .top = VINO_CLIPPING_START_ODD_D1,
+ .left = 0,
.bottom = VINO_CLIPPING_START_ODD_D1
+ VINO_NTSC_HEIGHT / 2 - 1,
- .right = VINO_NTSC_WIDTH,
+ .right = VINO_NTSC_WIDTH,
},
.even = {
- .top = VINO_CLIPPING_START_EVEN_D1,
- .left = 0,
+ .top = VINO_CLIPPING_START_EVEN_D1,
+ .left = 0,
.bottom = VINO_CLIPPING_START_EVEN_D1
+ VINO_NTSC_HEIGHT / 2 - 1,
- .right = VINO_NTSC_WIDTH,
+ .right = VINO_NTSC_WIDTH,
},
}
};
@@ -491,7 +500,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
.step = 1,
.default_value = INDYCAM_AGC_DEFAULT,
.flags = 0,
- .reserved = { 0, 0 },
+ .reserved = { INDYCAM_CONTROL_AGC, 0 },
},{
.id = V4L2_CID_AUTO_WHITE_BALANCE,
.type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -501,7 +510,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
.step = 1,
.default_value = INDYCAM_AWB_DEFAULT,
.flags = 0,
- .reserved = { 0, 0 },
+ .reserved = { INDYCAM_CONTROL_AWB, 0 },
},{
.id = V4L2_CID_GAIN,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -511,7 +520,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
.step = 1,
.default_value = INDYCAM_GAIN_DEFAULT,
.flags = 0,
- .reserved = { 0, 0 },
+ .reserved = { INDYCAM_CONTROL_GAIN, 0 },
},{
.id = V4L2_CID_PRIVATE_BASE,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -521,7 +530,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
.step = 1,
.default_value = INDYCAM_RED_SATURATION_DEFAULT,
.flags = 0,
- .reserved = { 0, 0 },
+ .reserved = { INDYCAM_CONTROL_RED_SATURATION, 0 },
},{
.id = V4L2_CID_PRIVATE_BASE + 1,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -531,7 +540,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
.step = 1,
.default_value = INDYCAM_BLUE_SATURATION_DEFAULT,
.flags = 0,
- .reserved = { 0, 0 },
+ .reserved = { INDYCAM_CONTROL_BLUE_SATURATION, 0 },
},{
.id = V4L2_CID_RED_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -541,7 +550,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
.step = 1,
.default_value = INDYCAM_RED_BALANCE_DEFAULT,
.flags = 0,
- .reserved = { 0, 0 },
+ .reserved = { INDYCAM_CONTROL_RED_BALANCE, 0 },
},{
.id = V4L2_CID_BLUE_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -551,7 +560,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
.step = 1,
.default_value = INDYCAM_BLUE_BALANCE_DEFAULT,
.flags = 0,
- .reserved = { 0, 0 },
+ .reserved = { INDYCAM_CONTROL_BLUE_BALANCE, 0 },
},{
.id = V4L2_CID_EXPOSURE,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -561,7 +570,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
.step = 1,
.default_value = INDYCAM_SHUTTER_DEFAULT,
.flags = 0,
- .reserved = { 0, 0 },
+ .reserved = { INDYCAM_CONTROL_SHUTTER, 0 },
},{
.id = V4L2_CID_GAMMA,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -571,11 +580,11 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
.step = 1,
.default_value = INDYCAM_GAMMA_DEFAULT,
.flags = 0,
- .reserved = { 0, 0 },
+ .reserved = { INDYCAM_CONTROL_GAMMA, 0 },
}
};
-#define VINO_SAA7191_V4L2_CONTROL_COUNT 2
+#define VINO_SAA7191_V4L2_CONTROL_COUNT 9
struct v4l2_queryctrl vino_saa7191_v4l2_controls[] = {
{
@@ -587,9 +596,59 @@ struct v4l2_queryctrl vino_saa7191_v4l2_controls[] = {
.step = 1,
.default_value = SAA7191_HUE_DEFAULT,
.flags = 0,
- .reserved = { 0, 0 },
+ .reserved = { SAA7191_CONTROL_HUE, 0 },
},{
.id = V4L2_CID_PRIVATE_BASE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Luminance Bandpass",
+ .minimum = SAA7191_BANDPASS_MIN,
+ .maximum = SAA7191_BANDPASS_MAX,
+ .step = 1,
+ .default_value = SAA7191_BANDPASS_DEFAULT,
+ .flags = 0,
+ .reserved = { SAA7191_CONTROL_BANDPASS, 0 },
+ },{
+ .id = V4L2_CID_PRIVATE_BASE + 1,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Luminance Bandpass Weight",
+ .minimum = SAA7191_BANDPASS_WEIGHT_MIN,
+ .maximum = SAA7191_BANDPASS_WEIGHT_MAX,
+ .step = 1,
+ .default_value = SAA7191_BANDPASS_WEIGHT_DEFAULT,
+ .flags = 0,
+ .reserved = { SAA7191_CONTROL_BANDPASS_WEIGHT, 0 },
+ },{
+ .id = V4L2_CID_PRIVATE_BASE + 2,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "HF Luminance Coring",
+ .minimum = SAA7191_CORING_MIN,
+ .maximum = SAA7191_CORING_MAX,
+ .step = 1,
+ .default_value = SAA7191_CORING_DEFAULT,
+ .flags = 0,
+ .reserved = { SAA7191_CONTROL_CORING, 0 },
+ },{
+ .id = V4L2_CID_PRIVATE_BASE + 3,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Force Colour",
+ .minimum = SAA7191_FORCE_COLOUR_MIN,
+ .maximum = SAA7191_FORCE_COLOUR_MAX,
+ .step = 1,
+ .default_value = SAA7191_FORCE_COLOUR_DEFAULT,
+ .flags = 0,
+ .reserved = { SAA7191_CONTROL_FORCE_COLOUR, 0 },
+ },{
+ .id = V4L2_CID_PRIVATE_BASE + 4,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Chrominance Gain Control",
+ .minimum = SAA7191_CHROMA_GAIN_MIN,
+ .maximum = SAA7191_CHROMA_GAIN_MAX,
+ .step = 1,
+ .default_value = SAA7191_CHROMA_GAIN_DEFAULT,
+ .flags = 0,
+ .reserved = { SAA7191_CONTROL_CHROMA_GAIN, 0 },
+ },{
+ .id = V4L2_CID_PRIVATE_BASE + 5,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "VTR Time Constant",
.minimum = SAA7191_VTRC_MIN,
@@ -597,7 +656,27 @@ struct v4l2_queryctrl vino_saa7191_v4l2_controls[] = {
.step = 1,
.default_value = SAA7191_VTRC_DEFAULT,
.flags = 0,
- .reserved = { 0, 0 },
+ .reserved = { SAA7191_CONTROL_VTRC, 0 },
+ },{
+ .id = V4L2_CID_PRIVATE_BASE + 6,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Luminance Delay Compensation",
+ .minimum = SAA7191_LUMA_DELAY_MIN,
+ .maximum = SAA7191_LUMA_DELAY_MAX,
+ .step = 1,
+ .default_value = SAA7191_LUMA_DELAY_DEFAULT,
+ .flags = 0,
+ .reserved = { SAA7191_CONTROL_LUMA_DELAY, 0 },
+ },{
+ .id = V4L2_CID_PRIVATE_BASE + 7,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Vertical Noise Reduction",
+ .minimum = SAA7191_VNR_MIN,
+ .maximum = SAA7191_VNR_MAX,
+ .step = 1,
+ .default_value = SAA7191_VNR_DEFAULT,
+ .flags = 0,
+ .reserved = { SAA7191_CONTROL_VNR, 0 },
}
};
@@ -639,9 +718,10 @@ static struct i2c_algo_sgi_data i2c_sgi_vino_data =
*/
static int i2c_vino_client_reg(struct i2c_client *client)
{
+ unsigned long flags;
int ret = 0;
- spin_lock(&vino_drvdata->input_lock);
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
switch (client->driver->id) {
case I2C_DRIVERID_SAA7191:
if (vino_drvdata->decoder.driver)
@@ -658,16 +738,17 @@ static int i2c_vino_client_reg(struct i2c_client *client)
default:
ret = -ENODEV;
}
- spin_unlock(&vino_drvdata->input_lock);
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
return ret;
}
static int i2c_vino_client_unreg(struct i2c_client *client)
{
+ unsigned long flags;
int ret = 0;
- spin_lock(&vino_drvdata->input_lock);
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
if (client == vino_drvdata->decoder.driver) {
if (vino_drvdata->decoder.owner != VINO_NO_CHANNEL)
ret = -EBUSY;
@@ -679,7 +760,7 @@ static int i2c_vino_client_unreg(struct i2c_client *client)
else
vino_drvdata->camera.driver = NULL;
}
- spin_unlock(&vino_drvdata->input_lock);
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
return ret;
}
@@ -727,7 +808,7 @@ static void vino_free_buffer_with_count(struct vino_framebuffer *fb,
dprintk("vino_free_buffer_with_count(): count = %d\n", count);
for (i = 0; i < count; i++) {
- mem_map_unreserve(virt_to_page(fb->desc_table.virtual[i]));
+ ClearPageReserved(virt_to_page(fb->desc_table.virtual[i]));
dma_unmap_single(NULL,
fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i],
PAGE_SIZE, DMA_FROM_DEVICE);
@@ -805,7 +886,7 @@ static int vino_allocate_buffer(struct vino_framebuffer *fb,
dma_data_addr + VINO_PAGE_SIZE * j;
}
- mem_map_reserve(virt_to_page(fb->desc_table.virtual[i]));
+ SetPageReserved(virt_to_page(fb->desc_table.virtual[i]));
}
/* page_count needs to be set anyway, because the descriptor table has
@@ -892,7 +973,7 @@ static int vino_prepare_user_buffer(struct vino_framebuffer *fb,
dma_data_addr + VINO_PAGE_SIZE * j;
}
- mem_map_reserve(virt_to_page(fb->desc_table.virtual[i]));
+ SetPageReserved(virt_to_page(fb->desc_table.virtual[i]));
}
/* page_count needs to be set anyway, because the descriptor table has
@@ -933,7 +1014,7 @@ static void vino_sync_buffer(struct vino_framebuffer *fb)
/* Framebuffer fifo functions (need to be locked externally) */
-static void vino_fifo_init(struct vino_framebuffer_fifo *f,
+static inline void vino_fifo_init(struct vino_framebuffer_fifo *f,
unsigned int length)
{
f->length = 0;
@@ -941,16 +1022,18 @@ static void vino_fifo_init(struct vino_framebuffer_fifo *f,
f->head = 0;
f->tail = 0;
- if (length > VINO_FRAMEBUFFER_MAX_COUNT)
- length = VINO_FRAMEBUFFER_MAX_COUNT;
+ if (length > VINO_FRAMEBUFFER_COUNT_MAX)
+ length = VINO_FRAMEBUFFER_COUNT_MAX;
f->length = length;
}
/* returns true/false */
-static int vino_fifo_has_id(struct vino_framebuffer_fifo *f, unsigned int id)
+static inline int vino_fifo_has_id(struct vino_framebuffer_fifo *f,
+ unsigned int id)
{
unsigned int i;
+
for (i = f->head; i == (f->tail - 1); i = (i + 1) % f->length) {
if (f->data[i] == id)
return 1;
@@ -959,13 +1042,15 @@ static int vino_fifo_has_id(struct vino_framebuffer_fifo *f, unsigned int id)
return 0;
}
+#if 0
/* returns true/false */
-static int vino_fifo_full(struct vino_framebuffer_fifo *f)
+static inline int vino_fifo_full(struct vino_framebuffer_fifo *f)
{
return (f->used == f->length);
}
+#endif
-static unsigned int vino_fifo_get_used(struct vino_framebuffer_fifo *f)
+static inline unsigned int vino_fifo_get_used(struct vino_framebuffer_fifo *f)
{
return f->used;
}
@@ -1076,8 +1161,8 @@ static int vino_queue_init(struct vino_framebuffer_queue *q,
down(&q->queue_sem);
- if (*length > VINO_FRAMEBUFFER_MAX_COUNT)
- *length = VINO_FRAMEBUFFER_MAX_COUNT;
+ if (*length > VINO_FRAMEBUFFER_COUNT_MAX)
+ *length = VINO_FRAMEBUFFER_COUNT_MAX;
q->length = 0;
@@ -1313,6 +1398,7 @@ out:
return ret;
}
+#if 0
static int vino_queue_get_total(struct vino_framebuffer_queue *q,
unsigned int *total)
{
@@ -1338,6 +1424,7 @@ out:
return ret;
}
+#endif
static struct vino_framebuffer *vino_queue_peek(struct
vino_framebuffer_queue *q,
@@ -1471,12 +1558,14 @@ static void vino_update_line_size(struct vino_channel_settings *vcs)
dprintk("update_line_size(): before: w = %d, d = %d, "
"line_size = %d\n", w, d, vcs->line_size);
+
/* line size must be multiple of 8 bytes */
lsize = (bpp * (w / d)) & ~7;
w = (lsize / bpp) * d;
vcs->clipping.right = vcs->clipping.left + w;
vcs->line_size = lsize;
+
dprintk("update_line_size(): after: w = %d, d = %d, "
"line_size = %d\n", w, d, vcs->line_size);
}
@@ -1532,7 +1621,7 @@ static void vino_set_clipping(struct vino_channel_settings *vcs,
}
/* execute with input_lock locked */
-static void vino_set_default_clipping(struct vino_channel_settings *vcs)
+static inline void vino_set_default_clipping(struct vino_channel_settings *vcs)
{
vino_set_clipping(vcs, 0, 0, vino_data_norms[vcs->data_norm].width,
vino_data_norms[vcs->data_norm].height);
@@ -1556,8 +1645,7 @@ static void vino_set_scaling(struct vino_channel_settings *vcs,
if (d < 1) {
d = 1;
- }
- if (d > 8) {
+ } else if (d > 8) {
d = 8;
}
@@ -1570,7 +1658,7 @@ static void vino_set_scaling(struct vino_channel_settings *vcs,
}
/* execute with input_lock locked */
-static void vino_reset_scaling(struct vino_channel_settings *vcs)
+static inline void vino_set_default_scaling(struct vino_channel_settings *vcs)
{
vino_set_scaling(vcs, vcs->clipping.right - vcs->clipping.left,
vcs->clipping.bottom - vcs->clipping.top);
@@ -1649,7 +1737,8 @@ static void vino_set_framerate(struct vino_channel_settings *vcs,
}
/* execute with input_lock locked */
-static void vino_set_default_framerate(struct vino_channel_settings *vcs)
+static inline void vino_set_default_framerate(struct
+ vino_channel_settings *vcs)
{
vino_set_framerate(vcs, vino_data_norms[vcs->data_norm].fps_max);
}
@@ -1687,6 +1776,9 @@ static int vino_dma_setup(struct vino_channel_settings *vcs,
* should be more than enough time */
udelay(VINO_DESC_FETCH_DELAY);
+ dprintk("vino_dma_setup(): start desc = %08x, next 4 desc = %08x\n",
+ ch->start_desc_tbl, ch->next_4_desc);
+
/* set the alpha register */
ch->alpha = vcs->alpha;
@@ -1700,9 +1792,6 @@ static int vino_dma_setup(struct vino_channel_settings *vcs,
VINO_CLIP_EVEN(norm->even.top +
vcs->clipping.bottom / 2 - 1) |
VINO_CLIP_X(vcs->clipping.right);
- /* FIXME: end-of-field bug workaround
- VINO_CLIP_X(VINO_PAL_WIDTH);
- */
/* set the size of actual content in the buffer (DECIMATION !) */
fb->data_size = ((vcs->clipping.right - vcs->clipping.left) /
@@ -1802,7 +1891,7 @@ static int vino_dma_setup(struct vino_channel_settings *vcs,
}
/* (execute only with vino_lock locked) */
-static void vino_dma_start(struct vino_channel_settings *vcs)
+static inline void vino_dma_start(struct vino_channel_settings *vcs)
{
u32 ctrl = vino->control;
@@ -1813,12 +1902,14 @@ static void vino_dma_start(struct vino_channel_settings *vcs)
}
/* (execute only with vino_lock locked) */
-static void vino_dma_stop(struct vino_channel_settings *vcs)
+static inline void vino_dma_stop(struct vino_channel_settings *vcs)
{
u32 ctrl = vino->control;
ctrl &= (vcs->channel == VINO_CHANNEL_A) ?
~VINO_CTRL_A_DMA_ENBL : ~VINO_CTRL_B_DMA_ENBL;
+ ctrl &= (vcs->channel == VINO_CHANNEL_A) ?
+ ~VINO_CTRL_A_INT : ~VINO_CTRL_B_INT;
vino->control = ctrl;
dprintk("vino_dma_stop():\n");
}
@@ -1902,7 +1993,7 @@ static int vino_capture_next(struct vino_channel_settings *vcs, int start)
struct vino_framebuffer *fb;
unsigned int incoming, id;
int err = 0;
- unsigned long flags, flags2;
+ unsigned long flags;
dprintk("vino_capture_next():\n");
@@ -1943,10 +2034,6 @@ static int vino_capture_next(struct vino_channel_settings *vcs, int start)
goto out;
}
- spin_lock_irqsave(&fb->state_lock, flags2);
- fb->state = VINO_FRAMEBUFFER_UNUSED;
- spin_unlock_irqrestore(&fb->state_lock, flags2);
-
if (start) {
vcs->capturing = 1;
}
@@ -1964,7 +2051,7 @@ out:
return err;
}
-static int vino_is_capturing(struct vino_channel_settings *vcs)
+static inline int vino_is_capturing(struct vino_channel_settings *vcs)
{
int ret;
unsigned long flags;
@@ -2076,6 +2163,7 @@ static void vino_capture_stop(struct vino_channel_settings *vcs)
dprintk("vino_capture_stop():\n");
spin_lock_irqsave(&vcs->capture_lock, flags);
+
/* unset capturing to stop queue processing */
vcs->capturing = 0;
@@ -2121,6 +2209,7 @@ out:
spin_unlock_irqrestore(&vcs->capture_lock, flags);
}
+#if 0
static int vino_capture_failed(struct vino_channel_settings *vcs)
{
struct vino_framebuffer *fb;
@@ -2165,9 +2254,31 @@ static int vino_capture_failed(struct vino_channel_settings *vcs)
return 0;
}
+#endif
+
+static void vino_skip_frame(struct vino_channel_settings *vcs)
+{
+ struct vino_framebuffer *fb;
+ unsigned long flags;
+ unsigned int id;
+
+ spin_lock_irqsave(&vcs->capture_lock, flags);
+ fb = vino_queue_peek(&vcs->fb_queue, &id);
+ if (!fb) {
+ spin_unlock_irqrestore(&vcs->capture_lock, flags);
+ dprintk("vino_skip_frame(): vino_queue_peek() failed!\n");
+ return;
+ }
+ spin_unlock_irqrestore(&vcs->capture_lock, flags);
+
+ spin_lock_irqsave(&fb->state_lock, flags);
+ fb->state = VINO_FRAMEBUFFER_UNUSED;
+ spin_unlock_irqrestore(&fb->state_lock, flags);
+
+ vino_capture_next(vcs, 0);
+}
-static void vino_frame_done(struct vino_channel_settings *vcs,
- unsigned int fc)
+static void vino_frame_done(struct vino_channel_settings *vcs)
{
struct vino_framebuffer *fb;
unsigned long flags;
@@ -2181,8 +2292,9 @@ static void vino_frame_done(struct vino_channel_settings *vcs,
}
spin_unlock_irqrestore(&vcs->capture_lock, flags);
- fb->frame_counter = fc;
- do_gettimeofday(&fb->timestamp);
+ fb->frame_counter = vcs->int_data.frame_counter;
+ memcpy(&fb->timestamp, &vcs->int_data.timestamp,
+ sizeof(struct timeval));
spin_lock_irqsave(&fb->state_lock, flags);
if (fb->state == VINO_FRAMEBUFFER_IN_USE)
@@ -2194,72 +2306,175 @@ static void vino_frame_done(struct vino_channel_settings *vcs,
vino_capture_next(vcs, 0);
}
+static void vino_capture_tasklet(unsigned long channel) {
+ struct vino_channel_settings *vcs;
+
+ vcs = (channel == VINO_CHANNEL_A)
+ ? &vino_drvdata->a : &vino_drvdata->b;
+
+ if (vcs->int_data.skip)
+ vcs->int_data.skip_count++;
+
+ if (vcs->int_data.skip && (vcs->int_data.skip_count
+ <= VINO_MAX_FRAME_SKIP_COUNT)) {
+ vino_skip_frame(vcs);
+ } else {
+ vcs->int_data.skip_count = 0;
+ vino_frame_done(vcs);
+ }
+}
+
static irqreturn_t vino_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
- u32 intr;
+ u32 ctrl, intr;
unsigned int fc_a, fc_b;
- int done_a = 0;
- int done_b = 0;
+ int handled_a = 0, skip_a = 0, done_a = 0;
+ int handled_b = 0, skip_b = 0, done_b = 0;
+
+#ifdef VINO_DEBUG_INT
+ int loop = 0;
+ unsigned int line_count = vino->a.line_count,
+ page_index = vino->a.page_index,
+ field_counter = vino->a.field_counter,
+ start_desc_tbl = vino->a.start_desc_tbl,
+ next_4_desc = vino->a.next_4_desc;
+ unsigned int line_count_2,
+ page_index_2,
+ field_counter_2,
+ start_desc_tbl_2,
+ next_4_desc_2;
+#endif
spin_lock(&vino_drvdata->vino_lock);
- intr = vino->intr_status;
- fc_a = vino->a.field_counter / 2;
- fc_b = vino->b.field_counter / 2;
-
- // TODO: handle error-interrupts in some special way ?
-
- if (intr & VINO_INTSTAT_A) {
- if (intr & VINO_INTSTAT_A_EOF) {
- vino_drvdata->a.field++;
- if (vino_drvdata->a.field > 1) {
+ while ((intr = vino->intr_status)) {
+ fc_a = vino->a.field_counter >> 1;
+ fc_b = vino->b.field_counter >> 1;
+
+ /* handle error-interrupts in some special way ?
+ * --> skips frames */
+ if (intr & VINO_INTSTAT_A) {
+ if (intr & VINO_INTSTAT_A_EOF) {
+ vino_drvdata->a.field++;
+ if (vino_drvdata->a.field > 1) {
+ vino_dma_stop(&vino_drvdata->a);
+ vino_clear_interrupt(&vino_drvdata->a);
+ vino_drvdata->a.field = 0;
+ done_a = 1;
+ } else {
+ if (vino->a.page_index
+ != vino_drvdata->a.line_size) {
+ vino->a.line_count = 0;
+ vino->a.page_index =
+ vino_drvdata->
+ a.line_size;
+ vino->a.next_4_desc =
+ vino->a.start_desc_tbl;
+ }
+ }
+ dprintk("channel A end-of-field "
+ "interrupt: %04x\n", intr);
+ } else {
vino_dma_stop(&vino_drvdata->a);
vino_clear_interrupt(&vino_drvdata->a);
vino_drvdata->a.field = 0;
- done_a = 1;
+ skip_a = 1;
+ dprintk("channel A error interrupt: %04x\n",
+ intr);
}
- dprintk("intr: channel A end-of-field interrupt: "
- "%04x\n", intr);
- } else {
- vino_dma_stop(&vino_drvdata->a);
- vino_clear_interrupt(&vino_drvdata->a);
- done_a = 1;
- dprintk("channel A error interrupt: %04x\n", intr);
+
+#ifdef VINO_DEBUG_INT
+ line_count_2 = vino->a.line_count;
+ page_index_2 = vino->a.page_index;
+ field_counter_2 = vino->a.field_counter;
+ start_desc_tbl_2 = vino->a.start_desc_tbl;
+ next_4_desc_2 = vino->a.next_4_desc;
+
+ printk("intr = %04x, loop = %d, field = %d\n",
+ intr, loop, vino_drvdata->a.field);
+ printk("1- line count = %04d, page index = %04d, "
+ "start = %08x, next = %08x\n"
+ " fieldc = %d, framec = %d\n",
+ line_count, page_index, start_desc_tbl,
+ next_4_desc, field_counter, fc_a);
+ printk("12-line count = %04d, page index = %04d, "
+ " start = %08x, next = %08x\n",
+ line_count_2, page_index_2, start_desc_tbl_2,
+ next_4_desc_2);
+
+ if (done_a)
+ printk("\n");
+#endif
}
- }
- if (intr & VINO_INTSTAT_B) {
- if (intr & VINO_INTSTAT_B_EOF) {
- vino_drvdata->b.field++;
- if (vino_drvdata->b.field > 1) {
+
+ if (intr & VINO_INTSTAT_B) {
+ if (intr & VINO_INTSTAT_B_EOF) {
+ vino_drvdata->b.field++;
+ if (vino_drvdata->b.field > 1) {
+ vino_dma_stop(&vino_drvdata->b);
+ vino_clear_interrupt(&vino_drvdata->b);
+ vino_drvdata->b.field = 0;
+ done_b = 1;
+ }
+ dprintk("channel B end-of-field "
+ "interrupt: %04x\n", intr);
+ } else {
vino_dma_stop(&vino_drvdata->b);
vino_clear_interrupt(&vino_drvdata->b);
vino_drvdata->b.field = 0;
- done_b = 1;
+ skip_b = 1;
+ dprintk("channel B error interrupt: %04x\n",
+ intr);
}
- dprintk("intr: channel B end-of-field interrupt: "
- "%04x\n", intr);
- } else {
- vino_dma_stop(&vino_drvdata->b);
- vino_clear_interrupt(&vino_drvdata->b);
- done_b = 1;
- dprintk("channel B error interrupt: %04x\n", intr);
}
- }
- /* always remember to clear interrupt status */
- vino->intr_status = ~intr;
+ /* Always remember to clear interrupt status.
+ * Disable VINO interrupts while we do this. */
+ ctrl = vino->control;
+ vino->control = ctrl & ~(VINO_CTRL_A_INT | VINO_CTRL_B_INT);
+ vino->intr_status = ~intr;
+ vino->control = ctrl;
- spin_unlock(&vino_drvdata->vino_lock);
+ spin_unlock(&vino_drvdata->vino_lock);
- if (done_a) {
- vino_frame_done(&vino_drvdata->a, fc_a);
- dprintk("channel A frame done, interrupt: %d\n", intr);
- }
- if (done_b) {
- vino_frame_done(&vino_drvdata->b, fc_b);
- dprintk("channel B frame done, interrupt: %d\n", intr);
+ if ((!handled_a) && (done_a || skip_a)) {
+ if (!skip_a) {
+ do_gettimeofday(&vino_drvdata->
+ a.int_data.timestamp);
+ vino_drvdata->a.int_data.frame_counter = fc_a;
+ }
+ vino_drvdata->a.int_data.skip = skip_a;
+
+ dprintk("channel A %s, interrupt: %d\n",
+ skip_a ? "skipping frame" : "frame done",
+ intr);
+ tasklet_hi_schedule(&vino_tasklet_a);
+ handled_a = 1;
+ }
+
+ if ((!handled_b) && (done_b || skip_b)) {
+ if (!skip_b) {
+ do_gettimeofday(&vino_drvdata->
+ b.int_data.timestamp);
+ vino_drvdata->b.int_data.frame_counter = fc_b;
+ }
+ vino_drvdata->b.int_data.skip = skip_b;
+
+ dprintk("channel B %s, interrupt: %d\n",
+ skip_b ? "skipping frame" : "frame done",
+ intr);
+ tasklet_hi_schedule(&vino_tasklet_b);
+ handled_b = 1;
+ }
+
+#ifdef VINO_DEBUG_INT
+ loop++;
+#endif
+ spin_lock(&vino_drvdata->vino_lock);
}
+ spin_unlock(&vino_drvdata->vino_lock);
+
return IRQ_HANDLED;
}
@@ -2279,11 +2494,13 @@ static int vino_get_saa7191_input(int input)
}
}
-static int vino_get_saa7191_norm(int norm)
+static int vino_get_saa7191_norm(unsigned int data_norm)
{
- switch (norm) {
+ switch (data_norm) {
case VINO_DATA_NORM_AUTO:
return SAA7191_NORM_AUTO;
+ case VINO_DATA_NORM_AUTO_EXT:
+ return SAA7191_NORM_AUTO_EXT;
case VINO_DATA_NORM_PAL:
return SAA7191_NORM_PAL;
case VINO_DATA_NORM_NTSC:
@@ -2297,6 +2514,57 @@ static int vino_get_saa7191_norm(int norm)
}
}
+static int vino_get_from_saa7191_norm(int saa7191_norm)
+{
+ switch (saa7191_norm) {
+ case SAA7191_NORM_PAL:
+ return VINO_DATA_NORM_PAL;
+ case SAA7191_NORM_NTSC:
+ return VINO_DATA_NORM_NTSC;
+ case SAA7191_NORM_SECAM:
+ return VINO_DATA_NORM_SECAM;
+ default:
+ printk(KERN_ERR "VINO: vino_get_from_saa7191_norm(): "
+ "invalid norm!\n");
+ return VINO_DATA_NORM_NONE;
+ }
+}
+
+static int vino_saa7191_set_norm(unsigned int *data_norm)
+{
+ int saa7191_norm, new_data_norm;
+ int err = 0;
+
+ saa7191_norm = vino_get_saa7191_norm(*data_norm);
+
+ err = i2c_decoder_command(DECODER_SAA7191_SET_NORM,
+ &saa7191_norm);
+ if (err)
+ goto out;
+
+ if ((*data_norm == VINO_DATA_NORM_AUTO)
+ || (*data_norm == VINO_DATA_NORM_AUTO_EXT)) {
+ struct saa7191_status status;
+
+ err = i2c_decoder_command(DECODER_SAA7191_GET_STATUS,
+ &status);
+ if (err)
+ goto out;
+
+ new_data_norm =
+ vino_get_from_saa7191_norm(status.norm);
+ if (new_data_norm == VINO_DATA_NORM_NONE) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ *data_norm = (unsigned int)new_data_norm;
+ }
+
+out:
+ return err;
+}
+
/* execute with input_lock locked */
static int vino_is_input_owner(struct vino_channel_settings *vcs)
{
@@ -2313,11 +2581,12 @@ static int vino_is_input_owner(struct vino_channel_settings *vcs)
static int vino_acquire_input(struct vino_channel_settings *vcs)
{
+ unsigned long flags;
int ret = 0;
dprintk("vino_acquire_input():\n");
- spin_lock(&vino_drvdata->input_lock);
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
/* First try D1 and then SAA7191 */
if (vino_drvdata->camera.driver
@@ -2332,23 +2601,48 @@ static int vino_acquire_input(struct vino_channel_settings *vcs)
vcs->data_norm = VINO_DATA_NORM_D1;
} else if (vino_drvdata->decoder.driver
&& (vino_drvdata->decoder.owner == VINO_NO_CHANNEL)) {
+ int input, data_norm;
int saa7191_input;
- int saa7191_norm;
if (i2c_use_client(vino_drvdata->decoder.driver)) {
ret = -ENODEV;
goto out;
}
- vino_drvdata->decoder.owner = vcs->channel;
- vcs->input = VINO_INPUT_COMPOSITE;
- vcs->data_norm = VINO_DATA_NORM_PAL;
+ input = VINO_INPUT_COMPOSITE;
+
+ saa7191_input = vino_get_saa7191_input(input);
+ ret = i2c_decoder_command(DECODER_SET_INPUT,
+ &saa7191_input);
+ if (ret) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
- saa7191_input = vino_get_saa7191_input(vcs->input);
- i2c_decoder_command(DECODER_SET_INPUT, &saa7191_input);
+ /* Don't hold spinlocks while auto-detecting norm
+ * as it may take a while... */
- saa7191_norm = vino_get_saa7191_norm(vcs->data_norm);
- i2c_decoder_command(DECODER_SAA7191_SET_NORM, &saa7191_norm);
+ data_norm = VINO_DATA_NORM_AUTO_EXT;
+
+ ret = vino_saa7191_set_norm(&data_norm);
+ if ((ret == -EBUSY) || (ret == -EAGAIN)) {
+ data_norm = VINO_DATA_NORM_PAL;
+ ret = vino_saa7191_set_norm(&data_norm);
+ }
+
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+
+ if (ret) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ vino_drvdata->decoder.owner = vcs->channel;
+
+ vcs->input = input;
+ vcs->data_norm = data_norm;
} else {
vcs->input = (vcs->channel == VINO_CHANNEL_A) ?
vino_drvdata->b.input : vino_drvdata->a.input;
@@ -2361,15 +2655,14 @@ static int vino_acquire_input(struct vino_channel_settings *vcs)
goto out;
}
- if (vino_is_input_owner(vcs)) {
- vino_set_default_clipping(vcs);
- vino_set_default_framerate(vcs);
- }
+ vino_set_default_clipping(vcs);
+ vino_set_default_scaling(vcs);
+ vino_set_default_framerate(vcs);
dprintk("vino_acquire_input(): %s\n", vino_inputs[vcs->input].name);
out:
- spin_unlock(&vino_drvdata->input_lock);
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
return ret;
}
@@ -2378,16 +2671,17 @@ static int vino_set_input(struct vino_channel_settings *vcs, int input)
{
struct vino_channel_settings *vcs2 = (vcs->channel == VINO_CHANNEL_A) ?
&vino_drvdata->b : &vino_drvdata->a;
+ unsigned long flags;
int ret = 0;
dprintk("vino_set_input():\n");
- spin_lock(&vino_drvdata->input_lock);
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
if (vcs->input == input)
goto out;
- switch(input) {
+ switch (input) {
case VINO_INPUT_COMPOSITE:
case VINO_INPUT_SVIDEO:
if (!vino_drvdata->decoder.driver) {
@@ -2404,19 +2698,43 @@ static int vino_set_input(struct vino_channel_settings *vcs, int input)
}
if (vino_drvdata->decoder.owner == vcs->channel) {
+ int data_norm;
int saa7191_input;
- int saa7191_norm;
- vcs->input = input;
- vcs->data_norm = VINO_DATA_NORM_PAL;
+ saa7191_input = vino_get_saa7191_input(input);
+ ret = i2c_decoder_command(DECODER_SET_INPUT,
+ &saa7191_input);
+ if (ret) {
+ vino_drvdata->decoder.owner = VINO_NO_CHANNEL;
+ ret = -EINVAL;
+ goto out;
+ }
+
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+
+ /* Don't hold spinlocks while auto-detecting norm
+ * as it may take a while... */
+
+ data_norm = VINO_DATA_NORM_AUTO_EXT;
+
+ ret = vino_saa7191_set_norm(&data_norm);
+ if ((ret == -EBUSY) || (ret == -EAGAIN)) {
+ data_norm = VINO_DATA_NORM_PAL;
+ ret = vino_saa7191_set_norm(&data_norm);
+ }
- saa7191_input = vino_get_saa7191_input(vcs->input);
- i2c_decoder_command(DECODER_SET_INPUT, &saa7191_input);
- saa7191_norm = vino_get_saa7191_norm(vcs->data_norm);
- i2c_decoder_command(DECODER_SAA7191_SET_NORM,
- &saa7191_norm);
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+
+ if (ret) {
+ vino_drvdata->decoder.owner = VINO_NO_CHANNEL;
+ ret = -EINVAL;
+ goto out;
+ }
+
+ vcs->input = input;
+ vcs->data_norm = data_norm;
} else {
- if (vcs2->input != input) {
+ if (input != vcs2->input) {
ret = -EBUSY;
goto out;
}
@@ -2471,12 +2789,13 @@ static int vino_set_input(struct vino_channel_settings *vcs, int input)
}
vino_set_default_clipping(vcs);
+ vino_set_default_scaling(vcs);
vino_set_default_framerate(vcs);
dprintk("vino_set_input(): %s\n", vino_inputs[vcs->input].name);
out:
- spin_unlock(&vino_drvdata->input_lock);
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
return ret;
}
@@ -2485,10 +2804,11 @@ static void vino_release_input(struct vino_channel_settings *vcs)
{
struct vino_channel_settings *vcs2 = (vcs->channel == VINO_CHANNEL_A) ?
&vino_drvdata->b : &vino_drvdata->a;
+ unsigned long flags;
dprintk("vino_release_input():\n");
- spin_lock(&vino_drvdata->input_lock);
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
/* Release ownership of the channel
* and if the other channel takes input from
@@ -2511,34 +2831,61 @@ static void vino_release_input(struct vino_channel_settings *vcs)
}
vcs->input = VINO_INPUT_NONE;
- spin_unlock(&vino_drvdata->input_lock);
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
}
/* execute with input_lock locked */
static int vino_set_data_norm(struct vino_channel_settings *vcs,
- unsigned int data_norm)
+ unsigned int data_norm,
+ unsigned long *flags)
{
- int saa7191_norm;
+ int err = 0;
+
+ if (data_norm == vcs->data_norm)
+ return 0;
switch (vcs->input) {
case VINO_INPUT_D1:
/* only one "norm" supported */
- if (data_norm != VINO_DATA_NORM_D1)
+ if ((data_norm != VINO_DATA_NORM_D1)
+ && (data_norm != VINO_DATA_NORM_AUTO)
+ && (data_norm != VINO_DATA_NORM_AUTO_EXT))
return -EINVAL;
break;
case VINO_INPUT_COMPOSITE:
- case VINO_INPUT_SVIDEO:
+ case VINO_INPUT_SVIDEO: {
+ if ((data_norm != VINO_DATA_NORM_PAL)
+ && (data_norm != VINO_DATA_NORM_NTSC)
+ && (data_norm != VINO_DATA_NORM_SECAM)
+ && (data_norm != VINO_DATA_NORM_AUTO)
+ && (data_norm != VINO_DATA_NORM_AUTO_EXT))
+ return -EINVAL;
- saa7191_norm = vino_get_saa7191_norm(data_norm);
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, *flags);
+
+ /* Don't hold spinlocks while setting norm
+ * as it may take a while... */
+
+ err = vino_saa7191_set_norm(&data_norm);
+
+ spin_lock_irqsave(&vino_drvdata->input_lock, *flags);
+
+ if (err)
+ goto out;
- i2c_decoder_command(DECODER_SAA7191_SET_NORM, &saa7191_norm);
vcs->data_norm = data_norm;
+
+ vino_set_default_clipping(vcs);
+ vino_set_default_scaling(vcs);
+ vino_set_default_framerate(vcs);
break;
+ }
default:
return -EINVAL;
}
- return 0;
+out:
+ return err;
}
/* V4L2 helper functions */
@@ -2558,8 +2905,9 @@ static int vino_find_data_format(__u32 pixelformat)
static int vino_enum_data_norm(struct vino_channel_settings *vcs, __u32 index)
{
int data_norm = VINO_DATA_NORM_NONE;
+ unsigned long flags;
- spin_lock(&vino_drvdata->input_lock);
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
switch(vcs->input) {
case VINO_INPUT_COMPOSITE:
case VINO_INPUT_SVIDEO:
@@ -2577,7 +2925,7 @@ static int vino_enum_data_norm(struct vino_channel_settings *vcs, __u32 index)
}
break;
}
- spin_unlock(&vino_drvdata->input_lock);
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
return data_norm;
}
@@ -2585,8 +2933,9 @@ static int vino_enum_data_norm(struct vino_channel_settings *vcs, __u32 index)
static int vino_enum_input(struct vino_channel_settings *vcs, __u32 index)
{
int input = VINO_INPUT_NONE;
+ unsigned long flags;
- spin_lock(&vino_drvdata->input_lock);
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
if (vino_drvdata->decoder.driver && vino_drvdata->camera.driver) {
switch (index) {
case 0:
@@ -2615,7 +2964,7 @@ static int vino_enum_input(struct vino_channel_settings *vcs, __u32 index)
break;
}
}
- spin_unlock(&vino_drvdata->input_lock);
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
return input;
}
@@ -2704,15 +3053,16 @@ static int vino_v4l2_enuminput(struct vino_channel_settings *vcs,
}
static int vino_v4l2_g_input(struct vino_channel_settings *vcs,
- struct v4l2_input *i)
+ unsigned int *i)
{
__u32 index;
int input;
+ unsigned long flags;
- spin_lock(&vino_drvdata->input_lock);
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
input = vcs->input;
index = vino_find_input_index(vcs);
- spin_unlock(&vino_drvdata->input_lock);
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
dprintk("input = %d\n", input);
@@ -2720,23 +3070,18 @@ static int vino_v4l2_g_input(struct vino_channel_settings *vcs,
return -EINVAL;
}
- memset(i, 0, sizeof(struct v4l2_input));
-
- i->index = index;
- i->type = V4L2_INPUT_TYPE_CAMERA;
- i->std = vino_inputs[input].std;
- strcpy(i->name, vino_inputs[input].name);
+ *i = index;
return 0;
}
static int vino_v4l2_s_input(struct vino_channel_settings *vcs,
- struct v4l2_input *i)
+ unsigned int *i)
{
int input;
- dprintk("requested input = %d\n", i->index);
+ dprintk("requested input = %d\n", *i);
- input = vino_enum_input(vcs, i->index);
+ input = vino_enum_input(vcs, *i);
if (input == VINO_INPUT_NONE)
return -EINVAL;
@@ -2747,7 +3092,9 @@ static int vino_v4l2_enumstd(struct vino_channel_settings *vcs,
struct v4l2_standard *s)
{
int index = s->index;
- int data_norm = vino_enum_data_norm(vcs, index);
+ int data_norm;
+
+ data_norm = vino_enum_data_norm(vcs, index);
dprintk("standard index = %d\n", index);
if (data_norm == VINO_DATA_NORM_NONE)
@@ -2771,13 +3118,55 @@ static int vino_v4l2_enumstd(struct vino_channel_settings *vcs,
return 0;
}
+static int vino_v4l2_querystd(struct vino_channel_settings *vcs,
+ v4l2_std_id *std)
+{
+ unsigned long flags;
+ int err = 0;
+
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+
+ switch (vcs->input) {
+ case VINO_INPUT_D1:
+ *std = vino_inputs[vcs->input].std;
+ break;
+ case VINO_INPUT_COMPOSITE:
+ case VINO_INPUT_SVIDEO: {
+ struct saa7191_status status;
+
+ i2c_decoder_command(DECODER_SAA7191_GET_STATUS, &status);
+
+ if (status.signal) {
+ if (status.signal_60hz) {
+ *std = V4L2_STD_NTSC;
+ } else {
+ *std = V4L2_STD_PAL | V4L2_STD_SECAM;
+ }
+ } else {
+ *std = vino_inputs[vcs->input].std;
+ }
+ break;
+ }
+ default:
+ err = -EINVAL;
+ }
+
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+
+ return err;
+}
+
static int vino_v4l2_g_std(struct vino_channel_settings *vcs,
v4l2_std_id *std)
{
- spin_lock(&vino_drvdata->input_lock);
- dprintk("current standard = %d\n", vcs->data_norm);
+ unsigned long flags;
+
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+
*std = vino_data_norms[vcs->data_norm].std;
- spin_unlock(&vino_drvdata->input_lock);
+ dprintk("current standard = %d\n", vcs->data_norm);
+
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
return 0;
}
@@ -2785,13 +3174,18 @@ static int vino_v4l2_g_std(struct vino_channel_settings *vcs,
static int vino_v4l2_s_std(struct vino_channel_settings *vcs,
v4l2_std_id *std)
{
+ unsigned long flags;
int ret = 0;
- spin_lock(&vino_drvdata->input_lock);
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+
+ if (!vino_is_input_owner(vcs)) {
+ ret = -EBUSY;
+ goto out;
+ }
/* check if the standard is valid for the current input */
- if (vino_is_input_owner(vcs)
- && (vino_inputs[vcs->input].std & (*std))) {
+ if ((*std) & vino_inputs[vcs->input].std) {
dprintk("standard accepted\n");
/* change the video norm for SAA7191
@@ -2800,24 +3194,33 @@ static int vino_v4l2_s_std(struct vino_channel_settings *vcs,
if (vcs->input == VINO_INPUT_D1)
goto out;
- if ((*std) & V4L2_STD_PAL) {
- vino_set_data_norm(vcs, VINO_DATA_NORM_PAL);
- vcs->data_norm = VINO_DATA_NORM_PAL;
+ if (((*std) & V4L2_STD_PAL)
+ && ((*std) & V4L2_STD_NTSC)
+ && ((*std) & V4L2_STD_SECAM)) {
+ ret = vino_set_data_norm(vcs, VINO_DATA_NORM_AUTO_EXT,
+ &flags);
+ } else if ((*std) & V4L2_STD_PAL) {
+ ret = vino_set_data_norm(vcs, VINO_DATA_NORM_PAL,
+ &flags);
} else if ((*std) & V4L2_STD_NTSC) {
- vino_set_data_norm(vcs, VINO_DATA_NORM_NTSC);
- vcs->data_norm = VINO_DATA_NORM_NTSC;
+ ret = vino_set_data_norm(vcs, VINO_DATA_NORM_NTSC,
+ &flags);
} else if ((*std) & V4L2_STD_SECAM) {
- vino_set_data_norm(vcs, VINO_DATA_NORM_SECAM);
- vcs->data_norm = VINO_DATA_NORM_SECAM;
+ ret = vino_set_data_norm(vcs, VINO_DATA_NORM_SECAM,
+ &flags);
} else {
ret = -EINVAL;
}
+
+ if (ret) {
+ ret = -EINVAL;
+ }
} else {
ret = -EINVAL;
}
out:
- spin_unlock(&vino_drvdata->input_lock);
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
return ret;
}
@@ -2855,6 +3258,7 @@ static int vino_v4l2_try_fmt(struct vino_channel_settings *vcs,
struct v4l2_format *f)
{
struct vino_channel_settings tempvcs;
+ unsigned long flags;
switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
@@ -2863,13 +3267,13 @@ static int vino_v4l2_try_fmt(struct vino_channel_settings *vcs,
dprintk("requested: w = %d, h = %d\n",
pf->width, pf->height);
- spin_lock(&vino_drvdata->input_lock);
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
memcpy(&tempvcs, vcs, sizeof(struct vino_channel_settings));
- spin_unlock(&vino_drvdata->input_lock);
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
tempvcs.data_format = vino_find_data_format(pf->pixelformat);
if (tempvcs.data_format == VINO_DATA_FMT_NONE) {
- tempvcs.data_format = VINO_DATA_FMT_RGB32;
+ tempvcs.data_format = VINO_DATA_FMT_GREY;
pf->pixelformat =
vino_data_formats[tempvcs.data_format].
pixelformat;
@@ -2908,10 +3312,13 @@ static int vino_v4l2_try_fmt(struct vino_channel_settings *vcs,
static int vino_v4l2_g_fmt(struct vino_channel_settings *vcs,
struct v4l2_format *f)
{
+ unsigned long flags;
+
switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
struct v4l2_pix_format *pf = &f->fmt.pix;
- spin_lock(&vino_drvdata->input_lock);
+
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
pf->width = (vcs->clipping.right - vcs->clipping.left) /
vcs->decimation;
@@ -2930,7 +3337,7 @@ static int vino_v4l2_g_fmt(struct vino_channel_settings *vcs,
pf->priv = 0;
- spin_unlock(&vino_drvdata->input_lock);
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
break;
}
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
@@ -2945,20 +3352,18 @@ static int vino_v4l2_s_fmt(struct vino_channel_settings *vcs,
struct v4l2_format *f)
{
int data_format;
+ unsigned long flags;
switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
struct v4l2_pix_format *pf = &f->fmt.pix;
- spin_lock(&vino_drvdata->input_lock);
- if (!vino_is_input_owner(vcs)) {
- spin_unlock(&vino_drvdata->input_lock);
- return -EINVAL;
- }
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
data_format = vino_find_data_format(pf->pixelformat);
+
if (data_format == VINO_DATA_FMT_NONE) {
- vcs->data_format = VINO_DATA_FMT_RGB32;
+ vcs->data_format = VINO_DATA_FMT_GREY;
pf->pixelformat =
vino_data_formats[vcs->data_format].
pixelformat;
@@ -2985,7 +3390,7 @@ static int vino_v4l2_s_fmt(struct vino_channel_settings *vcs,
pf->priv = 0;
- spin_unlock(&vino_drvdata->input_lock);
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
break;
}
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
@@ -3000,12 +3405,15 @@ static int vino_v4l2_cropcap(struct vino_channel_settings *vcs,
struct v4l2_cropcap *ccap)
{
const struct vino_data_norm *norm;
+ unsigned long flags;
switch (ccap->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- spin_lock(&vino_drvdata->input_lock);
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+
norm = &vino_data_norms[vcs->data_norm];
- spin_unlock(&vino_drvdata->input_lock);
+
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
ccap->bounds.left = 0;
ccap->bounds.top = 0;
@@ -3028,16 +3436,18 @@ static int vino_v4l2_cropcap(struct vino_channel_settings *vcs,
static int vino_v4l2_g_crop(struct vino_channel_settings *vcs,
struct v4l2_crop *c)
{
+ unsigned long flags;
+
switch (c->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- spin_lock(&vino_drvdata->input_lock);
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
c->c.left = vcs->clipping.left;
c->c.top = vcs->clipping.top;
c->c.width = vcs->clipping.right - vcs->clipping.left;
c->c.height = vcs->clipping.bottom - vcs->clipping.top;
- spin_unlock(&vino_drvdata->input_lock);
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
break;
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
default:
@@ -3050,18 +3460,16 @@ static int vino_v4l2_g_crop(struct vino_channel_settings *vcs,
static int vino_v4l2_s_crop(struct vino_channel_settings *vcs,
struct v4l2_crop *c)
{
+ unsigned long flags;
+
switch (c->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- spin_lock(&vino_drvdata->input_lock);
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
- if (!vino_is_input_owner(vcs)) {
- spin_unlock(&vino_drvdata->input_lock);
- return -EINVAL;
- }
vino_set_clipping(vcs, c->c.left, c->c.top,
c->c.width, c->c.height);
- spin_unlock(&vino_drvdata->input_lock);
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
break;
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
default:
@@ -3074,6 +3482,8 @@ static int vino_v4l2_s_crop(struct vino_channel_settings *vcs,
static int vino_v4l2_g_parm(struct vino_channel_settings *vcs,
struct v4l2_streamparm *sp)
{
+ unsigned long flags;
+
switch (sp->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
struct v4l2_captureparm *cp = &sp->parm.capture;
@@ -3082,9 +3492,11 @@ static int vino_v4l2_g_parm(struct vino_channel_settings *vcs,
cp->capability = V4L2_CAP_TIMEPERFRAME;
cp->timeperframe.numerator = 1;
- spin_lock(&vino_drvdata->input_lock);
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+
cp->timeperframe.denominator = vcs->fps;
- spin_unlock(&vino_drvdata->input_lock);
+
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
// TODO: cp->readbuffers = xxx;
break;
@@ -3100,15 +3512,13 @@ static int vino_v4l2_g_parm(struct vino_channel_settings *vcs,
static int vino_v4l2_s_parm(struct vino_channel_settings *vcs,
struct v4l2_streamparm *sp)
{
+ unsigned long flags;
+
switch (sp->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
struct v4l2_captureparm *cp = &sp->parm.capture;
- spin_lock(&vino_drvdata->input_lock);
- if (!vino_is_input_owner(vcs)) {
- spin_unlock(&vino_drvdata->input_lock);
- return -EINVAL;
- }
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
if ((cp->timeperframe.numerator == 0) ||
(cp->timeperframe.denominator == 0)) {
@@ -3118,7 +3528,8 @@ static int vino_v4l2_s_parm(struct vino_channel_settings *vcs,
vino_set_framerate(vcs, cp->timeperframe.denominator /
cp->timeperframe.numerator);
}
- spin_unlock(&vino_drvdata->input_lock);
+
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
// TODO: set buffers according to cp->readbuffers
break;
@@ -3145,21 +3556,23 @@ static int vino_v4l2_reqbufs(struct vino_channel_settings *vcs,
return -EINVAL;
}
- if (vino_is_capturing(vcs)) {
- dprintk("busy, capturing\n");
- return -EBUSY;
- }
-
dprintk("count = %d\n", rb->count);
if (rb->count > 0) {
+ if (vino_is_capturing(vcs)) {
+ dprintk("busy, capturing\n");
+ return -EBUSY;
+ }
+
if (vino_queue_has_mapped_buffers(&vcs->fb_queue)) {
dprintk("busy, buffers still mapped\n");
return -EBUSY;
} else {
+ vcs->streaming = 0;
vino_queue_free(&vcs->fb_queue);
vino_queue_init(&vcs->fb_queue, &rb->count);
}
} else {
+ vcs->streaming = 0;
vino_capture_stop(vcs);
vino_queue_free(&vcs->fb_queue);
}
@@ -3302,12 +3715,12 @@ static int vino_v4l2_dqbuf(struct vino_channel_settings *vcs,
err = vino_queue_get_incoming(&vcs->fb_queue, &incoming);
if (err) {
dprintk("vino_queue_get_incoming() failed\n");
- return -EIO;
+ return -EINVAL;
}
err = vino_queue_get_outgoing(&vcs->fb_queue, &outgoing);
if (err) {
dprintk("vino_queue_get_outgoing() failed\n");
- return -EIO;
+ return -EINVAL;
}
dprintk("incoming = %d, outgoing = %d\n", incoming, outgoing);
@@ -3327,8 +3740,10 @@ static int vino_v4l2_dqbuf(struct vino_channel_settings *vcs,
if (err) {
err = vino_wait_for_frame(vcs);
if (err) {
- /* interrupted */
- vino_capture_failed(vcs);
+ /* interrupted or
+ * no frames captured because
+ * of frame skipping */
+ // vino_capture_failed(vcs);
return -EIO;
}
}
@@ -3341,10 +3756,12 @@ static int vino_v4l2_dqbuf(struct vino_channel_settings *vcs,
}
err = vino_check_buffer(vcs, fb);
+
+ vino_v4l2_get_buffer_status(vcs, fb, b);
+
if (err)
return -EIO;
- vino_v4l2_get_buffer_status(vcs, fb, b);
break;
}
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
@@ -3401,8 +3818,8 @@ static int vino_v4l2_streamoff(struct vino_channel_settings *vcs)
if (!vcs->streaming)
return 0;
- vino_capture_stop(vcs);
vcs->streaming = 0;
+ vino_capture_stop(vcs);
return 0;
}
@@ -3410,10 +3827,11 @@ static int vino_v4l2_streamoff(struct vino_channel_settings *vcs)
static int vino_v4l2_queryctrl(struct vino_channel_settings *vcs,
struct v4l2_queryctrl *queryctrl)
{
+ unsigned long flags;
int i;
int err = 0;
- spin_lock(&vino_drvdata->input_lock);
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
switch (vcs->input) {
case VINO_INPUT_D1:
@@ -3423,6 +3841,7 @@ static int vino_v4l2_queryctrl(struct vino_channel_settings *vcs,
memcpy(queryctrl,
&vino_indycam_v4l2_controls[i],
sizeof(struct v4l2_queryctrl));
+ queryctrl->reserved[0] = 0;
goto found;
}
}
@@ -3437,6 +3856,7 @@ static int vino_v4l2_queryctrl(struct vino_channel_settings *vcs,
memcpy(queryctrl,
&vino_saa7191_v4l2_controls[i],
sizeof(struct v4l2_queryctrl));
+ queryctrl->reserved[0] = 0;
goto found;
}
}
@@ -3448,7 +3868,7 @@ static int vino_v4l2_queryctrl(struct vino_channel_settings *vcs,
}
found:
- spin_unlock(&vino_drvdata->input_lock);
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
return err;
}
@@ -3456,70 +3876,72 @@ static int vino_v4l2_queryctrl(struct vino_channel_settings *vcs,
static int vino_v4l2_g_ctrl(struct vino_channel_settings *vcs,
struct v4l2_control *control)
{
- struct indycam_control indycam_ctrl;
- struct saa7191_control saa7191_ctrl;
+ unsigned long flags;
+ int i;
int err = 0;
- spin_lock(&vino_drvdata->input_lock);
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
switch (vcs->input) {
- case VINO_INPUT_D1:
- i2c_camera_command(DECODER_INDYCAM_GET_CONTROLS,
- &indycam_ctrl);
+ case VINO_INPUT_D1: {
+ struct indycam_control indycam_ctrl;
- switch(control->id) {
- case V4L2_CID_AUTOGAIN:
- control->value = indycam_ctrl.agc;
- break;
- case V4L2_CID_AUTO_WHITE_BALANCE:
- control->value = indycam_ctrl.awb;
- break;
- case V4L2_CID_GAIN:
- control->value = indycam_ctrl.gain;
- break;
- case V4L2_CID_PRIVATE_BASE:
- control->value = indycam_ctrl.red_saturation;
- break;
- case V4L2_CID_PRIVATE_BASE + 1:
- control->value = indycam_ctrl.blue_saturation;
- break;
- case V4L2_CID_RED_BALANCE:
- control->value = indycam_ctrl.red_balance;
- break;
- case V4L2_CID_BLUE_BALANCE:
- control->value = indycam_ctrl.blue_balance;
- break;
- case V4L2_CID_EXPOSURE:
- control->value = indycam_ctrl.shutter;
- break;
- case V4L2_CID_GAMMA:
- control->value = indycam_ctrl.gamma;
- break;
- default:
+ for (i = 0; i < VINO_INDYCAM_V4L2_CONTROL_COUNT; i++) {
+ if (vino_indycam_v4l2_controls[i].id ==
+ control->id) {
+ goto found1;
+ }
+ }
+
+ err = -EINVAL;
+ goto out;
+
+found1:
+ indycam_ctrl.type = vino_indycam_v4l2_controls[i].reserved[0];
+
+ err = i2c_camera_command(DECODER_INDYCAM_GET_CONTROL,
+ &indycam_ctrl);
+ if (err) {
err = -EINVAL;
+ goto out;
}
+
+ control->value = indycam_ctrl.value;
break;
+ }
case VINO_INPUT_COMPOSITE:
- case VINO_INPUT_SVIDEO:
- i2c_decoder_command(DECODER_SAA7191_GET_CONTROLS,
- &saa7191_ctrl);
+ case VINO_INPUT_SVIDEO: {
+ struct saa7191_control saa7191_ctrl;
- switch(control->id) {
- case V4L2_CID_HUE:
- control->value = saa7191_ctrl.hue;
- break;
- case V4L2_CID_PRIVATE_BASE:
- control->value = saa7191_ctrl.vtrc;
- break;
- default:
+ for (i = 0; i < VINO_SAA7191_V4L2_CONTROL_COUNT; i++) {
+ if (vino_saa7191_v4l2_controls[i].id ==
+ control->id) {
+ goto found2;
+ }
+ }
+
+ err = -EINVAL;
+ goto out;
+
+found2:
+ saa7191_ctrl.type = vino_saa7191_v4l2_controls[i].reserved[0];
+
+ err = i2c_decoder_command(DECODER_SAA7191_GET_CONTROL,
+ &saa7191_ctrl);
+ if (err) {
err = -EINVAL;
+ goto out;
}
+
+ control->value = saa7191_ctrl.value;
break;
+ }
default:
err = -EINVAL;
}
- spin_unlock(&vino_drvdata->input_lock);
+out:
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
return err;
}
@@ -3527,15 +3949,21 @@ static int vino_v4l2_g_ctrl(struct vino_channel_settings *vcs,
static int vino_v4l2_s_ctrl(struct vino_channel_settings *vcs,
struct v4l2_control *control)
{
- struct indycam_control indycam_ctrl;
- struct saa7191_control saa7191_ctrl;
+ unsigned long flags;
int i;
int err = 0;
- spin_lock(&vino_drvdata->input_lock);
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+
+ if (!vino_is_input_owner(vcs)) {
+ err = -EBUSY;
+ goto out;
+ }
switch (vcs->input) {
- case VINO_INPUT_D1:
+ case VINO_INPUT_D1: {
+ struct indycam_control indycam_ctrl;
+
for (i = 0; i < VINO_INDYCAM_V4L2_CONTROL_COUNT; i++) {
if (vino_indycam_v4l2_controls[i].id ==
control->id) {
@@ -3544,65 +3972,31 @@ static int vino_v4l2_s_ctrl(struct vino_channel_settings *vcs,
&& (control->value <=
vino_indycam_v4l2_controls[i].
maximum)) {
- goto ok1;
+ goto found1;
} else {
err = -ERANGE;
- goto error;
+ goto out;
}
}
}
+
err = -EINVAL;
- goto error;
+ goto out;
-ok1:
- indycam_ctrl.agc = INDYCAM_VALUE_UNCHANGED;
- indycam_ctrl.awb = INDYCAM_VALUE_UNCHANGED;
- indycam_ctrl.shutter = INDYCAM_VALUE_UNCHANGED;
- indycam_ctrl.gain = INDYCAM_VALUE_UNCHANGED;
- indycam_ctrl.red_balance = INDYCAM_VALUE_UNCHANGED;
- indycam_ctrl.blue_balance = INDYCAM_VALUE_UNCHANGED;
- indycam_ctrl.red_saturation = INDYCAM_VALUE_UNCHANGED;
- indycam_ctrl.blue_saturation = INDYCAM_VALUE_UNCHANGED;
- indycam_ctrl.gamma = INDYCAM_VALUE_UNCHANGED;
-
- switch(control->id) {
- case V4L2_CID_AUTOGAIN:
- indycam_ctrl.agc = control->value;
- break;
- case V4L2_CID_AUTO_WHITE_BALANCE:
- indycam_ctrl.awb = control->value;
- break;
- case V4L2_CID_GAIN:
- indycam_ctrl.gain = control->value;
- break;
- case V4L2_CID_PRIVATE_BASE:
- indycam_ctrl.red_saturation = control->value;
- break;
- case V4L2_CID_PRIVATE_BASE + 1:
- indycam_ctrl.blue_saturation = control->value;
- break;
- case V4L2_CID_RED_BALANCE:
- indycam_ctrl.red_balance = control->value;
- break;
- case V4L2_CID_BLUE_BALANCE:
- indycam_ctrl.blue_balance = control->value;
- break;
- case V4L2_CID_EXPOSURE:
- indycam_ctrl.shutter = control->value;
- break;
- case V4L2_CID_GAMMA:
- indycam_ctrl.gamma = control->value;
- break;
- default:
- err = -EINVAL;
- }
+found1:
+ indycam_ctrl.type = vino_indycam_v4l2_controls[i].reserved[0];
+ indycam_ctrl.value = control->value;
- if (!err)
- i2c_camera_command(DECODER_INDYCAM_SET_CONTROLS,
- &indycam_ctrl);
+ err = i2c_camera_command(DECODER_INDYCAM_SET_CONTROL,
+ &indycam_ctrl);
+ if (err)
+ err = -EINVAL;
break;
+ }
case VINO_INPUT_COMPOSITE:
- case VINO_INPUT_SVIDEO:
+ case VINO_INPUT_SVIDEO: {
+ struct saa7191_control saa7191_ctrl;
+
for (i = 0; i < VINO_SAA7191_V4L2_CONTROL_COUNT; i++) {
if (vino_saa7191_v4l2_controls[i].id ==
control->id) {
@@ -3611,41 +4005,32 @@ ok1:
&& (control->value <=
vino_saa7191_v4l2_controls[i].
maximum)) {
- goto ok2;
+ goto found2;
} else {
err = -ERANGE;
- goto error;
+ goto out;
}
}
}
err = -EINVAL;
- goto error;
-
-ok2:
- saa7191_ctrl.hue = SAA7191_VALUE_UNCHANGED;
- saa7191_ctrl.vtrc = SAA7191_VALUE_UNCHANGED;
+ goto out;
- switch(control->id) {
- case V4L2_CID_HUE:
- saa7191_ctrl.hue = control->value;
- break;
- case V4L2_CID_PRIVATE_BASE:
- saa7191_ctrl.vtrc = control->value;
- break;
- default:
- err = -EINVAL;
- }
+found2:
+ saa7191_ctrl.type = vino_saa7191_v4l2_controls[i].reserved[0];
+ saa7191_ctrl.value = control->value;
- if (!err)
- i2c_decoder_command(DECODER_SAA7191_SET_CONTROLS,
- &saa7191_ctrl);
+ err = i2c_decoder_command(DECODER_SAA7191_SET_CONTROL,
+ &saa7191_ctrl);
+ if (err)
+ err = -EINVAL;
break;
+ }
default:
err = -EINVAL;
}
-error:
- spin_unlock(&vino_drvdata->input_lock);
+out:
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
return err;
}
@@ -3865,9 +4250,9 @@ static unsigned int vino_poll(struct file *file, poll_table *pt)
over:
dprintk("poll(): data %savailable\n",
(outgoing > 0) ? "" : "not ");
- if (outgoing > 0) {
+
+ if (outgoing > 0)
ret = POLLIN | POLLRDNORM;
- }
error:
@@ -3880,6 +4265,7 @@ static int vino_do_ioctl(struct inode *inode, struct file *file,
struct video_device *dev = video_devdata(file);
struct vino_channel_settings *vcs = video_get_drvdata(dev);
+#ifdef VINO_DEBUG
switch (_IOC_TYPE(cmd)) {
case 'v':
dprintk("ioctl(): V4L1 unsupported (0x%08x)\n", cmd);
@@ -3891,9 +4277,9 @@ static int vino_do_ioctl(struct inode *inode, struct file *file,
default:
dprintk("ioctl(): unsupported command 0x%08x\n", cmd);
}
+#endif
switch (cmd) {
- /* TODO: V4L1 interface (use compatibility layer?) */
/* V4L2 interface */
case VIDIOC_QUERYCAP: {
vino_v4l2_querycap(arg);
@@ -3911,6 +4297,9 @@ static int vino_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_ENUMSTD: {
return vino_v4l2_enumstd(vcs, arg);
}
+ case VIDIOC_QUERYSTD: {
+ return vino_v4l2_querystd(vcs, arg);
+ }
case VIDIOC_G_STD: {
return vino_v4l2_g_std(vcs, arg);
}
@@ -4100,8 +4489,7 @@ static int vino_probe(void)
return -ENODEV;
}
- printk(KERN_INFO "VINO with chip ID %ld, revision %ld found\n",
- VINO_ID_VALUE(rev_id), VINO_REV_NUM(rev_id));
+ printk(KERN_INFO "VINO revision %ld found\n", VINO_REV_NUM(rev_id));
return 0;
}
diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c
new file mode 100644
index 00000000000..a6936ad74fc
--- /dev/null
+++ b/drivers/media/video/wm8775.c
@@ -0,0 +1,259 @@
+/*
+ * wm8775 - driver version 0.0.1
+ *
+ * Copyright (C) 2004 Ulf Eklund <ivtv at eklund.to>
+ *
+ * Based on saa7115 driver
+ *
+ * Copyright (C) 2005 Hans Verkuil <hverkuil@xs4all.nl>
+ * - Cleanup
+ * - V4L2 API update
+ * - sound fixes
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <asm/uaccess.h>
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/videodev.h>
+#include <media/audiochip.h>
+
+MODULE_DESCRIPTION("wm8775 driver");
+MODULE_AUTHOR("Ulf Eklund, Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+#define wm8775_err(fmt, arg...) do { \
+ printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+#define wm8775_info(fmt, arg...) do { \
+ printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+
+
+static unsigned short normal_i2c[] = { 0x36 >> 1, I2C_CLIENT_END };
+
+
+I2C_CLIENT_INSMOD;
+
+/* ----------------------------------------------------------------------- */
+
+enum {
+ R7 = 7, R11 = 11,
+ R12, R13, R14, R15, R16, R17, R18, R19, R20, R21, R23 = 23,
+ TOT_REGS
+};
+
+struct wm8775_state {
+ u8 input; /* Last selected input (0-0xf) */
+ u8 muted;
+};
+
+static int wm8775_write(struct i2c_client *client, int reg, u16 val)
+{
+ int i;
+
+ if (reg < 0 || reg >= TOT_REGS) {
+ wm8775_err("Invalid register R%d\n", reg);
+ return -1;
+ }
+
+ for (i = 0; i < 3; i++) {
+ if (i2c_smbus_write_byte_data(client, (reg << 1) |
+ (val >> 8), val & 0xff) == 0) {
+ return 0;
+ }
+ }
+ wm8775_err("I2C: cannot write %03x to register R%d\n", val, reg);
+ return -1;
+}
+
+static int wm8775_command(struct i2c_client *client, unsigned int cmd,
+ void *arg)
+{
+ struct wm8775_state *state = i2c_get_clientdata(client);
+ int *input = arg;
+
+ switch (cmd) {
+ case AUDC_SET_INPUT:
+ wm8775_write(client, R21, 0x0c0);
+ wm8775_write(client, R14, 0x1d4);
+ wm8775_write(client, R15, 0x1d4);
+
+ if (*input == AUDIO_RADIO) {
+ wm8775_write(client, R21, 0x108);
+ state->input = 8;
+ state->muted = 0;
+ break;
+ }
+ if (*input == AUDIO_MUTE) {
+ state->muted = 1;
+ break;
+ }
+ if (*input == AUDIO_UNMUTE) {
+ wm8775_write(client, R21, 0x100 + state->input);
+ state->muted = 0;
+ break;
+ }
+ /* All other inputs... */
+ wm8775_write(client, R21, 0x102);
+ state->input = 2;
+ state->muted = 0;
+ break;
+
+ case VIDIOC_LOG_STATUS:
+ wm8775_info("Input: %s%s\n",
+ state->input == 8 ? "radio" : "default",
+ state->muted ? " (muted)" : "");
+ break;
+
+ case VIDIOC_S_FREQUENCY:
+ /* If I remove this, then it can happen that I have no
+ sound the first time I tune from static to a valid channel.
+ It's difficult to reproduce and is almost certainly related
+ to the zero cross detect circuit. */
+ wm8775_write(client, R21, 0x0c0);
+ wm8775_write(client, R14, 0x1d4);
+ wm8775_write(client, R15, 0x1d4);
+ wm8775_write(client, R21, 0x100 + state->input);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+
+static struct i2c_driver i2c_driver;
+
+static int wm8775_attach(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct i2c_client *client;
+ struct wm8775_state *state;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return 0;
+
+ client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (client == 0)
+ return -ENOMEM;
+
+ memset(client, 0, sizeof(struct i2c_client));
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &i2c_driver;
+ client->flags = I2C_CLIENT_ALLOW_USE;
+ snprintf(client->name, sizeof(client->name) - 1, "wm8775");
+
+ wm8775_info("chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+
+ state = kmalloc(sizeof(struct wm8775_state), GFP_KERNEL);
+ if (state == NULL) {
+ kfree(client);
+ return -ENOMEM;
+ }
+ state->input = 2;
+ state->muted = 0;
+ i2c_set_clientdata(client, state);
+
+ /* initialize wm8775 */
+ wm8775_write(client, R23, 0x000); /* RESET */
+ wm8775_write(client, R7, 0x000); /* Disable zero cross detect timeout */
+ wm8775_write(client, R11, 0x021); /* Left justified, 24-bit mode */
+ wm8775_write(client, R12, 0x102); /* Master mode, clock ratio 256fs */
+ wm8775_write(client, R13, 0x000); /* Powered up */
+ wm8775_write(client, R14, 0x1d4); /* ADC gain +2.5dB, enable zero cross */
+ wm8775_write(client, R15, 0x1d4); /* ADC gain +2.5dB, enable zero cross */
+ wm8775_write(client, R16, 0x1bf); /* ALC Stereo, ALC target level -1dB FS */
+ /* max gain +8dB */
+ wm8775_write(client, R17, 0x185); /* Enable gain control, use zero cross */
+ /* detection, ALC hold time 42.6 ms */
+ wm8775_write(client, R18, 0x0a2); /* ALC gain ramp up delay 34 s, */
+ /* ALC gain ramp down delay 33 ms */
+ wm8775_write(client, R19, 0x005); /* Enable noise gate, threshold -72dBfs */
+ wm8775_write(client, R20, 0x07a); /* Transient window 4ms, lower PGA gain */
+ /* limit -1dB */
+ wm8775_write(client, R21, 0x102); /* LRBOTH = 1, use input 2. */
+ i2c_attach_client(client);
+
+ return 0;
+}
+
+static int wm8775_probe(struct i2c_adapter *adapter)
+{
+#ifdef I2C_CLASS_TV_ANALOG
+ if (adapter->class & I2C_CLASS_TV_ANALOG)
+#else
+ if (adapter->id == I2C_HW_B_BT848)
+#endif
+ return i2c_probe(adapter, &addr_data, wm8775_attach);
+ return 0;
+}
+
+static int wm8775_detach(struct i2c_client *client)
+{
+ int err;
+
+ err = i2c_detach_client(client);
+ if (err) {
+ return err;
+ }
+ kfree(client);
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+static struct i2c_driver i2c_driver = {
+ .name = "wm8775",
+
+ .id = I2C_DRIVERID_WM8775,
+ .flags = I2C_DF_NOTIFY,
+
+ .attach_adapter = wm8775_probe,
+ .detach_client = wm8775_detach,
+ .command = wm8775_command,
+ .owner = THIS_MODULE,
+};
+
+
+static int __init wm8775_init_module(void)
+{
+ return i2c_add_driver(&i2c_driver);
+}
+
+static void __exit wm8775_cleanup_module(void)
+{
+ i2c_del_driver(&i2c_driver);
+}
+
+module_init(wm8775_init_module);
+module_exit(wm8775_cleanup_module);
diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c
index eed2acea177..39a0d238900 100644
--- a/drivers/media/video/zoran_card.c
+++ b/drivers/media/video/zoran_card.c
@@ -1057,10 +1057,8 @@ zr36057_init (struct zoran *zr)
KERN_ERR
"%s: zr36057_init() - kmalloc (STAT_COM) failed\n",
ZR_DEVNAME(zr));
- if (vdev)
- kfree(vdev);
- if (mem)
- kfree((void *)mem);
+ kfree(vdev);
+ kfree((void *)mem);
return -ENOMEM;
}
memset((void *) mem, 0, mem_needed);
@@ -1105,15 +1103,15 @@ zoran_release (struct zoran *zr)
/* unregister videocodec bus */
if (zr->codec) {
struct videocodec_master *master = zr->codec->master_data;
+
videocodec_detach(zr->codec);
- if (master)
- kfree(master);
+ kfree(master);
}
if (zr->vfe) {
struct videocodec_master *master = zr->vfe->master_data;
+
videocodec_detach(zr->vfe);
- if (master)
- kfree(master);
+ kfree(master);
}
/* unregister i2c bus */
diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c
index 53adeb70f2c..07bde9acd67 100644
--- a/drivers/media/video/zoran_driver.c
+++ b/drivers/media/video/zoran_driver.c
@@ -996,8 +996,6 @@ zoran_jpg_queue_frame (struct file *file,
return -EINVAL;
}
- spin_lock_irqsave(&zr->spinlock, flags);
-
if (fh->jpg_buffers.active == ZORAN_FREE) {
if (zr->jpg_buffers.active == ZORAN_FREE) {
zr->jpg_buffers = fh->jpg_buffers;
@@ -1016,6 +1014,8 @@ zoran_jpg_queue_frame (struct file *file,
zr36057_enable_jpg(zr, mode);
}
+ spin_lock_irqsave(&zr->spinlock, flags);
+
if (!res) {
switch (zr->jpg_buffers.buffer[num].state) {
case BUZ_STATE_DONE:
diff --git a/drivers/media/video/zr36016.c b/drivers/media/video/zr36016.c
index d4740a89cea..4ed898585c7 100644
--- a/drivers/media/video/zr36016.c
+++ b/drivers/media/video/zr36016.c
@@ -26,7 +26,6 @@
#define ZR016_VERSION "v0.7"
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
diff --git a/drivers/media/video/zr36050.c b/drivers/media/video/zr36050.c
index 13b1e7b6fd6..0144576a612 100644
--- a/drivers/media/video/zr36050.c
+++ b/drivers/media/video/zr36050.c
@@ -26,7 +26,6 @@
#define ZR050_VERSION "v0.7.1"
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
diff --git a/drivers/media/video/zr36060.c b/drivers/media/video/zr36060.c
index b50dc403e6d..129744a07ab 100644
--- a/drivers/media/video/zr36060.c
+++ b/drivers/media/video/zr36060.c
@@ -26,7 +26,6 @@
#define ZR060_VERSION "v0.7"
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>