summaryrefslogtreecommitdiff
path: root/linux/drivers/media/video
diff options
context:
space:
mode:
Diffstat (limited to 'linux/drivers/media/video')
-rw-r--r--linux/drivers/media/video/Kconfig1
-rw-r--r--linux/drivers/media/video/au0828/Kconfig8
-rw-r--r--linux/drivers/media/video/bt8xx/bttv-cards.c181
-rw-r--r--linux/drivers/media/video/bt8xx/bttv-driver.c17
-rw-r--r--linux/drivers/media/video/bt8xx/bttv.h2
-rw-r--r--linux/drivers/media/video/cx18/cx18-audio.c1
-rw-r--r--linux/drivers/media/video/cx18/cx18-av-core.c42
-rw-r--r--linux/drivers/media/video/cx18/cx18-av-core.h19
-rw-r--r--linux/drivers/media/video/cx18/cx18-av-vbi.c6
-rw-r--r--linux/drivers/media/video/cx18/cx18-controls.c40
-rw-r--r--linux/drivers/media/video/cx18/cx18-driver.c3
-rw-r--r--linux/drivers/media/video/cx18/cx18-streams.c5
-rw-r--r--linux/drivers/media/video/cx18/cx18-vbi.c9
-rw-r--r--linux/drivers/media/video/cx23885/Kconfig13
-rw-r--r--linux/drivers/media/video/cx23885/Makefile4
-rw-r--r--linux/drivers/media/video/cx23885/cimax2.c484
-rw-r--r--linux/drivers/media/video/cx23885/cimax2.h47
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-cards.c53
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-core.c20
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-dvb.c106
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-reg.h2
-rw-r--r--linux/drivers/media/video/cx23885/cx23885.h3
-rw-r--r--linux/drivers/media/video/cx23885/netup-eeprom.c117
-rw-r--r--linux/drivers/media/video/cx23885/netup-eeprom.h42
-rw-r--r--linux/drivers/media/video/cx23885/netup-init.c125
-rw-r--r--linux/drivers/media/video/cx23885/netup-init.h25
-rw-r--r--linux/drivers/media/video/cx88/cx88-input.c4
-rw-r--r--linux/drivers/media/video/cx88/cx88-video.c6
-rw-r--r--linux/drivers/media/video/cx88/cx88.h1
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-cards.c21
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-core.c5
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-dvb.c3
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-i2c.c6
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-video.c7
-rw-r--r--linux/drivers/media/video/em28xx/em28xx.h5
-rw-r--r--linux/drivers/media/video/gspca/gspca.c4
-rw-r--r--linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c6
-rw-r--r--linux/drivers/media/video/gspca/mars.c23
-rw-r--r--linux/drivers/media/video/gspca/sq905.c100
-rw-r--r--linux/drivers/media/video/gspca/vc032x.c2
-rw-r--r--linux/drivers/media/video/indycam.c323
-rw-r--r--linux/drivers/media/video/indycam.h19
-rw-r--r--linux/drivers/media/video/meye.c16
-rw-r--r--linux/drivers/media/video/ovcamchip/ovcamchip_core.c220
-rw-r--r--linux/drivers/media/video/ovcamchip/ovcamchip_priv.h7
-rw-r--r--linux/drivers/media/video/pvrusb2/Kconfig6
-rw-r--r--linux/drivers/media/video/saa7134/Kconfig5
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-cards.c189
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-dvb.c27
-rw-r--r--linux/drivers/media/video/saa7134/saa7134.h2
-rw-r--r--linux/drivers/media/video/saa7191.c508
-rw-r--r--linux/drivers/media/video/saa7191.h26
-rw-r--r--linux/drivers/media/video/stk-webcam.c14
-rw-r--r--linux/drivers/media/video/tvaudio.c2
-rw-r--r--linux/drivers/media/video/usbvision/usbvision-video.c10
-rw-r--r--linux/drivers/media/video/v4l2-dev.c7
-rw-r--r--linux/drivers/media/video/v4l2-ioctl.c175
-rw-r--r--linux/drivers/media/video/vino.c1389
-rw-r--r--linux/drivers/media/video/w9968cf.c131
-rw-r--r--linux/drivers/media/video/w9968cf.h24
-rw-r--r--linux/drivers/media/video/zoran/Kconfig1
-rw-r--r--linux/drivers/media/video/zoran/zoran_driver.c16
62 files changed, 2794 insertions, 1891 deletions
diff --git a/linux/drivers/media/video/Kconfig b/linux/drivers/media/video/Kconfig
index 6c26618b8..534a022c4 100644
--- a/linux/drivers/media/video/Kconfig
+++ b/linux/drivers/media/video/Kconfig
@@ -582,7 +582,6 @@ config VIDEO_SAA5249
config VIDEO_VINO
tristate "SGI Vino Video For Linux (EXPERIMENTAL)"
depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2
- select I2C_ALGO_SGI
select VIDEO_SAA7191 if VIDEO_HELPER_CHIPS_AUTO
help
Say Y here to build in support for the Vino video input system found
diff --git a/linux/drivers/media/video/au0828/Kconfig b/linux/drivers/media/video/au0828/Kconfig
index 018f72b8e..20993ae17 100644
--- a/linux/drivers/media/video/au0828/Kconfig
+++ b/linux/drivers/media/video/au0828/Kconfig
@@ -4,10 +4,10 @@ config VIDEO_AU0828
depends on I2C && INPUT && DVB_CORE && USB
select I2C_ALGOBIT
select VIDEO_TVEEPROM
- select DVB_AU8522 if !DVB_FE_CUSTOMIZE
- select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
- select MEDIA_TUNER_MXL5007T if !DVB_FE_CUSTOMIZE
- select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE
+ select DVB_AU8522 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMIZE
+ select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMIZE
+ select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMIZE
---help---
This is a video4linux driver for Auvitek's USB device.
diff --git a/linux/drivers/media/video/bt8xx/bttv-cards.c b/linux/drivers/media/video/bt8xx/bttv-cards.c
index a2719c6bd..aed55398d 100644
--- a/linux/drivers/media/video/bt8xx/bttv-cards.c
+++ b/linux/drivers/media/video/bt8xx/bttv-cards.c
@@ -76,6 +76,9 @@ static void geovision_muxsel(struct bttv *btv, unsigned int input);
static void phytec_muxsel(struct bttv *btv, unsigned int input);
+static void gv800s_muxsel(struct bttv *btv, unsigned int input);
+static void gv800s_init(struct bttv *btv);
+
static int terratec_active_radio_upgrade(struct bttv *btv);
static int tea5757_read(struct bttv *btv);
static int tea5757_write(struct bttv *btv, int value);
@@ -312,6 +315,10 @@ static struct CARD {
{ 0xd200dbc0, BTTV_BOARD_DVICO_FUSIONHDTV_2, "DViCO FusionHDTV 2" },
{ 0x763c008a, BTTV_BOARD_GEOVISION_GV600, "GeoVision GV-600" },
{ 0x18011000, BTTV_BOARD_ENLTV_FM_2, "Encore ENL TV-FM-2" },
+ { 0x763d800a, BTTV_BOARD_GEOVISION_GV800S, "GeoVision GV-800(S) (master)" },
+ { 0x763d800b, BTTV_BOARD_GEOVISION_GV800S_SL, "GeoVision GV-800(S) (slave)" },
+ { 0x763d800c, BTTV_BOARD_GEOVISION_GV800S_SL, "GeoVision GV-800(S) (slave)" },
+ { 0x763d800d, BTTV_BOARD_GEOVISION_GV800S_SL, "GeoVision GV-800(S) (slave)" },
{ 0, -1, NULL }
};
@@ -2847,7 +2854,60 @@ struct tvcard bttv_tvcards[] = {
.pll = PLL_28,
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
- }
+ },
+ [BTTV_BOARD_GEOVISION_GV800S] = {
+ /* Bruno Christo <bchristo@inf.ufsm.br>
+ *
+ * GeoVision GV-800(S) has 4 Conexant Fusion 878A:
+ * 1 audio input per BT878A = 4 audio inputs
+ * 4 video inputs per BT878A = 16 video inputs
+ * This is the first BT878A chip of the GV-800(S). It's the
+ * "master" chip and it controls the video inputs through an
+ * analog multiplexer (a CD22M3494) via some GPIO pins. The
+ * slaves should use card type 0x9e (following this one).
+ * There is a EEPROM on the card which is currently not handled.
+ * The audio input is not working yet.
+ */
+ .name = "Geovision GV-800(S) (master)",
+ .video_inputs = 4,
+ /* .audio_inputs= 1, */
+ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+ .svhs = NO_SVHS,
+ .gpiomask = 0xf107f,
+ .no_gpioirq = 1,
+ .muxsel = MUXSEL(2, 2, 2, 2),
+ .pll = PLL_28,
+ .no_msp34xx = 1,
+ .no_tda7432 = 1,
+ .no_tda9875 = 1,
+ .muxsel_hook = gv800s_muxsel,
+ },
+ [BTTV_BOARD_GEOVISION_GV800S_SL] = {
+ /* Bruno Christo <bchristo@inf.ufsm.br>
+ *
+ * GeoVision GV-800(S) has 4 Conexant Fusion 878A:
+ * 1 audio input per BT878A = 4 audio inputs
+ * 4 video inputs per BT878A = 16 video inputs
+ * The 3 other BT878A chips are "slave" chips of the GV-800(S)
+ * and should use this card type.
+ * The audio input is not working yet.
+ */
+ .name = "Geovision GV-800(S) (slave)",
+ .video_inputs = 4,
+ /* .audio_inputs= 1, */
+ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+ .svhs = NO_SVHS,
+ .gpiomask = 0x00,
+ .no_gpioirq = 1,
+ .muxsel = MUXSEL(2, 2, 2, 2),
+ .pll = PLL_28,
+ .no_msp34xx = 1,
+ .no_tda7432 = 1,
+ .no_tda9875 = 1,
+ .muxsel_hook = gv800s_muxsel,
+ },
};
static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
@@ -3376,6 +3436,9 @@ void __devinit bttv_init_card2(struct bttv *btv)
case BTTV_BOARD_KODICOM_4400R:
kodicom4400r_init(btv);
break;
+ case BTTV_BOARD_GEOVISION_GV800S:
+ gv800s_init(btv);
+ break;
}
/* pll configuration */
@@ -4595,6 +4658,122 @@ static void phytec_muxsel(struct bttv *btv, unsigned int input)
gpio_bits(0x3, mux);
}
+/*
+ * GeoVision GV-800(S) functions
+ * Bruno Christo <bchristo@inf.ufsm.br>
+*/
+
+/* This is a function to control the analog switch, which determines which
+ * camera is routed to which controller. The switch comprises an X-address
+ * (gpio bits 0-3, representing the camera, ranging from 0-15), and a
+ * Y-address (gpio bits 4-6, representing the controller, ranging from 0-3).
+ * A data value (gpio bit 18) of '1' enables the switch, and '0' disables
+ * the switch. A STROBE bit (gpio bit 17) latches the data value into the
+ * specified address. There is also a chip select (gpio bit 16).
+ * The idea is to set the address and chip select together, bring
+ * STROBE high, write the data, and finally bring STROBE back to low.
+ */
+static void gv800s_write(struct bttv *btv,
+ unsigned char xaddr,
+ unsigned char yaddr,
+ unsigned char data) {
+ /* On the "master" 878A:
+ * GPIO bits 0-9 are used for the analog switch:
+ * 00 - 03: camera selector
+ * 04 - 06: 878A (controller) selector
+ * 16: cselect
+ * 17: strobe
+ * 18: data (1->on, 0->off)
+ * 19: reset
+ */
+ const u32 ADDRESS = ((xaddr&0xf) | (yaddr&3)<<4);
+ const u32 CSELECT = 1<<16;
+ const u32 STROBE = 1<<17;
+ const u32 DATA = data<<18;
+
+ gpio_bits(0x1007f, ADDRESS | CSELECT); /* write ADDRESS and CSELECT */
+ gpio_bits(0x20000, STROBE); /* STROBE high */
+ gpio_bits(0x40000, DATA); /* write DATA */
+ gpio_bits(0x20000, ~STROBE); /* STROBE low */
+}
+
+/*
+ * GeoVision GV-800(S) muxsel
+ *
+ * Each of the 4 cards (controllers) use this function.
+ * The controller using this function selects the input through the GPIO pins
+ * of the "master" card. A pointer to this card is stored in master[btv->c.nr].
+ *
+ * The parameter 'input' is the requested camera number (0-4) on the controller.
+ * The map array has the address of each input. Note that the addresses in the
+ * array are in the sequence the original GeoVision driver uses, that is, set
+ * every controller to input 0, then to input 1, 2, 3, repeat. This means that
+ * the physical "camera 1" connector corresponds to controller 0 input 0,
+ * "camera 2" corresponds to controller 1 input 0, and so on.
+ *
+ * After getting the input address, the function then writes the appropriate
+ * data to the analog switch, and housekeeps the local copy of the switch
+ * information.
+ */
+static void gv800s_muxsel(struct bttv *btv, unsigned int input)
+{
+ struct bttv *mctlr;
+ char *sw_status;
+ int xaddr, yaddr;
+ static unsigned int map[4][4] = { { 0x0, 0x4, 0xa, 0x6 },
+ { 0x1, 0x5, 0xb, 0x7 },
+ { 0x2, 0x8, 0xc, 0xe },
+ { 0x3, 0x9, 0xd, 0xf } };
+ input = input%4;
+ mctlr = master[btv->c.nr];
+ if (mctlr == NULL) {
+ /* do nothing until the "master" is detected */
+ return;
+ }
+ yaddr = (btv->c.nr - mctlr->c.nr) & 3;
+ sw_status = (char *)(&mctlr->mbox_we);
+ xaddr = map[yaddr][input] & 0xf;
+
+ /* Check if the controller/camera pair has changed, ignore otherwise */
+ if (sw_status[yaddr] != xaddr) {
+ /* disable the old switch, enable the new one and save status */
+ gv800s_write(mctlr, sw_status[yaddr], yaddr, 0);
+ sw_status[yaddr] = xaddr;
+ gv800s_write(mctlr, xaddr, yaddr, 1);
+ }
+}
+
+/* GeoVision GV-800(S) "master" chip init */
+static void gv800s_init(struct bttv *btv)
+{
+ char *sw_status = (char *)(&btv->mbox_we);
+ int ix;
+
+ gpio_inout(0xf107f, 0xf107f);
+ gpio_write(1<<19); /* reset the analog MUX */
+ gpio_write(0);
+
+ /* Preset camera 0 to the 4 controllers */
+ for (ix = 0; ix < 4; ix++) {
+ sw_status[ix] = ix;
+ gv800s_write(btv, ix, ix, 1);
+ }
+
+ /* Inputs on the "master" controller need this brightness fix */
+ bttv_I2CWrite(btv, 0x18, 0x5, 0x90, 1);
+
+ if (btv->c.nr > BTTV_MAX-4)
+ return;
+ /*
+ * Store the "master" controller pointer in the master
+ * array for later use in the muxsel function.
+ */
+ master[btv->c.nr] = btv;
+ master[btv->c.nr+1] = btv;
+ master[btv->c.nr+2] = btv;
+ master[btv->c.nr+3] = btv;
+}
+
/* ----------------------------------------------------------------------- */
/* motherboard chipset specific stuff */
diff --git a/linux/drivers/media/video/bt8xx/bttv-driver.c b/linux/drivers/media/video/bt8xx/bttv-driver.c
index ab202761b..d34898f95 100644
--- a/linux/drivers/media/video/bt8xx/bttv-driver.c
+++ b/linux/drivers/media/video/bt8xx/bttv-driver.c
@@ -1922,16 +1922,11 @@ static int bttv_enum_input(struct file *file, void *priv,
{
struct bttv_fh *fh = priv;
struct bttv *btv = fh->btv;
- unsigned int n;
+ int n;
- n = i->index;
-
- if (n >= bttv_tvcards[btv->c.type].video_inputs)
+ if (i->index >= bttv_tvcards[btv->c.type].video_inputs)
return -EINVAL;
- memset(i, 0, sizeof(*i));
-
- i->index = n;
i->type = V4L2_INPUT_TYPE_CAMERA;
i->audioset = 1;
@@ -2960,13 +2955,11 @@ static int bttv_g_parm(struct file *file, void *f,
{
struct bttv_fh *fh = f;
struct bttv *btv = fh->btv;
- struct v4l2_standard s;
if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id,
- bttv_tvnorms[btv->tvnorm].name);
- parm->parm.capture.timeperframe = s.frameperiod;
+ v4l2_video_std_frame_period(bttv_tvnorms[btv->tvnorm].v4l2_id,
+ &parm->parm.capture.timeperframe);
return 0;
}
@@ -2982,7 +2975,6 @@ static int bttv_g_tuner(struct file *file, void *priv,
return -EINVAL;
mutex_lock(&btv->lock);
- memset(t, 0, sizeof(*t));
t->rxsubchans = V4L2_TUNER_SUB_MONO;
bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
strcpy(t->name, "Television");
@@ -3525,7 +3517,6 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
if (0 != t->index)
return -EINVAL;
mutex_lock(&btv->lock);
- memset(t, 0, sizeof(*t));
strcpy(t->name, "Radio");
t->type = V4L2_TUNER_RADIO;
diff --git a/linux/drivers/media/video/bt8xx/bttv.h b/linux/drivers/media/video/bt8xx/bttv.h
index 3a065b8a4..35f943337 100644
--- a/linux/drivers/media/video/bt8xx/bttv.h
+++ b/linux/drivers/media/video/bt8xx/bttv.h
@@ -182,6 +182,8 @@
#define BTTV_BOARD_VD012_X1 0x9a
#define BTTV_BOARD_VD012_X2 0x9b
#define BTTV_BOARD_IVCE8784 0x9c
+#define BTTV_BOARD_GEOVISION_GV800S 0x9d
+#define BTTV_BOARD_GEOVISION_GV800S_SL 0x9e
/* more card-specific defines */
diff --git a/linux/drivers/media/video/cx18/cx18-audio.c b/linux/drivers/media/video/cx18/cx18-audio.c
index ccd170887..bb5c5165d 100644
--- a/linux/drivers/media/video/cx18/cx18-audio.c
+++ b/linux/drivers/media/video/cx18/cx18-audio.c
@@ -24,6 +24,7 @@
#include "cx18-driver.h"
#include "cx18-io.h"
#include "cx18-cards.h"
+#include "cx18-audio.h"
#define CX18_AUDIO_ENABLE 0xc72014
diff --git a/linux/drivers/media/video/cx18/cx18-av-core.c b/linux/drivers/media/video/cx18/cx18-av-core.c
index cf256a999..21f4be839 100644
--- a/linux/drivers/media/video/cx18/cx18-av-core.c
+++ b/linux/drivers/media/video/cx18/cx18-av-core.c
@@ -292,23 +292,29 @@ void cx18_av_std_setup(struct cx18 *cx)
*
* vsync: always 6 half-lines of vsync pulses
* vactive: half lines of active video
- * vblank656: half lines, after line 3, of blanked video
- * vblank: half lines, after line 9, of blanked video
+ * vblank656: half lines, after line 3/mid-266, of blanked video
+ * vblank: half lines, after line 9/272, of blanked video
*
+ * As far as I can tell:
* vblank656 starts counting from the falling edge of the first
- * vsync pulse (start of line 4)
+ * vsync pulse (start of line 4 or mid-266)
* vblank starts counting from the after the 6 vsync pulses and
- * 6 equalization pulses (start of line 10)
+ * 6 or 5 equalization pulses (start of line 10 or 272)
*
* For 525 line systems the driver will extract VBI information
- * from lines 10 through 21. To avoid the EAV RP code from
- * toggling at the start of hblank at line 22, where sliced VBI
- * data from line 21 is stuffed, also treat line 22 as blanked.
+ * from lines 10-21 and lines 273-284.
*/
- vblank656 = 38; /* lines 4 through 22 */
- vblank = 26; /* lines 10 through 22 */
- vactive = 481; /* lines 23 through 262.5 */
+ vblank656 = 38; /* lines 4 - 22 & 266 - 284 */
+ vblank = 26; /* lines 10 - 22 & 272 - 284 */
+ vactive = 481; /* lines 23 - 263 & 285 - 525 */
+ /*
+ * For a 13.5 Mpps clock and 15,734.26 Hz line rate, a line is
+ * is 858 pixels = 720 active + 138 blanking. The Hsync leading
+ * edge should happen 1.2 us * 13.5 Mpps ~= 16 pixels after the
+ * end of active video, leaving 122 pixels of hblank to ignore
+ * before active video starts.
+ */
hactive = 720;
hblank = 122;
luma_lpf = 1;
@@ -867,8 +873,22 @@ static int cx18_av_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
Hsrc = (cx18_av_read(cx, 0x472) & 0x3f) << 4;
Hsrc |= (cx18_av_read(cx, 0x471) & 0xf0) >> 4;
- Vlines = pix->height + (is_50Hz ? 4 : 7);
+ /*
+ * This adjustment reflects the excess of vactive, set in
+ * cx18_av_std_setup(), above standard values:
+ *
+ * 480 + 1 for 60 Hz systems
+ * 576 + 4 for 50 Hz systems
+ */
+ Vlines = pix->height + (is_50Hz ? 4 : 1);
+ /*
+ * Invalid height and width scaling requests are:
+ * 1. width less than 1/16 of the source width
+ * 2. width greater than the source width
+ * 3. height less than 1/8 of the source height
+ * 4. height greater than the source height
+ */
if ((pix->width * 16 < Hsrc) || (Hsrc < pix->width) ||
(Vlines * 8 < Vsrc) || (Vsrc < Vlines)) {
CX18_ERR_DEV(sd, "%dx%d is not a valid size!\n",
diff --git a/linux/drivers/media/video/cx18/cx18-av-core.h b/linux/drivers/media/video/cx18/cx18-av-core.h
index fd0df4151..2687a2c91 100644
--- a/linux/drivers/media/video/cx18/cx18-av-core.h
+++ b/linux/drivers/media/video/cx18/cx18-av-core.h
@@ -89,16 +89,21 @@ struct cx18_av_state {
/*
* The VBI slicer starts operating and counting lines, begining at
- * slicer line count of 1, at D lines after the deassertion of VRESET
- * This staring field line, S, is 6 or 10 for 625 or 525 line systems.
- * Sliced ancillary data captured on VBI slicer line M is sent at the
- * beginning of the next VBI slicer line, VBI slicer line count N = M+1.
- * Thus when the VBI slicer reports a VBI slicer line number with
- * ancillary data, the IDID0 byte indicates VBI slicer line N.
- * The actual field line that the captured data comes from is
+ * slicer line count of 1, at D lines after the deassertion of VRESET.
+ * This staring field line, S, is 6 (& 319) or 10 (& 273) for 625 or 525
+ * line systems respectively. Sliced ancillary data captured on VBI
+ * slicer line M is inserted after the VBI slicer is done with line M,
+ * when VBI slicer line count is N = M+1. Thus when the VBI slicer
+ * reports a VBI slicer line number with ancillary data, the IDID0 byte
+ * indicates VBI slicer line N. The actual field line that the captured
+ * data comes from is
+ *
* L = M+(S+D-1) = N-1+(S+D-1) = N + (S+D-2).
*
+ * L is the line in the field, not frame, from which the VBI data came.
+ * N is the line reported by the slicer in the ancillary data.
* D is the slicer_line_delay value programmed into register 0x47f.
+ * S is 6 for 625 line systems or 10 for 525 line systems
* (S+D-2) is the slicer_line_offset used to convert slicer reported
* line counts to actual field lines.
*/
diff --git a/linux/drivers/media/video/cx18/cx18-av-vbi.c b/linux/drivers/media/video/cx18/cx18-av-vbi.c
index 43267d1af..27699839b 100644
--- a/linux/drivers/media/video/cx18/cx18-av-vbi.c
+++ b/linux/drivers/media/video/cx18/cx18-av-vbi.c
@@ -142,7 +142,7 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */
0, V4L2_SLICED_WSS_625, 0, /* 4 */
V4L2_SLICED_CAPTION_525, /* 6 */
- V4L2_SLICED_VPS, 0, 0, 0, 0, /* 7 - unlike cx25840 */
+ 0, 0, V4L2_SLICED_VPS, 0, 0, /* 9 */
0, 0, 0, 0
};
int is_pal = !(state->std & V4L2_STD_525_60);
@@ -243,7 +243,7 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
lcr[i] |= 6 << (4 * x);
break;
case V4L2_SLICED_VPS:
- lcr[i] |= 7 << (4 * x); /*'840 differs*/
+ lcr[i] |= 9 << (4 * x);
break;
}
}
@@ -301,7 +301,7 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
sdid = V4L2_SLICED_CAPTION_525;
err = !odd_parity(p[0]) || !odd_parity(p[1]);
break;
- case 7: /* Differs from cx25840 */
+ case 9:
sdid = V4L2_SLICED_VPS;
if (decode_vps(p, p) != 0)
err = 1;
diff --git a/linux/drivers/media/video/cx18/cx18-controls.c b/linux/drivers/media/video/cx18/cx18-controls.c
index 925e01fdb..82fc2f9d4 100644
--- a/linux/drivers/media/video/cx18/cx18-controls.c
+++ b/linux/drivers/media/video/cx18/cx18-controls.c
@@ -166,15 +166,26 @@ static int cx18_g_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
return 0;
}
-static int cx18_setup_vbi_fmt(struct cx18 *cx, enum v4l2_mpeg_stream_vbi_fmt fmt)
+static int cx18_setup_vbi_fmt(struct cx18 *cx,
+ enum v4l2_mpeg_stream_vbi_fmt fmt,
+ enum v4l2_mpeg_stream_type type)
{
if (!(cx->v4l2_cap & V4L2_CAP_SLICED_VBI_CAPTURE))
return -EINVAL;
if (atomic_read(&cx->ana_capturing) > 0)
return -EBUSY;
- /* First try to allocate sliced VBI buffers if needed. */
- if (fmt && cx->vbi.sliced_mpeg_data[0] == NULL) {
+ if (fmt != V4L2_MPEG_STREAM_VBI_FMT_IVTV ||
+ type != V4L2_MPEG_STREAM_TYPE_MPEG2_PS) {
+ /* We don't do VBI insertion aside from IVTV format in a PS */
+ cx->vbi.insert_mpeg = V4L2_MPEG_STREAM_VBI_FMT_NONE;
+ CX18_DEBUG_INFO("disabled insertion of sliced VBI data into "
+ "the MPEG stream\n");
+ return 0;
+ }
+
+ /* Allocate sliced VBI buffers if needed. */
+ if (cx->vbi.sliced_mpeg_data[0] == NULL) {
int i;
for (i = 0; i < CX18_VBI_FRAMES; i++) {
@@ -185,19 +196,27 @@ static int cx18_setup_vbi_fmt(struct cx18 *cx, enum v4l2_mpeg_stream_vbi_fmt fmt
kfree(cx->vbi.sliced_mpeg_data[i]);
cx->vbi.sliced_mpeg_data[i] = NULL;
}
+ cx->vbi.insert_mpeg =
+ V4L2_MPEG_STREAM_VBI_FMT_NONE;
+ CX18_WARN("Unable to allocate buffers for "
+ "sliced VBI data insertion\n");
return -ENOMEM;
}
}
}
cx->vbi.insert_mpeg = fmt;
+ CX18_DEBUG_INFO("enabled insertion of sliced VBI data into the MPEG PS,"
+ "when sliced VBI is enabled\n");
- if (cx->vbi.insert_mpeg == 0)
- return 0;
- /* Need sliced data for mpeg insertion */
+ /*
+ * If our current settings have no lines set for capture, store a valid,
+ * default set of service lines to capture, in our current settings.
+ */
if (cx18_get_service_set(cx->vbi.sliced_in) == 0) {
if (cx->is_60hz)
- cx->vbi.sliced_in->service_set = V4L2_SLICED_CAPTION_525;
+ cx->vbi.sliced_in->service_set =
+ V4L2_SLICED_CAPTION_525;
else
cx->vbi.sliced_in->service_set = V4L2_SLICED_WSS_625;
cx18_expand_service_set(cx->vbi.sliced_in, cx->is_50hz);
@@ -284,8 +303,11 @@ int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
priv.cx = cx;
priv.s = &cx->streams[id->type];
err = cx2341x_update(&priv, cx18_api_func, &cx->params, &p);
- if (!err && cx->params.stream_vbi_fmt != p.stream_vbi_fmt)
- err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt);
+ if (!err &&
+ (cx->params.stream_vbi_fmt != p.stream_vbi_fmt ||
+ cx->params.stream_type != p.stream_type))
+ err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt,
+ p.stream_type);
cx->params = p;
cx->dualwatch_stereo_mode = p.audio_properties & 0x0300;
idx = p.audio_properties & 0x03;
diff --git a/linux/drivers/media/video/cx18/cx18-driver.c b/linux/drivers/media/video/cx18/cx18-driver.c
index 8f294f436..f688ec7db 100644
--- a/linux/drivers/media/video/cx18/cx18-driver.c
+++ b/linux/drivers/media/video/cx18/cx18-driver.c
@@ -273,8 +273,7 @@ void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv)
u8 eedata[256];
memset(&c, 0, sizeof(c));
- strncpy(c.name, "cx18 tveeprom tmp", sizeof(c.name));
- c.name[sizeof(c.name)-1] = '\0';
+ strlcpy(c.name, "cx18 tveeprom tmp", sizeof(c.name));
c.adapter = &cx->i2c_adap[0];
c.addr = 0xA0 >> 1;
diff --git a/linux/drivers/media/video/cx18/cx18-streams.c b/linux/drivers/media/video/cx18/cx18-streams.c
index 0605c2d83..7c1db9c18 100644
--- a/linux/drivers/media/video/cx18/cx18-streams.c
+++ b/linux/drivers/media/video/cx18/cx18-streams.c
@@ -413,9 +413,8 @@ static void cx18_vbi_setup(struct cx18_stream *s)
* 0x90 (Task HorizontalBlank)
* 0xd0 (Task EvenField HorizontalBlank)
*
- * We have set the digitzer to consider the first active line
- * as part of VerticalBlank as well so we don't have to look for
- * these problem codes nor lose the last line of sliced data.
+ * We have set the digitzer such that we don't have to worry
+ * about these problem codes.
*/
data[4] = 0xB0F0B0F0;
/*
diff --git a/linux/drivers/media/video/cx18/cx18-vbi.c b/linux/drivers/media/video/cx18/cx18-vbi.c
index a81fe2e98..355737bff 100644
--- a/linux/drivers/media/video/cx18/cx18-vbi.c
+++ b/linux/drivers/media/video/cx18/cx18-vbi.c
@@ -169,7 +169,7 @@ void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
int streamtype)
{
u8 *p = (u8 *) buf->buf;
- u32 *q = (u32 *) buf->buf;
+ __be32 *q = (__be32 *) buf->buf;
u32 size = buf->bytesused;
u32 pts;
int lines;
@@ -178,8 +178,9 @@ void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
return;
/*
- * The CX23418 sends us data that is 32 bit LE swapped, but we want
- * the raw VBI bytes in the order they were in the raster line
+ * The CX23418 sends us data that is 32 bit little-endian swapped,
+ * but we want the raw VBI bytes in the order they were in the raster
+ * line. This has a side effect of making the 12 byte header big endian
*/
cx18_buf_swap(buf);
@@ -218,7 +219,7 @@ void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
/* Sliced VBI data with data insertion */
- pts = (be32_to_cpu(q[0] == 0x3fffffff)) ? be32_to_cpu(q[2]) : 0;
+ pts = (be32_to_cpu(q[0]) == 0x3fffffff) ? be32_to_cpu(q[2]) : 0;
/*
* For calls to compress_sliced_buf(), ensure there are an integral
diff --git a/linux/drivers/media/video/cx23885/Kconfig b/linux/drivers/media/video/cx23885/Kconfig
index 00f1e2e88..e603ceb28 100644
--- a/linux/drivers/media/video/cx23885/Kconfig
+++ b/linux/drivers/media/video/cx23885/Kconfig
@@ -15,12 +15,15 @@ config VIDEO_CX23885
select DVB_S5H1411 if !DVB_FE_CUSTOMISE
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
- select DVB_TDA10048 if !DVB_FE_CUSTOMIZE
+ select DVB_TDA10048 if !DVB_FE_CUSTOMISE
+ select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+ select DVB_STV6110 if !DVB_FE_CUSTOMISE
+ select DVB_STV0900 if !DVB_FE_CUSTOMISE
select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMIZE
- select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMIZE
- select MEDIA_TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
- select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE
- select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
+ select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMIZE
+ select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMIZE
+ select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMIZE
+ select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMIZE
---help---
This is a video4linux driver for Conexant 23885 based
TV cards.
diff --git a/linux/drivers/media/video/cx23885/Makefile b/linux/drivers/media/video/cx23885/Makefile
index 29c23b44c..ab8ea35c9 100644
--- a/linux/drivers/media/video/cx23885/Makefile
+++ b/linux/drivers/media/video/cx23885/Makefile
@@ -1,4 +1,6 @@
-cx23885-objs := cx23885-cards.o cx23885-video.o cx23885-vbi.o cx23885-core.o cx23885-i2c.o cx23885-dvb.o cx23885-417.o
+cx23885-objs := cx23885-cards.o cx23885-video.o cx23885-vbi.o \
+ cx23885-core.o cx23885-i2c.o cx23885-dvb.o cx23885-417.o \
+ netup-init.o cimax2.o netup-eeprom.o
obj-$(CONFIG_VIDEO_CX23885) += cx23885.o
diff --git a/linux/drivers/media/video/cx23885/cimax2.c b/linux/drivers/media/video/cx23885/cimax2.c
new file mode 100644
index 000000000..193d9b4cc
--- /dev/null
+++ b/linux/drivers/media/video/cx23885/cimax2.c
@@ -0,0 +1,484 @@
+/*
+ * cimax2.c
+ *
+ * CIMax2(R) SP2 driver in conjunction with NetUp Dual DVB-S2 CI card
+ *
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
+ *
+ * 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 "cx23885.h"
+#include "dvb_ca_en50221.h"
+/**** Bit definitions for MC417_RWD and MC417_OEN registers ***
+ bits 31-16
++-----------+
+| Reserved |
++-----------+
+ bit 15 bit 14 bit 13 bit 12 bit 11 bit 10 bit 9 bit 8
++-------+-------+-------+-------+-------+-------+-------+-------+
+| WR# | RD# | | ACK# | ADHI | ADLO | CS1# | CS0# |
++-------+-------+-------+-------+-------+-------+-------+-------+
+ bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
++-------+-------+-------+-------+-------+-------+-------+-------+
+| DATA7| DATA6| DATA5| DATA4| DATA3| DATA2| DATA1| DATA0|
++-------+-------+-------+-------+-------+-------+-------+-------+
+***/
+/* MC417 */
+#define NETUP_DATA 0x000000ff
+#define NETUP_WR 0x00008000
+#define NETUP_RD 0x00004000
+#define NETUP_ACK 0x00001000
+#define NETUP_ADHI 0x00000800
+#define NETUP_ADLO 0x00000400
+#define NETUP_CS1 0x00000200
+#define NETUP_CS0 0x00000100
+#define NETUP_EN_ALL 0x00001000
+#define NETUP_CTRL_OFF (NETUP_CS1 | NETUP_CS0 | NETUP_WR | NETUP_RD)
+#define NETUP_CI_CTL 0x04
+#define NETUP_CI_RD 1
+
+
+static unsigned int ci_dbg;
+module_param(ci_dbg, int, 0644);
+MODULE_PARM_DESC(ci_dbg, "Enable CI debugging");
+
+#define ci_dbg_print(args...) \
+ do { \
+ if (ci_dbg) \
+ printk(KERN_DEBUG args); \
+ } while (0)
+
+/* stores all private variables for communication with CI */
+struct netup_ci_state {
+ struct dvb_ca_en50221 ca;
+ struct mutex ca_mutex;
+ struct i2c_adapter *i2c_adap;
+ u8 ci_i2c_addr;
+ int status;
+ struct work_struct work;
+ void *priv;
+};
+
+struct mutex gpio_mutex;/* Two CiMax's uses same GPIO lines */
+
+int netup_read_i2c(struct i2c_adapter *i2c_adap, u8 addr, u8 reg,
+ u8 *buf, int len)
+{
+ int ret;
+ struct i2c_msg msg[] = {
+ {
+ .addr = addr,
+ .flags = 0,
+ .buf = &reg,
+ .len = 1
+ }, {
+ .addr = addr,
+ .flags = I2C_M_RD,
+ .buf = buf,
+ .len = len
+ }
+ };
+
+ ret = i2c_transfer(i2c_adap, msg, 2);
+
+ if (ret != 2) {
+ ci_dbg_print("%s: i2c read error, Reg = 0x%02x, Status = %d\n",
+ __func__, reg, ret);
+
+ return -1;
+ }
+
+ ci_dbg_print("%s: i2c read Addr=0x%04x, Reg = 0x%02x, data = %02x\n",
+ __func__, addr, reg, buf[0]);
+
+ return 0;
+}
+
+int netup_write_i2c(struct i2c_adapter *i2c_adap, u8 addr, u8 reg,
+ u8 *buf, int len)
+{
+ int ret;
+ u8 buffer[len + 1];
+
+ struct i2c_msg msg = {
+ .addr = addr,
+ .flags = 0,
+ .buf = &buffer[0],
+ .len = len + 1
+ };
+
+ buffer[0] = reg;
+ memcpy(&buffer[1], buf, len);
+
+ ret = i2c_transfer(i2c_adap, &msg, 1);
+
+ if (ret != 1) {
+ ci_dbg_print("%s: i2c write error, Reg=[0x%02x], Status=%d\n",
+ __func__, reg, ret);
+ return -1;
+ }
+
+ return 0;
+}
+
+int netup_ci_get_mem(struct cx23885_dev *dev)
+{
+ int mem;
+ unsigned long timeout = jiffies + msecs_to_jiffies(1);
+
+ for (;;) {
+ mem = cx_read(MC417_RWD);
+ if ((mem & NETUP_ACK) == 0)
+ break;
+ if (time_after(jiffies, timeout))
+ break;
+ udelay(1);
+ }
+
+ cx_set(MC417_RWD, NETUP_CTRL_OFF);
+
+ return mem & 0xff;
+}
+
+int netup_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot,
+ u8 flag, u8 read, u8 addr, u8 data)
+{
+ struct netup_ci_state *state = en50221->data;
+ struct cx23885_tsport *port = state->priv;
+ struct cx23885_dev *dev = port->dev;
+
+ u8 store;
+ int mem;
+ int ret;
+
+ if (0 != slot)
+ return -EINVAL;
+
+ ret = netup_read_i2c(state->i2c_adap, state->ci_i2c_addr,
+ 0, &store, 1);
+ if (ret != 0)
+ return ret;
+
+ store &= ~0x0c;
+ store |= flag;
+
+ ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
+ 0, &store, 1);
+ if (ret != 0)
+ return ret;
+
+ mutex_lock(&gpio_mutex);
+
+ /* write addr */
+ cx_write(MC417_OEN, NETUP_EN_ALL);
+ cx_write(MC417_RWD, NETUP_CTRL_OFF |
+ NETUP_ADLO | (0xff & addr));
+ cx_clear(MC417_RWD, NETUP_ADLO);
+ cx_write(MC417_RWD, NETUP_CTRL_OFF |
+ NETUP_ADHI | (0xff & (addr >> 8)));
+ cx_clear(MC417_RWD, NETUP_ADHI);
+
+ if (read) /* data in */
+ cx_write(MC417_OEN, NETUP_EN_ALL | NETUP_DATA);
+ else /* data out */
+ cx_write(MC417_RWD, NETUP_CTRL_OFF | data);
+
+ /* choose chip */
+ cx_clear(MC417_RWD,
+ (state->ci_i2c_addr == 0x40) ? NETUP_CS0 : NETUP_CS1);
+ /* read/write */
+ cx_clear(MC417_RWD, (read) ? NETUP_RD : NETUP_WR);
+ mem = netup_ci_get_mem(dev);
+
+ mutex_unlock(&gpio_mutex);
+
+ if (!read)
+ if (mem < 0)
+ return -EREMOTEIO;
+
+ ci_dbg_print("%s: %s: addr=[0x%02x], %s=%x\n", __func__,
+ (read) ? "read" : "write", addr,
+ (flag == NETUP_CI_CTL) ? "ctl" : "mem",
+ (read) ? mem : data);
+
+ if (read)
+ return mem;
+
+ return 0;
+}
+
+int netup_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221,
+ int slot, int addr)
+{
+ return netup_ci_op_cam(en50221, slot, 0, NETUP_CI_RD, addr, 0);
+}
+
+int netup_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221,
+ int slot, int addr, u8 data)
+{
+ return netup_ci_op_cam(en50221, slot, 0, 0, addr, data);
+}
+
+int netup_ci_read_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr)
+{
+ return netup_ci_op_cam(en50221, slot, NETUP_CI_CTL,
+ NETUP_CI_RD, addr, 0);
+}
+
+int netup_ci_write_cam_ctl(struct dvb_ca_en50221 *en50221, int slot,
+ u8 addr, u8 data)
+{
+ return netup_ci_op_cam(en50221, slot, NETUP_CI_CTL, 0, addr, data);
+}
+
+int netup_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot)
+{
+ struct netup_ci_state *state = en50221->data;
+ u8 buf = 0x80;
+ int ret;
+
+ if (0 != slot)
+ return -EINVAL;
+
+ udelay(500);
+ ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
+ 0, &buf, 1);
+
+ if (ret != 0)
+ return ret;
+
+ udelay(500);
+
+ buf = 0x00;
+ ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
+ 0, &buf, 1);
+
+ msleep(1000);
+ dvb_ca_en50221_camready_irq(&state->ca, 0);
+
+ return 0;
+
+}
+
+int netup_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot)
+{
+ /* not implemented */
+ return 0;
+}
+
+int netup_ci_slot_ts_ctl(struct dvb_ca_en50221 *en50221, int slot)
+{
+ struct netup_ci_state *state = en50221->data;
+ u8 buf = 0x60;
+
+ if (0 != slot)
+ return -EINVAL;
+
+ return netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
+ 0, &buf, 1);
+}
+
+/* work handler */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+static void netup_read_ci_status(void *_state)
+#else
+static void netup_read_ci_status(struct work_struct *work)
+#endif
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+ struct netup_ci_state *state = _state;
+#else
+ struct netup_ci_state *state =
+ container_of(work, struct netup_ci_state, work);
+#endif
+ u8 buf[33];
+ int ret;
+
+ ret = netup_read_i2c(state->i2c_adap, state->ci_i2c_addr,
+ 0, &buf[0], 33);
+
+ if (ret != 0)
+ return;
+
+ ci_dbg_print("%s: Slot Status Addr=[0x%04x], Reg=[0x%02x], data=%02x, "
+ "TS config = %02x\n", __func__, state->ci_i2c_addr, 0, buf[0],
+ buf[32]);
+
+ if (buf[0] && 1)
+ state->status = DVB_CA_EN50221_POLL_CAM_PRESENT |
+ DVB_CA_EN50221_POLL_CAM_READY;
+ else
+ state->status = 0;
+}
+
+/* CI irq handler */
+int netup_ci_slot_status(struct cx23885_dev *dev, u32 pci_status)
+{
+ struct cx23885_tsport *port = NULL;
+ struct netup_ci_state *state = NULL;
+
+ if (pci_status & PCI_MSK_GPIO0)
+ port = &dev->ts1;
+ else if (pci_status & PCI_MSK_GPIO1)
+ port = &dev->ts2;
+ else /* who calls ? */
+ return 0;
+
+ state = port->port_priv;
+
+ schedule_work(&state->work);
+
+ return 1;
+}
+
+int netup_poll_ci_slot_status(struct dvb_ca_en50221 *en50221, int slot, int open)
+{
+ struct netup_ci_state *state = en50221->data;
+
+ if (0 != slot)
+ return -EINVAL;
+
+ return state->status;
+}
+
+int netup_ci_init(struct cx23885_tsport *port)
+{
+ struct netup_ci_state *state;
+ u8 cimax_init[34] = {
+ 0x00, /* module A control*/
+ 0x00, /* auto select mask high A */
+ 0x00, /* auto select mask low A */
+ 0x00, /* auto select pattern high A */
+ 0x00, /* auto select pattern low A */
+ 0x44, /* memory access time A */
+ 0x00, /* invert input A */
+ 0x00, /* RFU */
+ 0x00, /* RFU */
+ 0x00, /* module B control*/
+ 0x00, /* auto select mask high B */
+ 0x00, /* auto select mask low B */
+ 0x00, /* auto select pattern high B */
+ 0x00, /* auto select pattern low B */
+ 0x44, /* memory access time B */
+ 0x00, /* invert input B */
+ 0x00, /* RFU */
+ 0x00, /* RFU */
+ 0x00, /* auto select mask high Ext */
+ 0x00, /* auto select mask low Ext */
+ 0x00, /* auto select pattern high Ext */
+ 0x00, /* auto select pattern low Ext */
+ 0x00, /* RFU */
+ 0x02, /* destination - module A */
+ 0x01, /* power on (use it like store place) */
+ 0x00, /* RFU */
+ 0x00, /* int status read only */
+ 0x01, /* all int unmasked */
+ 0x04, /* int config */
+ 0x00, /* USCG1 */
+ 0x04, /* ack active low */
+ 0x00, /* LOCK = 0 */
+ 0x33, /* serial mode, rising in, rising out, MSB first*/
+ 0x31, /* syncronization */
+ };
+ int ret;
+
+ ci_dbg_print("%s\n", __func__);
+ state = kzalloc(sizeof(struct netup_ci_state), GFP_KERNEL);
+ if (!state) {
+ ci_dbg_print("%s: Unable create CI structure!\n", __func__);
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ port->port_priv = state;
+
+ switch (port->nr) {
+ case 1:
+ state->ci_i2c_addr = 0x40;
+ mutex_init(&gpio_mutex);
+ break;
+ case 2:
+ state->ci_i2c_addr = 0x41;
+ break;
+ }
+
+ state->i2c_adap = &port->dev->i2c_bus[0].i2c_adap;
+ state->ca.owner = THIS_MODULE;
+ state->ca.read_attribute_mem = netup_ci_read_attribute_mem;
+ state->ca.write_attribute_mem = netup_ci_write_attribute_mem;
+ state->ca.read_cam_control = netup_ci_read_cam_ctl;
+ state->ca.write_cam_control = netup_ci_write_cam_ctl;
+ state->ca.slot_reset = netup_ci_slot_reset;
+ state->ca.slot_shutdown = netup_ci_slot_shutdown;
+ state->ca.slot_ts_enable = netup_ci_slot_ts_ctl;
+ state->ca.poll_slot_status = netup_poll_ci_slot_status;
+ state->ca.data = state;
+ state->priv = port;
+
+ ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
+ 0, &cimax_init[0], 34);
+ /* lock registers */
+ ret |= netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
+ 0x1f, &cimax_init[0x18], 1);
+ /* power on slots */
+ ret |= netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
+ 0x18, &cimax_init[0x18], 1);
+
+ if (0 != ret)
+ goto err;
+
+ ret = dvb_ca_en50221_init(&port->frontends.adapter,
+ &state->ca,
+ /* flags */ 0,
+ /* n_slots */ 1);
+ if (0 != ret)
+ goto err;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+ INIT_WORK(&state->work, netup_read_ci_status, state);
+#else
+ INIT_WORK(&state->work, netup_read_ci_status);
+#endif
+
+ ci_dbg_print("%s: CI initialized!\n", __func__);
+
+ return 0;
+err:
+ ci_dbg_print("%s: Cannot initialize CI: Error %d.\n", __func__, ret);
+ kfree(state);
+ return ret;
+}
+
+void netup_ci_exit(struct cx23885_tsport *port)
+{
+ struct netup_ci_state *state;
+
+ if (NULL == port)
+ return;
+
+ state = (struct netup_ci_state *)port->port_priv;
+ if (NULL == state)
+ return;
+
+ if (NULL == state->ca.data)
+ return;
+
+ dvb_ca_en50221_release(&state->ca);
+ kfree(state);
+}
diff --git a/linux/drivers/media/video/cx23885/cimax2.h b/linux/drivers/media/video/cx23885/cimax2.h
new file mode 100644
index 000000000..518744a4c
--- /dev/null
+++ b/linux/drivers/media/video/cx23885/cimax2.h
@@ -0,0 +1,47 @@
+/*
+ * cimax2.h
+ *
+ * CIMax(R) SP2 driver in conjunction with NetUp Dual DVB-S2 CI card
+ *
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
+ *
+ * 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 CIMAX2_H
+#define CIMAX2_H
+#include "dvb_ca_en50221.h"
+
+extern int netup_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221,
+ int slot, int addr);
+extern int netup_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221,
+ int slot, int addr, u8 data);
+extern int netup_ci_read_cam_ctl(struct dvb_ca_en50221 *en50221,
+ int slot, u8 addr);
+extern int netup_ci_write_cam_ctl(struct dvb_ca_en50221 *en50221,
+ int slot, u8 addr, u8 data);
+extern int netup_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot);
+extern int netup_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot);
+extern int netup_ci_slot_ts_ctl(struct dvb_ca_en50221 *en50221, int slot);
+extern int netup_ci_slot_status(struct cx23885_dev *dev, u32 pci_status);
+extern int netup_poll_ci_slot_status(struct dvb_ca_en50221 *en50221,
+ int slot, int open);
+extern int netup_ci_init(struct cx23885_tsport *port);
+extern void netup_ci_exit(struct cx23885_tsport *port);
+
+#endif
diff --git a/linux/drivers/media/video/cx23885/cx23885-cards.c b/linux/drivers/media/video/cx23885/cx23885-cards.c
index a8201ceaa..e6db78f8b 100644
--- a/linux/drivers/media/video/cx23885/cx23885-cards.c
+++ b/linux/drivers/media/video/cx23885/cx23885-cards.c
@@ -28,6 +28,7 @@
#include "compat.h"
#include "cx23885.h"
#include "tuner-xc2028.h"
+#include "netup-init.h"
/* ------------------------------------------------------------------ */
/* board config info */
@@ -175,6 +176,12 @@ struct cx23885_board cx23885_boards[] = {
.name = "DVBWorld DVB-S2 2005",
.portb = CX23885_MPEG_DVB,
},
+ [CX23885_BOARD_NETUP_DUAL_DVBS2_CI] = {
+ .cimax = 1,
+ .name = "NetUP Dual DVB-S2 CI",
+ .portb = CX23885_MPEG_DVB,
+ .portc = CX23885_MPEG_DVB,
+ },
};
const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
@@ -270,6 +277,10 @@ struct cx23885_subid cx23885_subids[] = {
.subvendor = 0x0001,
.subdevice = 0x2005,
.card = CX23885_BOARD_DVBWORLD_2005,
+ }, {
+ .subvendor = 0x1b55,
+ .subdevice = 0x2a2c,
+ .card = CX23885_BOARD_NETUP_DUAL_DVBS2_CI,
},
};
const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -583,6 +594,32 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
cx_write(MC417_OEN, 0x00001000);
cx_write(MC417_RWD, 0x00001800);
break;
+ case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+ /* GPIO-0 INTA from CiMax1
+ GPIO-1 INTB from CiMax2
+ GPIO-2 reset chips
+ GPIO-3 to GPIO-10 data/addr for CA
+ GPIO-11 ~CS0 to CiMax1
+ GPIO-12 ~CS1 to CiMax2
+ GPIO-13 ADL0 load LSB addr
+ GPIO-14 ADL1 load MSB addr
+ GPIO-15 ~RDY from CiMax
+ GPIO-17 ~RD to CiMax
+ GPIO-18 ~WR to CiMax
+ */
+ cx_set(GP0_IO, 0x00040000); /* GPIO as out */
+ /* GPIO1 and GPIO2 as INTA and INTB from CiMaxes, reset low */
+ cx_clear(GP0_IO, 0x00030004);
+ mdelay(100);/* reset delay */
+ cx_set(GP0_IO, 0x00040004); /* GPIO as out, reset high */
+ cx_write(MC417_CTL, 0x00000037);/* enable GPIO3-18 pins */
+ /* GPIO-15 IN as ~ACK, rest as OUT */
+ cx_write(MC417_OEN, 0x00001000);
+ /* ~RD, ~WR high; ADL0, ADL1 low; ~CS0, ~CS1 high */
+ cx_write(MC417_RWD, 0x0000c300);
+ /* enable irq */
+ cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/
+ break;
}
}
@@ -670,6 +707,14 @@ void cx23885_card_setup(struct cx23885_dev *dev)
ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
break;
+ case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+ ts1->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
+ ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
+ ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ break;
case CX23885_BOARD_HAUPPAUGE_HVR1250:
case CX23885_BOARD_HAUPPAUGE_HVR1500:
case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
@@ -694,9 +739,17 @@ void cx23885_card_setup(struct cx23885_dev *dev)
case CX23885_BOARD_HAUPPAUGE_HVR1700:
case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
+ case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
request_module("cx25840");
break;
}
+
+ /* AUX-PLL 27MHz CLK */
+ switch (dev->board) {
+ case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+ netup_initialize(dev);
+ break;
+ }
}
/* ------------------------------------------------------------------ */
diff --git a/linux/drivers/media/video/cx23885/cx23885-core.c b/linux/drivers/media/video/cx23885/cx23885-core.c
index 4f68156d2..6ae7ee247 100644
--- a/linux/drivers/media/video/cx23885/cx23885-core.c
+++ b/linux/drivers/media/video/cx23885/cx23885-core.c
@@ -32,6 +32,7 @@
#include <asm/div64.h>
#include "cx23885.h"
+#include "cimax2.h"
MODULE_DESCRIPTION("Driver for cx23885 based TV cards");
MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
@@ -792,6 +793,8 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
dev->pci_bus = dev->pci->bus->number;
dev->pci_slot = PCI_SLOT(dev->pci->devfn);
dev->pci_irqmask = 0x001f00;
+ if (cx23885_boards[dev->board].cimax > 0)
+ dev->pci_irqmask |= 0x01800000; /* for CiMaxes */
/* External Master 1 Bus */
dev->i2c_bus[0].nr = 0;
@@ -1654,7 +1657,9 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
(pci_status & PCI_MSK_VID_B) ||
(pci_status & PCI_MSK_VID_A) ||
(pci_status & PCI_MSK_AUD_INT) ||
- (pci_status & PCI_MSK_AUD_EXT)) {
+ (pci_status & PCI_MSK_AUD_EXT) ||
+ (pci_status & PCI_MSK_GPIO0) ||
+ (pci_status & PCI_MSK_GPIO1)) {
if (pci_status & PCI_MSK_RISC_RD)
dprintk(7, " (PCI_MSK_RISC_RD 0x%08x)\n",
@@ -1696,8 +1701,19 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
dprintk(7, " (PCI_MSK_AUD_EXT 0x%08x)\n",
PCI_MSK_AUD_EXT);
+ if (pci_status & PCI_MSK_GPIO0)
+ dprintk(7, " (PCI_MSK_GPIO0 0x%08x)\n",
+ PCI_MSK_GPIO0);
+
+ if (pci_status & PCI_MSK_GPIO1)
+ dprintk(7, " (PCI_MSK_GPIO1 0x%08x)\n",
+ PCI_MSK_GPIO1);
}
+ if ((pci_status & PCI_MSK_GPIO0) || (pci_status & PCI_MSK_GPIO1))
+ /* handled += cx23885_irq_gpio(dev, pci_status); */
+ handled += netup_ci_slot_status(dev, pci_status);
+
if (ts1_status) {
if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
handled += cx23885_irq_ts(ts1, ts1_status);
@@ -1770,6 +1786,8 @@ static int __devinit cx23885_initdev(struct pci_dev *pci_dev,
}
pci_set_drvdata(pci_dev, dev);
+ cx_set(PCI_INT_MSK, 0x01800000); /* for NetUP */
+
return 0;
fail_irq:
diff --git a/linux/drivers/media/video/cx23885/cx23885-dvb.c b/linux/drivers/media/video/cx23885/cx23885-dvb.c
index 90dbf49ea..5529dcf6a 100644
--- a/linux/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/linux/drivers/media/video/cx23885/cx23885-dvb.c
@@ -31,6 +31,7 @@
#include "cx23885.h"
#include <media/v4l2-common.h>
+#include "dvb_ca_en50221.h"
#include "s5h1409.h"
#include "s5h1411.h"
#include "mt2131.h"
@@ -44,7 +45,13 @@
#include "dib7000p.h"
#include "dibx000_common.h"
#include "zl10353.h"
+#include "stv0900.h"
+#include "stv6110.h"
+#include "lnbh24.h"
#include "cx24116.h"
+#include "cimax2.h"
+#include "netup-eeprom.h"
+#include "netup-init.h"
static unsigned int debug;
@@ -310,6 +317,31 @@ static struct zl10353_config dvico_fusionhdtv_xc3028 = {
.no_tuner = 1,
};
+static struct stv0900_config netup_stv0900_config = {
+ .demod_address = 0x68,
+ .xtal = 27000000,
+ .clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */
+ .diseqc_mode = 2,/* 2/3 PWM */
+ .path1_mode = 2,/*Serial continues clock */
+ .path2_mode = 2,/*Serial continues clock */
+ .tun1_maddress = 0,/* 0x60 */
+ .tun2_maddress = 3,/* 0x63 */
+ .tun1_adc = 1,/* 1 Vpp */
+ .tun2_adc = 1,/* 1 Vpp */
+};
+
+static struct stv6110_config netup_stv6110_tunerconfig_a = {
+ .i2c_address = 0x60,
+ .mclk = 27000000,
+ .iq_wiring = 0,
+};
+
+static struct stv6110_config netup_stv6110_tunerconfig_b = {
+ .i2c_address = 0x63,
+ .mclk = 27000000,
+ .iq_wiring = 1,
+};
+
static int tbs_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
{
struct cx23885_tsport *port = fe->dvb->priv;
@@ -341,6 +373,7 @@ static int dvb_register(struct cx23885_tsport *port)
struct cx23885_dev *dev = port->dev;
struct cx23885_i2c *i2c_bus = NULL;
struct videobuf_dvb_frontend *fe0;
+ int ret;
/* Get the first frontend */
fe0 = videobuf_dvb_get_frontend(&port->frontends, 1);
@@ -581,6 +614,51 @@ static int dvb_register(struct cx23885_tsport *port)
&dvbworld_cx24116_config,
&i2c_bus->i2c_adap);
break;
+ case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+ i2c_bus = &dev->i2c_bus[0];
+ switch (port->nr) {
+ /* port B */
+ case 1:
+ fe0->dvb.frontend = dvb_attach(stv0900_attach,
+ &netup_stv0900_config,
+ &i2c_bus->i2c_adap, 0);
+ if (fe0->dvb.frontend != NULL) {
+ if (dvb_attach(stv6110_attach,
+ fe0->dvb.frontend,
+ &netup_stv6110_tunerconfig_a,
+ &i2c_bus->i2c_adap)) {
+ if (!dvb_attach(lnbh24_attach,
+ fe0->dvb.frontend,
+ &i2c_bus->i2c_adap,
+ LNBH24_PCL, 0, 0x09))
+ printk(KERN_ERR
+ "No LNBH24 found!\n");
+
+ }
+ }
+ break;
+ /* port C */
+ case 2:
+ fe0->dvb.frontend = dvb_attach(stv0900_attach,
+ &netup_stv0900_config,
+ &i2c_bus->i2c_adap, 1);
+ if (fe0->dvb.frontend != NULL) {
+ if (dvb_attach(stv6110_attach,
+ fe0->dvb.frontend,
+ &netup_stv6110_tunerconfig_b,
+ &i2c_bus->i2c_adap)) {
+ if (!dvb_attach(lnbh24_attach,
+ fe0->dvb.frontend,
+ &i2c_bus->i2c_adap,
+ LNBH24_PCL, 0, 0x0a))
+ printk(KERN_ERR
+ "No LNBH24 found!\n");
+
+ }
+ }
+ break;
+ }
+ break;
default:
printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
" isn't supported yet\n",
@@ -602,9 +680,33 @@ static int dvb_register(struct cx23885_tsport *port)
fe0->dvb.frontend->ops.analog_ops.standby(fe0->dvb.frontend);
/* register everything */
- return videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
+ ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
&dev->pci->dev, adapter_nr, 0);
+ /* init CI & MAC */
+ switch (dev->board) {
+ case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: {
+ static struct netup_card_info cinfo;
+
+ netup_get_card_info(&dev->i2c_bus[0].i2c_adap, &cinfo);
+ memcpy(port->frontends.adapter.proposed_mac,
+ cinfo.port[port->nr - 1].mac, 6);
+ printk(KERN_INFO "NetUP Dual DVB-S2 CI card port%d MAC="
+ "%02X:%02X:%02X:%02X:%02X:%02X\n",
+ port->nr,
+ port->frontends.adapter.proposed_mac[0],
+ port->frontends.adapter.proposed_mac[1],
+ port->frontends.adapter.proposed_mac[2],
+ port->frontends.adapter.proposed_mac[3],
+ port->frontends.adapter.proposed_mac[4],
+ port->frontends.adapter.proposed_mac[5]);
+
+ netup_ci_init(port);
+ break;
+ }
+ }
+
+ return ret;
}
int cx23885_dvb_register(struct cx23885_tsport *port)
@@ -677,6 +779,8 @@ int cx23885_dvb_unregister(struct cx23885_tsport *port)
if (fe0->dvb.frontend)
videobuf_dvb_unregister_bus(&port->frontends);
+ netup_ci_exit(port);
+
return 0;
}
diff --git a/linux/drivers/media/video/cx23885/cx23885-reg.h b/linux/drivers/media/video/cx23885/cx23885-reg.h
index 20b68a236..eafbe5226 100644
--- a/linux/drivers/media/video/cx23885/cx23885-reg.h
+++ b/linux/drivers/media/video/cx23885/cx23885-reg.h
@@ -212,6 +212,8 @@ Channel manager Data Structure entry = 20 DWORD
#define DEV_CNTRL2 0x00040000
+#define PCI_MSK_GPIO1 (1 << 24)
+#define PCI_MSK_GPIO0 (1 << 23)
#define PCI_MSK_APB_DMA (1 << 12)
#define PCI_MSK_AL_WR (1 << 11)
#define PCI_MSK_AL_RD (1 << 10)
diff --git a/linux/drivers/media/video/cx23885/cx23885.h b/linux/drivers/media/video/cx23885/cx23885.h
index cae0a74bd..e8118c6bd 100644
--- a/linux/drivers/media/video/cx23885/cx23885.h
+++ b/linux/drivers/media/video/cx23885/cx23885.h
@@ -71,6 +71,7 @@
#define CX23885_BOARD_TBS_6920 14
#define CX23885_BOARD_TEVII_S470 15
#define CX23885_BOARD_DVBWORLD_2005 16
+#define CX23885_BOARD_NETUP_DUAL_DVBS2_CI 17
/* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */
#define CX23885_NORMS (\
@@ -188,6 +189,7 @@ struct cx23885_board {
*/
u32 clk_freq;
struct cx23885_input input[MAX_CX23885_INPUT];
+ int cimax; /* for NetUP */
};
struct cx23885_subid {
@@ -270,6 +272,7 @@ struct cx23885_tsport {
/* Allow a single tsport to have multiple frontends */
u32 num_frontends;
+ void *port_priv;
};
struct cx23885_dev {
diff --git a/linux/drivers/media/video/cx23885/netup-eeprom.c b/linux/drivers/media/video/cx23885/netup-eeprom.c
new file mode 100644
index 000000000..26b934cd7
--- /dev/null
+++ b/linux/drivers/media/video/cx23885/netup-eeprom.c
@@ -0,0 +1,117 @@
+
+/*
+ * netup-eeprom.c
+ *
+ * 24LC02 EEPROM driver in conjunction with NetUP Dual DVB-S2 CI card
+ *
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
+ *
+ * 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 "cx23885.h"
+#include "netup-eeprom.h"
+
+#define EEPROM_I2C_ADDR 0x50
+
+int netup_eeprom_read(struct i2c_adapter *i2c_adap, u8 addr)
+{
+ int ret;
+ unsigned char buf[2];
+
+ /* Read from EEPROM */
+ struct i2c_msg msg[] = {
+ {
+ .addr = EEPROM_I2C_ADDR,
+ .flags = 0,
+ .buf = &buf[0],
+ .len = 1
+ }, {
+ .addr = EEPROM_I2C_ADDR,
+ .flags = I2C_M_RD,
+ .buf = &buf[1],
+ .len = 1
+ }
+
+ };
+
+ buf[0] = addr;
+ buf[1] = 0x0;
+
+ ret = i2c_transfer(i2c_adap, msg, 2);
+
+ if (ret != 2) {
+ printk(KERN_ERR "eeprom i2c read error, status=%d\n", ret);
+ return -1;
+ }
+
+ return buf[1];
+};
+
+int netup_eeprom_write(struct i2c_adapter *i2c_adap, u8 addr, u8 data)
+{
+ int ret;
+ unsigned char bufw[2];
+
+ /* Write into EEPROM */
+ struct i2c_msg msg[] = {
+ {
+ .addr = EEPROM_I2C_ADDR,
+ .flags = 0,
+ .buf = &bufw[0],
+ .len = 2
+ }
+ };
+
+ bufw[0] = addr;
+ bufw[1] = data;
+
+ ret = i2c_transfer(i2c_adap, msg, 1);
+
+ if (ret != 1) {
+ printk(KERN_ERR "eeprom i2c write error, status=%d\n", ret);
+ return -1;
+ }
+
+ mdelay(10); /* prophylactic delay, datasheet write cycle time = 5 ms */
+ return 0;
+};
+
+void netup_get_card_info(struct i2c_adapter *i2c_adap,
+ struct netup_card_info *cinfo)
+{
+ int i, j;
+
+ cinfo->rev = netup_eeprom_read(i2c_adap, 13);
+
+ for (i = 0, j = 0; i < 6; i++, j++)
+ cinfo->port[0].mac[j] = netup_eeprom_read(i2c_adap, i);
+
+ for (i = 6, j = 0; i < 12; i++, j++)
+ cinfo->port[1].mac[j] = netup_eeprom_read(i2c_adap, i);
+#if 0
+ printk(KERN_INFO "NetUP Dual DVB-S2 CI card rev=0x%x MAC1=%02X:%02X:"
+ "%02X:%02X:%02X:%02X MAC2=%02X:%02X:%02X:%02X:%02X:%02X\n", cinfo->rev,
+ cinfo->port[0].mac[0], cinfo->port[0].mac[1],
+ cinfo->port[0].mac[2], cinfo->port[0].mac[3],
+ cinfo->port[0].mac[4], cinfo->port[0].mac[5],
+ cinfo->port[1].mac[0], cinfo->port[1].mac[1],
+ cinfo->port[1].mac[2], cinfo->port[1].mac[3],
+ cinfo->port[1].mac[4], cinfo->port[1].mac[5]);
+#endif
+};
diff --git a/linux/drivers/media/video/cx23885/netup-eeprom.h b/linux/drivers/media/video/cx23885/netup-eeprom.h
new file mode 100644
index 000000000..13926e18f
--- /dev/null
+++ b/linux/drivers/media/video/cx23885/netup-eeprom.h
@@ -0,0 +1,42 @@
+/*
+ * netup-eeprom.h
+ *
+ * 24LC02 EEPROM driver in conjunction with NetUP Dual DVB-S2 CI card
+ *
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
+ *
+ * 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 NETUP_EEPROM_H
+#define NETUP_EEPROM_H
+
+struct netup_port_info {
+ u8 mac[6];/* card MAC address */
+};
+
+struct netup_card_info {
+ struct netup_port_info port[2];/* ports - 1,2 */
+ u8 rev;/* card revision */
+};
+
+extern int netup_eeprom_read(struct i2c_adapter *i2c_adap, u8 addr);
+extern int netup_eeprom_write(struct i2c_adapter *i2c_adap, u8 addr, u8 data);
+extern void netup_get_card_info(struct i2c_adapter *i2c_adap,
+ struct netup_card_info *cinfo);
+
+#endif
diff --git a/linux/drivers/media/video/cx23885/netup-init.c b/linux/drivers/media/video/cx23885/netup-init.c
new file mode 100644
index 000000000..f4893e69c
--- /dev/null
+++ b/linux/drivers/media/video/cx23885/netup-init.c
@@ -0,0 +1,125 @@
+/*
+ * netup-init.c
+ *
+ * NetUP Dual DVB-S2 CI driver
+ *
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
+ *
+ * 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 "cx23885.h"
+
+static void i2c_av_write(struct i2c_adapter *i2c, u16 reg, u8 val)
+{
+ int ret;
+ u8 buf[3];
+ struct i2c_msg msg = {
+ .addr = 0x88 >> 1,
+ .flags = 0,
+ .buf = buf,
+ .len = 3
+ };
+
+ buf[0] = reg >> 8;
+ buf[1] = reg & 0xff;
+ buf[2] = val;
+
+ ret = i2c_transfer(i2c, &msg, 1);
+
+ if (ret != 1)
+ printk(KERN_ERR "%s: i2c write error!\n", __func__);
+}
+
+static void i2c_av_write4(struct i2c_adapter *i2c, u16 reg, u32 val)
+{
+ int ret;
+ u8 buf[6];
+ struct i2c_msg msg = {
+ .addr = 0x88 >> 1,
+ .flags = 0,
+ .buf = buf,
+ .len = 6
+ };
+
+ buf[0] = reg >> 8;
+ buf[1] = reg & 0xff;
+ buf[2] = val & 0xff;
+ buf[3] = (val >> 8) & 0xff;
+ buf[4] = (val >> 16) & 0xff;
+ buf[5] = val >> 24;
+
+ ret = i2c_transfer(i2c, &msg, 1);
+
+ if (ret != 1)
+ printk(KERN_ERR "%s: i2c write error!\n", __func__);
+}
+
+static u8 i2c_av_read(struct i2c_adapter *i2c, u16 reg)
+{
+ int ret;
+ u8 buf[2];
+ struct i2c_msg msg = {
+ .addr = 0x88 >> 1,
+ .flags = 0,
+ .buf = buf,
+ .len = 2
+ };
+
+ buf[0] = reg >> 8;
+ buf[1] = reg & 0xff;
+
+ ret = i2c_transfer(i2c, &msg, 1);
+
+ if (ret != 1)
+ printk(KERN_ERR "%s: i2c write error!\n", __func__);
+
+ msg.flags = I2C_M_RD;
+ msg.len = 1;
+
+ ret = i2c_transfer(i2c, &msg, 1);
+
+ if (ret != 1)
+ printk(KERN_ERR "%s: i2c read error!\n", __func__);
+
+ return buf[0];
+}
+
+static void i2c_av_and_or(struct i2c_adapter *i2c, u16 reg, unsigned and_mask,
+ u8 or_value)
+{
+ i2c_av_write(i2c, reg, (i2c_av_read(i2c, reg) & and_mask) | or_value);
+}
+/* set 27MHz on AUX_CLK */
+void netup_initialize(struct cx23885_dev *dev)
+{
+ struct cx23885_i2c *i2c_bus = &dev->i2c_bus[2];
+ struct i2c_adapter *i2c = &i2c_bus->i2c_adap;
+
+ /* Stop microcontroller */
+ i2c_av_and_or(i2c, 0x803, ~0x10, 0x00);
+
+ /* Aux PLL frac for 27 MHz */
+ i2c_av_write4(i2c, 0x114, 0xea0eb3);
+
+ /* Aux PLL int for 27 MHz */
+ i2c_av_write4(i2c, 0x110, 0x090319);
+
+ /* start microcontroller */
+ i2c_av_and_or(i2c, 0x803, ~0x10, 0x10);
+}
diff --git a/linux/drivers/media/video/cx23885/netup-init.h b/linux/drivers/media/video/cx23885/netup-init.h
new file mode 100644
index 000000000..d26ae4b15
--- /dev/null
+++ b/linux/drivers/media/video/cx23885/netup-init.h
@@ -0,0 +1,25 @@
+/*
+ * netup-init.h
+ *
+ * NetUP Dual DVB-S2 CI driver
+ *
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
+ *
+ * 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.
+ */
+extern void netup_initialize(struct cx23885_dev *dev);
diff --git a/linux/drivers/media/video/cx88/cx88-input.c b/linux/drivers/media/video/cx88/cx88-input.c
index bcecb5bbd..dbb6ee2d9 100644
--- a/linux/drivers/media/video/cx88/cx88-input.c
+++ b/linux/drivers/media/video/cx88/cx88-input.c
@@ -239,6 +239,8 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
case CX88_BOARD_HAUPPAUGE_HVR3000:
case CX88_BOARD_HAUPPAUGE_HVR4000:
case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
+ case CX88_BOARD_PCHDTV_HD3000:
+ case CX88_BOARD_PCHDTV_HD5500:
ir_codes = ir_codes_hauppauge_new;
ir_type = IR_TYPE_RC5;
ir->sampling = 1;
@@ -483,6 +485,8 @@ void cx88_ir_irq(struct cx88_core *core)
case CX88_BOARD_HAUPPAUGE_HVR3000:
case CX88_BOARD_HAUPPAUGE_HVR4000:
case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
+ case CX88_BOARD_PCHDTV_HD3000:
+ case CX88_BOARD_PCHDTV_HD5500:
ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
ir_dprintk("biphase decoded: %x\n", ircode);
/*
diff --git a/linux/drivers/media/video/cx88/cx88-video.c b/linux/drivers/media/video/cx88/cx88-video.c
index c8870cf06..005a78aab 100644
--- a/linux/drivers/media/video/cx88/cx88-video.c
+++ b/linux/drivers/media/video/cx88/cx88-video.c
@@ -1514,15 +1514,12 @@ int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i)
[ CX88_VMUX_DVB ] = "DVB",
[ CX88_VMUX_DEBUG ] = "for debug only",
};
- unsigned int n;
+ unsigned int n = i->index;
- n = i->index;
if (n >= 4)
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 ((CX88_VMUX_TELEVISION == INPUT(n).type) ||
@@ -1787,7 +1784,6 @@ static int radio_g_audio (struct file *file, void *priv, struct v4l2_audio *a)
if (unlikely(a->index))
return -EINVAL;
- memset(a,0,sizeof(*a));
strcpy(a->name,"Radio");
return 0;
}
diff --git a/linux/drivers/media/video/cx88/cx88.h b/linux/drivers/media/video/cx88/cx88.h
index d641c24c3..2227d93c7 100644
--- a/linux/drivers/media/video/cx88/cx88.h
+++ b/linux/drivers/media/video/cx88/cx88.h
@@ -306,7 +306,6 @@ struct cx88_dmaqueue {
struct btcx_riscmem stopper;
u32 count;
};
-struct cx88_core;
struct cx88_core {
struct list_head devlist;
diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c
index 74f35b6d6..fcb8131e6 100644
--- a/linux/drivers/media/video/em28xx/em28xx-cards.c
+++ b/linux/drivers/media/video/em28xx/em28xx-cards.c
@@ -135,6 +135,22 @@ static struct em28xx_reg_seq default_tuner_gpio[] = {
{ -1, -1, -1, -1},
};
+/* Mute/unmute */
+static struct em28xx_reg_seq compro_unmute_tv_gpio[] = {
+ {EM28XX_R08_GPIO, 5, 7, 10},
+ { -1, -1, -1, -1},
+};
+
+static struct em28xx_reg_seq compro_unmute_svid_gpio[] = {
+ {EM28XX_R08_GPIO, 4, 7, 10},
+ { -1, -1, -1, -1},
+};
+
+static struct em28xx_reg_seq compro_mute_gpio[] = {
+ {EM28XX_R08_GPIO, 6, 7, 10},
+ { -1, -1, -1, -1},
+};
+
/*
* Board definitions
*/
@@ -1290,14 +1306,17 @@ struct em28xx_board em28xx_boards[] = {
.tda9887_conf = TDA9887_PRESENT,
.decoder = EM28XX_TVP5150,
.adecoder = EM28XX_TVAUDIO,
+ .mute_gpio = compro_mute_gpio,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
- .amux = EM28XX_AMUX_LINE_IN,
+ .amux = EM28XX_AMUX_VIDEO,
+ .gpio = compro_unmute_tv_gpio,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = compro_unmute_svid_gpio,
} },
},
[EM2860_BOARD_KAIOMY_TVNPC_U2] = {
diff --git a/linux/drivers/media/video/em28xx/em28xx-core.c b/linux/drivers/media/video/em28xx/em28xx-core.c
index f10abc5b4..0d4c9fcc2 100644
--- a/linux/drivers/media/video/em28xx/em28xx-core.c
+++ b/linux/drivers/media/video/em28xx/em28xx-core.c
@@ -378,6 +378,11 @@ static int em28xx_set_audio_source(struct em28xx *dev)
}
}
+ if (dev->board.mute_gpio && dev->mute)
+ em28xx_gpio_set(dev, dev->board.mute_gpio);
+ else
+ em28xx_gpio_set(dev, INPUT(dev->ctl_input)->gpio);
+
ret = em28xx_write_reg_bits(dev, EM28XX_R0E_AUDIOSRC, input, 0xc0);
if (ret < 0)
return ret;
diff --git a/linux/drivers/media/video/em28xx/em28xx-dvb.c b/linux/drivers/media/video/em28xx/em28xx-dvb.c
index c76dbc029..edafe9bde 100644
--- a/linux/drivers/media/video/em28xx/em28xx-dvb.c
+++ b/linux/drivers/media/video/em28xx/em28xx-dvb.c
@@ -30,9 +30,6 @@
#include "lgdt330x.h"
#include "zl10353.h"
#include "s5h1409.h"
-#ifdef EM28XX_DRX397XD_SUPPORT
-#include "drx397xD.h"
-#endif
MODULE_DESCRIPTION("driver for em28xx based DVB cards");
MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
diff --git a/linux/drivers/media/video/em28xx/em28xx-i2c.c b/linux/drivers/media/video/em28xx/em28xx-i2c.c
index 1bdcf2500..e9abb2769 100644
--- a/linux/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/linux/drivers/media/video/em28xx/em28xx-i2c.c
@@ -510,12 +510,17 @@ static int attach_inform(struct i2c_client *client)
dprintk1(1, "attach_inform: tvp5150 detected.\n");
break;
+ case 0xb0:
+ dprintk1(1, "attach_inform: tda9874 detected\n");
+ break;
+
default:
if (!dev->tuner_addr)
dev->tuner_addr = client->addr;
dprintk1(1, "attach inform: detected I2C address %x\n",
client->addr << 1);
+ dprintk1(1, "driver id %d\n", client->driver->id);
}
@@ -557,6 +562,7 @@ static char *i2c_devs[128] = {
[0x80 >> 1] = "msp34xx",
[0x88 >> 1] = "msp34xx",
[0xa0 >> 1] = "eeprom",
+ [0xb0 >> 1] = "tda9874",
[0xb8 >> 1] = "tvp5150a",
[0xba >> 1] = "tvp5150a",
[0xc0 >> 1] = "tuner (analog)",
diff --git a/linux/drivers/media/video/em28xx/em28xx-video.c b/linux/drivers/media/video/em28xx/em28xx-video.c
index 448a02b04..ef02999ec 100644
--- a/linux/drivers/media/video/em28xx/em28xx-video.c
+++ b/linux/drivers/media/video/em28xx/em28xx-video.c
@@ -544,6 +544,13 @@ static void video_mux(struct em28xx *dev, int index)
&route);
}
+ if (dev->board.adecoder != EM28XX_NOADECODER) {
+ route.input = dev->ctl_ainput;
+ route.output = dev->ctl_aoutput;
+ em28xx_i2c_call_clients(dev, VIDIOC_INT_S_AUDIO_ROUTING,
+ &route);
+ }
+
em28xx_audio_analog_set(dev);
}
diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h
index 235b63499..c9be33aba 100644
--- a/linux/drivers/media/video/em28xx/em28xx.h
+++ b/linux/drivers/media/video/em28xx/em28xx.h
@@ -375,6 +375,7 @@ struct em28xx_board {
struct em28xx_reg_seq *dvb_gpio;
struct em28xx_reg_seq *suspend_gpio;
struct em28xx_reg_seq *tuner_gpio;
+ struct em28xx_reg_seq *mute_gpio;
unsigned int is_em2800:1;
unsigned int has_msp34xx:1;
@@ -571,11 +572,7 @@ struct em28xx {
/* Snapshot button */
char snapshot_button_path[30]; /* path of the input dev */
struct input_dev *sbutton_input_dev;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
- struct work_struct sbutton_query_work;
-#else
struct delayed_work sbutton_query_work;
-#endif
struct em28xx_dvb *dvb;
};
diff --git a/linux/drivers/media/video/gspca/gspca.c b/linux/drivers/media/video/gspca/gspca.c
index 8d78b9287..d629ce1dc 100644
--- a/linux/drivers/media/video/gspca/gspca.c
+++ b/linux/drivers/media/video/gspca/gspca.c
@@ -1111,7 +1111,6 @@ static int vidioc_s_audio(struct file *file, void *priv,
static int vidioc_g_audio(struct file *file, void *priv,
struct v4l2_audio *audio)
{
- memset(audio, 0, sizeof *audio);
strcpy(audio->name, "Microphone");
return 0;
}
@@ -1145,7 +1144,6 @@ static int vidioc_enum_input(struct file *file, void *priv,
if (input->index != 0)
return -EINVAL;
- memset(input, 0, sizeof *input);
input->type = V4L2_INPUT_TYPE_CAMERA;
strncpy(input->name, gspca_dev->sd_desc->name,
sizeof input->name);
@@ -1353,7 +1351,6 @@ static int vidioc_g_parm(struct file *filp, void *priv,
{
struct gspca_dev *gspca_dev = priv;
- memset(parm, 0, sizeof *parm);
parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
parm->parm.capture.readbuffers = gspca_dev->nbufread;
@@ -1423,7 +1420,6 @@ static int vidiocgmbuf(struct file *file, void *priv,
{
struct v4l2_format fmt;
- memset(&fmt, 0, sizeof fmt);
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
i = gspca_dev->cam.nmodes - 1; /* highest mode */
fmt.fmt.pix.width = gspca_dev->cam.cam_mode[i].width;
diff --git a/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c b/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
index 2bd7d4d99..7e79f7eca 100644
--- a/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
+++ b/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
@@ -104,7 +104,11 @@ int s5k4aa_probe(struct sd *sd)
}
/* Test some registers, but we don't know their exact meaning yet */
- if (m5602_read_sensor(sd, 0x00, prod_id, sizeof(prod_id)))
+ if (m5602_read_sensor(sd, 0x00, prod_id, 2))
+ return -ENODEV;
+ if (m5602_read_sensor(sd, 0x02, prod_id+2, 2))
+ return -ENODEV;
+ if (m5602_read_sensor(sd, 0x04, prod_id+4, 2))
return -ENODEV;
if (memcmp(prod_id, expected_prod_id, sizeof(prod_id)))
diff --git a/linux/drivers/media/video/gspca/mars.c b/linux/drivers/media/video/gspca/mars.c
index c5a19b5bc..5d54893eb 100644
--- a/linux/drivers/media/video/gspca/mars.c
+++ b/linux/drivers/media/video/gspca/mars.c
@@ -69,10 +69,10 @@ static struct ctrl sd_ctrls[] = {
.id = V4L2_CID_SATURATION,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Color",
- .minimum = 0,
- .maximum = 220,
+ .minimum = 1,
+ .maximum = 255,
.step = 1,
-#define COLOR_DEF 190
+#define COLOR_DEF 200
.default_value = COLOR_DEF,
},
.set = sd_setcolors,
@@ -191,7 +191,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
int err_code;
u8 *data;
- int i, val;
+ int i;
data = gspca_dev->usb_buf;
@@ -253,9 +253,11 @@ static int sd_start(struct gspca_dev *gspca_dev)
data[1] = 0; /* reg 94, Y Gain (auto) */
#if 1
/*jfm: from win trace*/
- val = sd->colors * 0x40 + 0x400;
- data[2] = val; /* reg 0x5f/0x60 (LE) = saturation */
- data[3] = val >> 8;
+ /* reg 0x5f/0x60 (LE) = saturation */
+ /* h (60): xxxx x100
+ * l (5f): xxxx x000 */
+ data[2] = sd->colors << 3;
+ data[3] = ((sd->colors >> 2) & 0xf8) | 0x04;
data[4] = sd->brightness; /* reg 0x61 = brightness */
data[5] = 0x00;
#else
@@ -403,10 +405,11 @@ static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
sd->colors = val;
if (gspca_dev->streaming) {
- val = val * 0x40 + 0x400;
+
+ /* see sd_start */
gspca_dev->usb_buf[0] = 0x5f;
- gspca_dev->usb_buf[1] = val;
- gspca_dev->usb_buf[2] = val >> 8;
+ gspca_dev->usb_buf[1] = sd->colors << 3;
+ gspca_dev->usb_buf[2] = ((sd->colors >> 2) & 0xf8) | 0x04;
reg_w(gspca_dev, 3);
}
return 0;
diff --git a/linux/drivers/media/video/gspca/sq905.c b/linux/drivers/media/video/gspca/sq905.c
index dafaed69e..da60eea51 100644
--- a/linux/drivers/media/video/gspca/sq905.c
+++ b/linux/drivers/media/video/gspca/sq905.c
@@ -60,23 +60,29 @@ MODULE_LICENSE("GPL");
#define SQ905_PING 0x07 /* when reading an "idling" command */
#define SQ905_READ_DONE 0xc0 /* ack bulk read completed */
+/* Any non-zero value in the bottom 2 bits of the 2nd byte of
+ * the ID appears to indicate the camera can do 640*480. If the
+ * LSB of that byte is set the image is just upside down, otherwise
+ * it is rotated 180 degrees. */
+#define SQ905_HIRES_MASK 0x00000300
+#define SQ905_ORIENTATION_MASK 0x00000100
+
/* Some command codes. These go in the "index" slot. */
#define SQ905_ID 0xf0 /* asks for model string */
#define SQ905_CONFIG 0x20 /* gets photo alloc. table, not used here */
#define SQ905_DATA 0x30 /* accesses photo data, not used here */
#define SQ905_CLEAR 0xa0 /* clear everything */
-#define SQ905_CAPTURE_LOW 0x60 /* Starts capture at 160x120 */
-#define SQ905_CAPTURE_MED 0x61 /* Starts capture at 320x240 */
+#define SQ905_CAPTURE_LOW 0x60 /* Starts capture at 160x120 */
+#define SQ905_CAPTURE_MED 0x61 /* Starts capture at 320x240 */
+#define SQ905_CAPTURE_HIGH 0x62 /* Starts capture at 640x480 (some cams only) */
/* note that the capture command also controls the output dimensions */
-/* 0x60 -> 160x120, 0x61 -> 320x240 0x62 -> 640x480 depends on camera */
-/* 0x62 is not correct, at least for some cams. Should be 0x63 ? */
/* Structure to hold all of our device specific stuff */
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- u8 cam_type;
+ const struct v4l2_pix_format *cap_mode;
/*
* Driver stuff
@@ -85,33 +91,24 @@ struct sd {
struct workqueue_struct *work_thread;
};
-/* The driver only supports 320x240 so far. */
-static struct v4l2_pix_format sq905_mode[1] = {
+static struct v4l2_pix_format sq905_mode[] = {
+ { 160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 160,
+ .sizeimage = 160 * 120,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
{ 320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
.bytesperline = 320,
.sizeimage = 320 * 240,
.colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+ { 640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480,
+ .colorspace = V4L2_COLORSPACE_SRGB,
.priv = 0}
};
-struct cam_type {
- u32 ident_word;
- char *name;
- struct v4l2_pix_format *min_mode;
- u8 num_modes;
- u8 sensor_flags;
-};
-
-#define SQ905_FLIP_HORIZ (1 << 0)
-#define SQ905_FLIP_VERT (1 << 1)
-
-/* Last entry is default if nothing else matches */
-static struct cam_type cam_types[] = {
- { 0x19010509, "PocketCam", &sq905_mode[0], 1, SQ905_FLIP_HORIZ },
- { 0x32010509, "Magpix", &sq905_mode[0], 1, SQ905_FLIP_HORIZ },
- { 0, "Default", &sq905_mode[0], 1, SQ905_FLIP_HORIZ | SQ905_FLIP_VERT }
-};
-
/*
* Send a command to the camera.
*/
@@ -240,7 +237,7 @@ static void sq905_dostream(struct work_struct *work)
/* request some data and then read it until we have
* a complete frame. */
- bytes_left = sq905_mode[0].sizeimage + FRAME_HEADER_LEN;
+ bytes_left = dev->cap_mode->sizeimage + FRAME_HEADER_LEN;
header_read = 0;
discarding = 0;
@@ -272,11 +269,18 @@ static void sq905_dostream(struct work_struct *work)
packet_type = INTER_PACKET;
}
frame = gspca_get_i_frame(gspca_dev);
- if (frame && !discarding)
+ if (frame && !discarding) {
gspca_frame_add(gspca_dev, packet_type,
frame, data, data_len);
- else
+ /* If entire frame fits in one packet we still
+ need to add a LAST_PACKET */
+ if ((packet_type == FIRST_PACKET) &&
+ (bytes_left == 0))
+ gspca_frame_add(gspca_dev, LAST_PACKET,
+ frame, data, 0);
+ } else {
discarding = 1;
+ }
}
/* acknowledge the frame */
mutex_lock(&gspca_dev->usb_lock);
@@ -301,8 +305,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
struct cam *cam = &gspca_dev->cam;
struct sd *dev = (struct sd *) gspca_dev;
- cam->cam_mode = sq905_mode;
- cam->nmodes = 1;
/* We don't use the buffer gspca allocates so make it small. */
cam->bulk_size = 64;
@@ -328,7 +330,6 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
/* this function is called at probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev)
{
- struct sd *dev = (struct sd *) gspca_dev;
u32 ident;
int ret;
@@ -344,17 +345,18 @@ static int sd_init(struct gspca_dev *gspca_dev)
ret = sq905_read_data(gspca_dev, gspca_dev->usb_buf, 4);
if (ret < 0)
return ret;
- /* usb_buf is allocated with kmalloc so is aligned. */
- ident = le32_to_cpup((u32 *)gspca_dev->usb_buf);
+ /* usb_buf is allocated with kmalloc so is aligned.
+ * Camera model number is the right way round if we assume this
+ * reverse engineered ID is supposed to be big endian. */
+ ident = be32_to_cpup((__be32 *)gspca_dev->usb_buf);
ret = sq905_command(gspca_dev, SQ905_CLEAR);
if (ret < 0)
return ret;
- dev->cam_type = 0;
- while (dev->cam_type < ARRAY_SIZE(cam_types) - 1 &&
- ident != cam_types[dev->cam_type].ident_word)
- dev->cam_type++;
- PDEBUG(D_CONF, "SQ905 camera %s, ID %08x detected",
- cam_types[dev->cam_type].name, ident);
+ PDEBUG(D_CONF, "SQ905 camera ID %08x detected", ident);
+ gspca_dev->cam.cam_mode = sq905_mode;
+ gspca_dev->cam.nmodes = ARRAY_SIZE(sq905_mode);
+ if (!(ident & SQ905_HIRES_MASK))
+ gspca_dev->cam.nmodes--;
return 0;
}
@@ -364,13 +366,29 @@ static int sd_start(struct gspca_dev *gspca_dev)
struct sd *dev = (struct sd *) gspca_dev;
int ret;
+ /* Set capture mode based on selected resolution. */
+ dev->cap_mode = gspca_dev->cam.cam_mode;
/* "Open the shutter" and set size, to start capture */
- ret = sq905_command(&dev->gspca_dev, SQ905_CAPTURE_MED);
+ switch (gspca_dev->width) {
+ case 640:
+ PDEBUG(D_STREAM, "Start streaming at high resolution");
+ dev->cap_mode += 2;
+ ret = sq905_command(&dev->gspca_dev, SQ905_CAPTURE_HIGH);
+ break;
+ case 320:
+ PDEBUG(D_STREAM, "Start streaming at medium resolution");
+ dev->cap_mode++;
+ ret = sq905_command(&dev->gspca_dev, SQ905_CAPTURE_MED);
+ break;
+ default:
+ PDEBUG(D_STREAM, "Start streaming at low resolution");
+ ret = sq905_command(&dev->gspca_dev, SQ905_CAPTURE_LOW);
+ }
+
if (ret < 0) {
PDEBUG(D_ERR, "Start streaming command failed");
return ret;
}
-
/* Start the workqueue function to do the streaming */
dev->work_thread = create_singlethread_workqueue(MODULE_NAME);
queue_work(dev->work_thread, &dev->work_struct);
diff --git a/linux/drivers/media/video/gspca/vc032x.c b/linux/drivers/media/video/gspca/vc032x.c
index 72cbf56c9..f1c149476 100644
--- a/linux/drivers/media/video/gspca/vc032x.c
+++ b/linux/drivers/media/video/gspca/vc032x.c
@@ -2316,7 +2316,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
break;
case SENSOR_MI1310_SOC:
GammaT = mi1320_gamma;
- MatrixT = mi0360_matrix;
+ MatrixT = mi1320_matrix;
switch (mode) {
case 1:
init = mi1310_socinitQVGA_JPG; /* 320x240 */
diff --git a/linux/drivers/media/video/indycam.c b/linux/drivers/media/video/indycam.c
index 84b9e4f2b..f2da0550b 100644
--- a/linux/drivers/media/video/indycam.c
+++ b/linux/drivers/media/video/indycam.c
@@ -19,10 +19,12 @@
#include <linux/mm.h>
#include <linux/slab.h>
-#include <linux/videodev.h>
/* IndyCam decodes stream of photons into digital image representation ;-) */
-#include <linux/video_decoder.h>
+#include <linux/videodev2.h>
#include <linux/i2c.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
#include "indycam.h"
@@ -33,6 +35,12 @@ MODULE_VERSION(INDYCAM_MODULE_VERSION);
MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>");
MODULE_LICENSE("GPL");
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
+static unsigned short normal_i2c[] = { 0x56 >> 1, I2C_CLIENT_END };
+
+I2C_CLIENT_INSMOD;
+#endif
+
// #define INDYCAM_DEBUG
#ifdef INDYCAM_DEBUG
@@ -44,11 +52,14 @@ MODULE_LICENSE("GPL");
#endif
struct indycam {
- struct i2c_client *client;
+ struct v4l2_subdev sd;
u8 version;
};
-static struct i2c_driver i2c_driver_indycam;
+static inline struct indycam *to_indycam(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct indycam, sd);
+}
static const u8 initseq[] = {
INDYCAM_CONTROL_AGCENA, /* INDYCAM_CONTROL */
@@ -63,8 +74,9 @@ static const u8 initseq[] = {
/* IndyCam register handling */
-static int indycam_read_reg(struct i2c_client *client, u8 reg, u8 *value)
+static int indycam_read_reg(struct v4l2_subdev *sd, u8 reg, u8 *value)
{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret;
if (reg == INDYCAM_REG_RESET) {
@@ -87,12 +99,12 @@ static int indycam_read_reg(struct i2c_client *client, u8 reg, u8 *value)
return 0;
}
-static int indycam_write_reg(struct i2c_client *client, u8 reg, u8 value)
+static int indycam_write_reg(struct v4l2_subdev *sd, u8 reg, u8 value)
{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
int err;
- if ((reg == INDYCAM_REG_BRIGHTNESS)
- || (reg == INDYCAM_REG_VERSION)) {
+ if (reg == INDYCAM_REG_BRIGHTNESS || reg == INDYCAM_REG_VERSION) {
dprintk("indycam_write_reg(): "
"skipping read-only register %d\n", reg);
return 0;
@@ -108,13 +120,13 @@ static int indycam_write_reg(struct i2c_client *client, u8 reg, u8 value)
return err;
}
-static int indycam_write_block(struct i2c_client *client, u8 reg,
+static int indycam_write_block(struct v4l2_subdev *sd, u8 reg,
u8 length, u8 *data)
{
int i, err;
for (i = 0; i < length; i++) {
- err = indycam_write_reg(client, reg + i, data[i]);
+ err = indycam_write_reg(sd, reg + i, data[i]);
if (err)
return err;
}
@@ -125,79 +137,78 @@ static int indycam_write_block(struct i2c_client *client, u8 reg,
/* Helper functions */
#ifdef INDYCAM_DEBUG
-static void indycam_regdump_debug(struct i2c_client *client)
+static void indycam_regdump_debug(struct v4l2_subdev *sd)
{
int i;
u8 val;
for (i = 0; i < 9; i++) {
- indycam_read_reg(client, i, &val);
+ indycam_read_reg(sd, i, &val);
dprintk("Reg %d = 0x%02x\n", i, val);
}
}
#endif
-static int indycam_get_control(struct i2c_client *client,
- struct indycam_control *ctrl)
+static int indycam_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct indycam *camera = i2c_get_clientdata(client);
+ struct indycam *camera = to_indycam(sd);
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);
+ switch (ctrl->id) {
+ case V4L2_CID_AUTOGAIN:
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ ret = indycam_read_reg(sd, INDYCAM_REG_CONTROL, &reg);
if (ret)
return -EIO;
- if (ctrl->type == INDYCAM_CONTROL_AGC)
+ if (ctrl->id == V4L2_CID_AUTOGAIN)
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);
+ case V4L2_CID_EXPOSURE:
+ ret = indycam_read_reg(sd, 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);
+ case V4L2_CID_GAIN:
+ ret = indycam_read_reg(sd, 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);
+ case V4L2_CID_RED_BALANCE:
+ ret = indycam_read_reg(sd, 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);
+ case V4L2_CID_BLUE_BALANCE:
+ ret = indycam_read_reg(sd, INDYCAM_REG_BLUE_BALANCE, &reg);
if (ret)
return -EIO;
ctrl->value = (s32)reg;
break;
case INDYCAM_CONTROL_RED_SATURATION:
- ret = indycam_read_reg(client,
+ ret = indycam_read_reg(sd,
INDYCAM_REG_RED_SATURATION, &reg);
if (ret)
return -EIO;
ctrl->value = (s32)reg;
break;
case INDYCAM_CONTROL_BLUE_SATURATION:
- ret = indycam_read_reg(client,
+ ret = indycam_read_reg(sd,
INDYCAM_REG_BLUE_SATURATION, &reg);
if (ret)
return -EIO;
ctrl->value = (s32)reg;
break;
- case INDYCAM_CONTROL_GAMMA:
+ case V4L2_CID_GAMMA:
if (camera->version == CAMERA_VERSION_MOOSE) {
- ret = indycam_read_reg(client,
+ ret = indycam_read_reg(sd,
INDYCAM_REG_GAMMA, &reg);
if (ret)
return -EIO;
@@ -213,21 +224,20 @@ static int indycam_get_control(struct i2c_client *client,
return ret;
}
-static int indycam_set_control(struct i2c_client *client,
- struct indycam_control *ctrl)
+static int indycam_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct indycam *camera = i2c_get_clientdata(client);
+ struct indycam *camera = to_indycam(sd);
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);
+ switch (ctrl->id) {
+ case V4L2_CID_AUTOGAIN:
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ ret = indycam_read_reg(sd, INDYCAM_REG_CONTROL, &reg);
if (ret)
break;
- if (ctrl->type == INDYCAM_CONTROL_AGC) {
+ if (ctrl->id == V4L2_CID_AUTOGAIN) {
if (ctrl->value)
reg |= INDYCAM_CONTROL_AGCENA;
else
@@ -239,34 +249,34 @@ static int indycam_set_control(struct i2c_client *client,
reg &= ~INDYCAM_CONTROL_AWBCTL;
}
- ret = indycam_write_reg(client, INDYCAM_REG_CONTROL, reg);
+ ret = indycam_write_reg(sd, INDYCAM_REG_CONTROL, reg);
break;
- case INDYCAM_CONTROL_SHUTTER:
+ case V4L2_CID_EXPOSURE:
reg = (ctrl->value == 0xff) ? 0x00 : (ctrl->value + 1);
- ret = indycam_write_reg(client, INDYCAM_REG_SHUTTER, reg);
+ ret = indycam_write_reg(sd, INDYCAM_REG_SHUTTER, reg);
break;
- case INDYCAM_CONTROL_GAIN:
- ret = indycam_write_reg(client, INDYCAM_REG_GAIN, ctrl->value);
+ case V4L2_CID_GAIN:
+ ret = indycam_write_reg(sd, INDYCAM_REG_GAIN, ctrl->value);
break;
- case INDYCAM_CONTROL_RED_BALANCE:
- ret = indycam_write_reg(client, INDYCAM_REG_RED_BALANCE,
+ case V4L2_CID_RED_BALANCE:
+ ret = indycam_write_reg(sd, INDYCAM_REG_RED_BALANCE,
ctrl->value);
break;
- case INDYCAM_CONTROL_BLUE_BALANCE:
- ret = indycam_write_reg(client, INDYCAM_REG_BLUE_BALANCE,
+ case V4L2_CID_BLUE_BALANCE:
+ ret = indycam_write_reg(sd, INDYCAM_REG_BLUE_BALANCE,
ctrl->value);
break;
case INDYCAM_CONTROL_RED_SATURATION:
- ret = indycam_write_reg(client, INDYCAM_REG_RED_SATURATION,
+ ret = indycam_write_reg(sd, INDYCAM_REG_RED_SATURATION,
ctrl->value);
break;
case INDYCAM_CONTROL_BLUE_SATURATION:
- ret = indycam_write_reg(client, INDYCAM_REG_BLUE_SATURATION,
+ ret = indycam_write_reg(sd, INDYCAM_REG_BLUE_SATURATION,
ctrl->value);
break;
- case INDYCAM_CONTROL_GAMMA:
+ case V4L2_CID_GAMMA:
if (camera->version == CAMERA_VERSION_MOOSE) {
- ret = indycam_write_reg(client, INDYCAM_REG_GAMMA,
+ ret = indycam_write_reg(sd, INDYCAM_REG_GAMMA,
ctrl->value);
}
break;
@@ -279,192 +289,107 @@ static int indycam_set_control(struct i2c_client *client,
/* I2C-interface */
-static int indycam_attach(struct i2c_adapter *adap, int addr, int kind)
+static int indycam_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *chip)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct indycam *camera = to_indycam(sd);
+
+ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_INDYCAM,
+ camera->version);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops indycam_core_ops = {
+ .g_chip_ident = indycam_g_chip_ident,
+ .g_ctrl = indycam_g_ctrl,
+ .s_ctrl = indycam_s_ctrl,
+};
+
+static const struct v4l2_subdev_ops indycam_ops = {
+ .core = &indycam_core_ops,
+};
+
+static int indycam_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
int err = 0;
struct indycam *camera;
- struct i2c_client *client;
+ struct v4l2_subdev *sd;
- printk(KERN_INFO "SGI IndyCam driver version %s\n",
- INDYCAM_MODULE_VERSION);
+ v4l_info(client, "chip found @ 0x%x (%s)\n",
+ client->addr << 1, client->adapter->name);
- client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (!client)
- return -ENOMEM;
camera = kzalloc(sizeof(struct indycam), GFP_KERNEL);
- if (!camera) {
- err = -ENOMEM;
- goto out_free_client;
- }
-
- client->addr = addr;
- client->adapter = adap;
- client->driver = &i2c_driver_indycam;
- client->flags = 0;
- strcpy(client->name, "IndyCam client");
- i2c_set_clientdata(client, camera);
-
- camera->client = client;
+ if (!camera)
+ return -ENOMEM;
- err = i2c_attach_client(client);
- if (err)
- goto out_free_camera;
+ sd = &camera->sd;
+ v4l2_i2c_subdev_init(sd, client, &indycam_ops);
camera->version = i2c_smbus_read_byte_data(client,
INDYCAM_REG_VERSION);
if (camera->version != CAMERA_VERSION_INDY &&
camera->version != CAMERA_VERSION_MOOSE) {
- err = -ENODEV;
- goto out_detach_client;
+ kfree(camera);
+ return -ENODEV;
}
+
printk(KERN_INFO "IndyCam v%d.%d detected\n",
INDYCAM_VERSION_MAJOR(camera->version),
INDYCAM_VERSION_MINOR(camera->version));
- indycam_regdump(client);
+ indycam_regdump(sd);
// initialize
- err = indycam_write_block(client, 0, sizeof(initseq), (u8 *)&initseq);
+ err = indycam_write_block(sd, 0, sizeof(initseq), (u8 *)&initseq);
if (err) {
printk(KERN_ERR "IndyCam initialization failed\n");
- err = -EIO;
- goto out_detach_client;
+ kfree(camera);
+ return -EIO;
}
- indycam_regdump(client);
+ indycam_regdump(sd);
// white balance
- err = indycam_write_reg(client, INDYCAM_REG_CONTROL,
+ err = indycam_write_reg(sd, INDYCAM_REG_CONTROL,
INDYCAM_CONTROL_AGCENA | INDYCAM_CONTROL_AWBCTL);
if (err) {
printk(KERN_ERR "IndyCam: White balancing camera failed\n");
- err = -EIO;
- goto out_detach_client;
+ kfree(camera);
+ return -EIO;
}
- indycam_regdump(client);
+ indycam_regdump(sd);
printk(KERN_INFO "IndyCam initialized\n");
return 0;
-
-out_detach_client:
- i2c_detach_client(client);
-out_free_camera:
- kfree(camera);
-out_free_client:
- kfree(client);
- return err;
-}
-
-static int indycam_probe(struct i2c_adapter *adap)
-{
- /* Indy specific crap */
- if (adap->id == I2C_HW_SGI_VINO)
- return indycam_attach(adap, INDYCAM_ADDR, 0);
- /* Feel free to add probe here :-) */
- return -ENODEV;
}
-static int indycam_detach(struct i2c_client *client)
+static int indycam_remove(struct i2c_client *client)
{
- struct indycam *camera = i2c_get_clientdata(client);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
- i2c_detach_client(client);
- kfree(camera);
- kfree(client);
+ v4l2_device_unregister_subdev(sd);
+ kfree(to_indycam(sd));
return 0;
}
-static int indycam_command(struct i2c_client *client, unsigned int cmd,
- void *arg)
-{
- // struct indycam *camera = i2c_get_clientdata(client);
-
- /* The old video_decoder interface just isn't enough,
- * so we'll use some custom commands. */
- switch (cmd) {
- case DECODER_GET_CAPABILITIES: {
- struct video_decoder_capability *cap = arg;
-
- cap->flags = VIDEO_DECODER_NTSC;
- cap->inputs = 1;
- cap->outputs = 1;
- break;
- }
- case DECODER_GET_STATUS: {
- int *iarg = arg;
-
- *iarg = DECODER_STATUS_GOOD | DECODER_STATUS_NTSC |
- DECODER_STATUS_COLOR;
- break;
- }
- case DECODER_SET_NORM: {
- int *iarg = arg;
-
- switch (*iarg) {
- case VIDEO_MODE_NTSC:
- break;
- default:
- return -EINVAL;
- }
- break;
- }
- case DECODER_SET_INPUT: {
- int *iarg = arg;
-
- if (*iarg != 0)
- return -EINVAL;
- break;
- }
- case DECODER_SET_OUTPUT: {
- int *iarg = arg;
-
- if (*iarg != 0)
- return -EINVAL;
- break;
- }
- case DECODER_ENABLE_OUTPUT: {
- /* Always enabled */
- break;
- }
- case DECODER_SET_PICTURE: {
- // struct video_picture *pic = arg;
- /* TODO: convert values for indycam_set_controls() */
- break;
- }
- case DECODER_INDYCAM_GET_CONTROL: {
- return indycam_get_control(client, arg);
- }
- case DECODER_INDYCAM_SET_CONTROL: {
- return indycam_set_control(client, arg);
- }
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static struct i2c_driver i2c_driver_indycam = {
- .driver = {
- .name = "indycam",
- },
- .id = I2C_DRIVERID_INDYCAM,
- .attach_adapter = indycam_probe,
- .detach_client = indycam_detach,
- .command = indycam_command,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id indycam_id[] = {
+ { "indycam", 0 },
+ { }
};
+MODULE_DEVICE_TABLE(i2c, indycam_id);
-static int __init indycam_init(void)
-{
- return i2c_add_driver(&i2c_driver_indycam);
-}
-
-static void __exit indycam_exit(void)
-{
- i2c_del_driver(&i2c_driver_indycam);
-}
-
-module_init(indycam_init);
-module_exit(indycam_exit);
+#endif
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "indycam",
+ .probe = indycam_probe,
+ .remove = indycam_remove,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = indycam_id,
+#endif
+};
diff --git a/linux/drivers/media/video/indycam.h b/linux/drivers/media/video/indycam.h
index e6ee82063..881f21c47 100644
--- a/linux/drivers/media/video/indycam.h
+++ b/linux/drivers/media/video/indycam.h
@@ -87,22 +87,7 @@
/* 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)
+#define INDYCAM_CONTROL_RED_SATURATION (V4L2_CID_PRIVATE_BASE + 0)
+#define INDYCAM_CONTROL_BLUE_SATURATION (V4L2_CID_PRIVATE_BASE + 1)
#endif
diff --git a/linux/drivers/media/video/meye.c b/linux/drivers/media/video/meye.c
index 323aa378b..85b2cff1a 100644
--- a/linux/drivers/media/video/meye.c
+++ b/linux/drivers/media/video/meye.c
@@ -1022,7 +1022,6 @@ static int meyeioc_stilljcapt(int *len)
static int vidioc_querycap(struct file *file, void *fh,
struct v4l2_capability *cap)
{
- memset(cap, 0, sizeof(*cap));
strcpy(cap->driver, "meye");
strcpy(cap->card, "meye");
sprintf(cap->bus_info, "PCI:%s", pci_name(meye.mchip_dev));
@@ -1041,8 +1040,6 @@ static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
if (i->index != 0)
return -EINVAL;
- memset(i, 0, sizeof(*i));
- i->index = 0;
strcpy(i->name, "Camera");
i->type = V4L2_INPUT_TYPE_CAMERA;
@@ -1269,16 +1266,12 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh,
if (f->index == 0) {
/* standard YUV 422 capture */
- memset(f, 0, sizeof(*f));
- f->index = 0;
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
f->flags = 0;
strcpy(f->description, "YUV422");
f->pixelformat = V4L2_PIX_FMT_YUYV;
} else {
/* compressed MJPEG capture */
- memset(f, 0, sizeof(*f));
- f->index = 1;
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
f->flags = V4L2_FMT_FLAG_COMPRESSED;
strcpy(f->description, "MJPEG");
@@ -1327,9 +1320,6 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *fh,
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
switch (meye.mchip_mode) {
case MCHIP_HIC_MODE_CONT_OUT:
default:
@@ -1346,8 +1336,6 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *fh,
f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
f->fmt.pix.sizeimage = f->fmt.pix.height *
f->fmt.pix.bytesperline;
- f->fmt.pix.colorspace = 0;
- f->fmt.pix.priv = 0;
return 0;
}
@@ -1451,10 +1439,6 @@ static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
if (index < 0 || index >= gbuffers)
return -EINVAL;
- memset(buf, 0, sizeof(*buf));
-
- buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buf->index = index;
buf->bytesused = meye.grab_buffer[index].size;
buf->flags = V4L2_BUF_FLAG_MAPPED;
diff --git a/linux/drivers/media/video/ovcamchip/ovcamchip_core.c b/linux/drivers/media/video/ovcamchip/ovcamchip_core.c
index c841f4e4f..63303b70f 100644
--- a/linux/drivers/media/video/ovcamchip/ovcamchip_core.c
+++ b/linux/drivers/media/video/ovcamchip/ovcamchip_core.c
@@ -15,6 +15,9 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-i2c-drv.h>
#include "ovcamchip_priv.h"
#define DRIVER_VERSION "v2.27 for Linux 2.6"
@@ -44,6 +47,20 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
+static unsigned short normal_i2c[] = {
+ /* ov7xxx */
+ 0x42 >> 1, 0x46 >> 1, 0x4a >> 1, 0x4e >> 1,
+ 0x52 >> 1, 0x56 >> 1, 0x5a >> 1, 0x5e >> 1,
+ /* ov6xxx */
+ 0xc0 >> 1, 0xc4 >> 1, 0xc8 >> 1, 0xcc >> 1,
+ 0xd0 >> 1, 0xd4 >> 1, 0xd8 >> 1, 0xdc >> 1,
+ I2C_CLIENT_END
+};
+
+I2C_CLIENT_INSMOD;
+#endif
+
/* Registers common to all chips, that are needed for detection */
#define GENERIC_REG_ID_HIGH 0x1C /* manufacturer ID MSB */
#define GENERIC_REG_ID_LOW 0x1D /* manufacturer ID LSB */
@@ -61,10 +78,6 @@ static char *chip_names[NUM_CC_TYPES] = {
[CC_OV6630AF] = "OV6630AF",
};
-/* Forward declarations */
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
/* ----------------------------------------------------------------------- */
int ov_write_regvals(struct i2c_client *c, struct ovcamchip_regvals *rvals)
@@ -253,112 +266,36 @@ static int ovcamchip_detect(struct i2c_client *c)
/* Test for 7xx0 */
PDEBUG(3, "Testing for 0V7xx0");
- c->addr = OV7xx0_SID;
- if (init_camchip(c) < 0) {
- /* Test for 6xx0 */
- PDEBUG(3, "Testing for 0V6xx0");
- c->addr = OV6xx0_SID;
- if (init_camchip(c) < 0) {
- return -ENODEV;
- } else {
- if (ov6xx0_detect(c) < 0) {
- PERROR("Failed to init OV6xx0");
- return -EIO;
- }
- }
- } else {
+ if (init_camchip(c) < 0)
+ return -ENODEV;
+ /* 7-bit addresses with bit 0 set are for the OV7xx0 */
+ if (c->addr & 1) {
if (ov7xx0_detect(c) < 0) {
PERROR("Failed to init OV7xx0");
return -EIO;
}
+ return 0;
+ }
+ /* Test for 6xx0 */
+ PDEBUG(3, "Testing for 0V6xx0");
+ if (ov6xx0_detect(c) < 0) {
+ PERROR("Failed to init OV6xx0");
+ return -EIO;
}
-
return 0;
}
/* ----------------------------------------------------------------------- */
-static int ovcamchip_attach(struct i2c_adapter *adap)
+static long ovcamchip_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
- int rc = 0;
- struct ovcamchip *ov;
- struct i2c_client *c;
-
- /* I2C is not a PnP bus, so we can never be certain that we're talking
- * to the right chip. To prevent damage to EEPROMS and such, only
- * attach to adapters that are known to contain OV camera chips. */
-
- switch (adap->id) {
- case I2C_HW_SMBUS_OV511:
- case I2C_HW_SMBUS_OV518:
- case I2C_HW_SMBUS_W9968CF:
- PDEBUG(1, "Adapter ID 0x%06x accepted", adap->id);
- break;
- default:
- PDEBUG(1, "Adapter ID 0x%06x rejected", adap->id);
- return -ENODEV;
- }
-
- c = kmalloc(sizeof *c, GFP_KERNEL);
- if (!c) {
- rc = -ENOMEM;
- goto no_client;
- }
- memcpy(c, &client_template, sizeof *c);
- c->adapter = adap;
- strcpy(c->name, "OV????");
-
- ov = kzalloc(sizeof *ov, GFP_KERNEL);
- if (!ov) {
- rc = -ENOMEM;
- goto no_ov;
- }
- i2c_set_clientdata(c, ov);
-
- rc = ovcamchip_detect(c);
- if (rc < 0)
- goto error;
-
- strcpy(c->name, chip_names[ov->subtype]);
-
- PDEBUG(1, "Camera chip detection complete");
-
- i2c_attach_client(c);
-
- return rc;
-error:
- kfree(ov);
-no_ov:
- kfree(c);
-no_client:
- PDEBUG(1, "returning %d", rc);
- return rc;
-}
-
-static int ovcamchip_detach(struct i2c_client *c)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- int rc;
-
- rc = ov->sops->free(c);
- if (rc < 0)
- return rc;
-
- i2c_detach_client(c);
-
- kfree(ov);
- kfree(c);
- return 0;
-}
-
-static int ovcamchip_command(struct i2c_client *c, unsigned int cmd, void *arg)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
+ struct ovcamchip *ov = to_ovcamchip(sd);
+ struct i2c_client *c = v4l2_get_subdevdata(sd);
if (!ov->initialized &&
cmd != OVCAMCHIP_CMD_Q_SUBTYPE &&
cmd != OVCAMCHIP_CMD_INITIALIZE) {
- dev_err(&c->dev, "ERROR: Camera chip not initialized yet!\n");
+ v4l2_err(sd, "Camera chip not initialized yet!\n");
return -EPERM;
}
@@ -379,10 +316,10 @@ static int ovcamchip_command(struct i2c_client *c, unsigned int cmd, void *arg)
if (ov->mono) {
if (ov->subtype != CC_OV7620)
- dev_warn(&c->dev, "Warning: Monochrome not "
+ v4l2_warn(sd, "Monochrome not "
"implemented for this chip\n");
else
- dev_info(&c->dev, "Initializing chip as "
+ v4l2_info(sd, "Initializing chip as "
"monochrome\n");
}
@@ -398,37 +335,84 @@ static int ovcamchip_command(struct i2c_client *c, unsigned int cmd, void *arg)
}
}
+static int ovcamchip_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+ return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
/* ----------------------------------------------------------------------- */
-static struct i2c_driver driver = {
- .driver = {
- .name = "ovcamchip",
- },
- .id = I2C_DRIVERID_OVCAMCHIP,
- .attach_adapter = ovcamchip_attach,
- .detach_client = ovcamchip_detach,
- .command = ovcamchip_command,
+static const struct v4l2_subdev_core_ops ovcamchip_core_ops = {
+ .ioctl = ovcamchip_ioctl,
};
-static struct i2c_client client_template = {
- .name = "(unset)",
- .driver = &driver,
+static const struct v4l2_subdev_ops ovcamchip_ops = {
+ .core = &ovcamchip_core_ops,
};
-static int __init ovcamchip_init(void)
+static int ovcamchip_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
-#ifdef DEBUG
- ovcamchip_debug = debug;
-#endif
+ struct ovcamchip *ov;
+ struct v4l2_subdev *sd;
+ int rc = 0;
+
+ ov = kzalloc(sizeof *ov, GFP_KERNEL);
+ if (!ov) {
+ rc = -ENOMEM;
+ goto no_ov;
+ }
+ sd = &ov->sd;
+ v4l2_i2c_subdev_init(sd, client, &ovcamchip_ops);
+
+ rc = ovcamchip_detect(client);
+ if (rc < 0)
+ goto error;
+
+ v4l_info(client, "%s found @ 0x%02x (%s)\n",
+ chip_names[ov->subtype], client->addr << 1, client->adapter->name);
+
+ PDEBUG(1, "Camera chip detection complete");
- PINFO(DRIVER_VERSION " : " DRIVER_DESC);
- return i2c_add_driver(&driver);
+ return rc;
+error:
+ kfree(ov);
+no_ov:
+ PDEBUG(1, "returning %d", rc);
+ return rc;
}
-static void __exit ovcamchip_exit(void)
+static int ovcamchip_remove(struct i2c_client *client)
{
- i2c_del_driver(&driver);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ovcamchip *ov = to_ovcamchip(sd);
+ int rc;
+
+ v4l2_device_unregister_subdev(sd);
+ rc = ov->sops->free(client);
+ if (rc < 0)
+ return rc;
+
+ kfree(ov);
+ return 0;
}
-module_init(ovcamchip_init);
-module_exit(ovcamchip_exit);
+/* ----------------------------------------------------------------------- */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id ovcamchip_id[] = {
+ { "ovcamchip", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ovcamchip_id);
+
+#endif
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "ovcamchip",
+ .command = ovcamchip_command,
+ .probe = ovcamchip_probe,
+ .remove = ovcamchip_remove,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = ovcamchip_id,
+#endif
+};
diff --git a/linux/drivers/media/video/ovcamchip/ovcamchip_priv.h b/linux/drivers/media/video/ovcamchip/ovcamchip_priv.h
index a05650fae..4f07b78c8 100644
--- a/linux/drivers/media/video/ovcamchip/ovcamchip_priv.h
+++ b/linux/drivers/media/video/ovcamchip/ovcamchip_priv.h
@@ -16,6 +16,7 @@
#define __LINUX_OVCAMCHIP_PRIV_H
#include <linux/i2c.h>
+#include <media/v4l2-subdev.h>
#include <media/ovcamchip.h>
#ifdef DEBUG
@@ -46,6 +47,7 @@ struct ovcamchip_ops {
};
struct ovcamchip {
+ struct v4l2_subdev sd;
struct ovcamchip_ops *sops;
void *spriv; /* Private data for OV7x10.c etc... */
int subtype; /* = SEN_OV7610 etc... */
@@ -53,6 +55,11 @@ struct ovcamchip {
int initialized; /* OVCAMCHIP_CMD_INITIALIZE was successful */
};
+static inline struct ovcamchip *to_ovcamchip(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct ovcamchip, sd);
+}
+
extern struct ovcamchip_ops ov6x20_ops;
extern struct ovcamchip_ops ov6x30_ops;
extern struct ovcamchip_ops ov7x10_ops;
diff --git a/linux/drivers/media/video/pvrusb2/Kconfig b/linux/drivers/media/video/pvrusb2/Kconfig
index 854c2a885..17cde1757 100644
--- a/linux/drivers/media/video/pvrusb2/Kconfig
+++ b/linux/drivers/media/video/pvrusb2/Kconfig
@@ -40,10 +40,10 @@ config VIDEO_PVRUSB2_DVB
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
select DVB_S5H1409 if !DVB_FE_CUSTOMISE
select DVB_S5H1411 if !DVB_FE_CUSTOMISE
- select DVB_TDA10048 if !DVB_FE_CUSTOMIZE
- select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE
+ select DVB_TDA10048 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMIZE
select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
- select MEDIA_TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
+ select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMIZE
---help---
This option enables a DVB interface for the pvrusb2 driver.
diff --git a/linux/drivers/media/video/saa7134/Kconfig b/linux/drivers/media/video/saa7134/Kconfig
index fc2164e28..51f17c82b 100644
--- a/linux/drivers/media/video/saa7134/Kconfig
+++ b/linux/drivers/media/video/saa7134/Kconfig
@@ -35,8 +35,13 @@ config VIDEO_SAA7134_DVB
select DVB_TDA10086 if !DVB_FE_CUSTOMISE
select DVB_TDA826X if !DVB_FE_CUSTOMISE
select DVB_ISL6421 if !DVB_FE_CUSTOMISE
+ select DVB_ISL6405 if !DVB_FE_CUSTOMISE
select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMIZE
select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
+ select DVB_ZL10036 if !DVB_FE_CUSTOMISE
+ select DVB_MT312 if !DVB_FE_CUSTOMISE
+ select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+ select DVB_ZL10353 if !DVB_FE_CUSTOMISE
---help---
This adds support for DVB cards based on the
Philips saa7134 chip.
diff --git a/linux/drivers/media/video/saa7134/saa7134-cards.c b/linux/drivers/media/video/saa7134/saa7134-cards.c
index 9db045cf5..725c05f9e 100644
--- a/linux/drivers/media/video/saa7134/saa7134-cards.c
+++ b/linux/drivers/media/video/saa7134/saa7134-cards.c
@@ -31,6 +31,7 @@
#include <media/v4l2-common.h>
#include <media/tveeprom.h>
#include "tea5767.h"
+#include "tda18271.h"
/* commly used strings */
static char name_mute[] = "mute";
@@ -3330,6 +3331,66 @@ struct saa7134_board saa7134_boards[] = {
.gpio = 0x0200100,
},
},
+ [SAA7134_BOARD_HAUPPAUGE_HVR1150] = {
+ .name = "Hauppauge WinTV-HVR1150",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tuner_config = 3,
+ .gpiomask = 0x0800100, /* GPIO 21 is an INPUT */
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ .gpio = 0x0000100,
+ }, {
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .name = name_radio,
+ .amux = TV,
+ .gpio = 0x0800100, /* GPIO 23 HI for FM */
+ },
+ },
+ [SAA7134_BOARD_HAUPPAUGE_HVR1110R3] = {
+ .name = "Hauppauge WinTV-HVR1110r3",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tuner_config = 3,
+ .gpiomask = 0x0800100, /* GPIO 21 is an INPUT */
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ .gpio = 0x0000100,
+ }, {
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .name = name_radio,
+ .amux = TV,
+ .gpio = 0x0800100, /* GPIO 23 HI for FM */
+ },
+ },
[SAA7134_BOARD_CINERGY_HT_PCMCIA] = {
.name = "Terratec Cinergy HT PCMCIA",
.audio_clock = 0x00187de7,
@@ -4460,8 +4521,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- /* no DVB support for now */
- /* .mpeg = SAA7134_MPEG_DVB, */
+ .mpeg = SAA7134_MPEG_DVB,
.inputs = { {
.name = name_comp,
.vmux = 1,
@@ -4480,8 +4540,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- /* no DVB support for now */
- /* .mpeg = SAA7134_MPEG_DVB, */
+ .mpeg = SAA7134_MPEG_DVB,
.inputs = { {
.name = name_comp,
.vmux = 1,
@@ -5444,6 +5503,36 @@ struct pci_device_id saa7134_pci_tbl[] = {
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x0070,
+ .subdevice = 0x6706,
+ .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1150,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x0070,
+ .subdevice = 0x6707,
+ .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110R3,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x0070,
+ .subdevice = 0x6708,
+ .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1150,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x0070,
+ .subdevice = 0x6709,
+ .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110R3,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x0070,
+ .subdevice = 0x670a,
+ .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110R3,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
.subvendor = 0x153b,
.subdevice = 0x1172,
.driver_data = SAA7134_BOARD_CINERGY_HT_PCMCIA,
@@ -5916,8 +6005,8 @@ static int saa7134_xc5000_callback(struct saa7134_dev *dev,
}
#endif
-static int saa7134_tda8290_callback(struct saa7134_dev *dev,
- int command, int arg)
+static int saa7134_tda8290_827x_callback(struct saa7134_dev *dev,
+ int command, int arg)
{
u8 sync_control;
@@ -5943,6 +6032,65 @@ static int saa7134_tda8290_callback(struct saa7134_dev *dev,
return 0;
}
+static inline int saa7134_tda18271_hvr11x0_toggle_agc(struct saa7134_dev *dev,
+ enum tda18271_mode mode)
+{
+ /* toggle AGC switch through GPIO 26 */
+ switch (mode) {
+ case TDA18271_ANALOG:
+ saa7134_set_gpio(dev, 26, 0);
+ break;
+ case TDA18271_DIGITAL:
+ saa7134_set_gpio(dev, 26, 1);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int saa7134_tda8290_18271_callback(struct saa7134_dev *dev,
+ int command, int arg)
+{
+ int ret = 0;
+
+ switch (command) {
+ case TDA18271_CALLBACK_CMD_AGC_ENABLE: /* 0 */
+ switch (dev->board) {
+ case SAA7134_BOARD_HAUPPAUGE_HVR1150:
+ case SAA7134_BOARD_HAUPPAUGE_HVR1110R3:
+ ret = saa7134_tda18271_hvr11x0_toggle_agc(dev, arg);
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int saa7134_tda8290_callback(struct saa7134_dev *dev,
+ int command, int arg)
+{
+ int ret;
+
+ switch (dev->board) {
+ case SAA7134_BOARD_HAUPPAUGE_HVR1150:
+ case SAA7134_BOARD_HAUPPAUGE_HVR1110R3:
+ /* tda8290 + tda18271 */
+ ret = saa7134_tda8290_18271_callback(dev, command, arg);
+ break;
+ default:
+ /* tda8290 + tda827x */
+ ret = saa7134_tda8290_827x_callback(dev, command, arg);
+ break;
+ }
+ return ret;
+}
+
int saa7134_tuner_callback(void *priv, int component, int command, int arg)
{
struct saa7134_dev *dev = priv;
@@ -5977,11 +6125,16 @@ static void hauppauge_eeprom(struct saa7134_dev *dev, u8 *eeprom_data)
switch (tv.model) {
case 67019: /* WinTV-HVR1110 (Retail, IR Blaster, hybrid, FM, SVid/Comp, 3.5mm audio in) */
case 67109: /* WinTV-HVR1000 (Retail, IR Receive, analog, no FM, SVid/Comp, 3.5mm audio in) */
+ case 67201: /* WinTV-HVR1150 (Retail, IR Receive, hybrid, FM, SVid/Comp, 3.5mm audio in) */
+ case 67301: /* WinTV-HVR1000 (Retail, IR Receive, analog, no FM, SVid/Comp, 3.5mm audio in) */
+ case 67209: /* WinTV-HVR1110 (Retail, IR Receive, hybrid, FM, SVid/Comp, 3.5mm audio in) */
case 67559: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */
case 67569: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM) */
case 67579: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM) */
case 67589: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */
case 67599: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */
+ case 67651: /* WinTV-HVR1150 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */
+ case 67659: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */
break;
default:
printk(KERN_WARNING "%s: warning: "
@@ -6162,6 +6315,16 @@ int saa7134_board_init1(struct saa7134_dev *dev)
saa_writeb (SAA7134_PRODUCTION_TEST_MODE, 0x00);
break;
+ case SAA7134_BOARD_HAUPPAUGE_HVR1150:
+ case SAA7134_BOARD_HAUPPAUGE_HVR1110R3:
+ /* GPIO 26 high for digital, low for analog */
+ saa7134_set_gpio(dev, 26, 0);
+ msleep(1);
+
+ saa7134_set_gpio(dev, 22, 0);
+ msleep(10);
+ saa7134_set_gpio(dev, 22, 1);
+ break;
/* i2c remotes */
case SAA7134_BOARD_PINNACLE_PCTV_110i:
case SAA7134_BOARD_PINNACLE_PCTV_310i:
@@ -6187,15 +6350,15 @@ int saa7134_board_init1(struct saa7134_dev *dev)
saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x8c040007, 0x8c040007);
saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0c0007cd, 0x0c0007cd);
break;
- case SAA7134_BOARD_AVERMEDIA_A700_PRO:
case SAA7134_BOARD_AVERMEDIA_A700_HYBRID:
- /* write windows gpio values */
- saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x80040100, 0x80040100);
- saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x80040100, 0x00040100);
printk("%s: %s: hybrid analog/dvb card\n"
- "%s: Sorry, only analog s-video and composite input "
+ "%s: Sorry, of the analog inputs, only analog s-video and composite "
"are supported for now.\n",
dev->name, card(dev).name, dev->name);
+ case SAA7134_BOARD_AVERMEDIA_A700_PRO:
+ /* write windows gpio values */
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x80040100, 0x80040100);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x80040100, 0x00040100);
break;
}
return 0;
@@ -6414,6 +6577,10 @@ int saa7134_board_init2(struct saa7134_dev *dev)
dev->name, saa7134_boards[dev->board].name);
}
break;
+ case SAA7134_BOARD_HAUPPAUGE_HVR1150:
+ case SAA7134_BOARD_HAUPPAUGE_HVR1110R3:
+ hauppauge_eeprom(dev, dev->eedata+0x80);
+ break;
case SAA7134_BOARD_HAUPPAUGE_HVR1110:
hauppauge_eeprom(dev, dev->eedata+0x80);
/* break intentionally omitted */
diff --git a/linux/drivers/media/video/saa7134/saa7134-dvb.c b/linux/drivers/media/video/saa7134/saa7134-dvb.c
index 27a4d9c83..7745cad95 100644
--- a/linux/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/linux/drivers/media/video/saa7134/saa7134-dvb.c
@@ -51,6 +51,9 @@
#include "zl10353.h"
+#include "zl10036.h"
+#include "mt312.h"
+
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
MODULE_LICENSE("GPL");
@@ -949,6 +952,17 @@ static struct nxt200x_config kworldatsc110 = {
.demod_address = 0x0a,
};
+/* ------------------------------------------------------------------ */
+
+static struct mt312_config avertv_a700_mt312 = {
+ .demod_address = 0x0e,
+ .voltage_inverted = 1,
+};
+
+static struct zl10036_config avertv_a700_tuner = {
+ .tuner_address = 0x60,
+};
+
/* ==================================================================
* Core code
*/
@@ -1379,6 +1393,19 @@ static int dvb_init(struct saa7134_dev *dev)
TUNER_PHILIPS_FMD1216ME_MK3);
}
break;
+ case SAA7134_BOARD_AVERMEDIA_A700_PRO:
+ case SAA7134_BOARD_AVERMEDIA_A700_HYBRID:
+ /* Zarlink ZL10313 */
+ fe0->dvb.frontend = dvb_attach(mt312_attach,
+ &avertv_a700_mt312, &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ if (dvb_attach(zl10036_attach, fe0->dvb.frontend,
+ &avertv_a700_tuner, &dev->i2c_adap) == NULL) {
+ wprintk("%s: No zl10036 found!\n",
+ __func__);
+ }
+ }
+ break;
default:
wprintk("Huh? unknown DVB card?\n");
break;
diff --git a/linux/drivers/media/video/saa7134/saa7134.h b/linux/drivers/media/video/saa7134/saa7134.h
index c9d4d4354..0e45c0931 100644
--- a/linux/drivers/media/video/saa7134/saa7134.h
+++ b/linux/drivers/media/video/saa7134/saa7134.h
@@ -279,6 +279,8 @@ struct saa7134_format {
#define SAA7134_BOARD_ASUSTeK_TIGER 152
#define SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG 153
#define SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS 154
+#define SAA7134_BOARD_HAUPPAUGE_HVR1150 155
+#define SAA7134_BOARD_HAUPPAUGE_HVR1110R3 156
#define SAA7134_MAXBOARDS 32
#define SAA7134_INPUT_MAX 8
diff --git a/linux/drivers/media/video/saa7191.c b/linux/drivers/media/video/saa7191.c
index c4f169c95..9df505e0f 100644
--- a/linux/drivers/media/video/saa7191.c
+++ b/linux/drivers/media/video/saa7191.c
@@ -19,9 +19,11 @@
#include <linux/mm.h>
#include <linux/slab.h>
-#include <linux/videodev.h>
-#include <linux/video_decoder.h>
+#include <linux/videodev2.h>
#include <linux/i2c.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
#include "compat.h"
#include "saa7191.h"
@@ -33,6 +35,12 @@ MODULE_VERSION(SAA7191_MODULE_VERSION);
MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>");
MODULE_LICENSE("GPL");
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
+static unsigned short normal_i2c[] = { 0x8a >> 1, 0x8e >> 1, I2C_CLIENT_END };
+
+I2C_CLIENT_INSMOD;
+#endif
+
// #define SAA7191_DEBUG
#ifdef SAA7191_DEBUG
@@ -45,17 +53,20 @@ MODULE_LICENSE("GPL");
#define SAA7191_SYNC_DELAY 100 /* milliseconds */
struct saa7191 {
- struct i2c_client *client;
+ struct v4l2_subdev sd;
/* the register values are stored here as the actual
* I2C-registers are write-only */
u8 reg[25];
int input;
- int norm;
+ v4l2_std_id norm;
};
-static struct i2c_driver i2c_driver_saa7191;
+static inline struct saa7191 *to_saa7191(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct saa7191, sd);
+}
static const u8 initseq[] = {
0, /* Subaddress */
@@ -101,15 +112,14 @@ static const u8 initseq[] = {
/* SAA7191 register handling */
-static u8 saa7191_read_reg(struct i2c_client *client,
- u8 reg)
+static u8 saa7191_read_reg(struct v4l2_subdev *sd, u8 reg)
{
- return ((struct saa7191 *)i2c_get_clientdata(client))->reg[reg];
+ return to_saa7191(sd)->reg[reg];
}
-static int saa7191_read_status(struct i2c_client *client,
- u8 *value)
+static int saa7191_read_status(struct v4l2_subdev *sd, u8 *value)
{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret;
ret = i2c_master_recv(client, value, 1);
@@ -122,21 +132,23 @@ static int saa7191_read_status(struct i2c_client *client,
}
-static int saa7191_write_reg(struct i2c_client *client, u8 reg,
- u8 value)
+static int saa7191_write_reg(struct v4l2_subdev *sd, u8 reg, u8 value)
{
- ((struct saa7191 *)i2c_get_clientdata(client))->reg[reg] = value;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ to_saa7191(sd)->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,
+static int saa7191_write_block(struct v4l2_subdev *sd,
u8 length, const u8 *data)
{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct saa7191 *decoder = to_saa7191(sd);
int i;
int ret;
- struct saa7191 *decoder = (struct saa7191 *)i2c_get_clientdata(client);
for (i = 0; i < (length - 1); i++) {
decoder->reg[data[0] + i] = data[i + 1];
}
@@ -153,14 +165,15 @@ static int saa7191_write_block(struct i2c_client *client,
/* Helper functions */
-static int saa7191_set_input(struct i2c_client *client, int input)
+static int saa7191_s_routing(struct v4l2_subdev *sd,
+ const struct v4l2_routing *route)
{
- 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);
+ struct saa7191 *decoder = to_saa7191(sd);
+ u8 luma = saa7191_read_reg(sd, SAA7191_REG_LUMA);
+ u8 iock = saa7191_read_reg(sd, SAA7191_REG_IOCK);
int err;
- switch (input) {
+ switch (route->input) {
case SAA7191_INPUT_COMPOSITE: /* Set Composite input */
iock &= ~(SAA7191_IOCK_CHRS | SAA7191_IOCK_GPSW1
| SAA7191_IOCK_GPSW2);
@@ -176,54 +189,50 @@ static int saa7191_set_input(struct i2c_client *client, int input)
return -EINVAL;
}
- err = saa7191_write_reg(client, SAA7191_REG_LUMA, luma);
+ err = saa7191_write_reg(sd, SAA7191_REG_LUMA, luma);
if (err)
return -EIO;
- err = saa7191_write_reg(client, SAA7191_REG_IOCK, iock);
+ err = saa7191_write_reg(sd, SAA7191_REG_IOCK, iock);
if (err)
return -EIO;
- decoder->input = input;
+ decoder->input = route->input;
return 0;
}
-static int saa7191_set_norm(struct i2c_client *client, int norm)
+static int saa7191_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
{
- struct saa7191 *decoder = i2c_get_clientdata(client);
- 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);
+ struct saa7191 *decoder = to_saa7191(sd);
+ u8 stdc = saa7191_read_reg(sd, SAA7191_REG_STDC);
+ u8 ctl3 = saa7191_read_reg(sd, SAA7191_REG_CTL3);
+ u8 chcv = saa7191_read_reg(sd, SAA7191_REG_CHCV);
int err;
- switch(norm) {
- case SAA7191_NORM_PAL:
+ if (norm & V4L2_STD_PAL) {
stdc &= ~SAA7191_STDC_SECS;
ctl3 &= ~(SAA7191_CTL3_AUFD | SAA7191_CTL3_FSEL);
chcv = SAA7191_CHCV_PAL;
- break;
- case SAA7191_NORM_NTSC:
+ } else if (norm & V4L2_STD_NTSC) {
stdc &= ~SAA7191_STDC_SECS;
ctl3 &= ~SAA7191_CTL3_AUFD;
ctl3 |= SAA7191_CTL3_FSEL;
chcv = SAA7191_CHCV_NTSC;
- break;
- case SAA7191_NORM_SECAM:
+ } else if (norm & V4L2_STD_SECAM) {
stdc |= SAA7191_STDC_SECS;
ctl3 &= ~(SAA7191_CTL3_AUFD | SAA7191_CTL3_FSEL);
chcv = SAA7191_CHCV_PAL;
- break;
- default:
+ } else {
return -EINVAL;
}
- err = saa7191_write_reg(client, SAA7191_REG_CTL3, ctl3);
+ err = saa7191_write_reg(sd, SAA7191_REG_CTL3, ctl3);
if (err)
return -EIO;
- err = saa7191_write_reg(client, SAA7191_REG_STDC, stdc);
+ err = saa7191_write_reg(sd, SAA7191_REG_STDC, stdc);
if (err)
return -EIO;
- err = saa7191_write_reg(client, SAA7191_REG_CHCV, chcv);
+ err = saa7191_write_reg(sd, SAA7191_REG_CHCV, chcv);
if (err)
return -EIO;
@@ -231,19 +240,19 @@ static int saa7191_set_norm(struct i2c_client *client, int norm)
dprintk("ctl3: %02x stdc: %02x chcv: %02x\n", ctl3,
stdc, chcv);
- dprintk("norm: %d\n", norm);
+ dprintk("norm: %llx\n", norm);
return 0;
}
-static int saa7191_wait_for_signal(struct i2c_client *client, u8 *status)
+static int saa7191_wait_for_signal(struct v4l2_subdev *sd, u8 *status)
{
int i = 0;
dprintk("Checking for signal...\n");
for (i = 0; i < SAA7191_SYNC_COUNT; i++) {
- if (saa7191_read_status(client, status))
+ if (saa7191_read_status(sd, status))
return -EIO;
if (((*status) & SAA7191_STATUS_HLCK) == 0) {
@@ -259,31 +268,34 @@ static int saa7191_wait_for_signal(struct i2c_client *client, u8 *status)
return -EBUSY;
}
-static int saa7191_autodetect_norm_extended(struct i2c_client *client)
+static int saa7191_querystd(struct v4l2_subdev *sd, v4l2_std_id *norm)
{
- u8 stdc = saa7191_read_reg(client, SAA7191_REG_STDC);
- u8 ctl3 = saa7191_read_reg(client, SAA7191_REG_CTL3);
+ struct saa7191 *decoder = to_saa7191(sd);
+ u8 stdc = saa7191_read_reg(sd, SAA7191_REG_STDC);
+ u8 ctl3 = saa7191_read_reg(sd, SAA7191_REG_CTL3);
u8 status;
+ v4l2_std_id old_norm = decoder->norm;
int err = 0;
dprintk("SAA7191 extended signal auto-detection...\n");
+ *norm = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM;
stdc &= ~SAA7191_STDC_SECS;
ctl3 &= ~(SAA7191_CTL3_FSEL);
- err = saa7191_write_reg(client, SAA7191_REG_STDC, stdc);
+ err = saa7191_write_reg(sd, SAA7191_REG_STDC, stdc);
if (err) {
err = -EIO;
goto out;
}
- err = saa7191_write_reg(client, SAA7191_REG_CTL3, ctl3);
+ err = saa7191_write_reg(sd, SAA7191_REG_CTL3, ctl3);
if (err) {
err = -EIO;
goto out;
}
ctl3 |= SAA7191_CTL3_AUFD;
- err = saa7191_write_reg(client, SAA7191_REG_CTL3, ctl3);
+ err = saa7191_write_reg(sd, SAA7191_REG_CTL3, ctl3);
if (err) {
err = -EIO;
goto out;
@@ -291,53 +303,54 @@ static int saa7191_autodetect_norm_extended(struct i2c_client *client)
msleep(SAA7191_SYNC_DELAY);
- err = saa7191_wait_for_signal(client, &status);
+ err = saa7191_wait_for_signal(sd, &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);
+ *norm = V4L2_STD_NTSC;
+ return 0;
}
/* 50Hz signal */
dprintk("50Hz signal: Trying PAL...\n");
/* try PAL first */
- err = saa7191_set_norm(client, SAA7191_NORM_PAL);
+ err = saa7191_s_std(sd, V4L2_STD_PAL);
if (err)
goto out;
msleep(SAA7191_SYNC_DELAY);
- err = saa7191_wait_for_signal(client, &status);
+ err = saa7191_wait_for_signal(sd, &status);
if (err)
goto out;
/* not 50Hz ? */
if (status & SAA7191_STATUS_FIDT) {
dprintk("No 50Hz signal\n");
- err = -EAGAIN;
- goto out;
+ saa7191_s_std(sd, old_norm);
+ return -EAGAIN;
}
if (status & SAA7191_STATUS_CODE) {
dprintk("PAL\n");
- return 0;
+ *norm = V4L2_STD_PAL;
+ return saa7191_s_std(sd, old_norm);
}
dprintk("No color detected with PAL - Trying SECAM...\n");
/* no color detected ? -> try SECAM */
- err = saa7191_set_norm(client,
- SAA7191_NORM_SECAM);
+ err = saa7191_s_std(sd, V4L2_STD_SECAM);
if (err)
goto out;
msleep(SAA7191_SYNC_DELAY);
- err = saa7191_wait_for_signal(client, &status);
+ err = saa7191_wait_for_signal(sd, &status);
if (err)
goto out;
@@ -351,32 +364,17 @@ static int saa7191_autodetect_norm_extended(struct i2c_client *client)
if (status & SAA7191_STATUS_CODE) {
/* Color detected -> SECAM */
dprintk("SECAM\n");
- return 0;
+ *norm = V4L2_STD_SECAM;
+ return saa7191_s_std(sd, old_norm);
}
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;
- }
- }
-
- return err;
+ return saa7191_s_std(sd, old_norm);
}
-static int saa7191_autodetect_norm(struct i2c_client *client)
+static int saa7191_autodetect_norm(struct v4l2_subdev *sd)
{
u8 status;
@@ -384,7 +382,7 @@ static int saa7191_autodetect_norm(struct i2c_client *client)
dprintk("Reading status...\n");
- if (saa7191_read_status(client, &status))
+ if (saa7191_read_status(sd, &status))
return -EIO;
dprintk("Checking for signal...\n");
@@ -400,26 +398,25 @@ static int saa7191_autodetect_norm(struct i2c_client *client)
if (status & SAA7191_STATUS_FIDT) {
/* 60hz signal -> NTSC */
dprintk("NTSC\n");
- return saa7191_set_norm(client, SAA7191_NORM_NTSC);
+ return saa7191_s_std(sd, V4L2_STD_NTSC);
} else {
/* 50hz signal -> PAL */
dprintk("PAL\n");
- return saa7191_set_norm(client, SAA7191_NORM_PAL);
+ return saa7191_s_std(sd, V4L2_STD_PAL);
}
}
-static int saa7191_get_control(struct i2c_client *client,
- struct saa7191_control *ctrl)
+static int saa7191_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
u8 reg;
int ret = 0;
- switch (ctrl->type) {
+ switch (ctrl->id) {
case SAA7191_CONTROL_BANDPASS:
case SAA7191_CONTROL_BANDPASS_WEIGHT:
case SAA7191_CONTROL_CORING:
- reg = saa7191_read_reg(client, SAA7191_REG_LUMA);
- switch (ctrl->type) {
+ reg = saa7191_read_reg(sd, SAA7191_REG_LUMA);
+ switch (ctrl->id) {
case SAA7191_CONTROL_BANDPASS:
ctrl->value = ((s32)reg & SAA7191_LUMA_BPSS_MASK)
>> SAA7191_LUMA_BPSS_SHIFT;
@@ -436,15 +433,15 @@ static int saa7191_get_control(struct i2c_client *client,
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)
+ reg = saa7191_read_reg(sd, SAA7191_REG_GAIN);
+ if (ctrl->id == 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);
+ case V4L2_CID_HUE:
+ reg = saa7191_read_reg(sd, SAA7191_REG_HUEC);
if (reg < 0x80)
reg += 0x80;
else
@@ -452,18 +449,18 @@ static int saa7191_get_control(struct i2c_client *client,
ctrl->value = (s32)reg;
break;
case SAA7191_CONTROL_VTRC:
- reg = saa7191_read_reg(client, SAA7191_REG_STDC);
+ reg = saa7191_read_reg(sd, 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);
+ reg = saa7191_read_reg(sd, 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);
+ reg = saa7191_read_reg(sd, SAA7191_REG_CTL4);
ctrl->value = ((s32)reg & SAA7191_CTL4_VNOI_MASK)
>> SAA7191_CTL4_VNOI_SHIFT;
break;
@@ -474,18 +471,17 @@ static int saa7191_get_control(struct i2c_client *client,
return ret;
}
-static int saa7191_set_control(struct i2c_client *client,
- struct saa7191_control *ctrl)
+static int saa7191_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
u8 reg;
int ret = 0;
- switch (ctrl->type) {
+ switch (ctrl->id) {
case SAA7191_CONTROL_BANDPASS:
case SAA7191_CONTROL_BANDPASS_WEIGHT:
case SAA7191_CONTROL_CORING:
- reg = saa7191_read_reg(client, SAA7191_REG_LUMA);
- switch (ctrl->type) {
+ reg = saa7191_read_reg(sd, SAA7191_REG_LUMA);
+ switch (ctrl->id) {
case SAA7191_CONTROL_BANDPASS:
reg &= ~SAA7191_LUMA_BPSS_MASK;
reg |= (ctrl->value << SAA7191_LUMA_BPSS_SHIFT)
@@ -502,12 +498,12 @@ static int saa7191_set_control(struct i2c_client *client,
& SAA7191_LUMA_CORI_MASK;
break;
}
- ret = saa7191_write_reg(client, SAA7191_REG_LUMA, reg);
+ ret = saa7191_write_reg(sd, 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) {
+ reg = saa7191_read_reg(sd, SAA7191_REG_GAIN);
+ if (ctrl->id == SAA7191_CONTROL_FORCE_COLOUR) {
if (ctrl->value)
reg |= SAA7191_GAIN_COLO;
else
@@ -517,41 +513,41 @@ static int saa7191_set_control(struct i2c_client *client,
reg |= (ctrl->value << SAA7191_GAIN_LFIS_SHIFT)
& SAA7191_GAIN_LFIS_MASK;
}
- ret = saa7191_write_reg(client, SAA7191_REG_GAIN, reg);
+ ret = saa7191_write_reg(sd, SAA7191_REG_GAIN, reg);
break;
- case SAA7191_CONTROL_HUE:
+ case V4L2_CID_HUE:
reg = ctrl->value & 0xff;
if (reg < 0x80)
reg += 0x80;
else
reg -= 0x80;
- ret = saa7191_write_reg(client, SAA7191_REG_HUEC, reg);
+ ret = saa7191_write_reg(sd, SAA7191_REG_HUEC, reg);
break;
case SAA7191_CONTROL_VTRC:
- reg = saa7191_read_reg(client, SAA7191_REG_STDC);
+ reg = saa7191_read_reg(sd, SAA7191_REG_STDC);
if (ctrl->value)
reg |= SAA7191_STDC_VTRC;
else
reg &= ~SAA7191_STDC_VTRC;
- ret = saa7191_write_reg(client, SAA7191_REG_STDC, reg);
+ ret = saa7191_write_reg(sd, 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_read_reg(sd, 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);
+ ret = saa7191_write_reg(sd, SAA7191_REG_CTL3, reg);
break;
}
case SAA7191_CONTROL_VNR:
- reg = saa7191_read_reg(client, SAA7191_REG_CTL4);
+ reg = saa7191_read_reg(sd, 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);
+ ret = saa7191_write_reg(sd, SAA7191_REG_CTL4, reg);
break;
default:
ret = -EINVAL;
@@ -562,247 +558,111 @@ static int saa7191_set_control(struct i2c_client *client,
/* I2C-interface */
-static int saa7191_attach(struct i2c_adapter *adap, int addr, int kind)
+static int saa7191_g_input_status(struct v4l2_subdev *sd, u32 *status)
{
- int err = 0;
- struct saa7191 *decoder;
- struct i2c_client *client;
-
- printk(KERN_INFO "Philips SAA7191 driver version %s\n",
- SAA7191_MODULE_VERSION);
-
- client = kzalloc(sizeof(*client), GFP_KERNEL);
- if (!client)
- return -ENOMEM;
- decoder = kzalloc(sizeof(*decoder), GFP_KERNEL);
- if (!decoder) {
- err = -ENOMEM;
- goto out_free_client;
- }
-
- client->addr = addr;
- client->adapter = adap;
- client->driver = &i2c_driver_saa7191;
- client->flags = 0;
- strcpy(client->name, "saa7191 client");
- i2c_set_clientdata(client, decoder);
-
- decoder->client = client;
-
- err = i2c_attach_client(client);
- if (err)
- goto out_free_decoder;
-
- err = saa7191_write_block(client, sizeof(initseq), initseq);
- if (err) {
- printk(KERN_ERR "SAA7191 initialization failed\n");
- goto out_detach_client;
- }
-
- 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");
- }
+ u8 status_reg;
+ int res = V4L2_IN_ST_NO_SIGNAL;
+ if (saa7191_read_status(sd, &status_reg))
+ return -EIO;
+ if ((status_reg & SAA7191_STATUS_HLCK) == 0)
+ res = 0;
+ if (!(status_reg & SAA7191_STATUS_CODE))
+ res |= V4L2_IN_ST_NO_COLOR;
+ *status = res;
return 0;
-
-out_detach_client:
- i2c_detach_client(client);
-out_free_decoder:
- kfree(decoder);
-out_free_client:
- kfree(client);
- return err;
}
-static int saa7191_probe(struct i2c_adapter *adap)
-{
- /* Always connected to VINO */
- if (adap->id == I2C_HW_SGI_VINO)
- return saa7191_attach(adap, SAA7191_ADDR, 0);
- /* Feel free to add probe here :-) */
- return -ENODEV;
-}
-static int saa7191_detach(struct i2c_client *client)
+static int saa7191_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *chip)
{
- struct saa7191 *decoder = i2c_get_clientdata(client);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- i2c_detach_client(client);
- kfree(decoder);
- kfree(client);
- return 0;
+ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA7191, 0);
}
-static int saa7191_command(struct i2c_client *client, unsigned int cmd,
- void *arg)
-{
- struct saa7191 *decoder = i2c_get_clientdata(client);
+/* ----------------------------------------------------------------------- */
- switch (cmd) {
- case DECODER_GET_CAPABILITIES: {
- struct video_decoder_capability *cap = arg;
+static const struct v4l2_subdev_core_ops saa7191_core_ops = {
+ .g_chip_ident = saa7191_g_chip_ident,
+ .g_ctrl = saa7191_g_ctrl,
+ .s_ctrl = saa7191_s_ctrl,
+};
- cap->flags = VIDEO_DECODER_PAL | VIDEO_DECODER_NTSC |
- VIDEO_DECODER_SECAM | VIDEO_DECODER_AUTO;
- cap->inputs = (client->adapter->id == I2C_HW_SGI_VINO) ? 2 : 1;
- cap->outputs = 1;
- break;
- }
- case DECODER_GET_STATUS: {
- int *iarg = arg;
- u8 status;
- int res = 0;
+static const struct v4l2_subdev_tuner_ops saa7191_tuner_ops = {
+ .s_std = saa7191_s_std,
+};
- if (saa7191_read_status(client, &status)) {
- return -EIO;
- }
- if ((status & SAA7191_STATUS_HLCK) == 0)
- res |= DECODER_STATUS_GOOD;
- if (status & SAA7191_STATUS_CODE)
- res |= DECODER_STATUS_COLOR;
- switch (decoder->norm) {
- case SAA7191_NORM_NTSC:
- res |= DECODER_STATUS_NTSC;
- break;
- case SAA7191_NORM_PAL:
- res |= DECODER_STATUS_PAL;
- break;
- case SAA7191_NORM_SECAM:
- res |= DECODER_STATUS_SECAM;
- break;
- case SAA7191_NORM_AUTO:
- default:
- if (status & SAA7191_STATUS_FIDT)
- res |= DECODER_STATUS_NTSC;
- else
- res |= DECODER_STATUS_PAL;
- break;
- }
- *iarg = res;
- break;
- }
- case DECODER_SET_NORM: {
- int *iarg = arg;
-
- switch (*iarg) {
- case VIDEO_MODE_AUTO:
- return saa7191_autodetect_norm(client);
- case VIDEO_MODE_PAL:
- return saa7191_set_norm(client, SAA7191_NORM_PAL);
- case VIDEO_MODE_NTSC:
- return saa7191_set_norm(client, SAA7191_NORM_NTSC);
- case VIDEO_MODE_SECAM:
- return saa7191_set_norm(client, SAA7191_NORM_SECAM);
- default:
- return -EINVAL;
- }
- break;
- }
- case DECODER_SET_INPUT: {
- int *iarg = arg;
-
- switch (client->adapter->id) {
- case I2C_HW_SGI_VINO:
- return saa7191_set_input(client, *iarg);
- default:
- if (*iarg != 0)
- return -EINVAL;
- }
- break;
- }
- case DECODER_SET_OUTPUT: {
- int *iarg = arg;
+static const struct v4l2_subdev_video_ops saa7191_video_ops = {
+ .s_routing = saa7191_s_routing,
+ .querystd = saa7191_querystd,
+ .g_input_status = saa7191_g_input_status,
+};
- /* not much choice of outputs */
- if (*iarg != 0)
- return -EINVAL;
- break;
- }
- case DECODER_ENABLE_OUTPUT: {
- /* Always enabled */
- break;
- }
- case DECODER_SET_PICTURE: {
- struct video_picture *pic = arg;
- unsigned val;
- int err;
+static const struct v4l2_subdev_ops saa7191_ops = {
+ .core = &saa7191_core_ops,
+ .video = &saa7191_video_ops,
+};
- val = (pic->hue >> 8) - 0x80;
+static int saa7191_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int err = 0;
+ struct saa7191 *decoder;
+ struct v4l2_subdev *sd;
- err = saa7191_write_reg(client, SAA7191_REG_HUEC, val);
- if (err)
- return -EIO;
+ v4l_info(client, "chip found @ 0x%x (%s)\n",
+ client->addr << 1, client->adapter->name);
- break;
- }
- case DECODER_SAA7191_GET_STATUS: {
- struct saa7191_status *status = arg;
- u8 status_reg;
+ decoder = kzalloc(sizeof(*decoder), GFP_KERNEL);
+ if (!decoder)
+ return -ENOMEM;
- if (saa7191_read_status(client, &status_reg))
- return -EIO;
+ sd = &decoder->sd;
+ v4l2_i2c_subdev_init(sd, client, &saa7191_ops);
- status->signal = ((status_reg & SAA7191_STATUS_HLCK) == 0)
- ? 1 : 0;
- status->signal_60hz = (status_reg & SAA7191_STATUS_FIDT)
- ? 1 : 0;
- status->color = (status_reg & SAA7191_STATUS_CODE) ? 1 : 0;
+ err = saa7191_write_block(sd, sizeof(initseq), initseq);
+ if (err) {
+ printk(KERN_ERR "SAA7191 initialization failed\n");
+ kfree(decoder);
+ return err;
+ }
- status->input = decoder->input;
- status->norm = decoder->norm;
+ printk(KERN_INFO "SAA7191 initialized\n");
- break;
- }
- case DECODER_SAA7191_SET_NORM: {
- int *norm = arg;
-
- 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_CONTROL: {
- return saa7191_get_control(client, arg);
- }
- case DECODER_SAA7191_SET_CONTROL: {
- return saa7191_set_control(client, arg);
- }
- default:
- return -EINVAL;
- }
+ decoder->input = SAA7191_INPUT_COMPOSITE;
+ decoder->norm = V4L2_STD_PAL;
+
+ err = saa7191_autodetect_norm(sd);
+ if (err && (err != -EBUSY))
+ printk(KERN_ERR "SAA7191: Signal auto-detection failed\n");
return 0;
}
-static struct i2c_driver i2c_driver_saa7191 = {
- .driver = {
- .name = "saa7191",
- },
- .id = I2C_DRIVERID_SAA7191,
- .attach_adapter = saa7191_probe,
- .detach_client = saa7191_detach,
- .command = saa7191_command
-};
-
-static int saa7191_init(void)
+static int saa7191_remove(struct i2c_client *client)
{
- return i2c_add_driver(&i2c_driver_saa7191);
-}
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
-static void saa7191_exit(void)
-{
- i2c_del_driver(&i2c_driver_saa7191);
+ v4l2_device_unregister_subdev(sd);
+ kfree(to_saa7191(sd));
+ return 0;
}
-module_init(saa7191_init);
-module_exit(saa7191_exit);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id saa7191_id[] = {
+ { "saa7191", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, saa7191_id);
+
+#endif
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "saa7191",
+ .probe = saa7191_probe,
+ .remove = saa7191_remove,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = saa7191_id,
+#endif
+};
diff --git a/linux/drivers/media/video/saa7191.h b/linux/drivers/media/video/saa7191.h
index a2310da19..803c74d60 100644
--- a/linux/drivers/media/video/saa7191.h
+++ b/linux/drivers/media/video/saa7191.h
@@ -176,11 +176,9 @@
#define SAA7191_INPUT_COMPOSITE 0
#define SAA7191_INPUT_SVIDEO 1
-#define SAA7191_NORM_AUTO 0
#define SAA7191_NORM_PAL 1
#define SAA7191_NORM_NTSC 2
#define SAA7191_NORM_SECAM 3
-#define SAA7191_NORM_AUTO_EXT 4 /* extended auto-detection */
struct saa7191_status {
/* 0=no signal, 1=signal detected */
@@ -232,24 +230,16 @@ struct saa7191_status {
#define SAA7191_VNR_MAX 0x03
#define SAA7191_VNR_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 {
- u8 type;
- s32 value;
-};
+#define SAA7191_CONTROL_BANDPASS (V4L2_CID_PRIVATE_BASE + 0)
+#define SAA7191_CONTROL_BANDPASS_WEIGHT (V4L2_CID_PRIVATE_BASE + 1)
+#define SAA7191_CONTROL_CORING (V4L2_CID_PRIVATE_BASE + 2)
+#define SAA7191_CONTROL_FORCE_COLOUR (V4L2_CID_PRIVATE_BASE + 3)
+#define SAA7191_CONTROL_CHROMA_GAIN (V4L2_CID_PRIVATE_BASE + 4)
+#define SAA7191_CONTROL_VTRC (V4L2_CID_PRIVATE_BASE + 5)
+#define SAA7191_CONTROL_LUMA_DELAY (V4L2_CID_PRIVATE_BASE + 6)
+#define SAA7191_CONTROL_VNR (V4L2_CID_PRIVATE_BASE + 7)
#define DECODER_SAA7191_GET_STATUS _IOR('d', 195, struct saa7191_status)
#define DECODER_SAA7191_SET_NORM _IOW('d', 196, int)
-#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/linux/drivers/media/video/stk-webcam.c b/linux/drivers/media/video/stk-webcam.c
index 3af084640..54efa2cc0 100644
--- a/linux/drivers/media/video/stk-webcam.c
+++ b/linux/drivers/media/video/stk-webcam.c
@@ -934,8 +934,6 @@ static int stk_vidioc_s_ctrl(struct file *filp,
static int stk_vidioc_enum_fmt_vid_cap(struct file *filp,
void *priv, struct v4l2_fmtdesc *fmtd)
{
- fmtd->flags = 0;
-
switch (fmtd->index) {
case 0:
fmtd->pixelformat = V4L2_PIX_FMT_RGB565;
@@ -993,7 +991,6 @@ static int stk_vidioc_g_fmt_vid_cap(struct file *filp,
pix_format->height = stk_sizes[i].h;
pix_format->field = V4L2_FIELD_NONE;
pix_format->colorspace = V4L2_COLORSPACE_SRGB;
- pix_format->priv = 0;
pix_format->pixelformat = dev->vsettings.palette;
if (dev->vsettings.palette == V4L2_PIX_FMT_SBGGR8)
pix_format->bytesperline = pix_format->width;
@@ -1140,16 +1137,10 @@ static int stk_vidioc_reqbufs(struct file *filp,
static int stk_vidioc_querybuf(struct file *filp,
void *priv, struct v4l2_buffer *buf)
{
- int index;
struct stk_camera *dev = priv;
struct stk_sio_buffer *sbuf;
- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- index = buf->index;
-
- if (index < 0 || index >= dev->n_sbufs)
+ if (buf->index < 0 || buf->index >= dev->n_sbufs)
return -EINVAL;
sbuf = dev->sio_bufs + buf->index;
*buf = sbuf->v4lbuf;
@@ -1253,13 +1244,10 @@ static int stk_vidioc_g_parm(struct file *filp,
if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- sp->parm.capture.capability = 0;
- sp->parm.capture.capturemode = 0;
/*FIXME This is not correct */
sp->parm.capture.timeperframe.numerator = 1;
sp->parm.capture.timeperframe.denominator = 30;
sp->parm.capture.readbuffers = 2;
- sp->parm.capture.extendedmode = 0;
return 0;
}
diff --git a/linux/drivers/media/video/tvaudio.c b/linux/drivers/media/video/tvaudio.c
index 755418a31..d630dca83 100644
--- a/linux/drivers/media/video/tvaudio.c
+++ b/linux/drivers/media/video/tvaudio.c
@@ -57,7 +57,7 @@ MODULE_LICENSE("GPL");
/* ---------------------------------------------------------------------- */
/* our structs */
-#define MAXREGS 64
+#define MAXREGS 256
struct CHIPSTATE;
typedef int (*getvalue)(int);
diff --git a/linux/drivers/media/video/usbvision/usbvision-video.c b/linux/drivers/media/video/usbvision/usbvision-video.c
index 33d79a5da..3d400e4b7 100644
--- a/linux/drivers/media/video/usbvision/usbvision-video.c
+++ b/linux/drivers/media/video/usbvision/usbvision-video.c
@@ -697,7 +697,6 @@ static int vidioc_g_audio (struct file *file, void *priv, struct v4l2_audio *a)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- memset(a,0,sizeof(*a));
if(usbvision->radio) {
strcpy(a->name,"Radio");
} else {
@@ -721,10 +720,6 @@ static int vidioc_queryctrl (struct file *file, void *priv,
struct v4l2_queryctrl *ctrl)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- int id=ctrl->id;
-
- memset(ctrl,0,sizeof(*ctrl));
- ctrl->id=id;
call_all(usbvision, core, queryctrl, ctrl);
@@ -788,9 +783,6 @@ static int vidioc_querybuf (struct file *file,
/* FIXME : must control
that buffers are mapped (VIDIOC_REQBUFS has been called) */
- if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
- return -EINVAL;
- }
if(vb->index>=usbvision->num_frames) {
return -EINVAL;
}
@@ -929,11 +921,9 @@ static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv,
if(vfd->index>=USBVISION_SUPPORTED_PALETTES-1) {
return -EINVAL;
}
- vfd->flags = 0;
vfd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
strcpy(vfd->description,usbvision_v4l2_format[vfd->index].desc);
vfd->pixelformat = usbvision_v4l2_format[vfd->index].format;
- memset(vfd->reserved, 0, sizeof(vfd->reserved));
return 0;
}
diff --git a/linux/drivers/media/video/v4l2-dev.c b/linux/drivers/media/video/v4l2-dev.c
index e6dc1279a..861e3194f 100644
--- a/linux/drivers/media/video/v4l2-dev.c
+++ b/linux/drivers/media/video/v4l2-dev.c
@@ -404,12 +404,11 @@ int video_register_device_index(struct video_device *vdev, int type, int nr,
/* A minor value of -1 marks this video device as never
having been registered */
- if (vdev)
- vdev->minor = -1;
+ vdev->minor = -1;
/* the release callback MUST be present */
- WARN_ON(!vdev || !vdev->release);
- if (!vdev || !vdev->release)
+ WARN_ON(!vdev->release);
+ if (!vdev->release)
return -EINVAL;
/* Part 1: check device type */
diff --git a/linux/drivers/media/video/v4l2-ioctl.c b/linux/drivers/media/video/v4l2-ioctl.c
index ec139df5c..230299801 100644
--- a/linux/drivers/media/video/v4l2-ioctl.c
+++ b/linux/drivers/media/video/v4l2-ioctl.c
@@ -25,7 +25,6 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-chip-ident.h>
-#include <linux/video_decoder.h>
#include "compat.h"
#define dbgarg(cmd, fmt, arg...) \
@@ -102,25 +101,27 @@ const char *v4l2_norm_to_name(v4l2_std_id id)
}
EXPORT_SYMBOL(v4l2_norm_to_name);
+/* Returns frame period for the given standard */
+void v4l2_video_std_frame_period(int id, struct v4l2_fract *frameperiod)
+{
+ if (id & V4L2_STD_525_60) {
+ frameperiod->numerator = 1001;
+ frameperiod->denominator = 30000;
+ } else {
+ frameperiod->numerator = 1;
+ frameperiod->denominator = 25;
+ }
+}
+EXPORT_SYMBOL(v4l2_video_std_frame_period);
+
/* Fill in the fields of a v4l2_standard structure according to the
'id' and 'transmission' parameters. Returns negative on error. */
int v4l2_video_std_construct(struct v4l2_standard *vs,
int id, const char *name)
{
- u32 index = vs->index;
-
- memset(vs, 0, sizeof(struct v4l2_standard));
- vs->index = index;
- vs->id = id;
- if (id & V4L2_STD_525_60) {
- vs->frameperiod.numerator = 1001;
- vs->frameperiod.denominator = 30000;
- vs->framelines = 525;
- } else {
- vs->frameperiod.numerator = 1;
- vs->frameperiod.denominator = 25;
- vs->framelines = 625;
- }
+ vs->id = id;
+ v4l2_video_std_frame_period(id, &vs->frameperiod);
+ vs->framelines = (id & V4L2_STD_525_60) ? 525 : 625;
strlcpy(vs->name, name, sizeof(vs->name));
return 0;
}
@@ -275,19 +276,6 @@ static const char *v4l2_ioctls[] = {
#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
static const char *v4l2_int_ioctls[] = {
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- [_IOC_NR(DECODER_GET_CAPABILITIES)] = "DECODER_GET_CAPABILITIES",
- [_IOC_NR(DECODER_GET_STATUS)] = "DECODER_GET_STATUS",
- [_IOC_NR(DECODER_SET_NORM)] = "DECODER_SET_NORM",
- [_IOC_NR(DECODER_SET_INPUT)] = "DECODER_SET_INPUT",
- [_IOC_NR(DECODER_SET_OUTPUT)] = "DECODER_SET_OUTPUT",
- [_IOC_NR(DECODER_ENABLE_OUTPUT)] = "DECODER_ENABLE_OUTPUT",
- [_IOC_NR(DECODER_SET_PICTURE)] = "DECODER_SET_PICTURE",
- [_IOC_NR(DECODER_SET_GPIO)] = "DECODER_SET_GPIO",
- [_IOC_NR(DECODER_INIT)] = "DECODER_INIT",
- [_IOC_NR(DECODER_SET_VBI_BYPASS)] = "DECODER_SET_VBI_BYPASS",
- [_IOC_NR(DECODER_DUMP)] = "DECODER_DUMP",
-#endif
[_IOC_NR(AUDC_SET_RADIO)] = "AUDC_SET_RADIO",
[_IOC_NR(TUNER_SET_TYPE_ADDR)] = "TUNER_SET_TYPE_ADDR",
@@ -656,8 +644,6 @@ static long __video_do_ioctl(struct file *file,
if (cmd == VIDIOCGMBUF) {
struct video_mbuf *p = arg;
- memset(p, 0, sizeof(*p));
-
if (!ops->vidiocgmbuf)
return ret;
ret = ops->vidiocgmbuf(file, fh, p);
@@ -684,7 +670,6 @@ static long __video_do_ioctl(struct file *file,
case VIDIOC_QUERYCAP:
{
struct v4l2_capability *cap = (struct v4l2_capability *)arg;
- memset(cap, 0, sizeof(*cap));
if (!ops->vidioc_querycap)
break;
@@ -727,16 +712,8 @@ static long __video_do_ioctl(struct file *file,
case VIDIOC_ENUM_FMT:
{
struct v4l2_fmtdesc *f = arg;
- enum v4l2_buf_type type;
- unsigned int index;
- index = f->index;
- type = f->type;
- memset(f, 0, sizeof(*f));
- f->index = index;
- f->type = type;
-
- switch (type) {
+ switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
if (ops->vidioc_enum_fmt_vid_cap)
ret = ops->vidioc_enum_fmt_vid_cap(file, fh, f);
@@ -773,8 +750,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_format *f = (struct v4l2_format *)arg;
- memset(f->fmt.raw_data, 0, sizeof(f->fmt.raw_data));
-
/* FIXME: Should be one dump per type */
dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names));
@@ -1090,7 +1065,6 @@ static long __video_do_ioctl(struct file *file,
return -EINVAL;
v4l2_video_std_construct(p, curr_id, descr);
- p->index = index;
dbgarg(cmd, "index=%d, id=0x%Lx, name=%s, fps=%d/%d, "
"framelines=%d\n", p->index,
@@ -1155,12 +1129,9 @@ static long __video_do_ioctl(struct file *file,
case VIDIOC_ENUMINPUT:
{
struct v4l2_input *p = arg;
- int i = p->index;
if (!ops->vidioc_enum_input)
break;
- memset(p, 0, sizeof(*p));
- p->index = i;
ret = ops->vidioc_enum_input(file, fh, p);
if (!ret)
@@ -1199,12 +1170,9 @@ static long __video_do_ioctl(struct file *file,
case VIDIOC_ENUMOUTPUT:
{
struct v4l2_output *p = arg;
- int i = p->index;
if (!ops->vidioc_enum_output)
break;
- memset(p, 0, sizeof(*p));
- p->index = i;
ret = ops->vidioc_enum_output(file, fh, p);
if (!ret)
@@ -1380,13 +1348,10 @@ static long __video_do_ioctl(struct file *file,
case VIDIOC_G_AUDIO:
{
struct v4l2_audio *p = arg;
- __u32 index = p->index;
if (!ops->vidioc_g_audio)
break;
- memset(p, 0, sizeof(*p));
- p->index = index;
ret = ops->vidioc_g_audio(file, fh, p);
if (!ret)
dbgarg(cmd, "index=%d, name=%s, capability=0x%x, "
@@ -1428,7 +1393,7 @@ static long __video_do_ioctl(struct file *file,
if (!ops->vidioc_g_audout)
break;
- dbgarg(cmd, "Enum for index=%d\n", p->index);
+
ret = ops->vidioc_g_audout(file, fh, p);
if (!ret)
dbgarg2("index=%d, name=%s, capability=%d, "
@@ -1481,15 +1446,10 @@ static long __video_do_ioctl(struct file *file,
case VIDIOC_G_CROP:
{
struct v4l2_crop *p = arg;
- __u32 type;
if (!ops->vidioc_g_crop)
break;
- type = p->type;
- memset(p, 0, sizeof(*p));
- p->type = type;
-
dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
ret = ops->vidioc_g_crop(file, fh, p);
if (!ret)
@@ -1510,16 +1470,11 @@ static long __video_do_ioctl(struct file *file,
case VIDIOC_CROPCAP:
{
struct v4l2_cropcap *p = arg;
- __u32 type;
/*FIXME: Should also show v4l2_fract pixelaspect */
if (!ops->vidioc_cropcap)
break;
- type = p->type;
- memset(p, 0, sizeof(*p));
- p->type = type;
-
dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
ret = ops->vidioc_cropcap(file, fh, p);
if (!ret) {
@@ -1535,8 +1490,6 @@ static long __video_do_ioctl(struct file *file,
if (!ops->vidioc_g_jpegcomp)
break;
- memset(p, 0, sizeof(*p));
-
ret = ops->vidioc_g_jpegcomp(file, fh, p);
if (!ret)
dbgarg(cmd, "quality=%d, APPn=%d, "
@@ -1577,7 +1530,6 @@ static long __video_do_ioctl(struct file *file,
if (!ops->vidioc_encoder_cmd)
break;
- memset(&p->raw, 0, sizeof(p->raw));
ret = ops->vidioc_encoder_cmd(file, fh, p);
if (!ret)
dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
@@ -1589,7 +1541,6 @@ static long __video_do_ioctl(struct file *file,
if (!ops->vidioc_try_encoder_cmd)
break;
- memset(&p->raw, 0, sizeof(p->raw));
ret = ops->vidioc_try_encoder_cmd(file, fh, p);
if (!ret)
dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
@@ -1598,23 +1549,15 @@ static long __video_do_ioctl(struct file *file,
case VIDIOC_G_PARM:
{
struct v4l2_streamparm *p = arg;
- __u32 type = p->type;
-
- memset(p, 0, sizeof(*p));
- p->type = type;
if (ops->vidioc_g_parm) {
ret = ops->vidioc_g_parm(file, fh, p);
} else {
- struct v4l2_standard s;
-
if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- v4l2_video_std_construct(&s, vfd->current_norm,
- v4l2_norm_to_name(vfd->current_norm));
-
- p->parm.capture.timeperframe = s.frameperiod;
+ v4l2_video_std_frame_period(vfd->current_norm,
+ &p->parm.capture.timeperframe);
ret = 0;
}
@@ -1634,14 +1577,10 @@ static long __video_do_ioctl(struct file *file,
case VIDIOC_G_TUNER:
{
struct v4l2_tuner *p = arg;
- __u32 index = p->index;
if (!ops->vidioc_g_tuner)
break;
- memset(p, 0, sizeof(*p));
- p->index = index;
-
ret = ops->vidioc_g_tuner(file, fh, p);
if (!ret)
dbgarg(cmd, "index=%d, name=%s, type=%d, "
@@ -1678,8 +1617,6 @@ static long __video_do_ioctl(struct file *file,
if (!ops->vidioc_g_frequency)
break;
- memset(p->reserved, 0, sizeof(p->reserved));
-
ret = ops->vidioc_g_frequency(file, fh, p);
if (!ret)
dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n",
@@ -1700,12 +1637,13 @@ static long __video_do_ioctl(struct file *file,
case VIDIOC_G_SLICED_VBI_CAP:
{
struct v4l2_sliced_vbi_cap *p = arg;
- __u32 type = p->type;
if (!ops->vidioc_g_sliced_vbi_cap)
break;
- memset(p, 0, sizeof(*p));
- p->type = type;
+
+ /* Clear up to type, everything after type is zerod already */
+ memset(p, 0, offsetof(struct v4l2_sliced_vbi_cap, type));
+
dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
ret = ops->vidioc_g_sliced_vbi_cap(file, fh, p);
if (!ret)
@@ -1778,8 +1716,6 @@ static long __video_do_ioctl(struct file *file,
if (!ops->vidioc_enum_framesizes)
break;
- memset(p, 0, sizeof(*p));
-
ret = ops->vidioc_enum_framesizes(file, fh, p);
dbgarg(cmd,
"index=%d, pixelformat=%d, type=%d ",
@@ -1811,8 +1747,6 @@ static long __video_do_ioctl(struct file *file,
if (!ops->vidioc_enum_frameintervals)
break;
- memset(p, 0, sizeof(*p));
-
ret = ops->vidioc_enum_frameintervals(file, fh, p);
dbgarg(cmd,
"index=%d, pixelformat=%d, width=%d, height=%d, type=%d ",
@@ -1861,6 +1795,44 @@ static long __video_do_ioctl(struct file *file,
return ret;
}
+/* In some cases, only a few fields are used as input, i.e. when the app sets
+ * "index" and then the driver fills in the rest of the structure for the thing
+ * with that index. We only need to copy up the first non-input field. */
+static unsigned long cmd_input_size(unsigned int cmd)
+{
+ /* Size of structure up to and including 'field' */
+#define CMDINSIZE(cmd, type, field) case _IOC_NR(VIDIOC_##cmd): return \
+ offsetof(struct v4l2_##type, field) + \
+ sizeof(((struct v4l2_##type *)0)->field);
+
+ switch (_IOC_NR(cmd)) {
+ CMDINSIZE(ENUM_FMT, fmtdesc, type);
+ CMDINSIZE(G_FMT, format, type);
+ CMDINSIZE(QUERYBUF, buffer, type);
+ CMDINSIZE(G_PARM, streamparm, type);
+ CMDINSIZE(ENUMSTD, standard, index);
+ CMDINSIZE(ENUMINPUT, input, index);
+ CMDINSIZE(G_CTRL, control, id);
+ CMDINSIZE(G_TUNER, tuner, index);
+ CMDINSIZE(QUERYCTRL, queryctrl, id);
+ CMDINSIZE(QUERYMENU, querymenu, index);
+ CMDINSIZE(ENUMOUTPUT, output, index);
+ CMDINSIZE(G_MODULATOR, modulator, index);
+ CMDINSIZE(G_FREQUENCY, frequency, tuner);
+ CMDINSIZE(CROPCAP, cropcap, type);
+ CMDINSIZE(G_CROP, crop, type);
+ CMDINSIZE(ENUMAUDIO, audio, index);
+ CMDINSIZE(ENUMAUDOUT, audioout, index);
+ CMDINSIZE(ENCODER_CMD, encoder_cmd, flags);
+ CMDINSIZE(TRY_ENCODER_CMD, encoder_cmd, flags);
+ CMDINSIZE(G_SLICED_VBI_CAP, sliced_vbi_cap, type);
+ CMDINSIZE(ENUM_FRAMESIZES, frmsizeenum, pixel_format);
+ CMDINSIZE(ENUM_FRAMEINTERVALS, frmivalenum, height);
+ default:
+ return _IOC_SIZE(cmd);
+ }
+}
+
long video_ioctl2(struct file *file,
unsigned int cmd, unsigned long arg)
{
@@ -1879,13 +1851,7 @@ long video_ioctl2(struct file *file,
cmd == VIDIOC_TRY_EXT_CTRLS);
/* Copy arguments into temp kernel buffer */
- switch (_IOC_DIR(cmd)) {
- case _IOC_NONE:
- parg = NULL;
- break;
- case _IOC_READ:
- case _IOC_WRITE:
- case (_IOC_WRITE | _IOC_READ):
+ if (_IOC_DIR(cmd) != _IOC_NONE) {
if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
parg = sbuf;
} else {
@@ -1897,10 +1863,19 @@ long video_ioctl2(struct file *file,
}
err = -EFAULT;
- if (_IOC_DIR(cmd) & _IOC_WRITE)
- if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
+ if (_IOC_DIR(cmd) & _IOC_WRITE) {
+ unsigned long n = cmd_input_size(cmd);
+
+ if (copy_from_user(parg, (void __user *)arg, n))
goto out;
- break;
+
+ /* zero out anything we don't copy from userspace */
+ if (n < _IOC_SIZE(cmd))
+ memset((u8 *)parg + n, 0, _IOC_SIZE(cmd) - n);
+ } else {
+ /* read-only ioctl */
+ memset(parg, 0, _IOC_SIZE(cmd));
+ }
}
if (is_ext_ctrl) {
diff --git a/linux/drivers/media/video/vino.c b/linux/drivers/media/video/vino.c
index 349ef053f..ba4e8b97d 100644
--- a/linux/drivers/media/video/vino.c
+++ b/linux/drivers/media/video/vino.c
@@ -8,6 +8,12 @@
*
* Based on the previous version of the driver for 2.4 kernels by:
* Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
+ *
+ * v4l2_device/v4l2_subdev conversion by:
+ * Copyright (C) 2009 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * Note: this conversion is untested! Please contact the linux-media
+ * mailinglist if you can test this, together with the test results.
*/
/*
@@ -33,12 +39,10 @@
#include <linux/kmod.h>
#include <linux/i2c.h>
-#include <linux/i2c-algo-sgi.h>
#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
-#include <linux/video_decoder.h>
#include <linux/mutex.h>
#include <asm/paccess.h>
@@ -139,13 +143,23 @@ MODULE_LICENSE("GPL");
#define VINO_DATA_NORM_PAL 1
#define VINO_DATA_NORM_SECAM 2
#define VINO_DATA_NORM_D1 3
-/* The following are special entries that can be used to
- * autodetect the norm. */
-#define VINO_DATA_NORM_AUTO 0xfe
-#define VINO_DATA_NORM_AUTO_EXT 0xff
#define VINO_DATA_NORM_COUNT 4
+/* I2C controller flags */
+#define SGI_I2C_FORCE_IDLE (0 << 0)
+#define SGI_I2C_NOT_IDLE (1 << 0)
+#define SGI_I2C_WRITE (0 << 1)
+#define SGI_I2C_READ (1 << 1)
+#define SGI_I2C_RELEASE_BUS (0 << 2)
+#define SGI_I2C_HOLD_BUS (1 << 2)
+#define SGI_I2C_XFER_DONE (0 << 4)
+#define SGI_I2C_XFER_BUSY (1 << 4)
+#define SGI_I2C_ACK (0 << 5)
+#define SGI_I2C_NACK (1 << 5)
+#define SGI_I2C_BUS_OK (0 << 7)
+#define SGI_I2C_BUS_ERR (1 << 7)
+
/* Internal data structure definitions */
struct vino_input {
@@ -289,22 +303,20 @@ struct vino_channel_settings {
struct vino_interrupt_data int_data;
/* V4L support */
- struct video_device *v4l_device;
-};
-
-struct vino_client {
- /* the channel which owns this client:
- * VINO_NO_CHANNEL, VINO_CHANNEL_A or VINO_CHANNEL_B */
- unsigned int owner;
- struct i2c_client *driver;
+ struct video_device *vdev;
};
struct vino_settings {
+ struct v4l2_device v4l2_dev;
struct vino_channel_settings a;
struct vino_channel_settings b;
- struct vino_client decoder;
- struct vino_client camera;
+ /* the channel which owns this client:
+ * VINO_NO_CHANNEL, VINO_CHANNEL_A or VINO_CHANNEL_B */
+ unsigned int decoder_owner;
+ struct v4l2_subdev *decoder;
+ unsigned int camera_owner;
+ struct v4l2_subdev *camera;
/* a lock for vino register access */
spinlock_t vino_lock;
@@ -344,11 +356,16 @@ static struct sgi_vino *vino;
static struct vino_settings *vino_drvdata;
+#define camera_call(o, f, args...) \
+ v4l2_subdev_call(vino_drvdata->camera, o, f, ##args)
+#define decoder_call(o, f, args...) \
+ v4l2_subdev_call(vino_drvdata->decoder, o, f, ##args)
+
static const char *vino_driver_name = "vino";
static const char *vino_driver_description = "SGI VINO";
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 const char *vino_vdev_name_a = "SGI VINO Channel A";
+static const char *vino_vdev_name_b = "SGI VINO Channel B";
static void vino_capture_tasklet(unsigned long channel);
@@ -360,11 +377,11 @@ static const struct vino_input vino_inputs[] = {
.name = "Composite",
.std = V4L2_STD_NTSC | V4L2_STD_PAL
| V4L2_STD_SECAM,
- },{
+ }, {
.name = "S-Video",
.std = V4L2_STD_NTSC | V4L2_STD_PAL
| V4L2_STD_SECAM,
- },{
+ }, {
.name = "D1/IndyCam",
.std = V4L2_STD_NTSC,
}
@@ -376,17 +393,17 @@ static const struct vino_data_format vino_data_formats[] = {
.bpp = 1,
.pixelformat = V4L2_PIX_FMT_GREY,
.colorspace = V4L2_COLORSPACE_SMPTE170M,
- },{
+ }, {
.description = "8-bit dithered RGB 3-3-2",
.bpp = 1,
.pixelformat = V4L2_PIX_FMT_RGB332,
.colorspace = V4L2_COLORSPACE_SRGB,
- },{
+ }, {
.description = "32-bit RGB",
.bpp = 4,
.pixelformat = V4L2_PIX_FMT_RGB32,
.colorspace = V4L2_COLORSPACE_SRGB,
- },{
+ }, {
.description = "YUV 4:2:2",
.bpp = 2,
.pixelformat = V4L2_PIX_FMT_YUYV, // XXX: swapped?
@@ -417,7 +434,7 @@ static const struct vino_data_norm vino_data_norms[] = {
+ VINO_NTSC_HEIGHT / 2 - 1,
.right = VINO_NTSC_WIDTH,
},
- },{
+ }, {
.description = "PAL",
.std = V4L2_STD_PAL,
.fps_min = 5,
@@ -439,7 +456,7 @@ static const struct vino_data_norm vino_data_norms[] = {
+ VINO_PAL_HEIGHT / 2 - 1,
.right = VINO_PAL_WIDTH,
},
- },{
+ }, {
.description = "SECAM",
.std = V4L2_STD_SECAM,
.fps_min = 5,
@@ -461,7 +478,7 @@ static const struct vino_data_norm vino_data_norms[] = {
+ VINO_PAL_HEIGHT / 2 - 1,
.right = VINO_PAL_WIDTH,
},
- },{
+ }, {
.description = "NTSC/D1",
.std = V4L2_STD_NTSC,
.fps_min = 6,
@@ -497,9 +514,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
.maximum = 1,
.step = 1,
.default_value = INDYCAM_AGC_DEFAULT,
- .flags = 0,
- .reserved = { INDYCAM_CONTROL_AGC, 0 },
- },{
+ }, {
.id = V4L2_CID_AUTO_WHITE_BALANCE,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Automatic White Balance",
@@ -507,9 +522,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
.maximum = 1,
.step = 1,
.default_value = INDYCAM_AWB_DEFAULT,
- .flags = 0,
- .reserved = { INDYCAM_CONTROL_AWB, 0 },
- },{
+ }, {
.id = V4L2_CID_GAIN,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Gain",
@@ -517,29 +530,23 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
.maximum = INDYCAM_GAIN_MAX,
.step = 1,
.default_value = INDYCAM_GAIN_DEFAULT,
- .flags = 0,
- .reserved = { INDYCAM_CONTROL_GAIN, 0 },
- },{
- .id = V4L2_CID_PRIVATE_BASE,
+ }, {
+ .id = INDYCAM_CONTROL_RED_SATURATION,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Red Saturation",
.minimum = INDYCAM_RED_SATURATION_MIN,
.maximum = INDYCAM_RED_SATURATION_MAX,
.step = 1,
.default_value = INDYCAM_RED_SATURATION_DEFAULT,
- .flags = 0,
- .reserved = { INDYCAM_CONTROL_RED_SATURATION, 0 },
- },{
- .id = V4L2_CID_PRIVATE_BASE + 1,
+ }, {
+ .id = INDYCAM_CONTROL_BLUE_SATURATION,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Blue Saturation",
.minimum = INDYCAM_BLUE_SATURATION_MIN,
.maximum = INDYCAM_BLUE_SATURATION_MAX,
.step = 1,
.default_value = INDYCAM_BLUE_SATURATION_DEFAULT,
- .flags = 0,
- .reserved = { INDYCAM_CONTROL_BLUE_SATURATION, 0 },
- },{
+ }, {
.id = V4L2_CID_RED_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Red Balance",
@@ -547,9 +554,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
.maximum = INDYCAM_RED_BALANCE_MAX,
.step = 1,
.default_value = INDYCAM_RED_BALANCE_DEFAULT,
- .flags = 0,
- .reserved = { INDYCAM_CONTROL_RED_BALANCE, 0 },
- },{
+ }, {
.id = V4L2_CID_BLUE_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Blue Balance",
@@ -557,9 +562,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
.maximum = INDYCAM_BLUE_BALANCE_MAX,
.step = 1,
.default_value = INDYCAM_BLUE_BALANCE_DEFAULT,
- .flags = 0,
- .reserved = { INDYCAM_CONTROL_BLUE_BALANCE, 0 },
- },{
+ }, {
.id = V4L2_CID_EXPOSURE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Shutter Control",
@@ -567,9 +570,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
.maximum = INDYCAM_SHUTTER_MAX,
.step = 1,
.default_value = INDYCAM_SHUTTER_DEFAULT,
- .flags = 0,
- .reserved = { INDYCAM_CONTROL_SHUTTER, 0 },
- },{
+ }, {
.id = V4L2_CID_GAMMA,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Gamma",
@@ -577,8 +578,6 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
.maximum = INDYCAM_GAMMA_MAX,
.step = 1,
.default_value = INDYCAM_GAMMA_DEFAULT,
- .flags = 0,
- .reserved = { INDYCAM_CONTROL_GAMMA, 0 },
}
};
@@ -593,209 +592,73 @@ struct v4l2_queryctrl vino_saa7191_v4l2_controls[] = {
.maximum = SAA7191_HUE_MAX,
.step = 1,
.default_value = SAA7191_HUE_DEFAULT,
- .flags = 0,
- .reserved = { SAA7191_CONTROL_HUE, 0 },
- },{
- .id = V4L2_CID_PRIVATE_BASE,
+ }, {
+ .id = SAA7191_CONTROL_BANDPASS,
.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,
+ }, {
+ .id = SAA7191_CONTROL_BANDPASS_WEIGHT,
.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,
+ }, {
+ .id = SAA7191_CONTROL_CORING,
.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,
+ }, {
+ .id = SAA7191_CONTROL_FORCE_COLOUR,
.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,
+ }, {
+ .id = SAA7191_CONTROL_CHROMA_GAIN,
.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,
+ }, {
+ .id = SAA7191_CONTROL_VTRC,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "VTR Time Constant",
.minimum = SAA7191_VTRC_MIN,
.maximum = SAA7191_VTRC_MAX,
.step = 1,
.default_value = SAA7191_VTRC_DEFAULT,
- .flags = 0,
- .reserved = { SAA7191_CONTROL_VTRC, 0 },
- },{
- .id = V4L2_CID_PRIVATE_BASE + 6,
+ }, {
+ .id = SAA7191_CONTROL_LUMA_DELAY,
.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,
+ }, {
+ .id = SAA7191_CONTROL_VNR,
.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 },
- }
-};
-
-/* VINO I2C bus functions */
-
-unsigned i2c_vino_getctrl(void *data)
-{
- return vino->i2c_control;
-}
-
-void i2c_vino_setctrl(void *data, unsigned val)
-{
- vino->i2c_control = val;
-}
-
-unsigned i2c_vino_rdata(void *data)
-{
- return vino->i2c_data;
-}
-
-void i2c_vino_wdata(void *data, unsigned val)
-{
- vino->i2c_data = val;
-}
-
-static struct i2c_algo_sgi_data i2c_sgi_vino_data =
-{
- .getctrl = &i2c_vino_getctrl,
- .setctrl = &i2c_vino_setctrl,
- .rdata = &i2c_vino_rdata,
- .wdata = &i2c_vino_wdata,
- .xfer_timeout = 200,
- .ack_timeout = 1000,
-};
-
-/*
- * There are two possible clients on VINO I2C bus, so we limit usage only
- * to them.
- */
-static int i2c_vino_client_reg(struct i2c_client *client)
-{
- unsigned long flags;
- int ret = 0;
-
- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
- switch (client->driver->id) {
- case I2C_DRIVERID_SAA7191:
- if (vino_drvdata->decoder.driver)
- ret = -EBUSY;
- else
- vino_drvdata->decoder.driver = client;
- break;
- case I2C_DRIVERID_INDYCAM:
- if (vino_drvdata->camera.driver)
- ret = -EBUSY;
- else
- vino_drvdata->camera.driver = client;
- break;
- default:
- ret = -ENODEV;
- }
- 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_irqsave(&vino_drvdata->input_lock, flags);
- if (client == vino_drvdata->decoder.driver) {
- if (vino_drvdata->decoder.owner != VINO_NO_CHANNEL)
- ret = -EBUSY;
- else
- vino_drvdata->decoder.driver = NULL;
- } else if (client == vino_drvdata->camera.driver) {
- if (vino_drvdata->camera.owner != VINO_NO_CHANNEL)
- ret = -EBUSY;
- else
- vino_drvdata->camera.driver = NULL;
}
- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
-
- return ret;
-}
-
-static struct i2c_adapter vino_i2c_adapter =
-{
- .name = "VINO I2C bus",
- .id = I2C_HW_SGI_VINO,
- .algo_data = &i2c_sgi_vino_data,
- .client_register = &i2c_vino_client_reg,
- .client_unregister = &i2c_vino_client_unreg,
};
-static int vino_i2c_add_bus(void)
-{
- return i2c_sgi_add_bus(&vino_i2c_adapter);
-}
-
-static int vino_i2c_del_bus(void)
-{
- return i2c_del_adapter(&vino_i2c_adapter);
-}
-
-static int i2c_camera_command(unsigned int cmd, void *arg)
-{
- return vino_drvdata->camera.driver->
- driver->command(vino_drvdata->camera.driver,
- cmd, arg);
-}
-
-static int i2c_decoder_command(unsigned int cmd, void *arg)
-{
- return vino_drvdata->decoder.driver->
- driver->command(vino_drvdata->decoder.driver,
- cmd, arg);
-}
-
/* VINO framebuffer/DMA descriptor management */
static void vino_free_buffer_with_count(struct vino_framebuffer *fb,
@@ -1741,6 +1604,184 @@ static inline void vino_set_default_framerate(struct
vino_set_framerate(vcs, vino_data_norms[vcs->data_norm].fps_max);
}
+/* VINO I2C bus functions */
+
+struct i2c_algo_sgi_data {
+ void *data; /* private data for lowlevel routines */
+ unsigned (*getctrl)(void *data);
+ void (*setctrl)(void *data, unsigned val);
+ unsigned (*rdata)(void *data);
+ void (*wdata)(void *data, unsigned val);
+
+ int xfer_timeout;
+ int ack_timeout;
+};
+
+static int wait_xfer_done(struct i2c_algo_sgi_data *adap)
+{
+ int i;
+
+ for (i = 0; i < adap->xfer_timeout; i++) {
+ if ((adap->getctrl(adap->data) & SGI_I2C_XFER_BUSY) == 0)
+ return 0;
+ udelay(1);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int wait_ack(struct i2c_algo_sgi_data *adap)
+{
+ int i;
+
+ if (wait_xfer_done(adap))
+ return -ETIMEDOUT;
+ for (i = 0; i < adap->ack_timeout; i++) {
+ if ((adap->getctrl(adap->data) & SGI_I2C_NACK) == 0)
+ return 0;
+ udelay(1);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int force_idle(struct i2c_algo_sgi_data *adap)
+{
+ int i;
+
+ adap->setctrl(adap->data, SGI_I2C_FORCE_IDLE);
+ for (i = 0; i < adap->xfer_timeout; i++) {
+ if ((adap->getctrl(adap->data) & SGI_I2C_NOT_IDLE) == 0)
+ goto out;
+ udelay(1);
+ }
+ return -ETIMEDOUT;
+out:
+ if (adap->getctrl(adap->data) & SGI_I2C_BUS_ERR)
+ return -EIO;
+ return 0;
+}
+
+static int do_address(struct i2c_algo_sgi_data *adap, unsigned int addr,
+ int rd)
+{
+ if (rd)
+ adap->setctrl(adap->data, SGI_I2C_NOT_IDLE);
+ /* Check if bus is idle, eventually force it to do so */
+ if (adap->getctrl(adap->data) & SGI_I2C_NOT_IDLE)
+ if (force_idle(adap))
+ return -EIO;
+ /* Write out the i2c chip address and specify operation */
+ adap->setctrl(adap->data,
+ SGI_I2C_HOLD_BUS | SGI_I2C_WRITE | SGI_I2C_NOT_IDLE);
+ if (rd)
+ addr |= 1;
+ adap->wdata(adap->data, addr);
+ if (wait_ack(adap))
+ return -EIO;
+ return 0;
+}
+
+static int i2c_read(struct i2c_algo_sgi_data *adap, unsigned char *buf,
+ unsigned int len)
+{
+ int i;
+
+ adap->setctrl(adap->data,
+ SGI_I2C_HOLD_BUS | SGI_I2C_READ | SGI_I2C_NOT_IDLE);
+ for (i = 0; i < len; i++) {
+ if (wait_xfer_done(adap))
+ return -EIO;
+ buf[i] = adap->rdata(adap->data);
+ }
+ adap->setctrl(adap->data, SGI_I2C_RELEASE_BUS | SGI_I2C_FORCE_IDLE);
+
+ return 0;
+
+}
+
+static int i2c_write(struct i2c_algo_sgi_data *adap, unsigned char *buf,
+ unsigned int len)
+{
+ int i;
+
+ /* We are already in write state */
+ for (i = 0; i < len; i++) {
+ adap->wdata(adap->data, buf[i]);
+ if (wait_ack(adap))
+ return -EIO;
+ }
+ return 0;
+}
+
+static int sgi_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
+ int num)
+{
+ struct i2c_algo_sgi_data *adap = i2c_adap->algo_data;
+ struct i2c_msg *p;
+ int i, err = 0;
+
+ for (i = 0; !err && i < num; i++) {
+ p = &msgs[i];
+ err = do_address(adap, p->addr, p->flags & I2C_M_RD);
+ if (err || !p->len)
+ continue;
+ if (p->flags & I2C_M_RD)
+ err = i2c_read(adap, p->buf, p->len);
+ else
+ err = i2c_write(adap, p->buf, p->len);
+ }
+
+ return (err < 0) ? err : i;
+}
+
+static u32 sgi_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm sgi_algo = {
+ .master_xfer = sgi_xfer,
+ .functionality = sgi_func,
+};
+
+static unsigned i2c_vino_getctrl(void *data)
+{
+ return vino->i2c_control;
+}
+
+static void i2c_vino_setctrl(void *data, unsigned val)
+{
+ vino->i2c_control = val;
+}
+
+static unsigned i2c_vino_rdata(void *data)
+{
+ return vino->i2c_data;
+}
+
+static void i2c_vino_wdata(void *data, unsigned val)
+{
+ vino->i2c_data = val;
+}
+
+static struct i2c_algo_sgi_data i2c_sgi_vino_data = {
+ .getctrl = &i2c_vino_getctrl,
+ .setctrl = &i2c_vino_setctrl,
+ .rdata = &i2c_vino_rdata,
+ .wdata = &i2c_vino_wdata,
+ .xfer_timeout = 200,
+ .ack_timeout = 1000,
+};
+
+static struct i2c_adapter vino_i2c_adapter = {
+ .name = "VINO I2C bus",
+ .id = I2C_HW_SGI_VINO,
+ .algo = &sgi_algo,
+ .algo_data = &i2c_sgi_vino_data,
+ .owner = THIS_MODULE,
+};
+
/*
* Prepare VINO for DMA transfer...
* (execute only with vino_lock and input_lock locked)
@@ -2494,86 +2535,15 @@ static int vino_get_saa7191_input(int input)
}
}
-static int vino_get_saa7191_norm(unsigned int data_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:
- return SAA7191_NORM_NTSC;
- case VINO_DATA_NORM_SECAM:
- return SAA7191_NORM_SECAM;
- default:
- printk(KERN_ERR "VINO: vino_get_saa7191_norm(): "
- "invalid norm!\n");
- return -1;
- }
-}
-
-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)
{
switch(vcs->input) {
case VINO_INPUT_COMPOSITE:
case VINO_INPUT_SVIDEO:
- return (vino_drvdata->decoder.owner == vcs->channel);
+ return vino_drvdata->decoder_owner == vcs->channel;
case VINO_INPUT_D1:
- return (vino_drvdata->camera.owner == vcs->channel);
+ return vino_drvdata->camera_owner == vcs->channel;
default:
return 0;
}
@@ -2589,23 +2559,22 @@ static int vino_acquire_input(struct vino_channel_settings *vcs)
spin_lock_irqsave(&vino_drvdata->input_lock, flags);
/* First try D1 and then SAA7191 */
- if (vino_drvdata->camera.driver
- && (vino_drvdata->camera.owner == VINO_NO_CHANNEL)) {
- i2c_use_client(vino_drvdata->camera.driver);
- vino_drvdata->camera.owner = vcs->channel;
+ if (vino_drvdata->camera
+ && (vino_drvdata->camera_owner == VINO_NO_CHANNEL)) {
+ vino_drvdata->camera_owner = vcs->channel;
vcs->input = VINO_INPUT_D1;
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;
+ } else if (vino_drvdata->decoder
+ && (vino_drvdata->decoder_owner == VINO_NO_CHANNEL)) {
+ int input;
+ int data_norm;
+ v4l2_std_id norm;
+ struct v4l2_routing route = { 0, 0 };
- i2c_use_client(vino_drvdata->decoder.driver);
input = VINO_INPUT_COMPOSITE;
- saa7191_input = vino_get_saa7191_input(input);
- ret = i2c_decoder_command(DECODER_SET_INPUT,
- &saa7191_input);
+ route.input = vino_get_saa7191_input(input);
+ ret = decoder_call(video, s_routing, &route);
if (ret) {
ret = -EINVAL;
goto out;
@@ -2616,12 +2585,15 @@ static int vino_acquire_input(struct vino_channel_settings *vcs)
/* 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);
+ ret = decoder_call(video, querystd, &norm);
+ if (!ret) {
+ for (data_norm = 0; data_norm < 3; data_norm++) {
+ if (vino_data_norms[data_norm].std & norm)
+ break;
+ }
+ if (data_norm == 3)
+ data_norm = VINO_DATA_NORM_PAL;
+ ret = decoder_call(tuner, s_std, norm);
}
spin_lock_irqsave(&vino_drvdata->input_lock, flags);
@@ -2631,7 +2603,7 @@ static int vino_acquire_input(struct vino_channel_settings *vcs)
goto out;
}
- vino_drvdata->decoder.owner = vcs->channel;
+ vino_drvdata->decoder_owner = vcs->channel;
vcs->input = input;
vcs->data_norm = data_norm;
@@ -2676,25 +2648,24 @@ static int vino_set_input(struct vino_channel_settings *vcs, int input)
switch (input) {
case VINO_INPUT_COMPOSITE:
case VINO_INPUT_SVIDEO:
- if (!vino_drvdata->decoder.driver) {
+ if (!vino_drvdata->decoder) {
ret = -EINVAL;
goto out;
}
- if (vino_drvdata->decoder.owner == VINO_NO_CHANNEL) {
- i2c_use_client(vino_drvdata->decoder.driver);
- vino_drvdata->decoder.owner = vcs->channel;
+ if (vino_drvdata->decoder_owner == VINO_NO_CHANNEL) {
+ vino_drvdata->decoder_owner = vcs->channel;
}
- if (vino_drvdata->decoder.owner == vcs->channel) {
+ if (vino_drvdata->decoder_owner == vcs->channel) {
int data_norm;
- int saa7191_input;
+ v4l2_std_id norm;
+ struct v4l2_routing route = { 0, 0 };
- saa7191_input = vino_get_saa7191_input(input);
- ret = i2c_decoder_command(DECODER_SET_INPUT,
- &saa7191_input);
+ route.input = vino_get_saa7191_input(input);
+ ret = decoder_call(video, s_routing, &route);
if (ret) {
- vino_drvdata->decoder.owner = VINO_NO_CHANNEL;
+ vino_drvdata->decoder_owner = VINO_NO_CHANNEL;
ret = -EINVAL;
goto out;
}
@@ -2704,18 +2675,21 @@ static int vino_set_input(struct vino_channel_settings *vcs, int input)
/* 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);
+ ret = decoder_call(video, querystd, &norm);
+ if (!ret) {
+ for (data_norm = 0; data_norm < 3; data_norm++) {
+ if (vino_data_norms[data_norm].std & norm)
+ break;
+ }
+ if (data_norm == 3)
+ data_norm = VINO_DATA_NORM_PAL;
+ ret = decoder_call(tuner, s_std, norm);
}
spin_lock_irqsave(&vino_drvdata->input_lock, flags);
if (ret) {
- vino_drvdata->decoder.owner = VINO_NO_CHANNEL;
+ vino_drvdata->decoder_owner = VINO_NO_CHANNEL;
ret = -EINVAL;
goto out;
}
@@ -2732,37 +2706,31 @@ static int vino_set_input(struct vino_channel_settings *vcs, int input)
vcs->data_norm = vcs2->data_norm;
}
- if (vino_drvdata->camera.owner == vcs->channel) {
+ if (vino_drvdata->camera_owner == vcs->channel) {
/* Transfer the ownership or release the input */
if (vcs2->input == VINO_INPUT_D1) {
- vino_drvdata->camera.owner = vcs2->channel;
+ vino_drvdata->camera_owner = vcs2->channel;
} else {
- i2c_release_client(vino_drvdata->
- camera.driver);
- vino_drvdata->camera.owner = VINO_NO_CHANNEL;
+ vino_drvdata->camera_owner = VINO_NO_CHANNEL;
}
}
break;
case VINO_INPUT_D1:
- if (!vino_drvdata->camera.driver) {
+ if (!vino_drvdata->camera) {
ret = -EINVAL;
goto out;
}
- if (vino_drvdata->camera.owner == VINO_NO_CHANNEL) {
- i2c_use_client(vino_drvdata->camera.driver);
- vino_drvdata->camera.owner = vcs->channel;
- }
+ if (vino_drvdata->camera_owner == VINO_NO_CHANNEL)
+ vino_drvdata->camera_owner = vcs->channel;
- if (vino_drvdata->decoder.owner == vcs->channel) {
+ if (vino_drvdata->decoder_owner == vcs->channel) {
/* Transfer the ownership or release the input */
if ((vcs2->input == VINO_INPUT_COMPOSITE) ||
(vcs2->input == VINO_INPUT_SVIDEO)) {
- vino_drvdata->decoder.owner = vcs2->channel;
+ vino_drvdata->decoder_owner = vcs2->channel;
} else {
- i2c_release_client(vino_drvdata->
- decoder.driver);
- vino_drvdata->decoder.owner = VINO_NO_CHANNEL;
+ vino_drvdata->decoder_owner = VINO_NO_CHANNEL;
}
}
@@ -2799,20 +2767,18 @@ static void vino_release_input(struct vino_channel_settings *vcs)
/* Release ownership of the channel
* and if the other channel takes input from
* the same source, transfer the ownership */
- if (vino_drvdata->camera.owner == vcs->channel) {
+ if (vino_drvdata->camera_owner == vcs->channel) {
if (vcs2->input == VINO_INPUT_D1) {
- vino_drvdata->camera.owner = vcs2->channel;
+ vino_drvdata->camera_owner = vcs2->channel;
} else {
- i2c_release_client(vino_drvdata->camera.driver);
- vino_drvdata->camera.owner = VINO_NO_CHANNEL;
+ vino_drvdata->camera_owner = VINO_NO_CHANNEL;
}
- } else if (vino_drvdata->decoder.owner == vcs->channel) {
+ } else if (vino_drvdata->decoder_owner == vcs->channel) {
if ((vcs2->input == VINO_INPUT_COMPOSITE) ||
(vcs2->input == VINO_INPUT_SVIDEO)) {
- vino_drvdata->decoder.owner = vcs2->channel;
+ vino_drvdata->decoder_owner = vcs2->channel;
} else {
- i2c_release_client(vino_drvdata->decoder.driver);
- vino_drvdata->decoder.owner = VINO_NO_CHANNEL;
+ vino_drvdata->decoder_owner = VINO_NO_CHANNEL;
}
}
vcs->input = VINO_INPUT_NONE;
@@ -2833,18 +2799,16 @@ static int vino_set_data_norm(struct vino_channel_settings *vcs,
switch (vcs->input) {
case VINO_INPUT_D1:
/* only one "norm" supported */
- if ((data_norm != VINO_DATA_NORM_D1)
- && (data_norm != VINO_DATA_NORM_AUTO)
- && (data_norm != VINO_DATA_NORM_AUTO_EXT))
+ if (data_norm != VINO_DATA_NORM_D1)
return -EINVAL;
break;
case VINO_INPUT_COMPOSITE:
case VINO_INPUT_SVIDEO: {
+ v4l2_std_id norm;
+
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))
+ && (data_norm != VINO_DATA_NORM_SECAM))
return -EINVAL;
spin_unlock_irqrestore(&vino_drvdata->input_lock, *flags);
@@ -2852,7 +2816,8 @@ static int vino_set_data_norm(struct vino_channel_settings *vcs,
/* Don't hold spinlocks while setting norm
* as it may take a while... */
- err = vino_saa7191_set_norm(&data_norm);
+ norm = vino_data_norms[data_norm].std;
+ err = decoder_call(tuner, s_std, norm);
spin_lock_irqsave(&vino_drvdata->input_lock, *flags);
@@ -2888,41 +2853,13 @@ static int vino_find_data_format(__u32 pixelformat)
return VINO_DATA_FMT_NONE;
}
-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_irqsave(&vino_drvdata->input_lock, flags);
- switch(vcs->input) {
- case VINO_INPUT_COMPOSITE:
- case VINO_INPUT_SVIDEO:
- if (index == 0) {
- data_norm = VINO_DATA_NORM_PAL;
- } else if (index == 1) {
- data_norm = VINO_DATA_NORM_NTSC;
- } else if (index == 2) {
- data_norm = VINO_DATA_NORM_SECAM;
- }
- break;
- case VINO_INPUT_D1:
- if (index == 0) {
- data_norm = VINO_DATA_NORM_D1;
- }
- break;
- }
- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
-
- return data_norm;
-}
-
-static int vino_enum_input(struct vino_channel_settings *vcs, __u32 index)
+static int vino_int_enum_input(struct vino_channel_settings *vcs, __u32 index)
{
int input = VINO_INPUT_NONE;
unsigned long flags;
spin_lock_irqsave(&vino_drvdata->input_lock, flags);
- if (vino_drvdata->decoder.driver && vino_drvdata->camera.driver) {
+ if (vino_drvdata->decoder && vino_drvdata->camera) {
switch (index) {
case 0:
input = VINO_INPUT_COMPOSITE;
@@ -2934,7 +2871,7 @@ static int vino_enum_input(struct vino_channel_settings *vcs, __u32 index)
input = VINO_INPUT_D1;
break;
}
- } else if (vino_drvdata->decoder.driver) {
+ } else if (vino_drvdata->decoder) {
switch (index) {
case 0:
input = VINO_INPUT_COMPOSITE;
@@ -2943,7 +2880,7 @@ static int vino_enum_input(struct vino_channel_settings *vcs, __u32 index)
input = VINO_INPUT_SVIDEO;
break;
}
- } else if (vino_drvdata->camera.driver) {
+ } else if (vino_drvdata->camera) {
switch (index) {
case 0:
input = VINO_INPUT_D1;
@@ -2961,7 +2898,7 @@ static __u32 vino_find_input_index(struct vino_channel_settings *vcs)
__u32 index = 0;
// FIXME: detect when no inputs available
- if (vino_drvdata->decoder.driver && vino_drvdata->camera.driver) {
+ if (vino_drvdata->decoder && vino_drvdata->camera) {
switch (vcs->input) {
case VINO_INPUT_COMPOSITE:
index = 0;
@@ -2973,7 +2910,7 @@ static __u32 vino_find_input_index(struct vino_channel_settings *vcs)
index = 2;
break;
}
- } else if (vino_drvdata->decoder.driver) {
+ } else if (vino_drvdata->decoder) {
switch (vcs->input) {
case VINO_INPUT_COMPOSITE:
index = 0;
@@ -2982,7 +2919,7 @@ static __u32 vino_find_input_index(struct vino_channel_settings *vcs)
index = 1;
break;
}
- } else if (vino_drvdata->camera.driver) {
+ } else if (vino_drvdata->camera) {
switch (vcs->input) {
case VINO_INPUT_D1:
index = 0;
@@ -2995,7 +2932,8 @@ static __u32 vino_find_input_index(struct vino_channel_settings *vcs)
/* V4L2 ioctls */
-static void vino_v4l2_querycap(struct v4l2_capability *cap)
+static int vino_querycap(struct file *file, void *__fh,
+ struct v4l2_capability *cap)
{
memset(cap, 0, sizeof(struct v4l2_capability));
@@ -3007,16 +2945,18 @@ static void vino_v4l2_querycap(struct v4l2_capability *cap)
V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_STREAMING;
// V4L2_CAP_OVERLAY, V4L2_CAP_READWRITE
+ return 0;
}
-static int vino_v4l2_enuminput(struct vino_channel_settings *vcs,
+static int vino_enum_input(struct file *file, void *__fh,
struct v4l2_input *i)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
__u32 index = i->index;
int input;
dprintk("requested index = %d\n", index);
- input = vino_enum_input(vcs, index);
+ input = vino_int_enum_input(vcs, index);
if (input == VINO_INPUT_NONE)
return -EINVAL;
@@ -3027,20 +2967,15 @@ static int vino_v4l2_enuminput(struct vino_channel_settings *vcs,
i->std = vino_inputs[input].std;
strcpy(i->name, vino_inputs[input].name);
- if ((input == VINO_INPUT_COMPOSITE)
- || (input == VINO_INPUT_SVIDEO)) {
- struct saa7191_status status;
- i2c_decoder_command(DECODER_SAA7191_GET_STATUS, &status);
- i->status |= status.signal ? 0 : V4L2_IN_ST_NO_SIGNAL;
- i->status |= status.color ? 0 : V4L2_IN_ST_NO_COLOR;
- }
-
+ if (input == VINO_INPUT_COMPOSITE || input == VINO_INPUT_SVIDEO)
+ decoder_call(video, g_input_status, &i->status);
return 0;
}
-static int vino_v4l2_g_input(struct vino_channel_settings *vcs,
+static int vino_g_input(struct file *file, void *__fh,
unsigned int *i)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
__u32 index;
int input;
unsigned long flags;
@@ -3061,52 +2996,24 @@ static int vino_v4l2_g_input(struct vino_channel_settings *vcs,
return 0;
}
-static int vino_v4l2_s_input(struct vino_channel_settings *vcs,
- unsigned int *i)
+static int vino_s_input(struct file *file, void *__fh,
+ unsigned int i)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
int input;
- dprintk("requested input = %d\n", *i);
+ dprintk("requested input = %d\n", i);
- input = vino_enum_input(vcs, *i);
+ input = vino_int_enum_input(vcs, i);
if (input == VINO_INPUT_NONE)
return -EINVAL;
return vino_set_input(vcs, input);
}
-static int vino_v4l2_enumstd(struct vino_channel_settings *vcs,
- struct v4l2_standard *s)
-{
- int index = s->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)
- return -EINVAL;
-
- dprintk("standard name = %s\n",
- vino_data_norms[data_norm].description);
-
- memset(s, 0, sizeof(struct v4l2_standard));
- s->index = index;
-
- s->id = vino_data_norms[data_norm].std;
- s->frameperiod.numerator = 1;
- s->frameperiod.denominator =
- vino_data_norms[data_norm].fps_max;
- s->framelines =
- vino_data_norms[data_norm].framelines;
- strcpy(s->name,
- vino_data_norms[data_norm].description);
-
- return 0;
-}
-
-static int vino_v4l2_querystd(struct vino_channel_settings *vcs,
+static int vino_querystd(struct file *file, void *__fh,
v4l2_std_id *std)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
unsigned long flags;
int err = 0;
@@ -3118,19 +3025,7 @@ static int vino_v4l2_querystd(struct vino_channel_settings *vcs,
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;
- }
+ decoder_call(video, querystd, std);
break;
}
default:
@@ -3142,9 +3037,10 @@ static int vino_v4l2_querystd(struct vino_channel_settings *vcs,
return err;
}
-static int vino_v4l2_g_std(struct vino_channel_settings *vcs,
+static int vino_g_std(struct file *file, void *__fh,
v4l2_std_id *std)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
unsigned long flags;
spin_lock_irqsave(&vino_drvdata->input_lock, flags);
@@ -3157,9 +3053,10 @@ static int vino_v4l2_g_std(struct vino_channel_settings *vcs,
return 0;
}
-static int vino_v4l2_s_std(struct vino_channel_settings *vcs,
+static int vino_s_std(struct file *file, void *__fh,
v4l2_std_id *std)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
unsigned long flags;
int ret = 0;
@@ -3180,12 +3077,7 @@ static int vino_v4l2_s_std(struct vino_channel_settings *vcs,
if (vcs->input == VINO_INPUT_D1)
goto out;
- 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) {
+ if ((*std) & V4L2_STD_PAL) {
ret = vino_set_data_norm(vcs, VINO_DATA_NORM_PAL,
&flags);
} else if ((*std) & V4L2_STD_NTSC) {
@@ -3211,185 +3103,152 @@ out:
return ret;
}
-static int vino_v4l2_enum_fmt(struct vino_channel_settings *vcs,
+static int vino_enum_fmt_vid_cap(struct file *file, void *__fh,
struct v4l2_fmtdesc *fd)
{
enum v4l2_buf_type type = fd->type;
int index = fd->index;
+
dprintk("format index = %d\n", index);
- switch (fd->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- if ((fd->index < 0) ||
- (fd->index >= VINO_DATA_FMT_COUNT))
- return -EINVAL;
- dprintk("format name = %s\n",
- vino_data_formats[index].description);
-
- memset(fd, 0, sizeof(struct v4l2_fmtdesc));
- fd->index = index;
- fd->type = type;
- fd->pixelformat = vino_data_formats[index].pixelformat;
- strcpy(fd->description, vino_data_formats[index].description);
- break;
- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
- default:
+ if ((fd->index < 0) ||
+ (fd->index >= VINO_DATA_FMT_COUNT))
return -EINVAL;
- }
-
+ dprintk("format name = %s\n",
+ vino_data_formats[index].description);
+
+ memset(fd, 0, sizeof(struct v4l2_fmtdesc));
+ fd->index = index;
+ fd->type = type;
+ fd->pixelformat = vino_data_formats[index].pixelformat;
+ strcpy(fd->description, vino_data_formats[index].description);
return 0;
}
-static int vino_v4l2_try_fmt(struct vino_channel_settings *vcs,
+static int vino_try_fmt_vid_cap(struct file *file, void *__fh,
struct v4l2_format *f)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
struct vino_channel_settings tempvcs;
unsigned long flags;
+ struct v4l2_pix_format *pf = &f->fmt.pix;
- switch (f->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
- struct v4l2_pix_format *pf = &f->fmt.pix;
-
- dprintk("requested: w = %d, h = %d\n",
- pf->width, pf->height);
-
- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
- memcpy(&tempvcs, vcs, sizeof(struct vino_channel_settings));
- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+ dprintk("requested: w = %d, h = %d\n",
+ pf->width, pf->height);
- tempvcs.data_format = vino_find_data_format(pf->pixelformat);
- if (tempvcs.data_format == VINO_DATA_FMT_NONE) {
- tempvcs.data_format = VINO_DATA_FMT_GREY;
- pf->pixelformat =
- vino_data_formats[tempvcs.data_format].
- pixelformat;
- }
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+ memcpy(&tempvcs, vcs, sizeof(struct vino_channel_settings));
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
- /* data format must be set before clipping/scaling */
- vino_set_scaling(&tempvcs, pf->width, pf->height);
+ tempvcs.data_format = vino_find_data_format(pf->pixelformat);
+ if (tempvcs.data_format == VINO_DATA_FMT_NONE) {
+ tempvcs.data_format = VINO_DATA_FMT_GREY;
+ pf->pixelformat =
+ vino_data_formats[tempvcs.data_format].
+ pixelformat;
+ }
- dprintk("data format = %s\n",
- vino_data_formats[tempvcs.data_format].description);
+ /* data format must be set before clipping/scaling */
+ vino_set_scaling(&tempvcs, pf->width, pf->height);
- pf->width = (tempvcs.clipping.right - tempvcs.clipping.left) /
- tempvcs.decimation;
- pf->height = (tempvcs.clipping.bottom - tempvcs.clipping.top) /
- tempvcs.decimation;
+ dprintk("data format = %s\n",
+ vino_data_formats[tempvcs.data_format].description);
- pf->field = V4L2_FIELD_INTERLACED;
- pf->bytesperline = tempvcs.line_size;
- pf->sizeimage = tempvcs.line_size *
- (tempvcs.clipping.bottom - tempvcs.clipping.top) /
- tempvcs.decimation;
- pf->colorspace =
- vino_data_formats[tempvcs.data_format].colorspace;
+ pf->width = (tempvcs.clipping.right - tempvcs.clipping.left) /
+ tempvcs.decimation;
+ pf->height = (tempvcs.clipping.bottom - tempvcs.clipping.top) /
+ tempvcs.decimation;
- pf->priv = 0;
- break;
- }
- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
- default:
- return -EINVAL;
- }
+ pf->field = V4L2_FIELD_INTERLACED;
+ pf->bytesperline = tempvcs.line_size;
+ pf->sizeimage = tempvcs.line_size *
+ (tempvcs.clipping.bottom - tempvcs.clipping.top) /
+ tempvcs.decimation;
+ pf->colorspace =
+ vino_data_formats[tempvcs.data_format].colorspace;
+ pf->priv = 0;
return 0;
}
-static int vino_v4l2_g_fmt(struct vino_channel_settings *vcs,
+static int vino_g_fmt_vid_cap(struct file *file, void *__fh,
struct v4l2_format *f)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
unsigned long flags;
+ struct v4l2_pix_format *pf = &f->fmt.pix;
- switch (f->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
- struct v4l2_pix_format *pf = &f->fmt.pix;
-
- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
-
- pf->width = (vcs->clipping.right - vcs->clipping.left) /
- vcs->decimation;
- pf->height = (vcs->clipping.bottom - vcs->clipping.top) /
- vcs->decimation;
- pf->pixelformat =
- vino_data_formats[vcs->data_format].pixelformat;
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
- pf->field = V4L2_FIELD_INTERLACED;
- pf->bytesperline = vcs->line_size;
- pf->sizeimage = vcs->line_size *
- (vcs->clipping.bottom - vcs->clipping.top) /
- vcs->decimation;
- pf->colorspace =
- vino_data_formats[vcs->data_format].colorspace;
+ pf->width = (vcs->clipping.right - vcs->clipping.left) /
+ vcs->decimation;
+ pf->height = (vcs->clipping.bottom - vcs->clipping.top) /
+ vcs->decimation;
+ pf->pixelformat =
+ vino_data_formats[vcs->data_format].pixelformat;
- pf->priv = 0;
+ pf->field = V4L2_FIELD_INTERLACED;
+ pf->bytesperline = vcs->line_size;
+ pf->sizeimage = vcs->line_size *
+ (vcs->clipping.bottom - vcs->clipping.top) /
+ vcs->decimation;
+ pf->colorspace =
+ vino_data_formats[vcs->data_format].colorspace;
- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
- break;
- }
- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
- default:
- return -EINVAL;
- }
+ pf->priv = 0;
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
return 0;
}
-static int vino_v4l2_s_fmt(struct vino_channel_settings *vcs,
+static int vino_s_fmt_vid_cap(struct file *file, void *__fh,
struct v4l2_format *f)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
int data_format;
unsigned long flags;
+ struct v4l2_pix_format *pf = &f->fmt.pix;
- switch (f->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
- struct v4l2_pix_format *pf = &f->fmt.pix;
-
- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
- data_format = vino_find_data_format(pf->pixelformat);
+ data_format = vino_find_data_format(pf->pixelformat);
- if (data_format == VINO_DATA_FMT_NONE) {
- vcs->data_format = VINO_DATA_FMT_GREY;
- pf->pixelformat =
- vino_data_formats[vcs->data_format].
- pixelformat;
- } else {
- vcs->data_format = data_format;
- }
-
- /* data format must be set before clipping/scaling */
- vino_set_scaling(vcs, pf->width, pf->height);
+ if (data_format == VINO_DATA_FMT_NONE) {
+ vcs->data_format = VINO_DATA_FMT_GREY;
+ pf->pixelformat =
+ vino_data_formats[vcs->data_format].
+ pixelformat;
+ } else {
+ vcs->data_format = data_format;
+ }
- dprintk("data format = %s\n",
- vino_data_formats[vcs->data_format].description);
+ /* data format must be set before clipping/scaling */
+ vino_set_scaling(vcs, pf->width, pf->height);
- pf->width = vcs->clipping.right - vcs->clipping.left;
- pf->height = vcs->clipping.bottom - vcs->clipping.top;
+ dprintk("data format = %s\n",
+ vino_data_formats[vcs->data_format].description);
- pf->field = V4L2_FIELD_INTERLACED;
- pf->bytesperline = vcs->line_size;
- pf->sizeimage = vcs->line_size *
- (vcs->clipping.bottom - vcs->clipping.top) /
- vcs->decimation;
- pf->colorspace =
- vino_data_formats[vcs->data_format].colorspace;
+ pf->width = vcs->clipping.right - vcs->clipping.left;
+ pf->height = vcs->clipping.bottom - vcs->clipping.top;
- pf->priv = 0;
+ pf->field = V4L2_FIELD_INTERLACED;
+ pf->bytesperline = vcs->line_size;
+ pf->sizeimage = vcs->line_size *
+ (vcs->clipping.bottom - vcs->clipping.top) /
+ vcs->decimation;
+ pf->colorspace =
+ vino_data_formats[vcs->data_format].colorspace;
- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
- break;
- }
- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
- default:
- return -EINVAL;
- }
+ pf->priv = 0;
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
return 0;
}
-static int vino_v4l2_cropcap(struct vino_channel_settings *vcs,
+static int vino_cropcap(struct file *file, void *__fh,
struct v4l2_cropcap *ccap)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
const struct vino_data_norm *norm;
unsigned long flags;
@@ -3419,9 +3278,10 @@ static int vino_v4l2_cropcap(struct vino_channel_settings *vcs,
return 0;
}
-static int vino_v4l2_g_crop(struct vino_channel_settings *vcs,
+static int vino_g_crop(struct file *file, void *__fh,
struct v4l2_crop *c)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
unsigned long flags;
switch (c->type) {
@@ -3443,9 +3303,10 @@ static int vino_v4l2_g_crop(struct vino_channel_settings *vcs,
return 0;
}
-static int vino_v4l2_s_crop(struct vino_channel_settings *vcs,
+static int vino_s_crop(struct file *file, void *__fh,
struct v4l2_crop *c)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
unsigned long flags;
switch (c->type) {
@@ -3465,9 +3326,10 @@ static int vino_v4l2_s_crop(struct vino_channel_settings *vcs,
return 0;
}
-static int vino_v4l2_g_parm(struct vino_channel_settings *vcs,
+static int vino_g_parm(struct file *file, void *__fh,
struct v4l2_streamparm *sp)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
unsigned long flags;
switch (sp->type) {
@@ -3495,9 +3357,10 @@ static int vino_v4l2_g_parm(struct vino_channel_settings *vcs,
return 0;
}
-static int vino_v4l2_s_parm(struct vino_channel_settings *vcs,
+static int vino_s_parm(struct file *file, void *__fh,
struct v4l2_streamparm *sp)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
unsigned long flags;
switch (sp->type) {
@@ -3528,9 +3391,10 @@ static int vino_v4l2_s_parm(struct vino_channel_settings *vcs,
return 0;
}
-static int vino_v4l2_reqbufs(struct vino_channel_settings *vcs,
+static int vino_reqbufs(struct file *file, void *__fh,
struct v4l2_requestbuffers *rb)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
if (vcs->reading)
return -EBUSY;
@@ -3610,9 +3474,10 @@ static void vino_v4l2_get_buffer_status(struct vino_channel_settings *vcs,
fb->id, fb->size, fb->data_size, fb->offset);
}
-static int vino_v4l2_querybuf(struct vino_channel_settings *vcs,
+static int vino_querybuf(struct file *file, void *__fh,
struct v4l2_buffer *b)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
if (vcs->reading)
return -EBUSY;
@@ -3645,9 +3510,10 @@ static int vino_v4l2_querybuf(struct vino_channel_settings *vcs,
return 0;
}
-static int vino_v4l2_qbuf(struct vino_channel_settings *vcs,
+static int vino_qbuf(struct file *file, void *__fh,
struct v4l2_buffer *b)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
if (vcs->reading)
return -EBUSY;
@@ -3683,10 +3549,11 @@ static int vino_v4l2_qbuf(struct vino_channel_settings *vcs,
return 0;
}
-static int vino_v4l2_dqbuf(struct vino_channel_settings *vcs,
- struct v4l2_buffer *b,
- unsigned int nonblocking)
+static int vino_dqbuf(struct file *file, void *__fh,
+ struct v4l2_buffer *b)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
+ unsigned int nonblocking = file->f_flags & O_NONBLOCK;
if (vcs->reading)
return -EBUSY;
@@ -3758,8 +3625,10 @@ static int vino_v4l2_dqbuf(struct vino_channel_settings *vcs,
return 0;
}
-static int vino_v4l2_streamon(struct vino_channel_settings *vcs)
+static int vino_streamon(struct file *file, void *__fh,
+ enum v4l2_buf_type i)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
unsigned int incoming;
int ret;
if (vcs->reading)
@@ -3796,8 +3665,10 @@ static int vino_v4l2_streamon(struct vino_channel_settings *vcs)
return 0;
}
-static int vino_v4l2_streamoff(struct vino_channel_settings *vcs)
+static int vino_streamoff(struct file *file, void *__fh,
+ enum v4l2_buf_type i)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
if (vcs->reading)
return -EBUSY;
@@ -3810,9 +3681,10 @@ static int vino_v4l2_streamoff(struct vino_channel_settings *vcs)
return 0;
}
-static int vino_v4l2_queryctrl(struct vino_channel_settings *vcs,
+static int vino_queryctrl(struct file *file, void *__fh,
struct v4l2_queryctrl *queryctrl)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
unsigned long flags;
int i;
int err = 0;
@@ -3859,9 +3731,10 @@ static int vino_v4l2_queryctrl(struct vino_channel_settings *vcs,
return err;
}
-static int vino_v4l2_g_ctrl(struct vino_channel_settings *vcs,
+static int vino_g_ctrl(struct file *file, void *__fh,
struct v4l2_control *control)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
unsigned long flags;
int i;
int err = 0;
@@ -3870,56 +3743,38 @@ static int vino_v4l2_g_ctrl(struct vino_channel_settings *vcs,
switch (vcs->input) {
case VINO_INPUT_D1: {
- struct indycam_control indycam_ctrl;
-
+ err = -EINVAL;
for (i = 0; i < VINO_INDYCAM_V4L2_CONTROL_COUNT; i++) {
- if (vino_indycam_v4l2_controls[i].id ==
- control->id) {
- goto found1;
+ if (vino_indycam_v4l2_controls[i].id == control->id) {
+ err = 0;
+ break;
}
}
- 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;
+ if (err)
goto out;
- }
- control->value = indycam_ctrl.value;
+ err = camera_call(core, g_ctrl, control);
+ if (err)
+ err = -EINVAL;
break;
}
case VINO_INPUT_COMPOSITE:
case VINO_INPUT_SVIDEO: {
- struct saa7191_control saa7191_ctrl;
-
+ err = -EINVAL;
for (i = 0; i < VINO_SAA7191_V4L2_CONTROL_COUNT; i++) {
- if (vino_saa7191_v4l2_controls[i].id ==
- control->id) {
- goto found2;
+ if (vino_saa7191_v4l2_controls[i].id == control->id) {
+ err = 0;
+ break;
}
}
- 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;
+ if (err)
goto out;
- }
- control->value = saa7191_ctrl.value;
+ err = decoder_call(core, g_ctrl, control);
+ if (err)
+ err = -EINVAL;
break;
}
default:
@@ -3932,9 +3787,10 @@ out:
return err;
}
-static int vino_v4l2_s_ctrl(struct vino_channel_settings *vcs,
+static int vino_s_ctrl(struct file *file, void *__fh,
struct v4l2_control *control)
{
+ struct vino_channel_settings *vcs = video_drvdata(file);
unsigned long flags;
int i;
int err = 0;
@@ -3948,65 +3804,43 @@ static int vino_v4l2_s_ctrl(struct vino_channel_settings *vcs,
switch (vcs->input) {
case VINO_INPUT_D1: {
- struct indycam_control indycam_ctrl;
-
+ err = -EINVAL;
for (i = 0; i < VINO_INDYCAM_V4L2_CONTROL_COUNT; i++) {
- if (vino_indycam_v4l2_controls[i].id ==
- control->id) {
- if ((control->value >=
- vino_indycam_v4l2_controls[i].minimum)
- && (control->value <=
- vino_indycam_v4l2_controls[i].
- maximum)) {
- goto found1;
- } else {
- err = -ERANGE;
- goto out;
- }
+ if (vino_indycam_v4l2_controls[i].id == control->id) {
+ err = 0;
+ break;
}
}
-
- err = -EINVAL;
- goto out;
-
-found1:
- indycam_ctrl.type = vino_indycam_v4l2_controls[i].reserved[0];
- indycam_ctrl.value = control->value;
-
- err = i2c_camera_command(DECODER_INDYCAM_SET_CONTROL,
- &indycam_ctrl);
+ if (err)
+ goto out;
+ if (control->value < vino_indycam_v4l2_controls[i].minimum ||
+ control->value > vino_indycam_v4l2_controls[i].maximum) {
+ err = -ERANGE;
+ goto out;
+ }
+ err = camera_call(core, s_ctrl, control);
if (err)
err = -EINVAL;
break;
}
case VINO_INPUT_COMPOSITE:
case VINO_INPUT_SVIDEO: {
- struct saa7191_control saa7191_ctrl;
-
+ err = -EINVAL;
for (i = 0; i < VINO_SAA7191_V4L2_CONTROL_COUNT; i++) {
- if (vino_saa7191_v4l2_controls[i].id ==
- control->id) {
- if ((control->value >=
- vino_saa7191_v4l2_controls[i].minimum)
- && (control->value <=
- vino_saa7191_v4l2_controls[i].
- maximum)) {
- goto found2;
- } else {
- err = -ERANGE;
- goto out;
- }
+ if (vino_saa7191_v4l2_controls[i].id == control->id) {
+ err = 0;
+ break;
}
}
- err = -EINVAL;
- goto out;
-
-found2:
- saa7191_ctrl.type = vino_saa7191_v4l2_controls[i].reserved[0];
- saa7191_ctrl.value = control->value;
+ if (err)
+ goto out;
+ if (control->value < vino_saa7191_v4l2_controls[i].minimum ||
+ control->value > vino_saa7191_v4l2_controls[i].maximum) {
+ err = -ERANGE;
+ goto out;
+ }
- err = i2c_decoder_command(DECODER_SAA7191_SET_CONTROL,
- &saa7191_ctrl);
+ err = decoder_call(core, s_ctrl, control);
if (err)
err = -EINVAL;
break;
@@ -4237,116 +4071,9 @@ over:
ret = POLLIN | POLLRDNORM;
error:
-
return ret;
}
-static long vino_do_ioctl(struct file *file, unsigned int cmd, void *arg)
-{
- struct vino_channel_settings *vcs = video_drvdata(file);
-
-#ifdef VINO_DEBUG
- switch (_IOC_TYPE(cmd)) {
- case 'v':
- dprintk("ioctl(): V4L1 unsupported (0x%08x)\n", cmd);
- break;
- case 'V':
- dprintk("ioctl(): V4L2 %s (0x%08x)\n",
- v4l2_ioctl_names[_IOC_NR(cmd)], cmd);
- break;
- default:
- dprintk("ioctl(): unsupported command 0x%08x\n", cmd);
- }
-#endif
-
- switch (cmd) {
- /* V4L2 interface */
- case VIDIOC_QUERYCAP: {
- vino_v4l2_querycap(arg);
- break;
- }
- case VIDIOC_ENUMINPUT: {
- return vino_v4l2_enuminput(vcs, arg);
- }
- case VIDIOC_G_INPUT: {
- return vino_v4l2_g_input(vcs, arg);
- }
- case VIDIOC_S_INPUT: {
- return vino_v4l2_s_input(vcs, arg);
- }
- 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);
- }
- case VIDIOC_S_STD: {
- return vino_v4l2_s_std(vcs, arg);
- }
- case VIDIOC_ENUM_FMT: {
- return vino_v4l2_enum_fmt(vcs, arg);
- }
- case VIDIOC_TRY_FMT: {
- return vino_v4l2_try_fmt(vcs, arg);
- }
- case VIDIOC_G_FMT: {
- return vino_v4l2_g_fmt(vcs, arg);
- }
- case VIDIOC_S_FMT: {
- return vino_v4l2_s_fmt(vcs, arg);
- }
- case VIDIOC_CROPCAP: {
- return vino_v4l2_cropcap(vcs, arg);
- }
- case VIDIOC_G_CROP: {
- return vino_v4l2_g_crop(vcs, arg);
- }
- case VIDIOC_S_CROP: {
- return vino_v4l2_s_crop(vcs, arg);
- }
- case VIDIOC_G_PARM: {
- return vino_v4l2_g_parm(vcs, arg);
- }
- case VIDIOC_S_PARM: {
- return vino_v4l2_s_parm(vcs, arg);
- }
- case VIDIOC_REQBUFS: {
- return vino_v4l2_reqbufs(vcs, arg);
- }
- case VIDIOC_QUERYBUF: {
- return vino_v4l2_querybuf(vcs, arg);
- }
- case VIDIOC_QBUF: {
- return vino_v4l2_qbuf(vcs, arg);
- }
- case VIDIOC_DQBUF: {
- return vino_v4l2_dqbuf(vcs, arg, file->f_flags & O_NONBLOCK);
- }
- case VIDIOC_STREAMON: {
- return vino_v4l2_streamon(vcs);
- }
- case VIDIOC_STREAMOFF: {
- return vino_v4l2_streamoff(vcs);
- }
- case VIDIOC_QUERYCTRL: {
- return vino_v4l2_queryctrl(vcs, arg);
- }
- case VIDIOC_G_CTRL: {
- return vino_v4l2_g_ctrl(vcs, arg);
- }
- case VIDIOC_S_CTRL: {
- return vino_v4l2_s_ctrl(vcs, arg);
- }
- default:
- return -ENOIOCTLCMD;
- }
-
- return 0;
-}
-
static long vino_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
@@ -4356,7 +4083,7 @@ static long vino_ioctl(struct file *file,
if (mutex_lock_interruptible(&vcs->mutex))
return -EINTR;
- ret = video_usercopy(file, cmd, arg, vino_do_ioctl);
+ ret = video_ioctl2(file, cmd, arg);
mutex_unlock(&vcs->mutex);
@@ -4368,45 +4095,75 @@ static long vino_ioctl(struct file *file,
/* __initdata */
static int vino_init_stage;
+const struct v4l2_ioctl_ops vino_ioctl_ops = {
+ .vidioc_enum_fmt_vid_cap = vino_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = vino_g_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vino_s_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = vino_try_fmt_vid_cap,
+ .vidioc_querycap = vino_querycap,
+ .vidioc_enum_input = vino_enum_input,
+ .vidioc_g_input = vino_g_input,
+ .vidioc_s_input = vino_s_input,
+ .vidioc_g_std = vino_g_std,
+ .vidioc_s_std = vino_s_std,
+ .vidioc_querystd = vino_querystd,
+ .vidioc_cropcap = vino_cropcap,
+ .vidioc_s_crop = vino_s_crop,
+ .vidioc_g_crop = vino_g_crop,
+ .vidioc_s_parm = vino_s_parm,
+ .vidioc_g_parm = vino_g_parm,
+ .vidioc_reqbufs = vino_reqbufs,
+ .vidioc_querybuf = vino_querybuf,
+ .vidioc_qbuf = vino_qbuf,
+ .vidioc_dqbuf = vino_dqbuf,
+ .vidioc_streamon = vino_streamon,
+ .vidioc_streamoff = vino_streamoff,
+ .vidioc_queryctrl = vino_queryctrl,
+ .vidioc_g_ctrl = vino_g_ctrl,
+ .vidioc_s_ctrl = vino_s_ctrl,
+};
+
static const struct v4l2_file_operations vino_fops = {
.owner = THIS_MODULE,
.open = vino_open,
.release = vino_close,
- .ioctl = vino_ioctl,
+ .unlocked_ioctl = vino_ioctl,
.mmap = vino_mmap,
.poll = vino_poll,
};
-static struct video_device v4l_device_template = {
+static struct video_device vdev_template = {
.name = "NOT SET",
.fops = &vino_fops,
+ .ioctl_ops = &vino_ioctl_ops,
+ .tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM,
.minor = -1,
};
static void vino_module_cleanup(int stage)
{
switch(stage) {
+ case 11:
+ video_unregister_device(vino_drvdata->b.vdev);
+ vino_drvdata->b.vdev = NULL;
case 10:
- video_unregister_device(vino_drvdata->b.v4l_device);
- vino_drvdata->b.v4l_device = NULL;
+ video_unregister_device(vino_drvdata->a.vdev);
+ vino_drvdata->a.vdev = NULL;
case 9:
- video_unregister_device(vino_drvdata->a.v4l_device);
- vino_drvdata->a.v4l_device = NULL;
+ i2c_del_adapter(&vino_i2c_adapter);
case 8:
- vino_i2c_del_bus();
- case 7:
free_irq(SGI_VINO_IRQ, NULL);
+ case 7:
+ if (vino_drvdata->b.vdev) {
+ video_device_release(vino_drvdata->b.vdev);
+ vino_drvdata->b.vdev = NULL;
+ }
case 6:
- if (vino_drvdata->b.v4l_device) {
- video_device_release(vino_drvdata->b.v4l_device);
- vino_drvdata->b.v4l_device = NULL;
+ if (vino_drvdata->a.vdev) {
+ video_device_release(vino_drvdata->a.vdev);
+ vino_drvdata->a.vdev = NULL;
}
case 5:
- if (vino_drvdata->a.v4l_device) {
- video_device_release(vino_drvdata->a.v4l_device);
- vino_drvdata->a.v4l_device = NULL;
- }
- case 4:
/* all entries in dma_cpu dummy table have the same address */
dma_unmap_single(NULL,
vino_drvdata->dummy_desc_table.dma_cpu[0],
@@ -4416,8 +4173,10 @@ static void vino_module_cleanup(int stage)
(void *)vino_drvdata->
dummy_desc_table.dma_cpu,
vino_drvdata->dummy_desc_table.dma);
- case 3:
+ case 4:
free_page(vino_drvdata->dummy_page);
+ case 3:
+ v4l2_device_unregister(&vino_drvdata->v4l2_dev);
case 2:
kfree(vino_drvdata);
case 1:
@@ -4472,6 +4231,7 @@ static int vino_probe(void)
static int vino_init(void)
{
dma_addr_t dma_dummy_address;
+ int err;
int i;
vino_drvdata = kzalloc(sizeof(struct vino_settings), GFP_KERNEL);
@@ -4480,6 +4240,12 @@ static int vino_init(void)
return -ENOMEM;
}
vino_init_stage++;
+ strlcpy(vino_drvdata->v4l2_dev.name, "vino",
+ sizeof(vino_drvdata->v4l2_dev.name));
+ err = v4l2_device_register(NULL, &vino_drvdata->v4l2_dev);
+ if (err)
+ return err;
+ vino_init_stage++;
/* create a dummy dma descriptor */
vino_drvdata->dummy_page = get_zeroed_page(GFP_KERNEL | GFP_DMA);
@@ -4546,25 +4312,27 @@ static int vino_init_channel_settings(struct vino_channel_settings *vcs,
spin_lock_init(&vcs->fb_queue.queue_lock);
init_waitqueue_head(&vcs->fb_queue.frame_wait_queue);
- vcs->v4l_device = video_device_alloc();
- if (!vcs->v4l_device) {
+ vcs->vdev = video_device_alloc();
+ if (!vcs->vdev) {
vino_module_cleanup(vino_init_stage);
return -ENOMEM;
}
vino_init_stage++;
- memcpy(vcs->v4l_device, &v4l_device_template,
+ memcpy(vcs->vdev, &vdev_template,
sizeof(struct video_device));
- strcpy(vcs->v4l_device->name, name);
- vcs->v4l_device->release = video_device_release;
+ strcpy(vcs->vdev->name, name);
+ vcs->vdev->release = video_device_release;
+ vcs->vdev->v4l2_dev = &vino_drvdata->v4l2_dev;
- video_set_drvdata(vcs->v4l_device, vcs);
+ video_set_drvdata(vcs->vdev, vcs);
return 0;
}
static int __init vino_module_init(void)
{
+ unsigned short addr[] = { 0, I2C_CLIENT_END };
int ret;
printk(KERN_INFO "SGI VINO driver version %s\n",
@@ -4584,12 +4352,12 @@ static int __init vino_module_init(void)
spin_lock_init(&vino_drvdata->input_lock);
ret = vino_init_channel_settings(&vino_drvdata->a, VINO_CHANNEL_A,
- vino_v4l_device_name_a);
+ vino_vdev_name_a);
if (ret)
return ret;
ret = vino_init_channel_settings(&vino_drvdata->b, VINO_CHANNEL_B,
- vino_v4l_device_name_b);
+ vino_vdev_name_b);
if (ret)
return ret;
@@ -4605,15 +4373,16 @@ static int __init vino_module_init(void)
}
vino_init_stage++;
- ret = vino_i2c_add_bus();
+ ret = i2c_add_adapter(&vino_i2c_adapter);
if (ret) {
printk(KERN_ERR "VINO I2C bus registration failed\n");
vino_module_cleanup(vino_init_stage);
return ret;
}
+ i2c_set_adapdata(&vino_i2c_adapter, &vino_drvdata->v4l2_dev);
vino_init_stage++;
- ret = video_register_device(vino_drvdata->a.v4l_device,
+ ret = video_register_device(vino_drvdata->a.vdev,
VFL_TYPE_GRABBER, -1);
if (ret < 0) {
printk(KERN_ERR "VINO channel A Video4Linux-device "
@@ -4623,7 +4392,7 @@ static int __init vino_module_init(void)
}
vino_init_stage++;
- ret = video_register_device(vino_drvdata->b.v4l_device,
+ ret = video_register_device(vino_drvdata->b.vdev,
VFL_TYPE_GRABBER, -1);
if (ret < 0) {
printk(KERN_ERR "VINO channel B Video4Linux-device "
@@ -4633,10 +4402,12 @@ static int __init vino_module_init(void)
}
vino_init_stage++;
-#ifdef MODULE
- request_module("saa7191");
- request_module("indycam");
-#endif
+ addr[0] = 0x45;
+ vino_drvdata->decoder = v4l2_i2c_new_probed_subdev(&vino_i2c_adapter,
+ "saa7191", "saa7191", addr);
+ addr[0] = 0x2b;
+ vino_drvdata->camera = v4l2_i2c_new_probed_subdev(&vino_i2c_adapter,
+ "indycam", "indycam", addr);
dprintk("init complete!\n");
diff --git a/linux/drivers/media/video/w9968cf.c b/linux/drivers/media/video/w9968cf.c
index 0b5109ed9..dd519e48c 100644
--- a/linux/drivers/media/video/w9968cf.c
+++ b/linux/drivers/media/video/w9968cf.c
@@ -68,7 +68,6 @@ MODULE_VERSION(W9968CF_MODULE_VERSION);
MODULE_LICENSE(W9968CF_MODULE_LICENSE);
MODULE_SUPPORTED_DEVICE("Video");
-static int ovmod_load = W9968CF_OVMOD_LOAD;
static unsigned short simcams = W9968CF_SIMCAMS;
static short video_nr[]={[0 ... W9968CF_MAX_DEVICES-1] = -1}; /*-1=first free*/
static unsigned int packet_size[] = {[0 ... W9968CF_MAX_DEVICES-1] =
@@ -111,9 +110,6 @@ static int specific_debug = W9968CF_SPECIFIC_DEBUG;
static unsigned int param_nv[24]; /* number of values per parameter */
-#ifdef CONFIG_MODULES
-module_param(ovmod_load, bool, 0644);
-#endif
module_param(simcams, ushort, 0644);
module_param_array(video_nr, short, &param_nv[0], 0444);
module_param_array(packet_size, uint, &param_nv[1], 0444);
@@ -144,18 +140,6 @@ module_param(debug, ushort, 0644);
module_param(specific_debug, bool, 0644);
#endif
-#ifdef CONFIG_MODULES
-MODULE_PARM_DESC(ovmod_load,
- "\n<0|1> Automatic 'ovcamchip' module loading."
- "\n0 disabled, 1 enabled."
- "\nIf enabled,'insmod' searches for the required 'ovcamchip'"
- "\nmodule in the system, according to its configuration, and"
- "\nattempts to load that module automatically. This action is"
- "\nperformed once as soon as the 'w9968cf' module is loaded"
- "\ninto memory."
- "\nDefault value is "__MODULE_STRING(W9968CF_OVMOD_LOAD)"."
- "\n");
-#endif
MODULE_PARM_DESC(simcams,
"\n<n> Number of cameras allowed to stream simultaneously."
"\nn may vary from 0 to "
@@ -447,8 +431,6 @@ static int w9968cf_i2c_smbus_xfer(struct i2c_adapter*, u16 addr,
unsigned short flags, char read_write,
u8 command, int size, union i2c_smbus_data*);
static u32 w9968cf_i2c_func(struct i2c_adapter*);
-static int w9968cf_i2c_attach_inform(struct i2c_client*);
-static int w9968cf_i2c_detach_inform(struct i2c_client*);
/* Memory management */
static void* rvmalloc(unsigned long size);
@@ -1451,19 +1433,11 @@ w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
unsigned short flags, char read_write, u8 command,
int size, union i2c_smbus_data *data)
{
- struct w9968cf_device* cam = i2c_get_adapdata(adapter);
+ struct v4l2_device *v4l2_dev = i2c_get_adapdata(adapter);
+ struct w9968cf_device *cam = to_cam(v4l2_dev);
u8 i;
int err = 0;
- switch (addr) {
- case OV6xx0_SID:
- case OV7xx0_SID:
- break;
- default:
- DBG(4, "Rejected slave ID 0x%04X", addr)
- return -EINVAL;
- }
-
if (size == I2C_SMBUS_BYTE) {
/* Why addr <<= 1? See OVXXX0_SID defines in ovcamchip.h */
addr <<= 1;
@@ -1471,8 +1445,17 @@ w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
if (read_write == I2C_SMBUS_WRITE)
err = w9968cf_i2c_adap_write_byte(cam, addr, command);
else if (read_write == I2C_SMBUS_READ)
- err = w9968cf_i2c_adap_read_byte(cam,addr,&data->byte);
-
+ for (i = 1; i <= W9968CF_I2C_RW_RETRIES; i++) {
+ err = w9968cf_i2c_adap_read_byte(cam, addr,
+ &data->byte);
+ if (err) {
+ if (w9968cf_smbus_refresh_bus(cam)) {
+ err = -EIO;
+ break;
+ }
+ } else
+ break;
+ }
} else if (size == I2C_SMBUS_BYTE_DATA) {
addr <<= 1;
@@ -1499,7 +1482,6 @@ w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
DBG(4, "Unsupported I2C transfer mode (%d)", size)
return -EINVAL;
}
-
return err;
}
@@ -1512,44 +1494,6 @@ static u32 w9968cf_i2c_func(struct i2c_adapter* adap)
}
-static int w9968cf_i2c_attach_inform(struct i2c_client* client)
-{
- struct w9968cf_device* cam = i2c_get_adapdata(client->adapter);
- int id = client->driver->id, err = 0;
-
- if (id == I2C_DRIVERID_OVCAMCHIP) {
- cam->sensor_client = client;
- err = w9968cf_sensor_init(cam);
- if (err) {
- cam->sensor_client = NULL;
- return err;
- }
- } else {
- DBG(4, "Rejected client [%s] with driver [%s]",
- client->name, client->driver->driver.name)
- return -EINVAL;
- }
-
- DBG(5, "I2C attach client [%s] with driver [%s]",
- client->name, client->driver->driver.name)
-
- return 0;
-}
-
-
-static int w9968cf_i2c_detach_inform(struct i2c_client* client)
-{
- struct w9968cf_device* cam = i2c_get_adapdata(client->adapter);
-
- if (cam->sensor_client == client)
- cam->sensor_client = NULL;
-
- DBG(5, "I2C detach client [%s]", client->name)
-
- return 0;
-}
-
-
static int w9968cf_i2c_init(struct w9968cf_device* cam)
{
int err = 0;
@@ -1565,15 +1509,16 @@ static int w9968cf_i2c_init(struct w9968cf_device* cam)
static struct i2c_adapter adap = {
.id = I2C_HW_SMBUS_W9968CF,
.owner = THIS_MODULE,
- .client_register = w9968cf_i2c_attach_inform,
- .client_unregister = w9968cf_i2c_detach_inform,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
+ .class = I2C_CLASS_TV_ANALOG,
+#endif
.algo = &algo,
};
memcpy(&cam->i2c_adapter, &adap, sizeof(struct i2c_adapter));
strcpy(cam->i2c_adapter.name, "w9968cf");
cam->i2c_adapter.dev.parent = &cam->usbdev->dev;
- i2c_set_adapdata(&cam->i2c_adapter, cam);
+ i2c_set_adapdata(&cam->i2c_adapter, &cam->v4l2_dev);
DBG(6, "Registering I2C adapter with kernel...")
@@ -2176,13 +2121,9 @@ w9968cf_sensor_get_control(struct w9968cf_device* cam, int cid, int* val)
static int
w9968cf_sensor_cmd(struct w9968cf_device* cam, unsigned int cmd, void* arg)
{
- struct i2c_client* c = cam->sensor_client;
- int rc = 0;
+ int rc;
- if (!c || !c->driver || !c->driver->command)
- return -EINVAL;
-
- rc = c->driver->command(c, cmd, arg);
+ rc = v4l2_subdev_call(cam->sensor_sd, core, ioctl, cmd, arg);
/* The I2C driver returns -EPERM on non-supported controls */
return (rc < 0 && rc != -EPERM) ? rc : 0;
}
@@ -2357,7 +2298,7 @@ static int w9968cf_sensor_init(struct w9968cf_device* cam)
goto error;
/* NOTE: Make sure width and height are a multiple of 16 */
- switch (cam->sensor_client->addr) {
+ switch (v4l2_i2c_subdev_addr(cam->sensor_sd)) {
case OV6xx0_SID:
cam->maxwidth = 352;
cam->maxheight = 288;
@@ -2662,6 +2603,7 @@ static void w9968cf_release_resources(struct w9968cf_device* cam)
w9968cf_deallocate_memory(cam);
kfree(cam->control_buffer);
kfree(cam->data_buffer);
+ v4l2_device_unregister(&cam->v4l2_dev);
mutex_unlock(&w9968cf_devlist_mutex);
}
@@ -3491,6 +3433,11 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
struct list_head* ptr;
u8 sc = 0; /* number of simultaneous cameras */
static unsigned short dev_nr; /* 0 - we are handling device number n */
+ static unsigned short addrs[] = {
+ OV7xx0_SID,
+ OV6xx0_SID,
+ I2C_CLIENT_END
+ };
if (le16_to_cpu(udev->descriptor.idVendor) == winbond_id_table[0].idVendor &&
le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[0].idProduct)
@@ -3506,12 +3453,14 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
if (!cam)
return -ENOMEM;
+ err = v4l2_device_register(&udev->dev, &cam->v4l2_dev);
+ if (err)
+ goto fail0;
+
mutex_init(&cam->dev_mutex);
mutex_lock(&cam->dev_mutex);
cam->usbdev = udev;
- /* NOTE: a local copy is used to avoid possible race conditions */
- memcpy(&cam->dev, &udev->dev, sizeof(struct device));
DBG(2, "%s detected", symbolic(camlist, mod_id))
@@ -3560,7 +3509,7 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
cam->v4ldev->minor = video_nr[dev_nr];
cam->v4ldev->release = video_device_release;
video_set_drvdata(cam->v4ldev, cam);
- cam->v4ldev->parent = &cam->dev;
+ cam->v4ldev->v4l2_dev = &cam->v4l2_dev;
err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
video_nr[dev_nr]);
@@ -3587,9 +3536,13 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
w9968cf_turn_on_led(cam);
w9968cf_i2c_init(cam);
+ cam->sensor_sd = v4l2_i2c_new_probed_subdev(&cam->i2c_adapter,
+ "ovcamchip", "ovcamchip", addrs);
usb_set_intfdata(intf, cam);
mutex_unlock(&cam->dev_mutex);
+
+ err = w9968cf_sensor_init(cam);
return 0;
fail: /* Free unused memory */
@@ -3598,6 +3551,8 @@ fail: /* Free unused memory */
if (cam->v4ldev)
video_device_release(cam->v4ldev);
mutex_unlock(&cam->dev_mutex);
+ v4l2_device_unregister(&cam->v4l2_dev);
+fail0:
kfree(cam);
return err;
}
@@ -3608,9 +3563,8 @@ static void w9968cf_usb_disconnect(struct usb_interface* intf)
struct w9968cf_device* cam =
(struct w9968cf_device*)usb_get_intfdata(intf);
- down_write(&w9968cf_disconnect);
-
if (cam) {
+ down_write(&w9968cf_disconnect);
/* Prevent concurrent accesses to data */
mutex_lock(&cam->dev_mutex);
@@ -3632,12 +3586,12 @@ static void w9968cf_usb_disconnect(struct usb_interface* intf)
w9968cf_release_resources(cam);
mutex_unlock(&cam->dev_mutex);
+ up_write(&w9968cf_disconnect);
- if (!cam->users)
+ if (!cam->users) {
kfree(cam);
+ }
}
-
- up_write(&w9968cf_disconnect);
}
@@ -3661,9 +3615,6 @@ static int __init w9968cf_module_init(void)
KDBG(2, W9968CF_MODULE_NAME" "W9968CF_MODULE_VERSION)
KDBG(3, W9968CF_MODULE_AUTHOR)
- if (ovmod_load)
- request_module("ovcamchip");
-
if ((err = usb_register(&w9968cf_usb_driver)))
return err;
diff --git a/linux/drivers/media/video/w9968cf.h b/linux/drivers/media/video/w9968cf.h
index 62c26b1ed..989d414d6 100644
--- a/linux/drivers/media/video/w9968cf.h
+++ b/linux/drivers/media/video/w9968cf.h
@@ -33,6 +33,7 @@
#include <linux/rwsem.h>
#include <linux/mutex.h>
+#include <media/v4l2-device.h>
#include <media/ovcamchip.h>
#include "compat.h"
@@ -43,7 +44,6 @@
* Default values *
****************************************************************************/
-#define W9968CF_OVMOD_LOAD 1 /* automatic 'ovcamchip' module loading */
#define W9968CF_VPPMOD_LOAD 1 /* automatic 'w9968cf-vpp' module loading */
/* Comment/uncomment the following line to enable/disable debugging messages */
@@ -196,10 +196,9 @@ enum w9968cf_vpp_flag {
/* Main device driver structure */
struct w9968cf_device {
- struct device dev; /* device structure */
-
enum w9968cf_model_id id; /* private device identifier */
+ struct v4l2_device v4l2_dev;
struct video_device* v4ldev; /* -> V4L structure */
struct list_head v4llist; /* entry of the list of V4L cameras */
@@ -266,7 +265,7 @@ struct w9968cf_device {
/* I2C interface to kernel */
struct i2c_adapter i2c_adapter;
- struct i2c_client* sensor_client;
+ struct v4l2_subdev *sensor_sd;
/* Locks */
struct mutex dev_mutex, /* for probe, disconnect,open and close */
@@ -278,6 +277,11 @@ struct w9968cf_device {
char command[16]; /* name of the program holding the device */
};
+static inline struct w9968cf_device *to_cam(struct v4l2_device *v4l2_dev)
+{
+ return container_of(v4l2_dev, struct w9968cf_device, v4l2_dev);
+}
+
/****************************************************************************
* Macros for debugging *
@@ -292,14 +296,14 @@ struct w9968cf_device {
if ( ((specific_debug) && (debug == (level))) || \
((!specific_debug) && (debug >= (level))) ) { \
if ((level) == 1) \
- dev_err(&cam->dev, fmt "\n", ## args); \
+ v4l2_err(&cam->v4l2_dev, fmt "\n", ## args); \
else if ((level) == 2 || (level) == 3) \
- dev_info(&cam->dev, fmt "\n", ## args); \
+ v4l2_info(&cam->v4l2_dev, fmt "\n", ## args); \
else if ((level) == 4) \
- dev_warn(&cam->dev, fmt "\n", ## args); \
+ v4l2_warn(&cam->v4l2_dev, fmt "\n", ## args); \
else if ((level) >= 5) \
- dev_info(&cam->dev, "[%s:%d] " fmt "\n", \
- __func__, __LINE__ , ## args); \
+ v4l2_info(&cam->v4l2_dev, "[%s:%d] " fmt "\n", \
+ __func__, __LINE__ , ## args); \
} \
}
/* For generic kernel (not device specific) messages */
@@ -322,7 +326,7 @@ struct w9968cf_device {
#undef PDBG
#define PDBG(fmt, args...) \
-dev_info(&cam->dev, "[%s:%d] " fmt "\n", __func__, __LINE__ , ## args);
+v4l2_info(&cam->v4l2_dev, "[%s:%d] " fmt "\n", __func__, __LINE__ , ## args);
#undef PDBGG
#define PDBGG(fmt, args...) do {;} while(0); /* nothing: it's a placeholder */
diff --git a/linux/drivers/media/video/zoran/Kconfig b/linux/drivers/media/video/zoran/Kconfig
index 925fb5159..fd4120e4c 100644
--- a/linux/drivers/media/video/zoran/Kconfig
+++ b/linux/drivers/media/video/zoran/Kconfig
@@ -68,6 +68,7 @@ config VIDEO_ZORAN_AVS6EYES
tristate "AverMedia 6 Eyes support (EXPERIMENTAL)"
depends on VIDEO_ZORAN_ZR36060 && EXPERIMENTAL
select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO
+ select VIDEO_BT866 if VIDEO_HELPER_CHIPS_AUTO
select VIDEO_KS0127 if VIDEO_HELPER_CHIPS_AUTO
help
Support for the AverMedia 6 Eyes video surveillance card.
diff --git a/linux/drivers/media/video/zoran/zoran_driver.c b/linux/drivers/media/video/zoran/zoran_driver.c
index 7ddbdf37d..1560c1e4c 100644
--- a/linux/drivers/media/video/zoran/zoran_driver.c
+++ b/linux/drivers/media/video/zoran/zoran_driver.c
@@ -1378,11 +1378,10 @@ setup_overlay (struct file *file,
/* get the status of a buffer in the clients buffer queue */
static int
-zoran_v4l2_buffer_status (struct file *file,
+zoran_v4l2_buffer_status (struct zoran_fh *fh,
struct v4l2_buffer *buf,
int num)
{
- struct zoran_fh *fh = file->private_data;
struct zoran *zr = fh->zr;
buf->flags = V4L2_BUF_FLAG_MAPPED;
@@ -2499,15 +2498,10 @@ static int zoran_querybuf(struct file *file, void *__fh, struct v4l2_buffer *buf
{
struct zoran_fh *fh = __fh;
struct zoran *zr = fh->zr;
- __u32 type = buf->type;
- int index = buf->index, res;
-
- memset(buf, 0, sizeof(*buf));
- buf->type = type;
- buf->index = index;
+ int res;
mutex_lock(&zr->resource_lock);
- res = zoran_v4l2_buffer_status(file, buf, buf->index);
+ res = zoran_v4l2_buffer_status(fh, buf, buf->index);
mutex_unlock(&zr->resource_lock);
return res;
@@ -2608,7 +2602,7 @@ static int zoran_dqbuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
if (res)
goto dqbuf_unlock_and_return;
zr->v4l_sync_tail++;
- res = zoran_v4l2_buffer_status(file, buf, num);
+ res = zoran_v4l2_buffer_status(fh, buf, num);
break;
case ZORAN_MAP_MODE_JPG_REC:
@@ -2639,7 +2633,7 @@ static int zoran_dqbuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
res = jpg_sync(file, &bs);
if (res)
goto dqbuf_unlock_and_return;
- res = zoran_v4l2_buffer_status(file, buf, bs.frame);
+ res = zoran_v4l2_buffer_status(fh, buf, bs.frame);
break;
}