summaryrefslogtreecommitdiff
path: root/linux/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'linux/drivers')
-rw-r--r--linux/drivers/media/common/ir-keymaps.c61
-rw-r--r--linux/drivers/media/common/tuners/tda827x.c15
-rw-r--r--linux/drivers/media/common/tuners/tda8290.c63
-rw-r--r--linux/drivers/media/common/tuners/tuner-xc2028.c19
-rw-r--r--linux/drivers/media/dvb/b2c2/Kconfig1
-rw-r--r--linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c2
-rw-r--r--linux/drivers/media/dvb/b2c2/flexcop-i2c.c6
-rw-r--r--linux/drivers/media/dvb/dvb-usb/dib0700_devices.c6
-rw-r--r--linux/drivers/media/dvb/dvb-usb/dw2102.c2
-rw-r--r--linux/drivers/media/dvb/frontends/Kconfig8
-rw-r--r--linux/drivers/media/dvb/frontends/Makefile1
-rw-r--r--linux/drivers/media/dvb/frontends/cx24113.c608
-rw-r--r--linux/drivers/media/dvb/frontends/cx24113.h8
-rw-r--r--linux/drivers/media/video/cx18/cx18-av-vbi.c5
-rw-r--r--linux/drivers/media/video/cx18/cx18-cards.c8
-rw-r--r--linux/drivers/media/video/cx18/cx18-cards.h5
-rw-r--r--linux/drivers/media/video/cx18/cx18-driver.c249
-rw-r--r--linux/drivers/media/video/cx18/cx18-driver.h24
-rw-r--r--linux/drivers/media/video/cx18/cx18-dvb.c4
-rw-r--r--linux/drivers/media/video/cx18/cx18-fileops.c37
-rw-r--r--linux/drivers/media/video/cx18/cx18-io.h6
-rw-r--r--linux/drivers/media/video/cx18/cx18-ioctl.c14
-rw-r--r--linux/drivers/media/video/cx18/cx18-mailbox.c28
-rw-r--r--linux/drivers/media/video/cx18/cx18-queue.c69
-rw-r--r--linux/drivers/media/video/cx18/cx18-queue.h19
-rw-r--r--linux/drivers/media/video/cx18/cx18-streams.c104
-rw-r--r--linux/drivers/media/video/cx18/cx18-streams.h3
-rw-r--r--linux/drivers/media/video/cx18/cx18-vbi.c5
-rw-r--r--linux/drivers/media/video/cx18/cx18-version.h2
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-cards.c12
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-dvb.c1
-rw-r--r--linux/drivers/media/video/cx23885/cx23885.h1
-rw-r--r--linux/drivers/media/video/cx88/cx88-alsa.c3
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-cards.c40
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-dvb.c2
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-video.c6
-rw-r--r--linux/drivers/media/video/em28xx/em28xx.h1
-rw-r--r--linux/drivers/media/video/mt9m001.c14
-rw-r--r--linux/drivers/media/video/mt9m111.c12
-rw-r--r--linux/drivers/media/video/mt9v022.c14
-rw-r--r--linux/drivers/media/video/ov772x.c97
-rw-r--r--linux/drivers/media/video/pxa_camera.c203
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-cards.c50
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-input.c14
-rw-r--r--linux/drivers/media/video/saa7134/saa7134.h1
-rw-r--r--linux/drivers/media/video/sh_mobile_ceu_camera.c52
-rw-r--r--linux/drivers/media/video/soc_camera.c166
-rw-r--r--linux/drivers/media/video/soc_camera_platform.c12
-rw-r--r--linux/drivers/media/video/uvc/uvc_ctrl.c57
-rw-r--r--linux/drivers/media/video/uvc/uvc_driver.c6
-rw-r--r--linux/drivers/media/video/uvc/uvc_video.c3
-rw-r--r--linux/drivers/media/video/uvc/uvcvideo.h5
52 files changed, 1772 insertions, 382 deletions
diff --git a/linux/drivers/media/common/ir-keymaps.c b/linux/drivers/media/common/ir-keymaps.c
index 6c0a80f45..ee9931f56 100644
--- a/linux/drivers/media/common/ir-keymaps.c
+++ b/linux/drivers/media/common/ir-keymaps.c
@@ -2441,6 +2441,67 @@ IR_KEYTAB_TYPE ir_codes_powercolor_real_angel[IR_KEYTAB_SIZE] = {
};
EXPORT_SYMBOL_GPL(ir_codes_powercolor_real_angel);
+/* Kworld Plus TV Analog Lite PCI IR
+ Mauro Carvalho Chehab <mchehab@infradead.org>
+ */
+IR_KEYTAB_TYPE ir_codes_kworld_plus_tv_analog[IR_KEYTAB_SIZE] = {
+ [0x0c] = KEY_PROG1, /* Kworld key */
+ [0x16] = KEY_CLOSECD, /* -> ) */
+ [0x1d] = KEY_POWER2,
+
+ [0x00] = KEY_1,
+ [0x01] = KEY_2,
+ [0x02] = KEY_3, /* Two keys have the same code: 3 and left */
+ [0x03] = KEY_4, /* Two keys have the same code: 3 and right */
+ [0x04] = KEY_5,
+ [0x05] = KEY_6,
+ [0x06] = KEY_7,
+ [0x07] = KEY_8,
+ [0x08] = KEY_9,
+ [0x0a] = KEY_0,
+
+ [0x09] = KEY_AGAIN,
+ [0x14] = KEY_MUTE,
+
+ [0x20] = KEY_UP,
+ [0x21] = KEY_DOWN,
+ [0x0b] = KEY_ENTER,
+
+ [0x10] = KEY_CHANNELUP,
+ [0x11] = KEY_CHANNELDOWN,
+
+ /* Couldn't map key left/key right since those
+ conflict with '3' and '4' scancodes
+ I dunno what the original driver does
+ */
+
+ [0x13] = KEY_VOLUMEUP,
+ [0x12] = KEY_VOLUMEDOWN,
+
+ /* The lower part of the IR
+ There are several duplicated keycodes there.
+ Most of them conflict with digits.
+ Add mappings just to the unused scancodes.
+ Somehow, the original driver has a way to know,
+ but this doesn't seem to be on some GPIO.
+ Also, it is not related to the time between keyup
+ and keydown.
+ */
+ [0x19] = KEY_PAUSE, /* Timeshift */
+ [0x1a] = KEY_STOP,
+ [0x1b] = KEY_RECORD,
+
+ [0x22] = KEY_TEXT,
+
+ [0x15] = KEY_AUDIO, /* ((*)) */
+ [0x0f] = KEY_ZOOM,
+ [0x1c] = KEY_SHUFFLE, /* snapshot */
+
+ [0x18] = KEY_RED, /* B */
+ [0x23] = KEY_GREEN, /* C */
+};
+EXPORT_SYMBOL_GPL(ir_codes_kworld_plus_tv_analog);
+
IR_KEYTAB_TYPE ir_codes_avermedia_a16d[IR_KEYTAB_SIZE] = {
[0x20] = KEY_LIST,
[0x00] = KEY_POWER,
diff --git a/linux/drivers/media/common/tuners/tda827x.c b/linux/drivers/media/common/tuners/tda827x.c
index 83a017c53..a14fe817d 100644
--- a/linux/drivers/media/common/tuners/tda827x.c
+++ b/linux/drivers/media/common/tuners/tda827x.c
@@ -81,10 +81,11 @@ static void tda827x_set_std(struct dvb_frontend *fe,
mode = "xx";
}
- if (params->mode == V4L2_TUNER_RADIO)
+ if (params->mode == V4L2_TUNER_RADIO) {
priv->sgIF = 88; /* if frequency is 5.5 MHz */
-
- dprintk("setting tda827x to system %s\n", mode);
+ dprintk("setting tda827x to radio FM\n");
+ } else
+ dprintk("setting tda827x to system %s\n", mode);
}
@@ -200,7 +201,7 @@ static int tda827xo_set_params(struct dvb_frontend *fe,
fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(priv->i2c_adap, &msg, 1);
- priv->frequency = tuner_freq - if_freq; // FIXME
+ priv->frequency = params->frequency;
priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
return 0;
@@ -305,7 +306,7 @@ static int tda827xo_set_analog_params(struct dvb_frontend *fe,
reg2[1] = 0x08; /* Vsync en */
i2c_transfer(priv->i2c_adap, &msg, 1);
- priv->frequency = freq * 62500;
+ priv->frequency = params->frequency;
return 0;
}
@@ -592,7 +593,7 @@ static int tda827xa_set_params(struct dvb_frontend *fe,
fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(priv->i2c_adap, &msg, 1);
- priv->frequency = tuner_freq - if_freq; // FIXME
+ priv->frequency = params->frequency;
priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
return 0;
@@ -692,7 +693,7 @@ static int tda827xa_set_analog_params(struct dvb_frontend *fe,
tuner_reg[1] = 0x19 + (priv->lpsel << 1);
i2c_transfer(priv->i2c_adap, &msg, 1);
- priv->frequency = freq * 62500;
+ priv->frequency = params->frequency;
return 0;
}
diff --git a/linux/drivers/media/common/tuners/tda8290.c b/linux/drivers/media/common/tuners/tda8290.c
index 637849ec8..6eaaacca0 100644
--- a/linux/drivers/media/common/tuners/tda8290.c
+++ b/linux/drivers/media/common/tuners/tda8290.c
@@ -33,6 +33,9 @@ static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "enable verbose debug messages");
+static int deemphasis_50;
+MODULE_PARM_DESC(deemphasis_50, "0 - 75us deemphasis; 1 - 50us deemphasis");
+
/* ---------------------------------------------------------------------- */
struct tda8290_priv {
@@ -162,9 +165,34 @@ static void set_audio(struct dvb_frontend *fe,
mode = "xx";
}
- tuner_dbg("setting tda829x to system %s\n", mode);
+ if (params->mode == V4L2_TUNER_RADIO) {
+ priv->tda8290_easy_mode = 0x01; /* Start with MN values */
+ tuner_dbg("setting to radio FM\n");
+ } else {
+ tuner_dbg("setting tda829x to system %s\n", mode);
+ }
}
+struct {
+ unsigned char seq[2];
+} fm_mode[] = {
+ { { 0x01, 0x81} }, /* Put device into expert mode */
+ { { 0x03, 0x48} }, /* Disable NOTCH and VIDEO filters */
+ { { 0x04, 0x04} }, /* Disable color carrier filter (SSIF) */
+ { { 0x05, 0x04} }, /* ADC headroom */
+ { { 0x06, 0x10} }, /* group delay flat */
+
+ { { 0x07, 0x00} }, /* use the same radio DTO values as a tda8295 */
+ { { 0x08, 0x00} },
+ { { 0x09, 0x80} },
+ { { 0x0a, 0xda} },
+ { { 0x0b, 0x4b} },
+ { { 0x0c, 0x68} },
+
+ { { 0x0d, 0x00} }, /* PLL off, no video carrier detect */
+ { { 0x14, 0x00} }, /* disable auto mute if no video */
+};
+
static void tda8290_set_params(struct dvb_frontend *fe,
struct analog_parameters *params)
{
@@ -201,15 +229,30 @@ static void tda8290_set_params(struct dvb_frontend *fe,
tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2);
msleep(1);
- expert_mode[1] = priv->tda8290_easy_mode + 0x80;
- tuner_i2c_xfer_send(&priv->i2c_props, expert_mode, 2);
- tuner_i2c_xfer_send(&priv->i2c_props, gainset_off, 2);
- tuner_i2c_xfer_send(&priv->i2c_props, if_agc_spd, 2);
- if (priv->tda8290_easy_mode & 0x60)
- tuner_i2c_xfer_send(&priv->i2c_props, adc_head_9, 2);
- else
- tuner_i2c_xfer_send(&priv->i2c_props, adc_head_6, 2);
- tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2);
+ if (params->mode == V4L2_TUNER_RADIO) {
+ int i;
+ unsigned char deemphasis[] = { 0x13, 1 };
+
+ /* FIXME: allow using a different deemphasis */
+
+ if (deemphasis_50)
+ deemphasis[1] = 2;
+
+ for (i = 0; i < ARRAY_SIZE(fm_mode); i++)
+ tuner_i2c_xfer_send(&priv->i2c_props, fm_mode[i].seq, 2);
+
+ tuner_i2c_xfer_send(&priv->i2c_props, deemphasis, 2);
+ } else {
+ expert_mode[1] = priv->tda8290_easy_mode + 0x80;
+ tuner_i2c_xfer_send(&priv->i2c_props, expert_mode, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, gainset_off, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, if_agc_spd, 2);
+ if (priv->tda8290_easy_mode & 0x60)
+ tuner_i2c_xfer_send(&priv->i2c_props, adc_head_9, 2);
+ else
+ tuner_i2c_xfer_send(&priv->i2c_props, adc_head_6, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2);
+ }
tda8290_i2c_bridge(fe, 1);
diff --git a/linux/drivers/media/common/tuners/tuner-xc2028.c b/linux/drivers/media/common/tuners/tuner-xc2028.c
index 7f43272ca..9536e3d3b 100644
--- a/linux/drivers/media/common/tuners/tuner-xc2028.c
+++ b/linux/drivers/media/common/tuners/tuner-xc2028.c
@@ -32,6 +32,12 @@ static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "enable verbose debug messages");
+static int no_poweroff;
+module_param(no_poweroff, int, 0644);
+MODULE_PARM_DESC(debug, "0 (default) powers device off when not used.\n"
+ "1 keep device energized and with tuner ready all the times.\n"
+ " Faster, but consumes more power and keeps the device hotter\n");
+
static char audio_std[8];
module_param_string(audio_std, audio_std, sizeof(audio_std), 0);
MODULE_PARM_DESC(audio_std,
@@ -1095,16 +1101,16 @@ static int xc2028_set_params(struct dvb_frontend *fe,
T_DIGITAL_TV, type, 0, demod);
}
-#if 0
-/* This is needed at sleep (S1/S3), but not at fe_standby. Otherwise,
- firmware will be loaded on every open()
- */
static int xc2028_sleep(struct dvb_frontend *fe)
{
struct xc2028_data *priv = fe->tuner_priv;
int rc = 0;
- tuner_dbg("%s called\n", __func__);
+ /* Avoid firmware reload on slow devices */
+ if (no_poweroff)
+ return 0;
+
+ tuner_dbg("Putting xc2028/3028 into poweroff mode.\n");
mutex_lock(&priv->lock);
@@ -1119,7 +1125,6 @@ static int xc2028_sleep(struct dvb_frontend *fe)
return rc;
}
-#endif
static int xc2028_dvb_release(struct dvb_frontend *fe)
{
@@ -1200,9 +1205,7 @@ static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = {
.get_frequency = xc2028_get_frequency,
.get_rf_strength = xc2028_signal,
.set_params = xc2028_set_params,
-#if 0
.sleep = xc2028_sleep,
-#endif
#if 0
int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
int (*get_status)(struct dvb_frontend *fe, u32 *status);
diff --git a/linux/drivers/media/dvb/b2c2/Kconfig b/linux/drivers/media/dvb/b2c2/Kconfig
index 73dc2ee9b..e5c27e355 100644
--- a/linux/drivers/media/dvb/b2c2/Kconfig
+++ b/linux/drivers/media/dvb/b2c2/Kconfig
@@ -14,6 +14,7 @@ config DVB_B2C2_FLEXCOP
select DVB_TUNER_ITD1000 if !DVB_FE_CUSTOMISE
select DVB_ISL6421 if !DVB_FE_CUSTOMISE
select DVB_CX24123 if !DVB_FE_CUSTOMISE
+ select DVB_TUNER_CX24113 if !DVB_FE_CUSTOMISE
help
Support for the digital TV receiver chip made by B2C2 Inc. included in
Technisats PCI cards and USB boxes.
diff --git a/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
index a127a4175..5cded3708 100644
--- a/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -628,12 +628,14 @@ int flexcop_frontend_init(struct flexcop_device *fc)
}
/* try the cable dvb (stv0297) */
+ fc->fc_i2c_adap[0].no_base_addr = 1;
fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c);
if (fc->fe != NULL) {
fc->dev_type = FC_CABLE;
fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params;
goto fe_found;
}
+ fc->fc_i2c_adap[0].no_base_addr = 0;
/* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */
fc->fe = dvb_attach(mt312_attach,
diff --git a/linux/drivers/media/dvb/b2c2/flexcop-i2c.c b/linux/drivers/media/dvb/b2c2/flexcop-i2c.c
index 05635c453..01d27613f 100644
--- a/linux/drivers/media/dvb/b2c2/flexcop-i2c.c
+++ b/linux/drivers/media/dvb/b2c2/flexcop-i2c.c
@@ -47,9 +47,13 @@ static int flexcop_i2c_read4(struct flexcop_i2c_adapter *i2c,
int len = r100.tw_sm_c_100.total_bytes, /* remember total_bytes is buflen-1 */
ret;
- r100.tw_sm_c_100.no_base_addr_ack_error = i2c->no_base_addr;
ret = flexcop_i2c_operation(i2c->fc, &r100);
if (ret != 0) {
+ deb_i2c("Retrying operation\n");
+ r100.tw_sm_c_100.no_base_addr_ack_error = i2c->no_base_addr;
+ ret = flexcop_i2c_operation(i2c->fc, &r100);
+ }
+ if (ret != 0) {
deb_i2c("read failed. %d\n", ret);
return ret;
}
diff --git a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c
index f28d3ae59..391732788 100644
--- a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -446,13 +446,13 @@ static int stk7700ph_tuner_attach(struct dvb_usb_adapter *adap)
== NULL ? -ENODEV : 0;
}
-#define DEFAULT_RC_INTERVAL 150
+#define DEFAULT_RC_INTERVAL 50
static u8 rc_request[] = { REQUEST_POLL_RC, 0 };
/* Number of keypresses to ignore before start repeating */
-#define RC_REPEAT_DELAY 2
-#define RC_REPEAT_DELAY_V1_20 5
+#define RC_REPEAT_DELAY 6
+#define RC_REPEAT_DELAY_V1_20 10
diff --git a/linux/drivers/media/dvb/dvb-usb/dw2102.c b/linux/drivers/media/dvb/dvb-usb/dw2102.c
index 9b32c9c0a..2b8ee587b 100644
--- a/linux/drivers/media/dvb/dvb-usb/dw2102.c
+++ b/linux/drivers/media/dvb/dvb-usb/dw2102.c
@@ -672,7 +672,7 @@ static int dw2102_load_firmware(struct usb_device *dev,
/* check STV0299 frontend */
dw210x_op_rw(dev, 0xb5, 0, 0, &reset16[0], 2,
DW210X_READ_MSG);
- if (reset16[0] == 0xa1) {
+ if ((reset16[0] == 0xa1) || (reset16[0] == 0x80)) {
dw2102_properties.i2c_algo = &dw2102_i2c_algo;
dw2102_properties.adapter->tuner_attach = &dw2102_tuner_attach;
break;
diff --git a/linux/drivers/media/dvb/frontends/Kconfig b/linux/drivers/media/dvb/frontends/Kconfig
index 2470d88e9..002695607 100644
--- a/linux/drivers/media/dvb/frontends/Kconfig
+++ b/linux/drivers/media/dvb/frontends/Kconfig
@@ -118,6 +118,14 @@ config DVB_TUNER_ITD1000
help
A DVB-S tuner module. Say Y when you want to support this frontend.
+config DVB_TUNER_CX24113
+ tristate "Conexant CX24113/CX24128 tuner for DVB-S/DSS"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
+
config DVB_TDA826X
tristate "Philips TDA826X silicon tuner"
depends on DVB_CORE && I2C
diff --git a/linux/drivers/media/dvb/frontends/Makefile b/linux/drivers/media/dvb/frontends/Makefile
index 7a19c0c7b..af7bdf0ad 100644
--- a/linux/drivers/media/dvb/frontends/Makefile
+++ b/linux/drivers/media/dvb/frontends/Makefile
@@ -54,6 +54,7 @@ obj-$(CONFIG_DVB_S5H1409) += s5h1409.o
obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o
obj-$(CONFIG_DVB_AU8522) += au8522.o
obj-$(CONFIG_DVB_TDA10048) += tda10048.o
+obj-$(CONFIG_DVB_TUNER_CX24113) += cx24113.o
obj-$(CONFIG_DVB_S5H1411) += s5h1411.o
obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o
obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o
diff --git a/linux/drivers/media/dvb/frontends/cx24113.c b/linux/drivers/media/dvb/frontends/cx24113.c
new file mode 100644
index 000000000..e2e5df9de
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/cx24113.c
@@ -0,0 +1,608 @@
+/*
+ * Driver for Conexant CX24113/CX24128 Tuner (Satelite)
+ *
+ * Copyright (C) 2007-8 Patrick Boettcher <pb@linuxtv.org>
+ *
+ * Developed for BBTI / Technisat
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include "dvb_frontend.h"
+#include "cx24113.h"
+
+static int debug;
+
+#define info(args...) do { printk(KERN_INFO "CX24113: " args); } while (0)
+#define err(args...) do { printk(KERN_ERR "CX24113: " args); } while (0)
+
+#define dprintk(args...) \
+ do { \
+ if (debug) { \
+ printk(KERN_DEBUG "CX24113: %s: ", __func__); \
+ printk(args); \
+ } \
+ } while (0)
+
+struct cx24113_state {
+ struct i2c_adapter *i2c;
+ const struct cx24113_config *config;
+
+#define REV_CX24113 0x23
+ u8 rev;
+ u8 ver;
+
+ u8 icp_mode:1;
+
+#define ICP_LEVEL1 0
+#define ICP_LEVEL2 1
+#define ICP_LEVEL3 2
+#define ICP_LEVEL4 3
+ u8 icp_man:2;
+ u8 icp_auto_low:2;
+ u8 icp_auto_mlow:2;
+ u8 icp_auto_mhi:2;
+ u8 icp_auto_hi:2;
+ u8 icp_dig;
+
+#define LNA_MIN_GAIN 0
+#define LNA_MID_GAIN 1
+#define LNA_MAX_GAIN 2
+ u8 lna_gain:2;
+
+ u8 acp_on:1;
+
+ u8 vco_mode:2;
+ u8 vco_shift:1;
+#define VCOBANDSEL_6 0x80
+#define VCOBANDSEL_5 0x01
+#define VCOBANDSEL_4 0x02
+#define VCOBANDSEL_3 0x04
+#define VCOBANDSEL_2 0x08
+#define VCOBANDSEL_1 0x10
+ u8 vco_band;
+
+#define VCODIV4 4
+#define VCODIV2 2
+ u8 vcodiv;
+
+ u8 bs_delay:4;
+ u16 bs_freqcnt:13;
+ u16 bs_rdiv;
+ u8 prescaler_mode:1;
+
+ u8 rfvga_bias_ctrl;
+
+ s16 tuner_gain_thres;
+ u8 gain_level;
+
+ u32 frequency;
+
+ u8 refdiv;
+
+ u8 Fwindow_enabled;
+};
+
+static int cx24113_writereg(struct cx24113_state *state, int reg, int data)
+{
+ u8 buf[] = { reg, data };
+ struct i2c_msg msg = { .addr = state->config->i2c_addr,
+ .flags = 0, .buf = buf, .len = 2 };
+ int err = i2c_transfer(state->i2c, &msg, 1);
+ if (err != 1) {
+ printk(KERN_DEBUG "%s: writereg error(err == %i, reg == 0x%02x,"
+ " data == 0x%02x)\n", __func__, err, reg, data);
+ return err;
+ }
+
+ return 0;
+}
+
+static int cx24113_readreg(struct cx24113_state *state, u8 reg)
+{
+ int ret;
+ u8 b;
+ struct i2c_msg msg[] = {
+ { .addr = state->config->i2c_addr,
+ .flags = 0, .buf = &reg, .len = 1 },
+ { .addr = state->config->i2c_addr,
+ .flags = I2C_M_RD, .buf = &b, .len = 1 }
+ };
+
+ ret = i2c_transfer(state->i2c, msg, 2);
+
+ if (ret != 2) {
+ printk(KERN_DEBUG "%s: reg=0x%x (error=%d)\n",
+ __func__, reg, ret);
+ return ret;
+ }
+
+ return b;
+}
+
+static void cx24113_set_parameters(struct cx24113_state *state)
+{
+ u8 r;
+
+ r = cx24113_readreg(state, 0x10) & 0x82;
+ r |= state->icp_mode;
+ r |= state->icp_man << 4;
+ r |= state->icp_dig << 2;
+ r |= state->prescaler_mode << 5;
+ cx24113_writereg(state, 0x10, r);
+
+ r = (state->icp_auto_low << 0) | (state->icp_auto_mlow << 2)
+ | (state->icp_auto_mhi << 4) | (state->icp_auto_hi << 6);
+ cx24113_writereg(state, 0x11, r);
+
+ if (state->rev == REV_CX24113) {
+ r = cx24113_readreg(state, 0x20) & 0xec;
+ r |= state->lna_gain;
+ r |= state->rfvga_bias_ctrl << 4;
+ cx24113_writereg(state, 0x20, r);
+ }
+
+ r = cx24113_readreg(state, 0x12) & 0x03;
+ r |= state->acp_on << 2;
+ r |= state->bs_delay << 4;
+ cx24113_writereg(state, 0x12, r);
+
+ r = cx24113_readreg(state, 0x18) & 0x40;
+ r |= state->vco_shift;
+ if (state->vco_band == VCOBANDSEL_6)
+ r |= (1 << 7);
+ else
+ r |= (state->vco_band << 1);
+ cx24113_writereg(state, 0x18, r);
+
+ r = cx24113_readreg(state, 0x14) & 0x20;
+ r |= (state->vco_mode << 6) | ((state->bs_freqcnt >> 8) & 0x1f);
+ cx24113_writereg(state, 0x14, r);
+ cx24113_writereg(state, 0x15, (state->bs_freqcnt & 0xff));
+
+ cx24113_writereg(state, 0x16, (state->bs_rdiv >> 4) & 0xff);
+ r = (cx24113_readreg(state, 0x17) & 0x0f) |
+ ((state->bs_rdiv & 0x0f) << 4);
+ cx24113_writereg(state, 0x17, r);
+}
+
+#define VGA_0 0x00
+#define VGA_1 0x04
+#define VGA_2 0x02
+#define VGA_3 0x06
+#define VGA_4 0x01
+#define VGA_5 0x05
+#define VGA_6 0x03
+#define VGA_7 0x07
+
+#define RFVGA_0 0x00
+#define RFVGA_1 0x01
+#define RFVGA_2 0x02
+#define RFVGA_3 0x03
+
+static int cx24113_set_gain_settings(struct cx24113_state *state,
+ s16 power_estimation)
+{
+ u8 ampout = cx24113_readreg(state, 0x1d) & 0xf0,
+ vga = cx24113_readreg(state, 0x1f) & 0x3f,
+ rfvga = cx24113_readreg(state, 0x20) & 0xf3;
+ u8 gain_level = power_estimation >= state->tuner_gain_thres;
+
+ dprintk("power estimation: %d, thres: %d, gain_level: %d/%d\n",
+ power_estimation, state->tuner_gain_thres,
+ state->gain_level, gain_level);
+
+ if (gain_level == state->gain_level)
+ return 0; /* nothing to be done */
+
+ ampout |= 0xf;
+
+ if (gain_level) {
+ rfvga |= RFVGA_0 << 2;
+ vga |= (VGA_7 << 3) | VGA_7;
+ } else {
+ rfvga |= RFVGA_2 << 2;
+ vga |= (VGA_6 << 3) | VGA_2;
+ }
+ state->gain_level = gain_level;
+
+ cx24113_writereg(state, 0x1d, ampout);
+ cx24113_writereg(state, 0x1f, vga);
+ cx24113_writereg(state, 0x20, rfvga);
+
+ return 1; /* did something */
+}
+
+static int cx24113_set_Fref(struct cx24113_state *state, u8 high)
+{
+ u8 xtal = cx24113_readreg(state, 0x02);
+ if (state->rev == 0x43 && state->vcodiv == VCODIV4)
+ high = 1;
+
+ xtal &= ~0x2;
+ if (high)
+ xtal |= high << 1;
+ return cx24113_writereg(state, 0x02, xtal);
+}
+
+static int cx24113_enable(struct cx24113_state *state, u8 enable)
+{
+ u8 r21 = (cx24113_readreg(state, 0x21) & 0xc0) | enable;
+ if (state->rev == REV_CX24113)
+ r21 |= (1 << 1);
+ return cx24113_writereg(state, 0x21, r21);
+}
+
+static int cx24113_set_bandwidth(struct cx24113_state *state, u32 bandwidth_khz)
+{
+ u8 r;
+
+ if (bandwidth_khz <= 19000)
+ r = 0x03 << 6;
+ else if (bandwidth_khz <= 25000)
+ r = 0x02 << 6;
+ else
+ r = 0x01 << 6;
+
+ dprintk("bandwidth to be set: %d\n", bandwidth_khz);
+ bandwidth_khz *= 10;
+ bandwidth_khz -= 10000;
+ bandwidth_khz /= 1000;
+ bandwidth_khz += 5;
+ bandwidth_khz /= 10;
+
+ dprintk("bandwidth: %d %d\n", r >> 6, bandwidth_khz);
+
+ r |= bandwidth_khz & 0x3f;
+
+ return cx24113_writereg(state, 0x1e, r);
+}
+
+static int cx24113_set_clk_inversion(struct cx24113_state *state, u8 on)
+{
+ u8 r = (cx24113_readreg(state, 0x10) & 0x7f) | ((on & 0x1) << 7);
+ return cx24113_writereg(state, 0x10, r);
+}
+
+static int cx24113_get_status(struct dvb_frontend *fe, u32 *status)
+{
+ struct cx24113_state *state = fe->tuner_priv;
+ u8 r = (cx24113_readreg(state, 0x10) & 0x02) >> 1;
+ if (r)
+ *status |= TUNER_STATUS_LOCKED;
+ dprintk("PLL locked: %d\n", r);
+ return 0;
+}
+
+static u8 cx24113_set_ref_div(struct cx24113_state *state, u8 refdiv)
+{
+ if (state->rev == 0x43 && state->vcodiv == VCODIV4)
+ refdiv = 2;
+ return state->refdiv = refdiv;
+}
+
+static void cx24113_calc_pll_nf(struct cx24113_state *state, u16 *n, s32 *f)
+{
+ s32 N;
+ s64 F;
+ u8 R, r;
+ u8 vcodiv;
+ u8 factor;
+ s32 freq_hz = state->frequency * 1000;
+
+ if (state->config->xtal_khz < 20000)
+ factor = 1;
+ else
+ factor = 2;
+
+ if (state->rev == REV_CX24113) {
+ if (state->frequency >= 1100000)
+ vcodiv = VCODIV2;
+ else
+ vcodiv = VCODIV4;
+ } else {
+ if (state->frequency >= 1165000)
+ vcodiv = VCODIV2;
+ else
+ vcodiv = VCODIV4;
+ }
+ state->vcodiv = vcodiv;
+
+ dprintk("calculating N/F for %dHz with vcodiv %d\n", freq_hz, vcodiv);
+ R = 0;
+ do {
+ R = cx24113_set_ref_div(state, R + 1);
+
+ /* calculate tuner PLL settings: */
+ N = (freq_hz / 100 * vcodiv) * R;
+ N /= (state->config->xtal_khz) * factor * 2;
+ N += 5; /* For round up. */
+ N /= 10;
+ N -= 32;
+ } while (N < 6 && R < 3);
+
+ if (N < 6) {
+ err("strange frequency: N < 6\n");
+ return;
+ }
+ F = freq_hz;
+ F *= (u64) (R * vcodiv * 262144);
+ dprintk("1 N: %d, F: %lld, R: %d\n", N, F, R);
+ do_div(F, state->config->xtal_khz*1000 * factor * 2);
+ dprintk("2 N: %d, F: %lld, R: %d\n", N, F, R);
+ F -= (N + 32) * 262144;
+
+ dprintk("3 N: %d, F: %lld, R: %d\n", N, F, R);
+
+ if (state->Fwindow_enabled) {
+ if (F > (262144 / 2 - 1638))
+ F = 262144 / 2 - 1638;
+ if (F < (-262144 / 2 + 1638))
+ F = -262144 / 2 + 1638;
+ if ((F < 3277 && F > 0) || (F > -3277 && F < 0)) {
+ F = 0;
+ r = cx24113_readreg(state, 0x10);
+ cx24113_writereg(state, 0x10, r | (1 << 6));
+ }
+ }
+ dprintk("4 N: %d, F: %lld, R: %d\n", N, F, R);
+
+ *n = (u16) N;
+ *f = (s32) F;
+}
+
+
+static void cx24113_set_nfr(struct cx24113_state *state, u16 n, s32 f, u8 r)
+{
+ u8 reg;
+ cx24113_writereg(state, 0x19, (n >> 1) & 0xff);
+
+ reg = ((n & 0x1) << 7) | ((f >> 11) & 0x7f);
+ cx24113_writereg(state, 0x1a, reg);
+
+ cx24113_writereg(state, 0x1b, (f >> 3) & 0xff);
+
+ reg = cx24113_readreg(state, 0x1c) & 0x1f;
+ cx24113_writereg(state, 0x1c, reg | ((f & 0x7) << 5));
+
+ cx24113_set_Fref(state, r - 1);
+}
+
+static int cx24113_set_frequency(struct cx24113_state *state, u32 frequency)
+{
+ u8 r = 1; /* or 2 */
+ u16 n = 6;
+ s32 f = 0;
+
+ r = cx24113_readreg(state, 0x14);
+ cx24113_writereg(state, 0x14, r & 0x3f);
+
+ r = cx24113_readreg(state, 0x10);
+ cx24113_writereg(state, 0x10, r & 0xbf);
+
+ state->frequency = frequency;
+
+ dprintk("tuning to frequency: %d\n", frequency);
+
+ cx24113_calc_pll_nf(state, &n, &f);
+ cx24113_set_nfr(state, n, f, state->refdiv);
+
+ r = cx24113_readreg(state, 0x18) & 0xbf;
+ if (state->vcodiv != VCODIV2)
+ r |= 1 << 6;
+ cx24113_writereg(state, 0x18, r);
+
+ /* The need for this sleep is not clear. But helps in some cases */
+ msleep(5);
+
+ r = cx24113_readreg(state, 0x1c) & 0xef;
+ cx24113_writereg(state, 0x1c, r | (1 << 4));
+ return 0;
+}
+
+static int cx24113_init(struct dvb_frontend *fe)
+{
+ struct cx24113_state *state = fe->tuner_priv;
+ int ret;
+
+ state->tuner_gain_thres = -50;
+ state->gain_level = 255; /* to force a gain-setting initialization */
+ state->icp_mode = 0;
+
+ if (state->config->xtal_khz < 11000) {
+ state->icp_auto_hi = ICP_LEVEL4;
+ state->icp_auto_mhi = ICP_LEVEL4;
+ state->icp_auto_mlow = ICP_LEVEL3;
+ state->icp_auto_low = ICP_LEVEL3;
+ } else {
+ state->icp_auto_hi = ICP_LEVEL4;
+ state->icp_auto_mhi = ICP_LEVEL4;
+ state->icp_auto_mlow = ICP_LEVEL3;
+ state->icp_auto_low = ICP_LEVEL2;
+ }
+
+ state->icp_dig = ICP_LEVEL3;
+ state->icp_man = ICP_LEVEL1;
+ state->acp_on = 1;
+ state->vco_mode = 0;
+ state->vco_shift = 0;
+ state->vco_band = VCOBANDSEL_1;
+ state->bs_delay = 8;
+ state->bs_freqcnt = 0x0fff;
+ state->bs_rdiv = 0x0fff;
+ state->prescaler_mode = 0;
+ state->lna_gain = LNA_MAX_GAIN;
+ state->rfvga_bias_ctrl = 1;
+ state->Fwindow_enabled = 1;
+
+ cx24113_set_Fref(state, 0);
+ cx24113_enable(state, 0x3d);
+ cx24113_set_parameters(state);
+
+ cx24113_set_gain_settings(state, -30);
+
+ cx24113_set_bandwidth(state, 18025);
+ cx24113_set_clk_inversion(state, 1);
+
+ if (state->config->xtal_khz >= 40000)
+ ret = cx24113_writereg(state, 0x02,
+ (cx24113_readreg(state, 0x02) & 0xfb) | (1 << 2));
+ else
+ ret = cx24113_writereg(state, 0x02,
+ (cx24113_readreg(state, 0x02) & 0xfb) | (0 << 2));
+
+ return ret;
+}
+
+static int cx24113_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct cx24113_state *state = fe->tuner_priv;
+ /* for a ROLL-OFF factor of 0.35, 0.2: 600, 0.25: 625 */
+ u32 roll_off = 675;
+ u32 bw;
+
+ bw = ((p->u.qpsk.symbol_rate/100) * roll_off) / 1000;
+ bw += (10000000/100) + 5;
+ bw /= 10;
+ bw += 1000;
+ cx24113_set_bandwidth(state, bw);
+
+ cx24113_set_frequency(state, p->frequency);
+ msleep(5);
+ return cx24113_get_status(fe, &bw);
+}
+
+static s8 cx24113_agc_table[2][10] = {
+ {-54, -41, -35, -30, -25, -21, -16, -10, -6, -2},
+ {-39, -35, -30, -25, -19, -15, -11, -5, 1, 9},
+};
+
+void cx24113_agc_callback(struct dvb_frontend *fe)
+{
+ struct cx24113_state *state = fe->tuner_priv;
+ s16 s, i;
+ if (!fe->ops.read_signal_strength)
+ return;
+
+ do {
+ /* this only works with the current CX24123 implementation */
+ fe->ops.read_signal_strength(fe, (u16 *) &s);
+ s >>= 8;
+ dprintk("signal strength: %d\n", s);
+ for (i = 0; i < sizeof(cx24113_agc_table[0]); i++)
+ if (cx24113_agc_table[state->gain_level][i] > s)
+ break;
+ s = -25 - i*5;
+ } while (cx24113_set_gain_settings(state, s));
+}
+EXPORT_SYMBOL(cx24113_agc_callback);
+
+static int cx24113_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct cx24113_state *state = fe->tuner_priv;
+ *frequency = state->frequency;
+ return 0;
+}
+
+static int cx24113_release(struct dvb_frontend *fe)
+{
+ struct cx24113_state *state = fe->tuner_priv;
+ dprintk("\n");
+ fe->tuner_priv = NULL;
+ kfree(state);
+ return 0;
+}
+
+static const struct dvb_tuner_ops cx24113_tuner_ops = {
+ .info = {
+ .name = "Conexant CX24113",
+ .frequency_min = 950000,
+ .frequency_max = 2150000,
+ .frequency_step = 125,
+ },
+
+ .release = cx24113_release,
+
+ .init = cx24113_init,
+ .sleep = NULL,
+
+ .set_params = cx24113_set_params,
+ .get_frequency = cx24113_get_frequency,
+ .get_bandwidth = NULL,
+ .get_status = cx24113_get_status,
+};
+
+struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe,
+ const struct cx24113_config *config, struct i2c_adapter *i2c)
+{
+ /* allocate memory for the internal state */
+ struct cx24113_state *state =
+ kzalloc(sizeof(struct cx24113_state), GFP_KERNEL);
+ if (state == NULL) {
+ err("Unable to kmalloc\n");
+ goto error;
+ }
+
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+
+ info("trying to detect myself\n");
+
+ /* making a dummy read, because of some expected troubles
+ * after power on */
+ cx24113_readreg(state, 0x00);
+
+ switch (state->rev = cx24113_readreg(state, 0x00)) {
+ case 0x43:
+ info("unknown device\n");
+ break;
+ case REV_CX24113:
+ info("CX24113\n");
+ break;
+ default:
+ err("unsupported revision: %x\n", state->rev);
+ goto error;
+ }
+ state->ver = cx24113_readreg(state, 0x01);
+ info("version: %x\n", state->ver);
+
+ /* create dvb_frontend */
+ memcpy(&fe->ops.tuner_ops, &cx24113_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+ fe->tuner_priv = state;
+ return fe;
+
+error:
+ kfree(state);
+
+ return NULL;
+}
+EXPORT_SYMBOL(cx24113_attach);
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
+
+MODULE_AUTHOR("Patrick Boettcher <pb@linuxtv.org>");
+MODULE_DESCRIPTION("DVB Frontend module for Conexant CX24113/CX24128hardware");
+MODULE_LICENSE("GPL");
+
diff --git a/linux/drivers/media/dvb/frontends/cx24113.h b/linux/drivers/media/dvb/frontends/cx24113.h
index d549041b2..5de0f7ffd 100644
--- a/linux/drivers/media/dvb/frontends/cx24113.h
+++ b/linux/drivers/media/dvb/frontends/cx24113.h
@@ -16,7 +16,7 @@
*
* 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.=
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef CX24113_H
@@ -30,10 +30,8 @@ struct cx24113_config {
u32 xtal_khz;
};
-/* TODO: #if defined(CONFIG_DVB_TUNER_CX24113) || \
- * (defined(CONFIG_DVB_TUNER_CX24113_MODULE) && defined(MODULE)) */
-
-#if 0
+#if defined(CONFIG_DVB_TUNER_CX24113) || \
+ (defined(CONFIG_DVB_TUNER_CX24113_MODULE) && defined(MODULE))
extern struct dvb_frontend *cx24113_attach(struct dvb_frontend *,
const struct cx24113_config *config, struct i2c_adapter *i2c);
diff --git a/linux/drivers/media/video/cx18/cx18-av-vbi.c b/linux/drivers/media/video/cx18/cx18-av-vbi.c
index 02fdf57bb..1527ea4f6 100644
--- a/linux/drivers/media/video/cx18/cx18-av-vbi.c
+++ b/linux/drivers/media/video/cx18/cx18-av-vbi.c
@@ -141,10 +141,11 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
u8 lcr[24];
fmt = arg;
- if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+ if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE &&
+ fmt->type != V4L2_BUF_TYPE_VBI_CAPTURE)
return -EINVAL;
svbi = &fmt->fmt.sliced;
- if (svbi->service_set == 0) {
+ if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
/* raw VBI */
memset(svbi, 0, sizeof(*svbi));
diff --git a/linux/drivers/media/video/cx18/cx18-cards.c b/linux/drivers/media/video/cx18/cx18-cards.c
index 23bd871b7..10cddba3e 100644
--- a/linux/drivers/media/video/cx18/cx18-cards.c
+++ b/linux/drivers/media/video/cx18/cx18-cards.c
@@ -51,7 +51,7 @@ static struct cx18_card_tuner_i2c cx18_i2c_std = {
static const struct cx18_card cx18_card_hvr1600_esmt = {
.type = CX18_CARD_HVR_1600_ESMT,
.name = "Hauppauge HVR-1600",
- .comment = "VBI is not yet supported\n",
+ .comment = "Raw VBI supported; Sliced VBI is not yet supported\n",
.v4l2_capabilities = CX18_CAP_ENCODER,
.hw_audio_ctrl = CX18_HW_CX23418,
.hw_muxer = CX18_HW_CS5345,
@@ -97,7 +97,7 @@ static const struct cx18_card cx18_card_hvr1600_esmt = {
static const struct cx18_card cx18_card_hvr1600_samsung = {
.type = CX18_CARD_HVR_1600_SAMSUNG,
.name = "Hauppauge HVR-1600 (Preproduction)",
- .comment = "VBI is not yet supported\n",
+ .comment = "Raw VBI supported; Sliced VBI is not yet supported\n",
.v4l2_capabilities = CX18_CAP_ENCODER,
.hw_audio_ctrl = CX18_HW_CX23418,
.hw_muxer = CX18_HW_CS5345,
@@ -152,7 +152,7 @@ static const struct cx18_card_pci_info cx18_pci_h900[] = {
static const struct cx18_card cx18_card_h900 = {
.type = CX18_CARD_COMPRO_H900,
.name = "Compro VideoMate H900",
- .comment = "VBI is not yet supported\n",
+ .comment = "Raw VBI supported; Sliced VBI is not yet supported\n",
.v4l2_capabilities = CX18_CAP_ENCODER,
.hw_audio_ctrl = CX18_HW_CX23418,
.hw_all = CX18_HW_TUNER,
@@ -249,7 +249,7 @@ static const struct cx18_card_pci_info cx18_pci_cnxt_raptor_pal[] = {
static const struct cx18_card cx18_card_cnxt_raptor_pal = {
.type = CX18_CARD_CNXT_RAPTOR_PAL,
.name = "Conexant Raptor PAL/SECAM",
- .comment = "VBI is not yet supported\n",
+ .comment = "Raw VBI supported; Sliced VBI is not yet supported\n",
.v4l2_capabilities = CX18_CAP_ENCODER,
.hw_audio_ctrl = CX18_HW_CX23418,
.hw_muxer = CX18_HW_GPIO,
diff --git a/linux/drivers/media/video/cx18/cx18-cards.h b/linux/drivers/media/video/cx18/cx18-cards.h
index a54aae9ed..6fa7bcb42 100644
--- a/linux/drivers/media/video/cx18/cx18-cards.h
+++ b/linux/drivers/media/video/cx18/cx18-cards.h
@@ -48,8 +48,9 @@
/* V4L2 capability aliases */
#define CX18_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \
- V4L2_CAP_AUDIO | V4L2_CAP_READWRITE)
-/* | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE) not yet */
+ V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | \
+ V4L2_CAP_VBI_CAPTURE)
+/* | V4L2_CAP_SLICED_VBI_CAPTURE) not yet */
struct cx18_card_video_input {
u8 video_type; /* video input type */
diff --git a/linux/drivers/media/video/cx18/cx18-driver.c b/linux/drivers/media/video/cx18/cx18-driver.c
index 1fa9a670b..cea4735b6 100644
--- a/linux/drivers/media/video/cx18/cx18-driver.c
+++ b/linux/drivers/media/video/cx18/cx18-driver.c
@@ -56,9 +56,6 @@ struct cx18 *cx18_cards[CX18_MAX_CARDS];
/* Protects cx18_cards_active */
DEFINE_SPINLOCK(cx18_cards_lock);
-/* Queue for deferrable IRQ handling work for all cx18 cards in system */
-struct workqueue_struct *cx18_work_queue;
-
/* add your revision and whatnot here */
static struct pci_device_id cx18_pci_tbl[] __devinitdata = {
{PCI_VENDOR_ID_CX, PCI_DEVICE_ID_CX23418,
@@ -86,12 +83,28 @@ static char secam[] = "--";
static char ntsc[] = "-";
/* Buffers */
-static int enc_mpg_buffers = CX18_DEFAULT_ENC_MPG_BUFFERS;
static int enc_ts_buffers = CX18_DEFAULT_ENC_TS_BUFFERS;
+static int enc_mpg_buffers = CX18_DEFAULT_ENC_MPG_BUFFERS;
+static int enc_idx_buffers = CX18_DEFAULT_ENC_IDX_BUFFERS;
static int enc_yuv_buffers = CX18_DEFAULT_ENC_YUV_BUFFERS;
static int enc_vbi_buffers = CX18_DEFAULT_ENC_VBI_BUFFERS;
static int enc_pcm_buffers = CX18_DEFAULT_ENC_PCM_BUFFERS;
+static int enc_ts_bufsize = CX18_DEFAULT_ENC_TS_BUFSIZE;
+static int enc_mpg_bufsize = CX18_DEFAULT_ENC_MPG_BUFSIZE;
+static int enc_idx_bufsize = CX18_DEFAULT_ENC_IDX_BUFSIZE;
+static int enc_yuv_bufsize = CX18_DEFAULT_ENC_YUV_BUFSIZE;
+/* VBI bufsize based on standards supported by card tuner for now */
+static int enc_pcm_bufsize = CX18_DEFAULT_ENC_PCM_BUFSIZE;
+
+static int enc_ts_bufs = -1;
+static int enc_mpg_bufs = -1;
+static int enc_idx_bufs = -1;
+static int enc_yuv_bufs = -1;
+static int enc_vbi_bufs = -1;
+static int enc_pcm_bufs = -1;
+
+
static int cx18_pci_latency = 1;
static int mmio_ndelay;
@@ -111,12 +124,27 @@ module_param(retry_mmio, int, 0644);
module_param(cx18_pci_latency, int, 0644);
module_param(cx18_first_minor, int, 0644);
-module_param(enc_mpg_buffers, int, 0644);
module_param(enc_ts_buffers, int, 0644);
+module_param(enc_mpg_buffers, int, 0644);
+module_param(enc_idx_buffers, int, 0644);
module_param(enc_yuv_buffers, int, 0644);
module_param(enc_vbi_buffers, int, 0644);
module_param(enc_pcm_buffers, int, 0644);
+module_param(enc_ts_bufsize, int, 0644);
+module_param(enc_mpg_bufsize, int, 0644);
+module_param(enc_idx_bufsize, int, 0644);
+module_param(enc_yuv_bufsize, int, 0644);
+/* VBI bufsize based on standards supported by card tuner for now */
+module_param(enc_pcm_bufsize, int, 0644);
+
+module_param(enc_ts_bufs, int, 0644);
+module_param(enc_mpg_bufs, int, 0644);
+module_param(enc_idx_bufs, int, 0644);
+module_param(enc_yuv_bufs, int, 0644);
+module_param(enc_vbi_bufs, int, 0644);
+module_param(enc_pcm_bufs, int, 0644);
+
MODULE_PARM_DESC(tuner, "Tuner type selection,\n"
"\t\t\tsee tuner.h for values");
MODULE_PARM_DESC(radio,
@@ -157,21 +185,57 @@ MODULE_PARM_DESC(retry_mmio,
MODULE_PARM_DESC(mmio_ndelay,
"(Deprecated) MMIO accesses are now never purposely delayed\n"
"\t\t\tEffectively: 0 ns");
-MODULE_PARM_DESC(enc_mpg_buffers,
- "Encoder MPG Buffers (in MB)\n"
- "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFFERS));
MODULE_PARM_DESC(enc_ts_buffers,
- "Encoder TS Buffers (in MB)\n"
+ "Encoder TS buffer memory (MB). (enc_ts_bufs can override)\n"
"\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_TS_BUFFERS));
+MODULE_PARM_DESC(enc_ts_bufsize,
+ "Size of an encoder TS buffer (kB)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_TS_BUFSIZE));
+MODULE_PARM_DESC(enc_ts_bufs,
+ "Number of encoder TS buffers\n"
+ "\t\t\tDefault is computed from other enc_ts_* parameters");
+MODULE_PARM_DESC(enc_mpg_buffers,
+ "Encoder MPG buffer memory (MB). (enc_mpg_bufs can override)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFFERS));
+MODULE_PARM_DESC(enc_mpg_bufsize,
+ "Size of an encoder MPG buffer (kB)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFSIZE));
+MODULE_PARM_DESC(enc_mpg_bufs,
+ "Number of encoder MPG buffers\n"
+ "\t\t\tDefault is computed from other enc_mpg_* parameters");
+MODULE_PARM_DESC(enc_idx_buffers,
+ "Encoder IDX buffer memory (MB). (enc_idx_bufs can override)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_IDX_BUFFERS));
+MODULE_PARM_DESC(enc_idx_bufsize,
+ "Size of an encoder IDX buffer (kB)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_IDX_BUFSIZE));
+MODULE_PARM_DESC(enc_idx_bufs,
+ "Number of encoder IDX buffers\n"
+ "\t\t\tDefault is computed from other enc_idx_* parameters");
MODULE_PARM_DESC(enc_yuv_buffers,
- "Encoder YUV Buffers (in MB)\n"
+ "Encoder YUV buffer memory (MB). (enc_yuv_bufs can override)\n"
"\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFFERS));
+MODULE_PARM_DESC(enc_yuv_bufsize,
+ "Size of an encoder YUV buffer (kB)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFSIZE));
+MODULE_PARM_DESC(enc_yuv_bufs,
+ "Number of encoder YUV buffers\n"
+ "\t\t\tDefault is computed from other enc_yuv_* parameters");
MODULE_PARM_DESC(enc_vbi_buffers,
- "Encoder VBI Buffers (in MB)\n"
+ "Encoder VBI buffer memory (MB). (enc_vbi_bufs can override)\n"
"\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_VBI_BUFFERS));
+MODULE_PARM_DESC(enc_vbi_bufs,
+ "Number of encoder VBI buffers\n"
+ "\t\t\tDefault is computed from enc_vbi_buffers & tuner std");
MODULE_PARM_DESC(enc_pcm_buffers,
- "Encoder PCM buffers (in MB)\n"
+ "Encoder PCM buffer memory (MB). (enc_pcm_bufs can override)\n"
"\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFFERS));
+MODULE_PARM_DESC(enc_pcm_bufsize,
+ "Size of an encoder PCM buffer (kB)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFSIZE));
+MODULE_PARM_DESC(enc_pcm_bufs,
+ "Number of encoder PCM buffers\n"
+ "\t\t\tDefault is computed from other enc_pcm_* parameters");
MODULE_PARM_DESC(cx18_first_minor, "Set kernel number assigned to first card");
@@ -364,11 +428,65 @@ static void cx18_process_options(struct cx18 *cx)
{
int i, j;
- cx->options.megabytes[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers;
cx->options.megabytes[CX18_ENC_STREAM_TYPE_TS] = enc_ts_buffers;
+ cx->options.megabytes[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers;
+ cx->options.megabytes[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_buffers;
cx->options.megabytes[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers;
cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers;
cx->options.megabytes[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers;
+ cx->options.megabytes[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control only */
+
+ cx->stream_buffers[CX18_ENC_STREAM_TYPE_TS] = enc_ts_bufs;
+ cx->stream_buffers[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_bufs;
+ cx->stream_buffers[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_bufs;
+ cx->stream_buffers[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_bufs;
+ cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_bufs;
+ cx->stream_buffers[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_bufs;
+ cx->stream_buffers[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control, no data */
+
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_TS] = enc_ts_bufsize;
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_bufsize;
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_bufsize;
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_bufsize;
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = 0; /* computed later */
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_bufsize;
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control no data */
+
+ /* Except for VBI ensure stream_buffers & stream_buf_size are valid */
+ for (i = 0; i < CX18_MAX_STREAMS; i++) {
+ /* User said to use 0 buffers */
+ if (cx->stream_buffers[i] == 0) {
+ cx->options.megabytes[i] = 0;
+ cx->stream_buf_size[i] = 0;
+ continue;
+ }
+ /* User said to use 0 MB total */
+ if (cx->options.megabytes[i] <= 0) {
+ cx->options.megabytes[i] = 0;
+ cx->stream_buffers[i] = 0;
+ cx->stream_buf_size[i] = 0;
+ continue;
+ }
+ /* VBI is computed later or user said buffer has size 0 */
+ if (cx->stream_buf_size[i] <= 0) {
+ if (i != CX18_ENC_STREAM_TYPE_VBI) {
+ cx->options.megabytes[i] = 0;
+ cx->stream_buffers[i] = 0;
+ cx->stream_buf_size[i] = 0;
+ }
+ continue;
+ }
+ if (cx->stream_buffers[i] < 0) {
+ cx->stream_buffers[i] = cx->options.megabytes[i] * 1024
+ / cx->stream_buf_size[i];
+ } else {
+ /* N.B. This might round down to 0 */
+ cx->options.megabytes[i] =
+ cx->stream_buffers[i] * cx->stream_buf_size[i] / 1024;
+ }
+ cx->stream_buf_size[i] *= 1024; /* convert from kB to bytes */
+ }
+
cx->options.cardtype = cardtype[cx->num];
cx->options.tuner = tuner[cx->num];
cx->options.radio = radio[cx->num];
@@ -446,6 +564,12 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
spin_lock_init(&cx->lock);
+ cx->work_queue = create_singlethread_workqueue(cx->name);
+ if (cx->work_queue == NULL) {
+ CX18_ERR("Unable to create work hander thread\n");
+ return -ENOMEM;
+ }
+
for (i = 0; i < CX18_MAX_EPU_WORK_ORDERS; i++) {
cx->epu_work_order[i].cx = cx;
cx->epu_work_order[i].str = cx->epu_debug_str;
@@ -475,15 +599,49 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
init_waitqueue_head(&cx->dma_waitq);
/* VBI */
- cx->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
+ cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
cx->vbi.sliced_in = &cx->vbi.in.fmt.sliced;
- cx->vbi.raw_size = 1456;
- cx->vbi.raw_decoder_line_size = 1456;
- cx->vbi.raw_decoder_sav_odd_field = 0x20;
- cx->vbi.raw_decoder_sav_even_field = 0x60;
- cx->vbi.sliced_decoder_line_size = 272;
- cx->vbi.sliced_decoder_sav_odd_field = 0xB0;
- cx->vbi.sliced_decoder_sav_even_field = 0xF0;
+
+ /*
+ * The VBI line sizes depend on the pixel clock and the horiz rate
+ *
+ * (1/Fh)*(2*Fp) = Samples/line
+ * = 4 bytes EAV + Anc data in hblank + 4 bytes SAV + active samples
+ *
+ * Sliced VBI is sent as ancillary data during horizontal blanking
+ * Raw VBI is sent as active video samples during vertcal blanking
+ *
+ * We use a BT.656 pxiel clock of 13.5 MHz and a BT.656 active line
+ * length of 720 pixels @ 4:2:2 sampling. Thus...
+ *
+ * For NTSC:
+ *
+ * (1/15,734 kHz) * 2 * 13.5 MHz = 1716 samples/line =
+ * 4 bytes SAV + 268 bytes anc data + 4 bytes SAV + 1440 active samples
+ *
+ * For PAL:
+ *
+ * (1/15,625 kHz) * 2 * 13.5 MHz = 1728 samples/line =
+ * 4 bytes SAV + 280 bytes anc data + 4 bytes SAV + 1440 active samples
+ *
+ */
+
+ /* CX18-AV-Core number of VBI samples output per horizontal line */
+ cx->vbi.raw_decoder_line_size = 1444; /* 4 byte SAV + 2 * 720 */
+ cx->vbi.sliced_decoder_line_size = 272; /* 60 Hz: 268+4, 50 Hz: 280+4 */
+
+ /* CX18-AV-Core VBI samples/line possibly rounded up */
+ cx->vbi.raw_size = 1444; /* Real max size is 1444 */
+ cx->vbi.sliced_size = 284; /* Real max size is 284 */
+
+ /*
+ * CX18-AV-Core SAV/EAV RP codes in VIP 1.x mode
+ * Task Field VerticalBlank HorizontalBlank 0 0 0 0
+ */
+ cx->vbi.raw_decoder_sav_odd_field = 0x20; /* V */
+ cx->vbi.raw_decoder_sav_even_field = 0x60; /* FV */
+ cx->vbi.sliced_decoder_sav_odd_field = 0xB0; /* T VH - actually EAV */
+ cx->vbi.sliced_decoder_sav_even_field = 0xF0; /* TFVH - actually EAV */
return 0;
}
@@ -516,6 +674,7 @@ static void __devinit cx18_init_struct2(struct cx18 *cx)
cx->av_state.aud_input = CX18_AV_AUDIO8;
cx->av_state.audclk_freq = 48000;
cx->av_state.audmode = V4L2_TUNER_MODE_LANG1;
+ /* FIXME - 8 is NTSC value, investigate */
cx->av_state.vbi_line_offset = 8;
}
@@ -660,12 +819,9 @@ static int __devinit cx18_probe(struct pci_dev *dev,
/* PCI Device Setup */
retval = cx18_setup_pci(cx, dev, pci_id);
- if (retval != 0) {
- if (retval == -EIO)
- goto free_workqueue;
- else if (retval == -ENXIO)
- goto free_mem;
- }
+ if (retval != 0)
+ goto free_workqueue;
+
/* save cx in the pci struct for later use */
pci_set_drvdata(dev, cx);
@@ -773,13 +929,18 @@ static int __devinit cx18_probe(struct pci_dev *dev,
}
cx->params.video_gop_size = cx->is_60hz ? 15 : 12;
- cx->stream_buf_size[CX18_ENC_STREAM_TYPE_MPG] = 0x08000;
- cx->stream_buf_size[CX18_ENC_STREAM_TYPE_TS] = 0x08000;
- cx->stream_buf_size[CX18_ENC_STREAM_TYPE_PCM] = 0x01200;
- cx->stream_buf_size[CX18_ENC_STREAM_TYPE_YUV] = 0x20000;
vbi_buf_size = cx->vbi.raw_size * (cx->is_60hz ? 24 : 36) / 2;
cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = vbi_buf_size;
+ if (cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] < 0)
+ cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] =
+ cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] * 1024 * 1024
+ / vbi_buf_size;
+ else
+ cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] =
+ cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] * vbi_buf_size
+ / (1024 * 1024);
+
if (cx->options.radio > 0)
cx->v4l2_cap |= V4L2_CAP_RADIO;
@@ -835,6 +996,7 @@ free_map:
free_mem:
release_mem_region(cx->base_addr, CX18_MEM_SIZE);
free_workqueue:
+ destroy_workqueue(cx->work_queue);
err:
if (retval == 0)
retval = -ENODEV;
@@ -917,6 +1079,7 @@ int cx18_init_on_first_open(struct cx18 *cx)
return 0;
}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
static void cx18_cancel_epu_work_orders(struct cx18 *cx)
{
int i;
@@ -924,6 +1087,7 @@ static void cx18_cancel_epu_work_orders(struct cx18 *cx)
cancel_work_sync(&cx->epu_work_order[i].work);
}
+#endif
static void cx18_remove(struct pci_dev *pci_dev)
{
struct cx18 *cx = pci_get_drvdata(pci_dev);
@@ -937,11 +1101,22 @@ static void cx18_remove(struct pci_dev *pci_dev)
/* Interrupts */
cx18_sw1_irq_disable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
cx18_sw2_irq_disable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
cx18_halt_firmware(cx);
cx18_cancel_epu_work_orders(cx);
+#else
+
+ flush_workqueue(cx->work_queue);
+
+ cx18_sw2_irq_disable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
+
+ cx18_halt_firmware(cx);
+#endif
+
+ destroy_workqueue(cx->work_queue);
cx18_streams_cleanup(cx, 1);
@@ -984,17 +1159,8 @@ static int module_start(void)
printk(KERN_INFO "cx18: Debug value must be >= 0 and <= 511!\n");
}
- cx18_work_queue = create_singlethread_workqueue("cx18");
- if (cx18_work_queue == NULL) {
- printk(KERN_ERR
- "cx18: Unable to create work hander thread\n");
- return -ENOMEM;
- }
-
if (pci_register_driver(&cx18_pci_driver)) {
printk(KERN_ERR "cx18: Error detecting PCI card\n");
- destroy_workqueue(cx18_work_queue);
- cx18_work_queue = NULL;
return -ENODEV;
}
printk(KERN_INFO "cx18: End initialization\n");
@@ -1007,9 +1173,6 @@ static void module_cleanup(void)
pci_unregister_driver(&cx18_pci_driver);
- destroy_workqueue(cx18_work_queue);
- cx18_work_queue = NULL;
-
for (i = 0; i < cx18_cards_active; i++) {
if (cx18_cards[i] == NULL)
continue;
diff --git a/linux/drivers/media/video/cx18/cx18-driver.h b/linux/drivers/media/video/cx18/cx18-driver.h
index ca1f43781..018d98f94 100644
--- a/linux/drivers/media/video/cx18/cx18-driver.h
+++ b/linux/drivers/media/video/cx18/cx18-driver.h
@@ -115,6 +115,17 @@
#define CX18_DEFAULT_ENC_VBI_BUFFERS 1
#define CX18_DEFAULT_ENC_PCM_BUFFERS 1
+/* Maximum firmware DMA buffers per stream */
+#define CX18_MAX_MDLS_PER_STREAM 63
+
+/* DMA buffer, default size in kB allocated */
+#define CX18_DEFAULT_ENC_TS_BUFSIZE 32
+#define CX18_DEFAULT_ENC_MPG_BUFSIZE 32
+#define CX18_DEFAULT_ENC_IDX_BUFSIZE 32
+#define CX18_DEFAULT_ENC_YUV_BUFSIZE 128
+/* Default VBI bufsize based on standards supported by card tuner for now */
+#define CX18_DEFAULT_ENC_PCM_BUFSIZE 4
+
/* i2c stuff */
#define I2C_CLIENTS_MAX 16
@@ -289,8 +300,8 @@ struct cx18_stream {
/* Buffer Queues */
struct cx18_queue q_free; /* free buffers */
- struct cx18_queue q_full; /* full buffers */
- struct cx18_queue q_io; /* waiting for I/O */
+ struct cx18_queue q_busy; /* busy buffers - in use by firmware */
+ struct cx18_queue q_full; /* full buffers - data for user apps */
/* DVB / Digital Transport */
struct cx18_dvb dvb;
@@ -408,6 +419,7 @@ struct cx18 {
struct mutex serialize_lock; /* mutex used to serialize open/close/start/stop/ioctl operations */
struct cx18_options options; /* User options */
+ int stream_buffers[CX18_MAX_STREAMS]; /* # of buffers for each stream */
int stream_buf_size[CX18_MAX_STREAMS]; /* Stream buffer size */
struct cx18_stream streams[CX18_MAX_STREAMS]; /* Stream data */
unsigned long i_flags; /* global cx18 flags */
@@ -447,6 +459,7 @@ struct cx18 {
u32 sw2_irq_mask;
u32 hw2_irq_mask;
+ struct workqueue_struct *work_queue;
struct cx18_epu_work_order epu_work_order[CX18_MAX_EPU_WORK_ORDERS];
char epu_debug_str[256]; /* CX18_EPU_DEBUG is rare: use shared space */
@@ -478,7 +491,6 @@ extern struct cx18 *cx18_cards[];
extern int cx18_cards_active;
extern int cx18_first_minor;
extern spinlock_t cx18_cards_lock;
-extern struct workqueue_struct *cx18_work_queue;
/*==============Prototypes==================*/
@@ -492,4 +504,10 @@ void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv);
/* First-open initialization: load firmware, etc. */
int cx18_init_on_first_open(struct cx18 *cx);
+/* Test if the current VBI mode is raw (1) or sliced (0) */
+static inline int cx18_raw_vbi(const struct cx18 *cx)
+{
+ return cx->vbi.in.type == V4L2_BUF_TYPE_VBI_CAPTURE;
+}
+
#endif /* CX18_DRIVER_H */
diff --git a/linux/drivers/media/video/cx18/cx18-dvb.c b/linux/drivers/media/video/cx18/cx18-dvb.c
index 034e09a37..bd5e6f3fd 100644
--- a/linux/drivers/media/video/cx18/cx18-dvb.c
+++ b/linux/drivers/media/video/cx18/cx18-dvb.c
@@ -217,6 +217,10 @@ int cx18_dvb_register(struct cx18_stream *stream)
dvb_net_init(dvb_adapter, &dvb->dvbnet, dmx);
CX18_INFO("DVB Frontend registered\n");
+ CX18_INFO("Registered DVB adapter%d for %s (%d x %d kB)\n",
+ stream->dvb.dvb_adapter.num, stream->name,
+ stream->buffers, stream->buf_size/1024);
+
mutex_init(&dvb->feedlock);
dvb->enabled = 1;
return ret;
diff --git a/linux/drivers/media/video/cx18/cx18-fileops.c b/linux/drivers/media/video/cx18/cx18-fileops.c
index 45b5f402e..ef4589ef6 100644
--- a/linux/drivers/media/video/cx18/cx18-fileops.c
+++ b/linux/drivers/media/video/cx18/cx18-fileops.c
@@ -67,12 +67,11 @@ static int cx18_claim_stream(struct cx18_open_id *id, int type)
}
s->id = id->open_id;
- /* CX18_DEC_STREAM_TYPE_MPG needs to claim CX18_DEC_STREAM_TYPE_VBI,
- CX18_ENC_STREAM_TYPE_MPG needs to claim CX18_ENC_STREAM_TYPE_VBI
+ /* CX18_ENC_STREAM_TYPE_MPG needs to claim CX18_ENC_STREAM_TYPE_VBI
(provided VBI insertion is on and sliced VBI is selected), for all
other streams we're done */
if (type == CX18_ENC_STREAM_TYPE_MPG &&
- cx->vbi.insert_mpeg && cx->vbi.sliced_in->service_set) {
+ cx->vbi.insert_mpeg && !cx18_raw_vbi(cx)) {
vbi_type = CX18_ENC_STREAM_TYPE_VBI;
} else {
return 0;
@@ -224,8 +223,10 @@ static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block,
!test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) {
while ((buf = cx18_dequeue(s_vbi, &s_vbi->q_full))) {
/* byteswap and process VBI data */
-/* cx18_process_vbi_data(cx, buf, s_vbi->dma_pts, s_vbi->type); */
- cx18_enqueue(s_vbi, buf, &s_vbi->q_free);
+ cx18_process_vbi_data(cx, buf,
+ s_vbi->dma_pts,
+ s_vbi->type);
+ cx18_stream_put_buf_fw(s_vbi, buf);
}
}
buf = &cx->vbi.sliced_mpeg_buf;
@@ -233,11 +234,6 @@ static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block,
return buf;
}
- /* do we have leftover data? */
- buf = cx18_dequeue(s, &s->q_io);
- if (buf)
- return buf;
-
/* do we have new data? */
buf = cx18_dequeue(s, &s->q_full);
if (buf) {
@@ -301,7 +297,7 @@ static size_t cx18_copy_buf_to_user(struct cx18_stream *s,
if (len > ucount)
len = ucount;
if (cx->vbi.insert_mpeg && s->type == CX18_ENC_STREAM_TYPE_MPG &&
- cx->vbi.sliced_in->service_set && buf != &cx->vbi.sliced_mpeg_buf) {
+ !cx18_raw_vbi(cx) && buf != &cx->vbi.sliced_mpeg_buf) {
const char *start = buf->buf + buf->readpos;
const char *p = start + 1;
const u8 *q;
@@ -376,8 +372,7 @@ static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf,
/* Each VBI buffer is one frame, the v4l2 API says that for VBI the
frames should arrive one-by-one, so make sure we never output more
than one VBI frame at a time */
- if (s->type == CX18_ENC_STREAM_TYPE_VBI &&
- cx->vbi.sliced_in->service_set)
+ if (s->type == CX18_ENC_STREAM_TYPE_VBI && !cx18_raw_vbi(cx))
single_frame = 1;
for (;;) {
@@ -404,16 +399,10 @@ static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf,
tot_count - tot_written);
if (buf != &cx->vbi.sliced_mpeg_buf) {
- if (buf->readpos == buf->bytesused) {
- cx18_buf_sync_for_device(s, buf);
- cx18_enqueue(s, buf, &s->q_free);
- cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5,
- s->handle,
- (void __iomem *)&cx->scb->cpu_mdl[buf->id] -
- cx->enc_mem,
- 1, buf->id, s->buf_size);
- } else
- cx18_enqueue(s, buf, &s->q_io);
+ if (buf->readpos == buf->bytesused)
+ cx18_stream_put_buf_fw(s, buf);
+ else
+ cx18_push(s, buf, &s->q_full);
} else if (buf->readpos == buf->bytesused) {
int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES;
@@ -557,7 +546,7 @@ unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait)
CX18_DEBUG_HI_FILE("Encoder poll\n");
poll_wait(filp, &s->waitq, wait);
- if (atomic_read(&s->q_full.buffers) || atomic_read(&s->q_io.buffers))
+ if (atomic_read(&s->q_full.buffers))
return POLLIN | POLLRDNORM;
if (eof)
return POLLHUP;
diff --git a/linux/drivers/media/video/cx18/cx18-io.h b/linux/drivers/media/video/cx18/cx18-io.h
index e6716dcb1..2635b3a8c 100644
--- a/linux/drivers/media/video/cx18/cx18-io.h
+++ b/linux/drivers/media/video/cx18/cx18-io.h
@@ -83,10 +83,14 @@ void cx18_writel_expect(struct cx18 *cx, u32 val, void __iomem *addr,
u32 eval, u32 mask)
{
int i;
+ u32 r;
eval &= mask;
for (i = 0; i < CX18_MAX_MMIO_WR_RETRIES; i++) {
cx18_writel_noretry(cx, val, addr);
- if (eval == (cx18_readl(cx, addr) & mask))
+ r = cx18_readl(cx, addr);
+ if (r == 0xffffffff && eval != 0xffffffff)
+ continue;
+ if (eval == (r & mask))
break;
}
}
diff --git a/linux/drivers/media/video/cx18/cx18-ioctl.c b/linux/drivers/media/video/cx18/cx18-ioctl.c
index 5d9c1146e..c83fcc0c5 100644
--- a/linux/drivers/media/video/cx18/cx18-ioctl.c
+++ b/linux/drivers/media/video/cx18/cx18-ioctl.c
@@ -284,13 +284,12 @@ static int cx18_s_fmt_vbi_cap(struct file *file, void *fh,
if (ret)
return ret;
- if (id->type == CX18_ENC_STREAM_TYPE_VBI &&
- cx->vbi.sliced_in->service_set &&
- atomic_read(&cx->ana_capturing) > 0)
+ if (!cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0)
return -EBUSY;
cx->vbi.sliced_in->service_set = 0;
- cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in);
+ cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
+ cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
return cx18_g_fmt_vbi_cap(file, fh, fmt);
}
@@ -315,9 +314,9 @@ static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh,
if (check_service_set(vbifmt, cx->is_50hz) == 0)
return -EINVAL;
- if (atomic_read(&cx->ana_capturing) > 0 &&
- cx->vbi.sliced_in->service_set == 0)
+ if (cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0)
return -EBUSY;
+ cx->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in));
return 0;
@@ -851,8 +850,7 @@ static int cx18_log_status(struct file *file, void *fh)
continue;
CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n",
s->name, s->s_flags,
- (s->buffers - atomic_read(&s->q_free.buffers))
- * 100 / s->buffers,
+ atomic_read(&s->q_full.buffers) * 100 / s->buffers,
(s->buffers * s->buf_size) / 1024, s->buffers);
}
CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n",
diff --git a/linux/drivers/media/video/cx18/cx18-mailbox.c b/linux/drivers/media/video/cx18/cx18-mailbox.c
index 8415b9683..eb5c31af6 100644
--- a/linux/drivers/media/video/cx18/cx18-mailbox.c
+++ b/linux/drivers/media/video/cx18/cx18-mailbox.c
@@ -163,7 +163,7 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_epu_work_order *order)
* it's filled in).
*
* cx18_queue_get buf() will detect the lost buffers
- * and put them back in rotation eventually.
+ * and send them back to q_free for fw rotation eventually.
*/
if ((order->flags & CX18_F_EWO_MB_STALE_UPON_RECEIPT) &&
!(id >= s->mdl_offset &&
@@ -174,33 +174,27 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_epu_work_order *order)
break;
}
buf = cx18_queue_get_buf(s, id, mdl_ack->data_used);
+
CX18_DEBUG_HI_DMA("DMA DONE for %s (buffer %d)\n", s->name, id);
if (buf == NULL) {
CX18_WARN("Could not find buf %d for stream %s\n",
id, s->name);
+ /* Put as many buffers as possible back into fw use */
+ cx18_stream_load_fw_queue(s);
continue;
}
- cx18_buf_sync_for_cpu(s, buf);
if (s->type == CX18_ENC_STREAM_TYPE_TS && s->dvb.enabled) {
CX18_DEBUG_HI_DMA("TS recv bytesused = %d\n",
buf->bytesused);
-
dvb_dmx_swfilter(&s->dvb.demux, buf->buf,
buf->bytesused);
-
- cx18_buf_sync_for_device(s, buf);
- cx18_enqueue(s, buf, &s->q_free);
-
- if (s->handle != CX18_INVALID_TASK_HANDLE &&
- test_bit(CX18_F_S_STREAMING, &s->s_flags))
- cx18_vapi(cx,
- CX18_CPU_DE_SET_MDL, 5, s->handle,
- (void __iomem *)
- &cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
- 1, buf->id, s->buf_size);
- } else
- set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags);
+ }
+ /* Put as many buffers as possible back into fw use */
+ cx18_stream_load_fw_queue(s);
+ /* Put back TS buffer, since it was removed from all queues */
+ if (s->type == CX18_ENC_STREAM_TYPE_TS)
+ cx18_stream_put_buf_fw(s, buf);
}
wake_up(&cx->dma_waitq);
if (s->id != -1)
@@ -460,7 +454,7 @@ void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu)
*/
submit = epu_cmd_irq(cx, order);
if (submit > 0) {
- queue_work(cx18_work_queue, &order->work);
+ queue_work(cx->work_queue, &order->work);
}
}
diff --git a/linux/drivers/media/video/cx18/cx18-queue.c b/linux/drivers/media/video/cx18/cx18-queue.c
index 7b09c9a3e..a6b0666f0 100644
--- a/linux/drivers/media/video/cx18/cx18-queue.c
+++ b/linux/drivers/media/video/cx18/cx18-queue.c
@@ -42,21 +42,32 @@ void cx18_queue_init(struct cx18_queue *q)
q->bytesused = 0;
}
-void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
- struct cx18_queue *q)
+struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
+ struct cx18_queue *q, int to_front)
{
- /* clear the buffer if it is going to be enqueued to the free queue */
- if (q == &s->q_free) {
+ /* clear the buffer if it is not to be enqueued to the full queue */
+ if (q != &s->q_full) {
buf->bytesused = 0;
buf->readpos = 0;
buf->b_flags = 0;
buf->skipped = 0;
}
+
mutex_lock(&s->qlock);
- list_add_tail(&buf->list, &q->list);
- atomic_inc(&q->buffers);
+
+ /* q_busy is restricted to 63 buffers to stay within firmware limits */
+ if (q == &s->q_busy && atomic_read(&q->buffers) >= 63)
+ q = &s->q_free;
+
+ if (to_front)
+ list_add(&buf->list, &q->list); /* LIFO */
+ else
+ list_add_tail(&buf->list, &q->list); /* FIFO */
q->bytesused += buf->bytesused - buf->readpos;
+ atomic_inc(&q->buffers);
+
mutex_unlock(&s->qlock);
+ return q;
}
struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q)
@@ -67,9 +78,9 @@ struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q)
if (!list_empty(&q->list)) {
buf = list_entry(q->list.next, struct cx18_buffer, list);
list_del_init(q->list.next);
- atomic_dec(&q->buffers);
q->bytesused -= buf->bytesused - buf->readpos;
buf->skipped = 0;
+ atomic_dec(&q->buffers);
}
mutex_unlock(&s->qlock);
return buf;
@@ -82,59 +93,51 @@ struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id,
struct cx18_buffer *buf;
struct cx18_buffer *ret = NULL;
struct list_head *p, *t;
- LIST_HEAD(r);
mutex_lock(&s->qlock);
- list_for_each_safe(p, t, &s->q_free.list) {
+ list_for_each_safe(p, t, &s->q_busy.list) {
buf = list_entry(p, struct cx18_buffer, list);
if (buf->id != id) {
buf->skipped++;
- if (buf->skipped >= atomic_read(&s->q_free.buffers)-1) {
+ if (buf->skipped >= atomic_read(&s->q_busy.buffers)-1) {
/* buffer must have fallen out of rotation */
- atomic_dec(&s->q_free.buffers);
- list_move_tail(&buf->list, &r);
CX18_WARN("Skipped %s, buffer %d, %d "
"times - it must have dropped out of "
"rotation\n", s->name, buf->id,
buf->skipped);
+ /* move it to q_free */
+ list_move_tail(&buf->list, &s->q_free.list);
+ buf->bytesused = buf->readpos = buf->b_flags =
+ buf->skipped = 0;
+ atomic_dec(&s->q_busy.buffers);
+ atomic_inc(&s->q_free.buffers);
}
continue;
}
buf->bytesused = bytesused;
- atomic_dec(&s->q_free.buffers);
+ /* Sync the buffer before we release the qlock */
+ cx18_buf_sync_for_cpu(s, buf);
if (s->type == CX18_ENC_STREAM_TYPE_TS) {
/*
- * TS doesn't use q_full, but for sweeping up lost
- * buffers, we want the TS to requeue the buffer just
- * before sending the MDL back to the firmware, so we
- * pull it off the list here.
+ * TS doesn't use q_full. As we pull the buffer off of
+ * the queue here, the caller will have to put it back.
*/
list_del_init(&buf->list);
} else {
- atomic_inc(&s->q_full.buffers);
- s->q_full.bytesused += buf->bytesused;
+ /* Move buffer from q_busy to q_full */
list_move_tail(&buf->list, &s->q_full.list);
+ set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags);
+ s->q_full.bytesused += buf->bytesused;
+ atomic_inc(&s->q_full.buffers);
}
+ atomic_dec(&s->q_busy.buffers);
ret = buf;
break;
}
mutex_unlock(&s->qlock);
-
- /* Put lost buffers back into firmware transfer rotation */
- while (!list_empty(&r)) {
- buf = list_entry(r.next, struct cx18_buffer, list);
- list_del_init(r.next);
- cx18_enqueue(s, buf, &s->q_free);
- cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
- (void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
- 1, buf->id, s->buf_size);
- CX18_INFO("Returning %s, buffer %d back to transfer rotation\n",
- s->name, buf->id);
- /* and there was much rejoicing... */
- }
return ret;
}
@@ -159,7 +162,7 @@ static void cx18_queue_flush(struct cx18_stream *s, struct cx18_queue *q)
void cx18_flush_queues(struct cx18_stream *s)
{
- cx18_queue_flush(s, &s->q_io);
+ cx18_queue_flush(s, &s->q_busy);
cx18_queue_flush(s, &s->q_full);
}
diff --git a/linux/drivers/media/video/cx18/cx18-queue.h b/linux/drivers/media/video/cx18/cx18-queue.h
index ff50a2b7e..456cec3bc 100644
--- a/linux/drivers/media/video/cx18/cx18-queue.h
+++ b/linux/drivers/media/video/cx18/cx18-queue.h
@@ -43,9 +43,24 @@ static inline void cx18_buf_sync_for_device(struct cx18_stream *s,
void cx18_buf_swap(struct cx18_buffer *buf);
/* cx18_queue utility functions */
+struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
+ struct cx18_queue *q, int to_front);
+
+static inline
+struct cx18_queue *cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
+ struct cx18_queue *q)
+{
+ return _cx18_enqueue(s, buf, q, 0); /* FIFO */
+}
+
+static inline
+struct cx18_queue *cx18_push(struct cx18_stream *s, struct cx18_buffer *buf,
+ struct cx18_queue *q)
+{
+ return _cx18_enqueue(s, buf, q, 1); /* LIFO */
+}
+
void cx18_queue_init(struct cx18_queue *q);
-void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
- struct cx18_queue *q);
struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q);
struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id,
u32 bytesused);
diff --git a/linux/drivers/media/video/cx18/cx18-streams.c b/linux/drivers/media/video/cx18/cx18-streams.c
index f7a7f38d8..9ed542624 100644
--- a/linux/drivers/media/video/cx18/cx18-streams.c
+++ b/linux/drivers/media/video/cx18/cx18-streams.c
@@ -111,7 +111,6 @@ static void cx18_stream_init(struct cx18 *cx, int type)
{
struct cx18_stream *s = &cx->streams[type];
struct video_device *dev = s->v4l2dev;
- u32 max_size = cx->options.megabytes[type] * 1024 * 1024;
/* we need to keep v4l2dev, so restore it afterwards */
memset(s, 0, sizeof(*s));
@@ -124,21 +123,15 @@ static void cx18_stream_init(struct cx18 *cx, int type)
s->handle = CX18_INVALID_TASK_HANDLE;
s->dma = cx18_stream_info[type].dma;
+ s->buffers = cx->stream_buffers[type];
s->buf_size = cx->stream_buf_size[type];
- if (s->buf_size)
- s->buffers = max_size / s->buf_size;
- if (s->buffers > 63) {
- /* Each stream has a maximum of 63 buffers,
- ensure we do not exceed that. */
- s->buffers = 63;
- s->buf_size = (max_size / s->buffers) & ~0xfff;
- }
+
mutex_init(&s->qlock);
init_waitqueue_head(&s->waitq);
s->id = -1;
cx18_queue_init(&s->q_free);
+ cx18_queue_init(&s->q_busy);
cx18_queue_init(&s->q_full);
- cx18_queue_init(&s->q_io);
}
static int cx18_prep_dev(struct cx18 *cx, int type)
@@ -168,7 +161,7 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
/* User explicitly selected 0 buffers for these streams, so don't
create them. */
if (cx18_stream_info[type].dma != PCI_DMA_NONE &&
- cx->options.megabytes[type] == 0) {
+ cx->stream_buffers[type] == 0) {
CX18_INFO("Disabled %s device\n", cx18_stream_info[type].name);
return 0;
}
@@ -268,8 +261,9 @@ static int cx18_reg_dev(struct cx18 *cx, int type)
switch (vfl_type) {
case VFL_TYPE_GRABBER:
- CX18_INFO("Registered device video%d for %s (%d MB)\n",
- num, s->name, cx->options.megabytes[type]);
+ CX18_INFO("Registered device video%d for %s (%d x %d kB)\n",
+ num, s->name, cx->stream_buffers[type],
+ cx->stream_buf_size[type]/1024);
break;
case VFL_TYPE_RADIO:
@@ -278,10 +272,11 @@ static int cx18_reg_dev(struct cx18 *cx, int type)
break;
case VFL_TYPE_VBI:
- if (cx->options.megabytes[type])
- CX18_INFO("Registered device vbi%d for %s (%d MB)\n",
- num,
- s->name, cx->options.megabytes[type]);
+ if (cx->stream_buffers[type])
+ CX18_INFO("Registered device vbi%d for %s "
+ "(%d x %d bytes)\n",
+ num, s->name, cx->stream_buffers[type],
+ cx->stream_buf_size[type]);
else
CX18_INFO("Registered device vbi%d for %s\n",
num, s->name);
@@ -345,7 +340,7 @@ void cx18_streams_cleanup(struct cx18 *cx, int unregister)
static void cx18_vbi_setup(struct cx18_stream *s)
{
struct cx18 *cx = s->cx;
- int raw = cx->vbi.sliced_in->service_set == 0;
+ int raw = cx18_raw_vbi(cx);
u32 data[CX2341X_MBOX_MAX_DATA];
int lines;
@@ -363,8 +358,7 @@ static void cx18_vbi_setup(struct cx18_stream *s)
cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in);
/* determine number of lines and total number of VBI bytes.
- A raw line takes 1443 bytes: 2 * 720 + 4 byte frame header - 1
- The '- 1' byte is probably an unused U or V byte. Or something...
+ A raw line takes 1444 bytes: 4 byte SAV code + 2 * 720
A sliced line takes 51 bytes: 4 byte frame header, 4 byte internal
header, 42 data bytes + checksum (to be confirmed) */
if (raw) {
@@ -382,14 +376,15 @@ static void cx18_vbi_setup(struct cx18_stream *s)
/* Lines per field */
data[1] = (lines / 2) | ((lines / 2) << 16);
/* bytes per line */
- data[2] = (raw ? cx->vbi.raw_size : cx->vbi.sliced_size);
+ data[2] = (raw ? cx->vbi.raw_decoder_line_size
+ : cx->vbi.sliced_decoder_line_size);
/* Every X number of frames a VBI interrupt arrives
(frames as in 25 or 30 fps) */
data[3] = 1;
/* Setup VBI for the cx25840 digitizer */
if (raw) {
data[4] = 0x20602060;
- data[5] = 0x30703070;
+ data[5] = 0x307090d0;
} else {
data[4] = 0xB0F0B0F0;
data[5] = 0xA0E0A0E0;
@@ -402,11 +397,52 @@ static void cx18_vbi_setup(struct cx18_stream *s)
cx18_api(cx, CX18_CPU_SET_RAW_VBI_PARAM, 6, data);
}
+struct cx18_queue *cx18_stream_put_buf_fw(struct cx18_stream *s,
+ struct cx18_buffer *buf)
+{
+ struct cx18 *cx = s->cx;
+ struct cx18_queue *q;
+
+ /* Don't give it to the firmware, if we're not running a capture */
+ if (s->handle == CX18_INVALID_TASK_HANDLE ||
+ !test_bit(CX18_F_S_STREAMING, &s->s_flags))
+ return cx18_enqueue(s, buf, &s->q_free);
+
+ q = cx18_enqueue(s, buf, &s->q_busy);
+ if (q != &s->q_busy)
+ return q; /* The firmware has the max buffers it can handle */
+
+ cx18_buf_sync_for_device(s, buf);
+ cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
+ (void __iomem *) &cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
+ 1, buf->id, s->buf_size);
+ return q;
+}
+
+void cx18_stream_load_fw_queue(struct cx18_stream *s)
+{
+ struct cx18_queue *q;
+ struct cx18_buffer *buf;
+
+ if (atomic_read(&s->q_free.buffers) == 0 ||
+ atomic_read(&s->q_busy.buffers) >= 63)
+ return;
+
+ /* Move from q_free to q_busy notifying the firmware, until the limit */
+ do {
+ buf = cx18_dequeue(s, &s->q_free);
+ if (buf == NULL)
+ break;
+ q = cx18_stream_put_buf_fw(s, buf);
+ } while (atomic_read(&s->q_busy.buffers) < 63 && q == &s->q_busy);
+}
+
int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
{
u32 data[MAX_MB_ARGUMENTS];
struct cx18 *cx = s->cx;
struct list_head *p;
+ struct cx18_buffer *buf;
int ts = 0;
int captype = 0;
@@ -435,8 +471,8 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
captype = CAPTURE_CHANNEL_TYPE_PCM;
break;
case CX18_ENC_STREAM_TYPE_VBI:
- captype = cx->vbi.sliced_in->service_set ?
- CAPTURE_CHANNEL_TYPE_SLICED_VBI : CAPTURE_CHANNEL_TYPE_VBI;
+ captype = cx18_raw_vbi(cx) ?
+ CAPTURE_CHANNEL_TYPE_VBI : CAPTURE_CHANNEL_TYPE_SLICED_VBI;
cx->vbi.frame = 0;
cx->vbi.inserted_frame = 0;
memset(cx->vbi.sliced_mpeg_size,
@@ -489,16 +525,18 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
(void __iomem *)&cx->scb->cpu_mdl_ack[s->type][0] - cx->enc_mem,
(void __iomem *)&cx->scb->cpu_mdl_ack[s->type][1] - cx->enc_mem);
+ /* Init all the cpu_mdls for this stream */
+ cx18_flush_queues(s);
+ mutex_lock(&s->qlock);
list_for_each(p, &s->q_free.list) {
- struct cx18_buffer *buf = list_entry(p, struct cx18_buffer, list);
-
+ buf = list_entry(p, struct cx18_buffer, list);
cx18_writel(cx, buf->dma_handle,
&cx->scb->cpu_mdl[buf->id].paddr);
cx18_writel(cx, s->buf_size, &cx->scb->cpu_mdl[buf->id].length);
- cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
- (void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
- 1, buf->id, s->buf_size);
}
+ mutex_unlock(&s->qlock);
+ cx18_stream_load_fw_queue(s);
+
/* begin_capture */
if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) {
CX18_DEBUG_WARN("Error starting capture!\n");
@@ -507,9 +545,15 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, 1);
else
cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle);
+ clear_bit(CX18_F_S_STREAMING, &s->s_flags);
+ /* FIXME - CX18_F_S_STREAMOFF as well? */
cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle);
cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle);
- /* FIXME - clean-up DSP0_INT mask, i_flags, s_flags, etc. */
+ s->handle = CX18_INVALID_TASK_HANDLE;
+ if (atomic_read(&cx->tot_capturing) == 0) {
+ set_bit(CX18_F_I_EOS, &cx->i_flags);
+ cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK);
+ }
return -EINVAL;
}
diff --git a/linux/drivers/media/video/cx18/cx18-streams.h b/linux/drivers/media/video/cx18/cx18-streams.h
index 7218b1504..420e0a172 100644
--- a/linux/drivers/media/video/cx18/cx18-streams.h
+++ b/linux/drivers/media/video/cx18/cx18-streams.h
@@ -29,6 +29,9 @@ int cx18_streams_register(struct cx18 *cx);
void cx18_streams_cleanup(struct cx18 *cx, int unregister);
/* Capture related */
+void cx18_stream_load_fw_queue(struct cx18_stream *s);
+struct cx18_queue *cx18_stream_put_buf_fw(struct cx18_stream *s,
+ struct cx18_buffer *buf);
int cx18_start_v4l2_encode_stream(struct cx18_stream *s);
int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end);
diff --git a/linux/drivers/media/video/cx18/cx18-vbi.c b/linux/drivers/media/video/cx18/cx18-vbi.c
index 22e76ee3f..fb595bd54 100644
--- a/linux/drivers/media/video/cx18/cx18-vbi.c
+++ b/linux/drivers/media/video/cx18/cx18-vbi.c
@@ -160,11 +160,14 @@ void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
return;
/* Raw VBI data */
- if (cx->vbi.sliced_in->service_set == 0) {
+ if (cx18_raw_vbi(cx)) {
u8 type;
cx18_buf_swap(buf);
+ /* Skip 12 bytes of header that gets stuffed in */
+ size -= 12;
+ memcpy(p, &buf->buf[12], size);
type = p[3];
size = buf->bytesused = compress_raw_buf(cx, p, size);
diff --git a/linux/drivers/media/video/cx18/cx18-version.h b/linux/drivers/media/video/cx18/cx18-version.h
index eb043d599..84c0ff13b 100644
--- a/linux/drivers/media/video/cx18/cx18-version.h
+++ b/linux/drivers/media/video/cx18/cx18-version.h
@@ -25,7 +25,7 @@
#define CX18_DRIVER_NAME "cx18"
#define CX18_DRIVER_VERSION_MAJOR 1
#define CX18_DRIVER_VERSION_MINOR 0
-#define CX18_DRIVER_VERSION_PATCHLEVEL 3
+#define CX18_DRIVER_VERSION_PATCHLEVEL 4
#define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL)
#define CX18_DRIVER_VERSION KERNEL_VERSION(CX18_DRIVER_VERSION_MAJOR, \
diff --git a/linux/drivers/media/video/cx23885/cx23885-cards.c b/linux/drivers/media/video/cx23885/cx23885-cards.c
index dc3f79638..db1e8bdab 100644
--- a/linux/drivers/media/video/cx23885/cx23885-cards.c
+++ b/linux/drivers/media/video/cx23885/cx23885-cards.c
@@ -159,6 +159,10 @@ struct cx23885_board cx23885_boards[] = {
.name = "Leadtek Winfast PxDVR3200 H",
.portc = CX23885_MPEG_DVB,
},
+ [CX23885_BOARD_COMPRO_VIDEOMATE_E650F] = {
+ .name = "Compro VideoMate E650F",
+ .portc = CX23885_MPEG_DVB,
+ },
};
const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
@@ -238,6 +242,10 @@ struct cx23885_subid cx23885_subids[] = {
.subvendor = 0x107d,
.subdevice = 0x6681,
.card = CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H,
+ }, {
+ .subvendor = 0x185b,
+ .subdevice = 0xe800,
+ .card = CX23885_BOARD_COMPRO_VIDEOMATE_E650F,
},
};
const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -391,6 +399,7 @@ int cx23885_tuner_callback(void *priv, int component, int command, int arg)
case CX23885_BOARD_HAUPPAUGE_HVR1500:
case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+ case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
/* Tuner Reset Command */
bitmask = 0x04;
break;
@@ -531,6 +540,7 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
cx_set(GP0_IO, 0x000f000f);
break;
case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+ case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
/* GPIO-2 xc3028 tuner reset */
/* The following GPIO's are on the internal AVCore (cx25840) */
@@ -631,6 +641,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
case CX23885_BOARD_HAUPPAUGE_HVR1700:
case CX23885_BOARD_HAUPPAUGE_HVR1400:
case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+ case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
default:
ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
@@ -645,6 +656,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
case CX23885_BOARD_HAUPPAUGE_HVR1700:
case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+ case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
request_module("cx25840");
break;
}
diff --git a/linux/drivers/media/video/cx23885/cx23885-dvb.c b/linux/drivers/media/video/cx23885/cx23885-dvb.c
index a11fdbfb5..990fd217b 100644
--- a/linux/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/linux/drivers/media/video/cx23885/cx23885-dvb.c
@@ -503,6 +503,7 @@ static int dvb_register(struct cx23885_tsport *port)
break;
}
case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+ case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
i2c_bus = &dev->i2c_bus[0];
fe0->dvb.frontend = dvb_attach(zl10353_attach,
diff --git a/linux/drivers/media/video/cx23885/cx23885.h b/linux/drivers/media/video/cx23885/cx23885.h
index 26f755354..ad93e0e88 100644
--- a/linux/drivers/media/video/cx23885/cx23885.h
+++ b/linux/drivers/media/video/cx23885/cx23885.h
@@ -67,6 +67,7 @@
#define CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP 10
#define CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP 11
#define CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H 12
+#define CX23885_BOARD_COMPRO_VIDEOMATE_E650F 13
/* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */
#define CX23885_NORMS (\
diff --git a/linux/drivers/media/video/cx88/cx88-alsa.c b/linux/drivers/media/video/cx88/cx88-alsa.c
index 3dd2f6629..f7171586d 100644
--- a/linux/drivers/media/video/cx88/cx88-alsa.c
+++ b/linux/drivers/media/video/cx88/cx88-alsa.c
@@ -795,7 +795,6 @@ static int __devinit snd_cx88_create(struct snd_card *card,
core = cx88_core_get(pci);
if (NULL == core) {
err = -EINVAL;
- kfree (chip);
return err;
}
@@ -872,7 +871,7 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci,
err = snd_cx88_create(card, pci, &chip);
if (err < 0)
- return (err);
+ goto error;
err = snd_cx88_pcm(chip, 0, "CX88 Digital");
if (err < 0)
diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c
index d38b3ba72..23d3820a2 100644
--- a/linux/drivers/media/video/em28xx/em28xx-cards.c
+++ b/linux/drivers/media/video/em28xx/em28xx-cards.c
@@ -687,6 +687,32 @@ struct em28xx_board em28xx_boards[] = {
.gpio = hauppauge_wintv_hvr_900_analog,
} },
},
+ [EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850] = {
+ .name = "Hauppauge WinTV HVR 850",
+ .tuner_type = TUNER_XC2028,
+ .tuner_gpio = default_tuner_gpio,
+ .mts_firmware = 1,
+ .has_dvb = 1,
+ .dvb_gpio = hauppauge_wintv_hvr_900_digital,
+ .ir_codes = ir_codes_hauppauge_new,
+ .decoder = EM28XX_TVP5150,
+ .input = { {
+ .type = EM28XX_VMUX_TELEVISION,
+ .vmux = TVP5150_COMPOSITE0,
+ .amux = EM28XX_AMUX_VIDEO,
+ .gpio = hauppauge_wintv_hvr_900_analog,
+ }, {
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = TVP5150_COMPOSITE1,
+ .amux = EM28XX_AMUX_LINE_IN,
+ .gpio = hauppauge_wintv_hvr_900_analog,
+ }, {
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = TVP5150_SVIDEO,
+ .amux = EM28XX_AMUX_LINE_IN,
+ .gpio = hauppauge_wintv_hvr_900_analog,
+ } },
+ },
[EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950] = {
.name = "Hauppauge WinTV HVR 950",
.tuner_type = TUNER_XC2028,
@@ -1212,19 +1238,17 @@ struct em28xx_board em28xx_boards[] = {
},
[EM2883_BOARD_KWORLD_HYBRID_A316] = {
.name = "Kworld PlusTV HD Hybrid 330",
- .valid = EM28XX_BOARD_NOT_VALIDATED,
.tuner_type = TUNER_XC2028,
.tuner_gpio = default_tuner_gpio,
.decoder = EM28XX_TVP5150,
-#if 0 /* FIXME: add an entry at em28xx-dvb */
+ .mts_firmware = 1,
.has_dvb = 1,
- .dvb_gpio = hauppauge_wintv_hvr_900_digital,
-#endif
+ .dvb_gpio = default_digital,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
.amux = EM28XX_AMUX_VIDEO,
- .gpio = hauppauge_wintv_hvr_900_analog,
+ .gpio = default_analog,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
@@ -1354,8 +1378,8 @@ struct usb_device_id em28xx_id_table [] = {
.driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 },
{ USB_DEVICE(0x2040, 0x651b), /* RP HVR-950 */
.driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 },
- { USB_DEVICE(0x2040, 0x651f), /* HCW HVR-850 */
- .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 },
+ { USB_DEVICE(0x2040, 0x651f),
+ .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 },
{ USB_DEVICE(0x0438, 0xb002),
.driver_info = EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 },
{ USB_DEVICE(0x2001, 0xf112),
@@ -1575,6 +1599,7 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
ctl->demod = XC3028_FE_DEFAULT;
ctl->fname = XC3028L_DEFAULT_FIRMWARE;
break;
+ case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850:
case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
/* FIXME: Better to specify the needed IF */
@@ -1759,6 +1784,7 @@ void em28xx_card_setup(struct em28xx *dev)
case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
+ case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850:
case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
{
struct tveeprom tv;
diff --git a/linux/drivers/media/video/em28xx/em28xx-dvb.c b/linux/drivers/media/video/em28xx/em28xx-dvb.c
index a06659f28..8d3ed7dc8 100644
--- a/linux/drivers/media/video/em28xx/em28xx-dvb.c
+++ b/linux/drivers/media/video/em28xx/em28xx-dvb.c
@@ -410,8 +410,10 @@ static int dvb_init(struct em28xx *dev)
em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
/* init frontend */
switch (dev->model) {
+ case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850:
case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
+ case EM2883_BOARD_KWORLD_HYBRID_A316:
case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
dvb->frontend = dvb_attach(lgdt330x_attach,
&em2880_lgdt3303_dev,
diff --git a/linux/drivers/media/video/em28xx/em28xx-video.c b/linux/drivers/media/video/em28xx/em28xx-video.c
index 00d49c45f..ff960f90c 100644
--- a/linux/drivers/media/video/em28xx/em28xx-video.c
+++ b/linux/drivers/media/video/em28xx/em28xx-video.c
@@ -1758,6 +1758,9 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
return 0;
}
+ /* Save some power by putting tuner to sleep */
+ em28xx_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL);
+
/* do this before setting alternate! */
em28xx_uninit_isoc(dev);
em28xx_set_mode(dev, EM28XX_SUSPEND);
@@ -2203,6 +2206,9 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
mutex_unlock(&em28xx_extension_devlist_lock);
mutex_unlock(&em28xx_devlist_mutex);
+ /* Save some power by putting tuner to sleep */
+ em28xx_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL);
+
return 0;
fail_reg_devices:
diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h
index 667cb70cf..4de9a8190 100644
--- a/linux/drivers/media/video/em28xx/em28xx.h
+++ b/linux/drivers/media/video/em28xx/em28xx.h
@@ -99,6 +99,7 @@
#define EM2883_BOARD_KWORLD_HYBRID_A316 57
#define EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU 58
#define EM2874_BOARD_PINNACLE_PCTV_80E 59
+#define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 60
/* Limits minimum and default number of buffers */
#define EM28XX_MIN_BUF 4
diff --git a/linux/drivers/media/video/mt9m001.c b/linux/drivers/media/video/mt9m001.c
index 228183c54..edacba723 100644
--- a/linux/drivers/media/video/mt9m001.c
+++ b/linux/drivers/media/video/mt9m001.c
@@ -285,8 +285,8 @@ static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd)
width_flag;
}
-static int mt9m001_set_fmt_cap(struct soc_camera_device *icd,
- __u32 pixfmt, struct v4l2_rect *rect)
+static int mt9m001_set_fmt(struct soc_camera_device *icd,
+ __u32 pixfmt, struct v4l2_rect *rect)
{
struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
int ret;
@@ -298,7 +298,7 @@ static int mt9m001_set_fmt_cap(struct soc_camera_device *icd,
ret = reg_write(icd, MT9M001_VERTICAL_BLANKING, vblank);
/* The caller provides a supported format, as verified per
- * call to icd->try_fmt_cap() */
+ * call to icd->try_fmt() */
if (!ret)
ret = reg_write(icd, MT9M001_COLUMN_START, rect->left);
if (!ret)
@@ -325,8 +325,8 @@ static int mt9m001_set_fmt_cap(struct soc_camera_device *icd,
return ret;
}
-static int mt9m001_try_fmt_cap(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int mt9m001_try_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
{
if (f->fmt.pix.height < 32 + icd->y_skip_top)
f->fmt.pix.height = 32 + icd->y_skip_top;
@@ -447,8 +447,8 @@ static struct soc_camera_ops mt9m001_ops = {
.release = mt9m001_release,
.start_capture = mt9m001_start_capture,
.stop_capture = mt9m001_stop_capture,
- .set_fmt_cap = mt9m001_set_fmt_cap,
- .try_fmt_cap = mt9m001_try_fmt_cap,
+ .set_fmt = mt9m001_set_fmt,
+ .try_fmt = mt9m001_try_fmt,
.set_bus_param = mt9m001_set_bus_param,
.query_bus_param = mt9m001_query_bus_param,
.controls = mt9m001_controls,
diff --git a/linux/drivers/media/video/mt9m111.c b/linux/drivers/media/video/mt9m111.c
index ceff40edc..1fde94514 100644
--- a/linux/drivers/media/video/mt9m111.c
+++ b/linux/drivers/media/video/mt9m111.c
@@ -452,8 +452,8 @@ static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt)
return ret;
}
-static int mt9m111_set_fmt_cap(struct soc_camera_device *icd,
- __u32 pixfmt, struct v4l2_rect *rect)
+static int mt9m111_set_fmt(struct soc_camera_device *icd,
+ __u32 pixfmt, struct v4l2_rect *rect)
{
struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
int ret;
@@ -473,8 +473,8 @@ static int mt9m111_set_fmt_cap(struct soc_camera_device *icd,
return ret;
}
-static int mt9m111_try_fmt_cap(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int mt9m111_try_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
{
if (f->fmt.pix.height > MT9M111_MAX_HEIGHT)
f->fmt.pix.height = MT9M111_MAX_HEIGHT;
@@ -597,8 +597,8 @@ static struct soc_camera_ops mt9m111_ops = {
.release = mt9m111_release,
.start_capture = mt9m111_start_capture,
.stop_capture = mt9m111_stop_capture,
- .set_fmt_cap = mt9m111_set_fmt_cap,
- .try_fmt_cap = mt9m111_try_fmt_cap,
+ .set_fmt = mt9m111_set_fmt,
+ .try_fmt = mt9m111_try_fmt,
.query_bus_param = mt9m111_query_bus_param,
.set_bus_param = mt9m111_set_bus_param,
.controls = mt9m111_controls,
diff --git a/linux/drivers/media/video/mt9v022.c b/linux/drivers/media/video/mt9v022.c
index bea695a2c..1ca28c087 100644
--- a/linux/drivers/media/video/mt9v022.c
+++ b/linux/drivers/media/video/mt9v022.c
@@ -337,14 +337,14 @@ static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd)
width_flag;
}
-static int mt9v022_set_fmt_cap(struct soc_camera_device *icd,
- __u32 pixfmt, struct v4l2_rect *rect)
+static int mt9v022_set_fmt(struct soc_camera_device *icd,
+ __u32 pixfmt, struct v4l2_rect *rect)
{
struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
int ret;
/* The caller provides a supported format, as verified per call to
- * icd->try_fmt_cap(), datawidth is from our supported format list */
+ * icd->try_fmt(), datawidth is from our supported format list */
switch (pixfmt) {
case V4L2_PIX_FMT_GREY:
case V4L2_PIX_FMT_Y16:
@@ -400,8 +400,8 @@ static int mt9v022_set_fmt_cap(struct soc_camera_device *icd,
return 0;
}
-static int mt9v022_try_fmt_cap(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int mt9v022_try_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
{
if (f->fmt.pix.height < 32 + icd->y_skip_top)
f->fmt.pix.height = 32 + icd->y_skip_top;
@@ -538,8 +538,8 @@ static struct soc_camera_ops mt9v022_ops = {
.release = mt9v022_release,
.start_capture = mt9v022_start_capture,
.stop_capture = mt9v022_stop_capture,
- .set_fmt_cap = mt9v022_set_fmt_cap,
- .try_fmt_cap = mt9v022_try_fmt_cap,
+ .set_fmt = mt9v022_set_fmt,
+ .try_fmt = mt9v022_try_fmt,
.set_bus_param = mt9v022_set_bus_param,
.query_bus_param = mt9v022_query_bus_param,
.controls = mt9v022_controls,
diff --git a/linux/drivers/media/video/ov772x.c b/linux/drivers/media/video/ov772x.c
index 2ddc2ab70..c023bbc84 100644
--- a/linux/drivers/media/video/ov772x.c
+++ b/linux/drivers/media/video/ov772x.c
@@ -112,34 +112,34 @@
#define AREF7 0x55 /* Analog reference control */
#define UFIX 0x60 /* U channel fixed value output */
#define VFIX 0x61 /* V channel fixed value output */
-#define AW_BB_BLK 0x62 /* AWB option for advanced AWB */
-#define AW_B_CTRL0 0x63 /* AWB control byte 0 */
+#define AWBB_BLK 0x62 /* AWB option for advanced AWB */
+#define AWB_CTRL0 0x63 /* AWB control byte 0 */
#define DSP_CTRL1 0x64 /* DSP control byte 1 */
#define DSP_CTRL2 0x65 /* DSP control byte 2 */
#define DSP_CTRL3 0x66 /* DSP control byte 3 */
#define DSP_CTRL4 0x67 /* DSP control byte 4 */
-#define AW_B_BIAS 0x68 /* AWB BLC level clip */
-#define AW_BCTRL1 0x69 /* AWB control 1 */
-#define AW_BCTRL2 0x6A /* AWB control 2 */
-#define AW_BCTRL3 0x6B /* AWB control 3 */
-#define AW_BCTRL4 0x6C /* AWB control 4 */
-#define AW_BCTRL5 0x6D /* AWB control 5 */
-#define AW_BCTRL6 0x6E /* AWB control 6 */
-#define AW_BCTRL7 0x6F /* AWB control 7 */
-#define AW_BCTRL8 0x70 /* AWB control 8 */
-#define AW_BCTRL9 0x71 /* AWB control 9 */
-#define AW_BCTRL10 0x72 /* AWB control 10 */
-#define AW_BCTRL11 0x73 /* AWB control 11 */
-#define AW_BCTRL12 0x74 /* AWB control 12 */
-#define AW_BCTRL13 0x75 /* AWB control 13 */
-#define AW_BCTRL14 0x76 /* AWB control 14 */
-#define AW_BCTRL15 0x77 /* AWB control 15 */
-#define AW_BCTRL16 0x78 /* AWB control 16 */
-#define AW_BCTRL17 0x79 /* AWB control 17 */
-#define AW_BCTRL18 0x7A /* AWB control 18 */
-#define AW_BCTRL19 0x7B /* AWB control 19 */
-#define AW_BCTRL20 0x7C /* AWB control 20 */
-#define AW_BCTRL21 0x7D /* AWB control 21 */
+#define AWB_BIAS 0x68 /* AWB BLC level clip */
+#define AWB_CTRL1 0x69 /* AWB control 1 */
+#define AWB_CTRL2 0x6A /* AWB control 2 */
+#define AWB_CTRL3 0x6B /* AWB control 3 */
+#define AWB_CTRL4 0x6C /* AWB control 4 */
+#define AWB_CTRL5 0x6D /* AWB control 5 */
+#define AWB_CTRL6 0x6E /* AWB control 6 */
+#define AWB_CTRL7 0x6F /* AWB control 7 */
+#define AWB_CTRL8 0x70 /* AWB control 8 */
+#define AWB_CTRL9 0x71 /* AWB control 9 */
+#define AWB_CTRL10 0x72 /* AWB control 10 */
+#define AWB_CTRL11 0x73 /* AWB control 11 */
+#define AWB_CTRL12 0x74 /* AWB control 12 */
+#define AWB_CTRL13 0x75 /* AWB control 13 */
+#define AWB_CTRL14 0x76 /* AWB control 14 */
+#define AWB_CTRL15 0x77 /* AWB control 15 */
+#define AWB_CTRL16 0x78 /* AWB control 16 */
+#define AWB_CTRL17 0x79 /* AWB control 17 */
+#define AWB_CTRL18 0x7A /* AWB control 18 */
+#define AWB_CTRL19 0x7B /* AWB control 19 */
+#define AWB_CTRL20 0x7C /* AWB control 20 */
+#define AWB_CTRL21 0x7D /* AWB control 21 */
#define GAM1 0x7E /* Gamma Curve 1st segment input end point */
#define GAM2 0x7F /* Gamma Curve 2nd segment input end point */
#define GAM3 0x80 /* Gamma Curve 3rd segment input end point */
@@ -593,12 +593,30 @@ static int ov772x_reset(struct i2c_client *client)
static int ov772x_init(struct soc_camera_device *icd)
{
- return 0;
+ struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+ int ret = 0;
+
+ if (priv->info->link.power) {
+ ret = priv->info->link.power(&priv->client->dev, 1);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (priv->info->link.reset)
+ ret = priv->info->link.reset(&priv->client->dev);
+
+ return ret;
}
static int ov772x_release(struct soc_camera_device *icd)
{
- return 0;
+ struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+ int ret = 0;
+
+ if (priv->info->link.power)
+ ret = priv->info->link.power(&priv->client->dev, 0);
+
+ return ret;
}
static int ov772x_start_capture(struct soc_camera_device *icd)
@@ -737,9 +755,9 @@ static int ov772x_set_register(struct soc_camera_device *icd,
}
#endif
-static int ov772x_set_fmt_cap(struct soc_camera_device *icd,
- __u32 pixfmt,
- struct v4l2_rect *rect)
+static int ov772x_set_fmt(struct soc_camera_device *icd,
+ __u32 pixfmt,
+ struct v4l2_rect *rect)
{
struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
int ret = -EINVAL;
@@ -760,8 +778,8 @@ static int ov772x_set_fmt_cap(struct soc_camera_device *icd,
return ret;
}
-static int ov772x_try_fmt_cap(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int ov772x_try_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
{
struct v4l2_pix_format *pix = &f->fmt.pix;
struct ov772x_priv *priv;
@@ -814,9 +832,6 @@ static int ov772x_video_probe(struct soc_camera_device *icd)
icd->formats = ov772x_fmt_lists;
icd->num_formats = ARRAY_SIZE(ov772x_fmt_lists);
- if (priv->info->link.power)
- priv->info->link.power(&priv->client->dev, 1);
-
/*
* check and show product ID and manufacturer ID
*/
@@ -824,8 +839,8 @@ static int ov772x_video_probe(struct soc_camera_device *icd)
ver = i2c_smbus_read_byte_data(priv->client, VER);
if (pid != 0x77 ||
ver != 0x21) {
- if (priv->info->link.power)
- priv->info->link.power(&priv->client->dev, 0);
+ dev_err(&icd->dev,
+ "Product ID error %x:%x\n", pid, ver);
return -ENODEV;
}
@@ -842,13 +857,7 @@ static int ov772x_video_probe(struct soc_camera_device *icd)
static void ov772x_video_remove(struct soc_camera_device *icd)
{
- struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
-
soc_camera_video_stop(icd);
-
- if (priv->info->link.power)
- priv->info->link.power(&priv->client->dev, 0);
-
}
static struct soc_camera_ops ov772x_ops = {
@@ -859,8 +868,8 @@ static struct soc_camera_ops ov772x_ops = {
.release = ov772x_release,
.start_capture = ov772x_start_capture,
.stop_capture = ov772x_stop_capture,
- .set_fmt_cap = ov772x_set_fmt_cap,
- .try_fmt_cap = ov772x_try_fmt_cap,
+ .set_fmt = ov772x_set_fmt,
+ .try_fmt = ov772x_try_fmt,
.set_bus_param = ov772x_set_bus_param,
.query_bus_param = ov772x_query_bus_param,
.get_chip_id = ov772x_get_chip_id,
diff --git a/linux/drivers/media/video/pxa_camera.c b/linux/drivers/media/video/pxa_camera.c
index 08723ed84..210a99780 100644
--- a/linux/drivers/media/video/pxa_camera.c
+++ b/linux/drivers/media/video/pxa_camera.c
@@ -770,6 +770,9 @@ static int test_platform_param(struct pxa_camera_dev *pcdev,
if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8))
return -EINVAL;
*flags |= SOCAM_DATAWIDTH_8;
+ break;
+ default:
+ return -EINVAL;
}
return 0;
@@ -828,12 +831,10 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
* We fix bit-per-pixel equal to data-width... */
switch (common_flags & SOCAM_DATAWIDTH_MASK) {
case SOCAM_DATAWIDTH_10:
- icd->buswidth = 10;
dw = 4;
bpp = 0x40;
break;
case SOCAM_DATAWIDTH_9:
- icd->buswidth = 9;
dw = 3;
bpp = 0x20;
break;
@@ -841,7 +842,6 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
/* Actually it can only be 8 now,
* default is just to silence compiler warnings */
case SOCAM_DATAWIDTH_8:
- icd->buswidth = 8;
dw = 2;
bpp = 0;
}
@@ -867,7 +867,17 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
case V4L2_PIX_FMT_YUV422P:
pcdev->channels = 3;
cicr1 |= CICR1_YCBCR_F;
+ /*
+ * Normally, pxa bus wants as input UYVY format. We allow all
+ * reorderings of the YUV422 format, as no processing is done,
+ * and the YUV stream is just passed through without any
+ * transformation. Note that UYVY is the only format that
+ * should be used if pxa framebuffer Overlay2 is used.
+ */
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_VYUY:
case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_YVYU:
cicr1 |= CICR1_COLOR_SP_VAL(2);
break;
case V4L2_PIX_FMT_RGB555:
@@ -893,13 +903,14 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
return 0;
}
-static int pxa_camera_try_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
+static int pxa_camera_try_bus_param(struct soc_camera_device *icd,
+ unsigned char buswidth)
{
struct soc_camera_host *ici =
to_soc_camera_host(icd->dev.parent);
struct pxa_camera_dev *pcdev = ici->priv;
unsigned long bus_flags, camera_flags;
- int ret = test_platform_param(pcdev, icd->buswidth, &bus_flags);
+ int ret = test_platform_param(pcdev, buswidth, &bus_flags);
if (ret < 0)
return ret;
@@ -909,28 +920,174 @@ static int pxa_camera_try_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
return soc_camera_bus_param_compatible(camera_flags, bus_flags) ? 0 : -EINVAL;
}
-static int pxa_camera_set_fmt_cap(struct soc_camera_device *icd,
- __u32 pixfmt, struct v4l2_rect *rect)
+static const struct soc_camera_data_format pxa_camera_formats[] = {
+ {
+ .name = "Planar YUV422 16 bit",
+ .depth = 16,
+ .fourcc = V4L2_PIX_FMT_YUV422P,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ },
+};
+
+static bool buswidth_supported(struct soc_camera_device *icd, int depth)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct pxa_camera_dev *pcdev = ici->priv;
+
+ switch (depth) {
+ case 8:
+ return !!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8);
+ case 9:
+ return !!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_9);
+ case 10:
+ return !!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_10);
+ }
+ return false;
+}
+
+static int required_buswidth(const struct soc_camera_data_format *fmt)
+{
+ switch (fmt->fourcc) {
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_VYUY:
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_YVYU:
+ case V4L2_PIX_FMT_RGB565:
+ case V4L2_PIX_FMT_RGB555:
+ return 8;
+ default:
+ return fmt->depth;
+ }
+}
+
+static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
+ struct soc_camera_format_xlate *xlate)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ int formats = 0, buswidth, ret;
+
+ buswidth = required_buswidth(icd->formats + idx);
+
+ if (!buswidth_supported(icd, buswidth))
+ return 0;
+
+ ret = pxa_camera_try_bus_param(icd, buswidth);
+ if (ret < 0)
+ return 0;
+
+ switch (icd->formats[idx].fourcc) {
+ case V4L2_PIX_FMT_UYVY:
+ formats++;
+ if (xlate) {
+ xlate->host_fmt = &pxa_camera_formats[0];
+ xlate->cam_fmt = icd->formats + idx;
+ xlate->buswidth = buswidth;
+ xlate++;
+ dev_dbg(&ici->dev, "Providing format %s using %s\n",
+ pxa_camera_formats[0].name,
+ icd->formats[idx].name);
+ }
+ case V4L2_PIX_FMT_VYUY:
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_YVYU:
+ case V4L2_PIX_FMT_RGB565:
+ case V4L2_PIX_FMT_RGB555:
+ formats++;
+ if (xlate) {
+ xlate->host_fmt = icd->formats + idx;
+ xlate->cam_fmt = icd->formats + idx;
+ xlate->buswidth = buswidth;
+ xlate++;
+ dev_dbg(&ici->dev, "Providing format %s packed\n",
+ icd->formats[idx].name);
+ }
+ break;
+ default:
+ /* Generic pass-through */
+ formats++;
+ if (xlate) {
+ xlate->host_fmt = icd->formats + idx;
+ xlate->cam_fmt = icd->formats + idx;
+ xlate->buswidth = icd->formats[idx].depth;
+ xlate++;
+ dev_dbg(&ici->dev,
+ "Providing format %s in pass-through mode\n",
+ icd->formats[idx].name);
+ }
+ }
+
+ return formats;
+}
+
+static int pxa_camera_set_fmt(struct soc_camera_device *icd,
+ __u32 pixfmt, struct v4l2_rect *rect)
{
- return icd->ops->set_fmt_cap(icd, pixfmt, rect);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ const struct soc_camera_data_format *host_fmt, *cam_fmt = NULL;
+ const struct soc_camera_format_xlate *xlate;
+ int ret, buswidth;
+
+ xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+ if (!xlate) {
+ dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
+ return -EINVAL;
+ }
+
+ buswidth = xlate->buswidth;
+ host_fmt = xlate->host_fmt;
+ cam_fmt = xlate->cam_fmt;
+
+ switch (pixfmt) {
+ case 0: /* Only geometry change */
+ ret = icd->ops->set_fmt(icd, pixfmt, rect);
+ break;
+ default:
+ ret = icd->ops->set_fmt(icd, cam_fmt->fourcc, rect);
+ }
+
+ if (ret < 0)
+ dev_warn(&ici->dev, "Failed to configure for format %x\n",
+ pixfmt);
+
+ if (pixfmt && !ret) {
+ icd->buswidth = buswidth;
+ icd->current_fmt = host_fmt;
+ }
+
+ return ret;
}
-static int pxa_camera_try_fmt_cap(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int pxa_camera_try_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ const struct soc_camera_format_xlate *xlate;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ __u32 pixfmt = pix->pixelformat;
+
+ xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+ if (!xlate) {
+ dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
+ return -EINVAL;
+ }
+
/* limit to pxa hardware capabilities */
- if (f->fmt.pix.height < 32)
- f->fmt.pix.height = 32;
- if (f->fmt.pix.height > 2048)
- f->fmt.pix.height = 2048;
- if (f->fmt.pix.width < 48)
- f->fmt.pix.width = 48;
- if (f->fmt.pix.width > 2048)
- f->fmt.pix.width = 2048;
- f->fmt.pix.width &= ~0x01;
+ if (pix->height < 32)
+ pix->height = 32;
+ if (pix->height > 2048)
+ pix->height = 2048;
+ if (pix->width < 48)
+ pix->width = 48;
+ if (pix->width > 2048)
+ pix->width = 2048;
+ pix->width &= ~0x01;
+
+ pix->bytesperline = pix->width *
+ DIV_ROUND_UP(xlate->host_fmt->depth, 8);
+ pix->sizeimage = pix->height * pix->bytesperline;
/* limit to sensor capabilities */
- return icd->ops->try_fmt_cap(icd, f);
+ return icd->ops->try_fmt(icd, f);
}
static int pxa_camera_reqbufs(struct soc_camera_file *icf,
@@ -1038,13 +1195,13 @@ static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
.remove = pxa_camera_remove_device,
.suspend = pxa_camera_suspend,
.resume = pxa_camera_resume,
- .set_fmt_cap = pxa_camera_set_fmt_cap,
- .try_fmt_cap = pxa_camera_try_fmt_cap,
+ .get_formats = pxa_camera_get_formats,
+ .set_fmt = pxa_camera_set_fmt,
+ .try_fmt = pxa_camera_try_fmt,
.init_videobuf = pxa_camera_init_videobuf,
.reqbufs = pxa_camera_reqbufs,
.poll = pxa_camera_poll,
.querycap = pxa_camera_querycap,
- .try_bus_param = pxa_camera_try_bus_param,
.set_bus_param = pxa_camera_set_bus_param,
};
diff --git a/linux/drivers/media/video/saa7134/saa7134-cards.c b/linux/drivers/media/video/saa7134/saa7134-cards.c
index d4c432cb3..54be8314f 100644
--- a/linux/drivers/media/video/saa7134/saa7134-cards.c
+++ b/linux/drivers/media/video/saa7134/saa7134-cards.c
@@ -4645,6 +4645,43 @@ struct saa7134_board saa7134_boards[] = {
.gpio = 0x0200000,
},
},
+ [SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG] = {
+ .name = "Kworld Plus TV Analog Lite PCI",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_YMEC_TVF_5533MF,
+ .radio_type = TUNER_TEA5767,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x80000700,
+ .inputs = { {
+ .name = name_tv,
+ .vmux = 1,
+ .amux = LINE2,
+ .tv = 1,
+ .gpio = 0x100,
+ }, {
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x200,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ .gpio = 0x200,
+ } },
+ .radio = {
+ .name = name_radio,
+ .vmux = 1,
+ .amux = LINE1,
+ .gpio = 0x100,
+ },
+ .mute = {
+ .name = name_mute,
+ .vmux = 8,
+ .amux = 2,
+ },
+ },
};
const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -4775,6 +4812,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
.driver_data = SAA7134_BOARD_MD7134,
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x16be, /* CTX946 analog TV, HW mpeg, DVB-T */
+ .subdevice = 0x5000, /* only analog TV and DVB-T for now */
+ .driver_data = SAA7134_BOARD_MD7134,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7130,
.subvendor = 0x1048,
.subdevice = 0x226b,
@@ -5692,6 +5735,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subdevice = 0x4878, /* REV:1.02G */
.driver_data = SAA7134_BOARD_ASUSTeK_TIGER_3IN1,
}, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x17de,
+ .subdevice = 0x7128,
+ .driver_data = SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG,
+ }, {
/* --- boards without eeprom + subsystem ID --- */
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -5979,6 +6028,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_BEHOLD_507_9FM:
case SAA7134_BOARD_GENIUS_TVGO_A11MCE:
case SAA7134_BOARD_REAL_ANGEL_220:
+ case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG:
dev->has_remote = SAA7134_REMOTE_GPIO;
break;
case SAA7134_BOARD_FLYDVBS_LR300:
diff --git a/linux/drivers/media/video/saa7134/saa7134-input.c b/linux/drivers/media/video/saa7134/saa7134-input.c
index 1c4bd413e..272490b92 100644
--- a/linux/drivers/media/video/saa7134/saa7134-input.c
+++ b/linux/drivers/media/video/saa7134/saa7134-input.c
@@ -97,6 +97,15 @@ static int build_key(struct saa7134_dev *dev)
dprintk("build_key gpio=0x%x mask=0x%x data=%d\n",
gpio, ir->mask_keycode, data);
+ switch (dev->board) {
+ case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG:
+ if (data == ir->mask_keycode)
+ ir_input_nokey(ir->dev, &ir->ir);
+ else
+ ir_input_keydown(ir->dev, &ir->ir, data, data);
+ return 0;
+ }
+
if (ir->polling) {
if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) ||
(ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) {
@@ -586,6 +595,11 @@ int saa7134_input_init1(struct saa7134_dev *dev)
mask_keyup = 0x4000;
polling = 50; /* ms */
break;
+ case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG:
+ ir_codes = ir_codes_kworld_plus_tv_analog;
+ mask_keycode = 0x7f;
+ polling = 40; /* ms */
+ break;
}
if (NULL == ir_codes) {
printk("%s: Oops: IR config error [card=%d]\n",
diff --git a/linux/drivers/media/video/saa7134/saa7134.h b/linux/drivers/media/video/saa7134/saa7134.h
index 82f9a889a..3bb599673 100644
--- a/linux/drivers/media/video/saa7134/saa7134.h
+++ b/linux/drivers/media/video/saa7134/saa7134.h
@@ -276,6 +276,7 @@ struct saa7134_format {
#define SAA7134_BOARD_REAL_ANGEL_220 150
#define SAA7134_BOARD_ADS_INSTANT_HDTV_PCI 151
#define SAA7134_BOARD_ASUSTeK_TIGER 152
+#define SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG 153
#define SAA7134_MAXBOARDS 32
#define SAA7134_INPUT_MAX 8
diff --git a/linux/drivers/media/video/sh_mobile_ceu_camera.c b/linux/drivers/media/video/sh_mobile_ceu_camera.c
index 2fb8bee0b..e2e816213 100644
--- a/linux/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/linux/drivers/media/video/sh_mobile_ceu_camera.c
@@ -445,15 +445,46 @@ static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd,
return 0;
}
-static int sh_mobile_ceu_set_fmt_cap(struct soc_camera_device *icd,
- __u32 pixfmt, struct v4l2_rect *rect)
+static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
+ __u32 pixfmt, struct v4l2_rect *rect)
{
- return icd->ops->set_fmt_cap(icd, pixfmt, rect);
+ const struct soc_camera_data_format *cam_fmt;
+ int ret;
+
+ /*
+ * TODO: find a suitable supported by the SoC output format, check
+ * whether the sensor supports one of acceptable input formats.
+ */
+ if (pixfmt) {
+ cam_fmt = soc_camera_format_by_fourcc(icd, pixfmt);
+ if (!cam_fmt)
+ return -EINVAL;
+ }
+
+ ret = icd->ops->set_fmt(icd, pixfmt, rect);
+ if (pixfmt && !ret)
+ icd->current_fmt = cam_fmt;
+
+ return ret;
}
-static int sh_mobile_ceu_try_fmt_cap(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
{
+ const struct soc_camera_data_format *cam_fmt;
+ int ret = sh_mobile_ceu_try_bus_param(icd, f->fmt.pix.pixelformat);
+
+ if (ret < 0)
+ return ret;
+
+ /*
+ * TODO: find a suitable supported by the SoC output format, check
+ * whether the sensor supports one of acceptable input formats.
+ */
+ cam_fmt = soc_camera_format_by_fourcc(icd, f->fmt.pix.pixelformat);
+ if (!cam_fmt)
+ return -EINVAL;
+
/* FIXME: calculate using depth and bus width */
if (f->fmt.pix.height < 4)
@@ -467,8 +498,12 @@ static int sh_mobile_ceu_try_fmt_cap(struct soc_camera_device *icd,
f->fmt.pix.width &= ~0x01;
f->fmt.pix.height &= ~0x03;
+ f->fmt.pix.bytesperline = f->fmt.pix.width *
+ DIV_ROUND_UP(cam_fmt->depth, 8);
+ f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+
/* limit to sensor capabilities */
- return icd->ops->try_fmt_cap(icd, f);
+ return icd->ops->try_fmt(icd, f);
}
static int sh_mobile_ceu_reqbufs(struct soc_camera_file *icf,
@@ -536,12 +571,11 @@ static struct soc_camera_host_ops sh_mobile_ceu_host_ops = {
.owner = THIS_MODULE,
.add = sh_mobile_ceu_add_device,
.remove = sh_mobile_ceu_remove_device,
- .set_fmt_cap = sh_mobile_ceu_set_fmt_cap,
- .try_fmt_cap = sh_mobile_ceu_try_fmt_cap,
+ .set_fmt = sh_mobile_ceu_set_fmt,
+ .try_fmt = sh_mobile_ceu_try_fmt,
.reqbufs = sh_mobile_ceu_reqbufs,
.poll = sh_mobile_ceu_poll,
.querycap = sh_mobile_ceu_querycap,
- .try_bus_param = sh_mobile_ceu_try_bus_param,
.set_bus_param = sh_mobile_ceu_set_bus_param,
.init_videobuf = sh_mobile_ceu_init_videobuf,
};
diff --git a/linux/drivers/media/video/soc_camera.c b/linux/drivers/media/video/soc_camera.c
index 7a46697c4..4a9c52c37 100644
--- a/linux/drivers/media/video/soc_camera.c
+++ b/linux/drivers/media/video/soc_camera.c
@@ -36,8 +36,8 @@ static LIST_HEAD(devices);
static DEFINE_MUTEX(list_lock);
static DEFINE_MUTEX(video_lock);
-const static struct soc_camera_data_format*
-format_by_fourcc(struct soc_camera_device *icd, unsigned int fourcc)
+const struct soc_camera_data_format *soc_camera_format_by_fourcc(
+ struct soc_camera_device *icd, unsigned int fourcc)
{
unsigned int i;
@@ -46,52 +46,47 @@ format_by_fourcc(struct soc_camera_device *icd, unsigned int fourcc)
return icd->formats + i;
return NULL;
}
+EXPORT_SYMBOL(soc_camera_format_by_fourcc);
+
+const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc(
+ struct soc_camera_device *icd, unsigned int fourcc)
+{
+ unsigned int i;
+
+ for (i = 0; i < icd->num_user_formats; i++)
+ if (icd->user_formats[i].host_fmt->fourcc == fourcc)
+ return icd->user_formats + i;
+ return NULL;
+}
+EXPORT_SYMBOL(soc_camera_xlate_by_fourcc);
static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
+ struct v4l2_format *f)
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
struct soc_camera_host *ici =
to_soc_camera_host(icd->dev.parent);
enum v4l2_field field;
- const struct soc_camera_data_format *fmt;
int ret;
WARN_ON(priv != file->private_data);
- fmt = format_by_fourcc(icd, f->fmt.pix.pixelformat);
- if (!fmt) {
- dev_dbg(&icd->dev, "invalid format 0x%08x\n",
- f->fmt.pix.pixelformat);
- return -EINVAL;
- }
-
- dev_dbg(&icd->dev, "fmt: 0x%08x\n", fmt->fourcc);
-
+ /*
+ * TODO: this might also have to migrate to host-drivers, if anyone
+ * wishes to support other fields
+ */
field = f->fmt.pix.field;
if (field == V4L2_FIELD_ANY) {
- field = V4L2_FIELD_NONE;
- } else if (V4L2_FIELD_NONE != field) {
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+ } else if (field != V4L2_FIELD_NONE) {
dev_err(&icd->dev, "Field type invalid.\n");
return -EINVAL;
}
- /* test physical bus parameters */
- ret = ici->ops->try_bus_param(icd, f->fmt.pix.pixelformat);
- if (ret)
- return ret;
-
/* limit format to hardware capabilities */
- ret = ici->ops->try_fmt_cap(icd, f);
-
- /* calculate missing fields */
- f->fmt.pix.field = field;
- f->fmt.pix.bytesperline =
- (f->fmt.pix.width * fmt->depth) >> 3;
- f->fmt.pix.sizeimage =
- f->fmt.pix.height * f->fmt.pix.bytesperline;
+ ret = ici->ops->try_fmt(icd, f);
return ret;
}
@@ -179,6 +174,59 @@ static int soc_camera_dqbuf(struct file *file, void *priv,
return videobuf_dqbuf(&icf->vb_vidq, p, file->f_flags & O_NONBLOCK);
}
+static int soc_camera_init_user_formats(struct soc_camera_device *icd)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ int i, fmts = 0;
+
+ if (!ici->ops->get_formats)
+ /*
+ * Fallback mode - the host will have to serve all
+ * sensor-provided formats one-to-one to the user
+ */
+ fmts = icd->num_formats;
+ else
+ /*
+ * First pass - only count formats this host-sensor
+ * configuration can provide
+ */
+ for (i = 0; i < icd->num_formats; i++)
+ fmts += ici->ops->get_formats(icd, i, NULL);
+
+ if (!fmts)
+ return -ENXIO;
+
+ icd->user_formats =
+ vmalloc(fmts * sizeof(struct soc_camera_format_xlate));
+ if (!icd->user_formats)
+ return -ENOMEM;
+
+ icd->num_user_formats = fmts;
+ fmts = 0;
+
+ dev_dbg(&icd->dev, "Found %d supported formats.\n", fmts);
+
+ /* Second pass - actually fill data formats */
+ for (i = 0; i < icd->num_formats; i++)
+ if (!ici->ops->get_formats) {
+ icd->user_formats[i].host_fmt = icd->formats + i;
+ icd->user_formats[i].cam_fmt = icd->formats + i;
+ icd->user_formats[i].buswidth = icd->formats[i].depth;
+ } else {
+ fmts += ici->ops->get_formats(icd, i,
+ &icd->user_formats[fmts]);
+ }
+
+ icd->current_fmt = icd->user_formats[0].host_fmt;
+
+ return 0;
+}
+
+static void soc_camera_free_user_formats(struct soc_camera_device *icd)
+{
+ vfree(icd->user_formats);
+}
+
static int soc_camera_open(struct inode *inode, struct file *file)
{
struct video_device *vdev;
@@ -215,10 +263,12 @@ static int soc_camera_open(struct inode *inode, struct file *file)
/* Now we really have to activate the camera */
if (icd->use_count == 1) {
+ ret = soc_camera_init_user_formats(icd);
+ if (ret < 0)
+ goto eiufmt;
ret = ici->ops->add(icd);
if (ret < 0) {
dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret);
- icd->use_count--;
goto eiciadd;
}
}
@@ -234,6 +284,9 @@ static int soc_camera_open(struct inode *inode, struct file *file)
/* All errors are entered with the video_lock held */
eiciadd:
+ soc_camera_free_user_formats(icd);
+eiufmt:
+ icd->use_count--;
module_put(ici->ops->owner);
emgi:
module_put(icd->ops->owner);
@@ -252,8 +305,10 @@ static int soc_camera_close(struct inode *inode, struct file *file)
mutex_lock(&video_lock);
icd->use_count--;
- if (!icd->use_count)
+ if (!icd->use_count) {
ici->ops->remove(icd);
+ soc_camera_free_user_formats(icd);
+ }
module_put(icd->ops->owner);
module_put(ici->ops->owner);
mutex_unlock(&video_lock);
@@ -266,7 +321,7 @@ static int soc_camera_close(struct inode *inode, struct file *file)
}
static ssize_t soc_camera_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
+ size_t count, loff_t *ppos)
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
@@ -311,7 +366,6 @@ static unsigned int soc_camera_poll(struct file *file, poll_table *pt)
return ici->ops->poll(file, pt);
}
-
static struct file_operations soc_camera_fops = {
.owner = THIS_MODULE,
.open = soc_camera_open,
@@ -323,28 +377,20 @@ static struct file_operations soc_camera_fops = {
.llseek = no_llseek,
};
-
static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
+ struct v4l2_format *f)
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
struct soc_camera_host *ici =
to_soc_camera_host(icd->dev.parent);
+ __u32 pixfmt = f->fmt.pix.pixelformat;
int ret;
struct v4l2_rect rect;
- const static struct soc_camera_data_format *data_fmt;
WARN_ON(priv != file->private_data);
- data_fmt = format_by_fourcc(icd, f->fmt.pix.pixelformat);
- if (!data_fmt)
- return -EINVAL;
-
- /* buswidth may be further adjusted by the ici */
- icd->buswidth = data_fmt->depth;
-
- ret = soc_camera_try_fmt_vid_cap(file, icf, f);
+ ret = soc_camera_try_fmt_vid_cap(file, priv, f);
if (ret < 0)
return ret;
@@ -352,15 +398,20 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
rect.top = icd->y_current;
rect.width = f->fmt.pix.width;
rect.height = f->fmt.pix.height;
- ret = ici->ops->set_fmt_cap(icd, f->fmt.pix.pixelformat, &rect);
- if (ret < 0)
+ ret = ici->ops->set_fmt(icd, f->fmt.pix.pixelformat, &rect);
+ if (ret < 0) {
return ret;
+ } else if (!icd->current_fmt ||
+ icd->current_fmt->fourcc != pixfmt) {
+ dev_err(&ici->dev,
+ "Host driver hasn't set up current format correctly!\n");
+ return -EINVAL;
+ }
- icd->current_fmt = data_fmt;
icd->width = rect.width;
icd->height = rect.height;
icf->vb_vidq.field = f->fmt.pix.field;
- if (V4L2_BUF_TYPE_VIDEO_CAPTURE != f->type)
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n",
f->type);
@@ -368,11 +419,11 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
icd->width, icd->height);
/* set physical bus parameters */
- return ici->ops->set_bus_param(icd, f->fmt.pix.pixelformat);
+ return ici->ops->set_bus_param(icd, pixfmt);
}
static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
+ struct v4l2_fmtdesc *f)
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
@@ -380,10 +431,10 @@ static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv,
WARN_ON(priv != file->private_data);
- if (f->index >= icd->num_formats)
+ if (f->index >= icd->num_user_formats)
return -EINVAL;
- format = &icd->formats[f->index];
+ format = icd->user_formats[f->index].host_fmt;
strlcpy(f->description, format->name, sizeof(f->description));
f->pixelformat = format->fourcc;
@@ -391,7 +442,7 @@ static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv,
}
static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
+ struct v4l2_format *f)
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
@@ -402,10 +453,9 @@ static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.height = icd->height;
f->fmt.pix.field = icf->vb_vidq.field;
f->fmt.pix.pixelformat = icd->current_fmt->fourcc;
- f->fmt.pix.bytesperline =
- (f->fmt.pix.width * icd->current_fmt->depth) >> 3;
- f->fmt.pix.sizeimage =
- f->fmt.pix.height * f->fmt.pix.bytesperline;
+ f->fmt.pix.bytesperline = f->fmt.pix.width *
+ DIV_ROUND_UP(icd->current_fmt->depth, 8);
+ f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
dev_dbg(&icd->dev, "current_fmt->fourcc: 0x%08x\n",
icd->current_fmt->fourcc);
return 0;
@@ -575,7 +625,7 @@ static int soc_camera_s_crop(struct file *file, void *fh,
if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- ret = ici->ops->set_fmt_cap(icd, 0, &a->c);
+ ret = ici->ops->set_fmt(icd, 0, &a->c);
if (!ret) {
icd->width = a->c.width;
icd->height = a->c.height;
@@ -941,8 +991,6 @@ int soc_camera_video_start(struct soc_camera_device *icd)
vdev->minor = -1;
vdev->tvnorms = V4L2_STD_UNKNOWN,
- icd->current_fmt = &icd->formats[0];
-
err = video_register_device(vdev, VFL_TYPE_GRABBER, vdev->minor);
if (err < 0) {
dev_err(vdev->parent, "video_register_device failed\n");
diff --git a/linux/drivers/media/video/soc_camera_platform.c b/linux/drivers/media/video/soc_camera_platform.c
index bb7a9d480..c23871e4c 100644
--- a/linux/drivers/media/video/soc_camera_platform.c
+++ b/linux/drivers/media/video/soc_camera_platform.c
@@ -79,14 +79,14 @@ soc_camera_platform_query_bus_param(struct soc_camera_device *icd)
return p->bus_param;
}
-static int soc_camera_platform_set_fmt_cap(struct soc_camera_device *icd,
- __u32 pixfmt, struct v4l2_rect *rect)
+static int soc_camera_platform_set_fmt(struct soc_camera_device *icd,
+ __u32 pixfmt, struct v4l2_rect *rect)
{
return 0;
}
-static int soc_camera_platform_try_fmt_cap(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int soc_camera_platform_try_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
{
struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd);
@@ -124,8 +124,8 @@ static struct soc_camera_ops soc_camera_platform_ops = {
.release = soc_camera_platform_release,
.start_capture = soc_camera_platform_start_capture,
.stop_capture = soc_camera_platform_stop_capture,
- .set_fmt_cap = soc_camera_platform_set_fmt_cap,
- .try_fmt_cap = soc_camera_platform_try_fmt_cap,
+ .set_fmt = soc_camera_platform_set_fmt,
+ .try_fmt = soc_camera_platform_try_fmt,
.set_bus_param = soc_camera_platform_set_bus_param,
.query_bus_param = soc_camera_platform_query_bus_param,
};
diff --git a/linux/drivers/media/video/uvc/uvc_ctrl.c b/linux/drivers/media/video/uvc/uvc_ctrl.c
index 9de8a1db5..01c72935d 100644
--- a/linux/drivers/media/video/uvc/uvc_ctrl.c
+++ b/linux/drivers/media/video/uvc/uvc_ctrl.c
@@ -545,11 +545,16 @@ static inline __u8 *uvc_ctrl_data(struct uvc_control *ctrl, int id)
return ctrl->data + id * ctrl->info->size;
}
-static inline int uvc_get_bit(const __u8 *data, int bit)
+static inline int uvc_test_bit(const __u8 *data, int bit)
{
return (data[bit >> 3] >> (bit & 7)) & 1;
}
+static inline void uvc_clear_bit(__u8 *data, int bit)
+{
+ data[bit >> 3] &= ~(1 << (bit & 7));
+}
+
/* Extract the bit string specified by mapping->offset and mapping->size
* from the little-endian data stored at 'data' and return the result as
* a signed 32bit integer. Sign extension will be performed if the mapping
@@ -1308,6 +1313,51 @@ end:
}
/*
+ * Prune an entity of its bogus controls. This currently includes processing
+ * unit auto controls for which no corresponding manual control is available.
+ * Such auto controls make little sense if any, and are known to crash at
+ * least the SiGma Micro webcam.
+ */
+static void
+uvc_ctrl_prune_entity(struct uvc_entity *entity)
+{
+ static const struct {
+ u8 idx_manual;
+ u8 idx_auto;
+ } blacklist[] = {
+ { 2, 11 }, /* Hue */
+ { 6, 12 }, /* White Balance Temperature */
+ { 7, 13 }, /* White Balance Component */
+ };
+
+ u8 *controls;
+ unsigned int size;
+ unsigned int i;
+
+ if (UVC_ENTITY_TYPE(entity) != VC_PROCESSING_UNIT)
+ return;
+
+ controls = entity->processing.bmControls;
+ size = entity->processing.bControlSize;
+
+ for (i = 0; i < ARRAY_SIZE(blacklist); ++i) {
+ if (blacklist[i].idx_auto >= 8 * size ||
+ blacklist[i].idx_manual >= 8 * size)
+ continue;
+
+ if (!uvc_test_bit(controls, blacklist[i].idx_auto) ||
+ uvc_test_bit(controls, blacklist[i].idx_manual))
+ continue;
+
+ uvc_trace(UVC_TRACE_CONTROL, "Auto control %u/%u has no "
+ "matching manual control, removing it.\n", entity->id,
+ blacklist[i].idx_auto);
+
+ uvc_clear_bit(controls, blacklist[i].idx_auto);
+ }
+}
+
+/*
* Initialize device controls.
*/
int uvc_ctrl_init_device(struct uvc_device *dev)
@@ -1333,6 +1383,9 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
bControlSize = entity->camera.bControlSize;
}
+ if (dev->quirks & UVC_QUIRK_PRUNE_CONTROLS)
+ uvc_ctrl_prune_entity(entity);
+
for (i = 0; i < bControlSize; ++i)
ncontrols += hweight8(bmControls[i]);
@@ -1347,7 +1400,7 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
ctrl = entity->controls;
for (i = 0; i < bControlSize * 8; ++i) {
- if (uvc_get_bit(bmControls, i) == 0)
+ if (uvc_test_bit(bmControls, i) == 0)
continue;
ctrl->entity = entity;
diff --git a/linux/drivers/media/video/uvc/uvc_driver.c b/linux/drivers/media/video/uvc/uvc_driver.c
index 0a0ef6611..343792f0f 100644
--- a/linux/drivers/media/video/uvc/uvc_driver.c
+++ b/linux/drivers/media/video/uvc/uvc_driver.c
@@ -44,6 +44,7 @@
#define DRIVER_VERSION "v0.1.0"
#endif
+unsigned int uvc_no_drop_param;
static unsigned int uvc_quirks_param;
unsigned int uvc_trace_param;
@@ -1895,7 +1896,8 @@ static struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = UVC_QUIRK_PROBE_MINMAX
- | UVC_QUIRK_IGNORE_SELECTOR_UNIT},
+ | UVC_QUIRK_IGNORE_SELECTOR_UNIT
+ | UVC_QUIRK_PRUNE_CONTROLS },
/* Generic USB Video Class */
{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },
{}
@@ -1945,6 +1947,8 @@ static void __exit uvc_cleanup(void)
module_init(uvc_init);
module_exit(uvc_cleanup);
+module_param_named(nodrop, uvc_no_drop_param, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(nodrop, "Don't drop incomplete frames");
module_param_named(quirks, uvc_quirks_param, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(quirks, "Forced device quirks");
module_param_named(trace, uvc_trace_param, uint, S_IRUGO|S_IWUSR);
diff --git a/linux/drivers/media/video/uvc/uvc_video.c b/linux/drivers/media/video/uvc/uvc_video.c
index 3be776a47..b19e91dd5 100644
--- a/linux/drivers/media/video/uvc/uvc_video.c
+++ b/linux/drivers/media/video/uvc/uvc_video.c
@@ -1007,7 +1007,8 @@ int uvc_video_enable(struct uvc_video_device *video, int enable)
return 0;
}
- if (video->streaming->cur_format->flags & UVC_FMT_FLAG_COMPRESSED)
+ if ((video->streaming->cur_format->flags & UVC_FMT_FLAG_COMPRESSED) ||
+ uvc_no_drop_param)
video->queue.flags &= ~UVC_QUEUE_DROP_INCOMPLETE;
else
video->queue.flags |= UVC_QUEUE_DROP_INCOMPLETE;
diff --git a/linux/drivers/media/video/uvc/uvcvideo.h b/linux/drivers/media/video/uvc/uvcvideo.h
index f95040380..a699c0bb1 100644
--- a/linux/drivers/media/video/uvc/uvcvideo.h
+++ b/linux/drivers/media/video/uvc/uvcvideo.h
@@ -4,8 +4,6 @@
#include <linux/kernel.h>
#include <linux/videodev2.h>
-#include "compat.h"
-
/*
* Dynamic controls
*/
@@ -69,6 +67,7 @@ struct uvc_xu_control {
#ifdef __KERNEL__
#include <linux/poll.h>
+#include "compat.h"
/* --------------------------------------------------------------------------
* UVC constants
@@ -317,6 +316,7 @@ struct uvc_xu_control {
#define UVC_QUIRK_BUILTIN_ISIGHT 0x00000008
#define UVC_QUIRK_STREAM_NO_FID 0x00000010
#define UVC_QUIRK_IGNORE_SELECTOR_UNIT 0x00000020
+#define UVC_QUIRK_PRUNE_CONTROLS 0x00000040
/* Format flags */
#define UVC_FMT_FLAG_COMPRESSED 0x00000001
@@ -684,6 +684,7 @@ struct uvc_driver {
#define UVC_WARN_MINMAX 0
#define UVC_WARN_PROBE_DEF 1
+extern unsigned int uvc_no_drop_param;
extern unsigned int uvc_trace_param;
#define uvc_trace(flag, msg...) \