summaryrefslogtreecommitdiff
path: root/linux/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'linux/drivers')
-rw-r--r--linux/drivers/media/common/tuners/Kconfig8
-rw-r--r--linux/drivers/media/common/tuners/Makefile1
-rw-r--r--linux/drivers/media/common/tuners/mc44s803.c371
-rw-r--r--linux/drivers/media/common/tuners/mc44s803.h46
-rw-r--r--linux/drivers/media/common/tuners/mc44s803_priv.h208
-rw-r--r--linux/drivers/media/dvb/dvb-core/dvbdev.c4
-rw-r--r--linux/drivers/media/dvb/dvb-usb/Kconfig1
-rw-r--r--linux/drivers/media/dvb/dvb-usb/af9015.c40
-rw-r--r--linux/drivers/media/radio/dsbr100.c6
-rw-r--r--linux/drivers/media/radio/radio-mr800.c217
-rw-r--r--linux/drivers/media/radio/radio-si470x.c4
-rw-r--r--linux/drivers/media/video/cx18/cx18-audio.c3
-rw-r--r--linux/drivers/media/video/cx18/cx18-av-core.c89
-rw-r--r--linux/drivers/media/video/cx18/cx18-av-core.h19
-rw-r--r--linux/drivers/media/video/cx18/cx18-av-firmware.c3
-rw-r--r--linux/drivers/media/video/cx18/cx18-av-vbi.c106
-rw-r--r--linux/drivers/media/video/cx18/cx18-cards.c8
-rw-r--r--linux/drivers/media/video/cx18/cx18-cards.h3
-rw-r--r--linux/drivers/media/video/cx18/cx18-controls.c4
-rw-r--r--linux/drivers/media/video/cx18/cx18-driver.c120
-rw-r--r--linux/drivers/media/video/cx18/cx18-driver.h147
-rw-r--r--linux/drivers/media/video/cx18/cx18-fileops.c58
-rw-r--r--linux/drivers/media/video/cx18/cx18-ioctl.c147
-rw-r--r--linux/drivers/media/video/cx18/cx18-streams.c142
-rw-r--r--linux/drivers/media/video/cx18/cx18-vbi.c118
-rw-r--r--linux/drivers/media/video/cx18/cx18-vbi.h2
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-driver.c93
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-driver.h24
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-fileops.c2
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-firmware.c2
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-gpio.c4
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-i2c.c14
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-ioctl.c20
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-irq.c4
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-queue.c8
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-queue.h8
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-streams.c68
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-udma.c10
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-udma.h4
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-yuv.c6
-rw-r--r--linux/drivers/media/video/ivtv/ivtvfb.c6
-rw-r--r--linux/drivers/media/video/v4l2-ioctl.c3
42 files changed, 1617 insertions, 534 deletions
diff --git a/linux/drivers/media/common/tuners/Kconfig b/linux/drivers/media/common/tuners/Kconfig
index 6f92beaa5..7969b695c 100644
--- a/linux/drivers/media/common/tuners/Kconfig
+++ b/linux/drivers/media/common/tuners/Kconfig
@@ -29,6 +29,7 @@ config MEDIA_TUNER
select MEDIA_TUNER_TEA5767 if !MEDIA_TUNER_CUSTOMIZE
select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
select MEDIA_TUNER_TDA9887 if !MEDIA_TUNER_CUSTOMIZE
+ select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMIZE
menuconfig MEDIA_TUNER_CUSTOMIZE
bool "Customize analog and hybrid tuner modules to build"
@@ -164,4 +165,11 @@ config MEDIA_TUNER_MXL5007T
help
A driver for the silicon tuner MxL5007T from MaxLinear.
+config MEDIA_TUNER_MC44S803
+ tristate "Freescale MC44S803 Low Power CMOS Broadband tuners"
+ depends on VIDEO_MEDIA && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ Say Y here to support the Freescale MC44S803 based tuners
+
endif # MEDIA_TUNER_CUSTOMIZE
diff --git a/linux/drivers/media/common/tuners/Makefile b/linux/drivers/media/common/tuners/Makefile
index 4dfbe5b82..4132b2be7 100644
--- a/linux/drivers/media/common/tuners/Makefile
+++ b/linux/drivers/media/common/tuners/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_MEDIA_TUNER_QT1010) += qt1010.o
obj-$(CONFIG_MEDIA_TUNER_MT2131) += mt2131.o
obj-$(CONFIG_MEDIA_TUNER_MXL5005S) += mxl5005s.o
obj-$(CONFIG_MEDIA_TUNER_MXL5007T) += mxl5007t.o
+obj-$(CONFIG_MEDIA_TUNER_MC44S803) += mc44s803.o
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/linux/drivers/media/common/tuners/mc44s803.c b/linux/drivers/media/common/tuners/mc44s803.c
new file mode 100644
index 000000000..20c4485ce
--- /dev/null
+++ b/linux/drivers/media/common/tuners/mc44s803.c
@@ -0,0 +1,371 @@
+/*
+ * Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner
+ *
+ * Copyright (c) 2009 Jochen Friedrich <jochen@scram.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+
+#include "dvb_frontend.h"
+
+#include "mc44s803.h"
+#include "mc44s803_priv.h"
+
+#define mc_printk(level, format, arg...) \
+ printk(level "mc44s803: " format , ## arg)
+
+/* Writes a single register */
+static int mc44s803_writereg(struct mc44s803_priv *priv, u32 val)
+{
+ u8 buf[3];
+ struct i2c_msg msg = {
+ .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 3
+ };
+
+ buf[0] = (val & 0xff0000) >> 16;
+ buf[1] = (val & 0xff00) >> 8;
+ buf[2] = (val & 0xff);
+
+ if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+ mc_printk(KERN_WARNING, "I2C write failed\n");
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+/* Reads a single register */
+static int mc44s803_readreg(struct mc44s803_priv *priv, u8 reg, u32 *val)
+{
+ u32 wval;
+ u8 buf[3];
+ int ret;
+ struct i2c_msg msg[] = {
+ { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD,
+ .buf = buf, .len = 3 },
+ };
+
+ wval = MC44S803_REG_SM(MC44S803_REG_DATAREG, MC44S803_ADDR) |
+ MC44S803_REG_SM(reg, MC44S803_D);
+
+ ret = mc44s803_writereg(priv, wval);
+ if (ret)
+ return ret;
+
+ if (i2c_transfer(priv->i2c, msg, 1) != 1) {
+ mc_printk(KERN_WARNING, "I2C read failed\n");
+ return -EREMOTEIO;
+ }
+
+ *val = (buf[0] << 16) | (buf[1] << 8) | buf[2];
+
+ return 0;
+}
+
+static int mc44s803_release(struct dvb_frontend *fe)
+{
+ struct mc44s803_priv *priv = fe->tuner_priv;
+
+ fe->tuner_priv = NULL;
+ kfree(priv);
+
+ return 0;
+}
+
+static int mc44s803_init(struct dvb_frontend *fe)
+{
+ struct mc44s803_priv *priv = fe->tuner_priv;
+ u32 val;
+ int err;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+/* Reset chip */
+ val = MC44S803_REG_SM(MC44S803_REG_RESET, MC44S803_ADDR) |
+ MC44S803_REG_SM(1, MC44S803_RS);
+
+ err = mc44s803_writereg(priv, val);
+ if (err)
+ goto exit;
+
+ val = MC44S803_REG_SM(MC44S803_REG_RESET, MC44S803_ADDR);
+
+ err = mc44s803_writereg(priv, val);
+ if (err)
+ goto exit;
+
+/* Power Up and Start Osc */
+
+ val = MC44S803_REG_SM(MC44S803_REG_REFOSC, MC44S803_ADDR) |
+ MC44S803_REG_SM(0xC0, MC44S803_REFOSC) |
+ MC44S803_REG_SM(1, MC44S803_OSCSEL);
+
+ err = mc44s803_writereg(priv, val);
+ if (err)
+ goto exit;
+
+ val = MC44S803_REG_SM(MC44S803_REG_POWER, MC44S803_ADDR) |
+ MC44S803_REG_SM(0x200, MC44S803_POWER);
+
+ err = mc44s803_writereg(priv, val);
+ if (err)
+ goto exit;
+
+ msleep(10);
+
+ val = MC44S803_REG_SM(MC44S803_REG_REFOSC, MC44S803_ADDR) |
+ MC44S803_REG_SM(0x40, MC44S803_REFOSC) |
+ MC44S803_REG_SM(1, MC44S803_OSCSEL);
+
+ err = mc44s803_writereg(priv, val);
+ if (err)
+ goto exit;
+
+ msleep(20);
+
+/* Setup Mixer */
+
+ val = MC44S803_REG_SM(MC44S803_REG_MIXER, MC44S803_ADDR) |
+ MC44S803_REG_SM(1, MC44S803_TRI_STATE) |
+ MC44S803_REG_SM(0x7F, MC44S803_MIXER_RES);
+
+ err = mc44s803_writereg(priv, val);
+ if (err)
+ goto exit;
+
+/* Setup Cirquit Adjust */
+
+ val = MC44S803_REG_SM(MC44S803_REG_CIRCADJ, MC44S803_ADDR) |
+ MC44S803_REG_SM(1, MC44S803_G1) |
+ MC44S803_REG_SM(1, MC44S803_G3) |
+ MC44S803_REG_SM(0x3, MC44S803_CIRCADJ_RES) |
+ MC44S803_REG_SM(1, MC44S803_G6) |
+ MC44S803_REG_SM(priv->cfg->dig_out, MC44S803_S1) |
+ MC44S803_REG_SM(0x3, MC44S803_LP) |
+ MC44S803_REG_SM(1, MC44S803_CLRF) |
+ MC44S803_REG_SM(1, MC44S803_CLIF);
+
+ err = mc44s803_writereg(priv, val);
+ if (err)
+ goto exit;
+
+ val = MC44S803_REG_SM(MC44S803_REG_CIRCADJ, MC44S803_ADDR) |
+ MC44S803_REG_SM(1, MC44S803_G1) |
+ MC44S803_REG_SM(1, MC44S803_G3) |
+ MC44S803_REG_SM(0x3, MC44S803_CIRCADJ_RES) |
+ MC44S803_REG_SM(1, MC44S803_G6) |
+ MC44S803_REG_SM(priv->cfg->dig_out, MC44S803_S1) |
+ MC44S803_REG_SM(0x3, MC44S803_LP);
+
+ err = mc44s803_writereg(priv, val);
+ if (err)
+ goto exit;
+
+/* Setup Digtune */
+
+ val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) |
+ MC44S803_REG_SM(3, MC44S803_XOD);
+
+ err = mc44s803_writereg(priv, val);
+ if (err)
+ goto exit;
+
+/* Setup AGC */
+
+ val = MC44S803_REG_SM(MC44S803_REG_LNAAGC, MC44S803_ADDR) |
+ MC44S803_REG_SM(1, MC44S803_AT1) |
+ MC44S803_REG_SM(1, MC44S803_AT2) |
+ MC44S803_REG_SM(1, MC44S803_AGC_AN_DIG) |
+ MC44S803_REG_SM(1, MC44S803_AGC_READ_EN) |
+ MC44S803_REG_SM(1, MC44S803_LNA0);
+
+ err = mc44s803_writereg(priv, val);
+ if (err)
+ goto exit;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ return 0;
+
+exit:
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ mc_printk(KERN_WARNING, "I/O Error\n");
+ return err;
+}
+
+static int mc44s803_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
+{
+ struct mc44s803_priv *priv = fe->tuner_priv;
+ u32 r1, r2, n1, n2, lo1, lo2, freq, val;
+ int err;
+
+ priv->frequency = params->frequency;
+
+ r1 = MC44S803_OSC / 1000000;
+ r2 = MC44S803_OSC / 100000;
+
+ n1 = (params->frequency + MC44S803_IF1 + 500000) / 1000000;
+ freq = MC44S803_OSC / r1 * n1;
+ lo1 = ((60 * n1) + (r1 / 2)) / r1;
+ freq = freq - params->frequency;
+
+ n2 = (freq - MC44S803_IF2 + 50000) / 100000;
+ lo2 = ((60 * n2) + (r2 / 2)) / r2;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ val = MC44S803_REG_SM(MC44S803_REG_REFDIV, MC44S803_ADDR) |
+ MC44S803_REG_SM(r1-1, MC44S803_R1) |
+ MC44S803_REG_SM(r2-1, MC44S803_R2) |
+ MC44S803_REG_SM(1, MC44S803_REFBUF_EN);
+
+ err = mc44s803_writereg(priv, val);
+ if (err)
+ goto exit;
+
+ val = MC44S803_REG_SM(MC44S803_REG_LO1, MC44S803_ADDR) |
+ MC44S803_REG_SM(n1-2, MC44S803_LO1);
+
+ err = mc44s803_writereg(priv, val);
+ if (err)
+ goto exit;
+
+ val = MC44S803_REG_SM(MC44S803_REG_LO2, MC44S803_ADDR) |
+ MC44S803_REG_SM(n2-2, MC44S803_LO2);
+
+ err = mc44s803_writereg(priv, val);
+ if (err)
+ goto exit;
+
+ val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) |
+ MC44S803_REG_SM(1, MC44S803_DA) |
+ MC44S803_REG_SM(lo1, MC44S803_LO_REF) |
+ MC44S803_REG_SM(1, MC44S803_AT);
+
+ err = mc44s803_writereg(priv, val);
+ if (err)
+ goto exit;
+
+ val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) |
+ MC44S803_REG_SM(2, MC44S803_DA) |
+ MC44S803_REG_SM(lo2, MC44S803_LO_REF) |
+ MC44S803_REG_SM(1, MC44S803_AT);
+
+ err = mc44s803_writereg(priv, val);
+ if (err)
+ goto exit;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ return 0;
+
+exit:
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ mc_printk(KERN_WARNING, "I/O Error\n");
+ return err;
+}
+
+static int mc44s803_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct mc44s803_priv *priv = fe->tuner_priv;
+ *frequency = priv->frequency;
+ return 0;
+}
+
+static const struct dvb_tuner_ops mc44s803_tuner_ops = {
+ .info = {
+ .name = "Freescale MC44S803",
+ .frequency_min = 48000000,
+ .frequency_max = 1000000000,
+ .frequency_step = 100000,
+ },
+
+ .release = mc44s803_release,
+ .init = mc44s803_init,
+ .set_params = mc44s803_set_params,
+ .get_frequency = mc44s803_get_frequency
+};
+
+/* This functions tries to identify a MC44S803 tuner by reading the ID
+ register. This is hasty. */
+struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c, struct mc44s803_config *cfg)
+{
+ struct mc44s803_priv *priv;
+ u32 reg;
+ u8 id;
+ int ret;
+
+ reg = 0;
+
+ priv = kzalloc(sizeof(struct mc44s803_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return NULL;
+
+ priv->cfg = cfg;
+ priv->i2c = i2c;
+ priv->fe = fe;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+ ret = mc44s803_readreg(priv, MC44S803_REG_ID, &reg);
+ if (ret)
+ goto error;
+
+ id = MC44S803_REG_MS(reg, MC44S803_ID);
+
+ if (id != 0x14) {
+ mc_printk(KERN_ERR, "unsupported ID "
+ "(%x should be 0x14)\n", id);
+ goto error;
+ }
+
+ mc_printk(KERN_INFO, "successfully identified (ID = %x)\n", id);
+ memcpy(&fe->ops.tuner_ops, &mc44s803_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+
+ fe->tuner_priv = priv;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+ return fe;
+
+error:
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+ kfree(priv);
+ return NULL;
+}
+EXPORT_SYMBOL(mc44s803_attach);
+
+MODULE_AUTHOR("Jochen Friedrich");
+MODULE_DESCRIPTION("Freescale MC44S803 silicon tuner driver");
+MODULE_LICENSE("GPL");
diff --git a/linux/drivers/media/common/tuners/mc44s803.h b/linux/drivers/media/common/tuners/mc44s803.h
new file mode 100644
index 000000000..34f3892d3
--- /dev/null
+++ b/linux/drivers/media/common/tuners/mc44s803.h
@@ -0,0 +1,46 @@
+/*
+ * Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner
+ *
+ * Copyright (c) 2009 Jochen Friedrich <jochen@scram.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#ifndef MC44S803_H
+#define MC44S803_H
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+struct mc44s803_config {
+ u8 i2c_address;
+ u8 dig_out;
+};
+
+#if defined(CONFIG_MEDIA_TUNER_MC44S803) || \
+ (defined(CONFIG_MEDIA_TUNER_MC44S803_MODULE) && defined(MODULE))
+extern struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c, struct mc44s803_config *cfg);
+#else
+static inline struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c, struct mc44s803_config *cfg)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif /* CONFIG_MEDIA_TUNER_MC44S803 */
+
+#endif
diff --git a/linux/drivers/media/common/tuners/mc44s803_priv.h b/linux/drivers/media/common/tuners/mc44s803_priv.h
new file mode 100644
index 000000000..14a927809
--- /dev/null
+++ b/linux/drivers/media/common/tuners/mc44s803_priv.h
@@ -0,0 +1,208 @@
+/*
+ * Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner
+ *
+ * Copyright (c) 2009 Jochen Friedrich <jochen@scram.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#ifndef MC44S803_PRIV_H
+#define MC44S803_PRIV_H
+
+/* This driver is based on the information available in the datasheet
+ http://www.freescale.com/files/rf_if/doc/data_sheet/MC44S803.pdf
+
+ SPI or I2C Address : 0xc0-0xc6
+
+ Reg.No | Function
+ -------------------------------------------
+ 00 | Power Down
+ 01 | Reference Oszillator
+ 02 | Reference Dividers
+ 03 | Mixer and Reference Buffer
+ 04 | Reset/Serial Out
+ 05 | LO 1
+ 06 | LO 2
+ 07 | Circuit Adjust
+ 08 | Test
+ 09 | Digital Tune
+ 0A | LNA AGC
+ 0B | Data Register Address
+ 0C | Regulator Test
+ 0D | VCO Test
+ 0E | LNA Gain/Input Power
+ 0F | ID Bits
+
+*/
+
+#define MC44S803_OSC 26000000 /* 26 MHz */
+#define MC44S803_IF1 1086000000 /* 1086 MHz */
+#define MC44S803_IF2 36125000 /* 36.125 MHz */
+
+#define MC44S803_REG_POWER 0
+#define MC44S803_REG_REFOSC 1
+#define MC44S803_REG_REFDIV 2
+#define MC44S803_REG_MIXER 3
+#define MC44S803_REG_RESET 4
+#define MC44S803_REG_LO1 5
+#define MC44S803_REG_LO2 6
+#define MC44S803_REG_CIRCADJ 7
+#define MC44S803_REG_TEST 8
+#define MC44S803_REG_DIGTUNE 9
+#define MC44S803_REG_LNAAGC 0x0A
+#define MC44S803_REG_DATAREG 0x0B
+#define MC44S803_REG_REGTEST 0x0C
+#define MC44S803_REG_VCOTEST 0x0D
+#define MC44S803_REG_LNAGAIN 0x0E
+#define MC44S803_REG_ID 0x0F
+
+/* Register definitions */
+#define MC44S803_ADDR 0x0F
+#define MC44S803_ADDR_S 0
+/* REG_POWER */
+#define MC44S803_POWER 0xFFFFF0
+#define MC44S803_POWER_S 4
+/* REG_REFOSC */
+#define MC44S803_REFOSC 0x1FF0
+#define MC44S803_REFOSC_S 4
+#define MC44S803_OSCSEL 0x2000
+#define MC44S803_OSCSEL_S 13
+/* REG_REFDIV */
+#define MC44S803_R2 0x1FF0
+#define MC44S803_R2_S 4
+#define MC44S803_REFBUF_EN 0x2000
+#define MC44S803_REFBUF_EN_S 13
+#define MC44S803_R1 0x7C000
+#define MC44S803_R1_S 14
+/* REG_MIXER */
+#define MC44S803_R3 0x70
+#define MC44S803_R3_S 4
+#define MC44S803_MUX3 0x80
+#define MC44S803_MUX3_S 7
+#define MC44S803_MUX4 0x100
+#define MC44S803_MUX4_S 8
+#define MC44S803_OSC_SCR 0x200
+#define MC44S803_OSC_SCR_S 9
+#define MC44S803_TRI_STATE 0x400
+#define MC44S803_TRI_STATE_S 10
+#define MC44S803_BUF_GAIN 0x800
+#define MC44S803_BUF_GAIN_S 11
+#define MC44S803_BUF_IO 0x1000
+#define MC44S803_BUF_IO_S 12
+#define MC44S803_MIXER_RES 0xFE000
+#define MC44S803_MIXER_RES_S 13
+/* REG_RESET */
+#define MC44S803_RS 0x10
+#define MC44S803_RS_S 4
+#define MC44S803_SO 0x20
+#define MC44S803_SO_S 5
+/* REG_LO1 */
+#define MC44S803_LO1 0xFFF0
+#define MC44S803_LO1_S 4
+/* REG_LO2 */
+#define MC44S803_LO2 0x7FFF0
+#define MC44S803_LO2_S 4
+/* REG_CIRCADJ */
+#define MC44S803_G1 0x20
+#define MC44S803_G1_S 5
+#define MC44S803_G3 0x80
+#define MC44S803_G3_S 7
+#define MC44S803_CIRCADJ_RES 0x300
+#define MC44S803_CIRCADJ_RES_S 8
+#define MC44S803_G6 0x400
+#define MC44S803_G6_S 10
+#define MC44S803_G7 0x800
+#define MC44S803_G7_S 11
+#define MC44S803_S1 0x1000
+#define MC44S803_S1_S 12
+#define MC44S803_LP 0x7E000
+#define MC44S803_LP_S 13
+#define MC44S803_CLRF 0x80000
+#define MC44S803_CLRF_S 19
+#define MC44S803_CLIF 0x100000
+#define MC44S803_CLIF_S 20
+/* REG_TEST */
+/* REG_DIGTUNE */
+#define MC44S803_DA 0xF0
+#define MC44S803_DA_S 4
+#define MC44S803_XOD 0x300
+#define MC44S803_XOD_S 8
+#define MC44S803_RST 0x10000
+#define MC44S803_RST_S 16
+#define MC44S803_LO_REF 0x1FFF00
+#define MC44S803_LO_REF_S 8
+#define MC44S803_AT 0x200000
+#define MC44S803_AT_S 21
+#define MC44S803_MT 0x400000
+#define MC44S803_MT_S 22
+/* REG_LNAAGC */
+#define MC44S803_G 0x3F0
+#define MC44S803_G_S 4
+#define MC44S803_AT1 0x400
+#define MC44S803_AT1_S 10
+#define MC44S803_AT2 0x800
+#define MC44S803_AT2_S 11
+#define MC44S803_HL_GR_EN 0x8000
+#define MC44S803_HL_GR_EN_S 15
+#define MC44S803_AGC_AN_DIG 0x10000
+#define MC44S803_AGC_AN_DIG_S 16
+#define MC44S803_ATTEN_EN 0x20000
+#define MC44S803_ATTEN_EN_S 17
+#define MC44S803_AGC_READ_EN 0x40000
+#define MC44S803_AGC_READ_EN_S 18
+#define MC44S803_LNA0 0x80000
+#define MC44S803_LNA0_S 19
+#define MC44S803_AGC_SEL 0x100000
+#define MC44S803_AGC_SEL_S 20
+#define MC44S803_AT0 0x200000
+#define MC44S803_AT0_S 21
+#define MC44S803_B 0xC00000
+#define MC44S803_B_S 22
+/* REG_DATAREG */
+#define MC44S803_D 0xF0
+#define MC44S803_D_S 4
+/* REG_REGTEST */
+/* REG_VCOTEST */
+/* REG_LNAGAIN */
+#define MC44S803_IF_PWR 0x700
+#define MC44S803_IF_PWR_S 8
+#define MC44S803_RF_PWR 0x3800
+#define MC44S803_RF_PWR_S 11
+#define MC44S803_LNA_GAIN 0xFC000
+#define MC44S803_LNA_GAIN_S 14
+/* REG_ID */
+#define MC44S803_ID 0x3E00
+#define MC44S803_ID_S 9
+
+/* Some macros to read/write fields */
+
+/* First shift, then mask */
+#define MC44S803_REG_SM(_val, _reg) \
+ (((_val) << _reg##_S) & (_reg))
+
+/* First mask, then shift */
+#define MC44S803_REG_MS(_val, _reg) \
+ (((_val) & (_reg)) >> _reg##_S)
+
+struct mc44s803_priv {
+ struct mc44s803_config *cfg;
+ struct i2c_adapter *i2c;
+ struct dvb_frontend *fe;
+
+ u32 frequency;
+};
+
+#endif
diff --git a/linux/drivers/media/dvb/dvb-core/dvbdev.c b/linux/drivers/media/dvb/dvb-core/dvbdev.c
index 4609e3ebd..f6084e19d 100644
--- a/linux/drivers/media/dvb/dvb-core/dvbdev.c
+++ b/linux/drivers/media/dvb/dvb-core/dvbdev.c
@@ -83,7 +83,11 @@ static int dvb_device_open(struct inode *inode, struct file *file)
file->private_data = dvbdev;
old_fops = file->f_op;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17)
file->f_op = fops_get(dvbdev->fops);
+#else
+ file->f_op = (struct file_operations *)fops_get(dvbdev->fops);
+#endif
if (file->f_op == NULL) {
file->f_op = old_fops;
goto fail;
diff --git a/linux/drivers/media/dvb/dvb-usb/Kconfig b/linux/drivers/media/dvb/dvb-usb/Kconfig
index 49f7b20c2..bbddc9fb6 100644
--- a/linux/drivers/media/dvb/dvb-usb/Kconfig
+++ b/linux/drivers/media/dvb/dvb-usb/Kconfig
@@ -297,5 +297,6 @@ config DVB_USB_AF9015
select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMIZE
select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMIZE
select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMIZE
+ select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE
help
Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver
diff --git a/linux/drivers/media/dvb/dvb-usb/af9015.c b/linux/drivers/media/dvb/dvb-usb/af9015.c
index e518d47fe..88a365ad9 100644
--- a/linux/drivers/media/dvb/dvb-usb/af9015.c
+++ b/linux/drivers/media/dvb/dvb-usb/af9015.c
@@ -27,9 +27,7 @@
#include "qt1010.h"
#include "tda18271.h"
#include "mxl5005s.h"
-#if 0 /* keep */
-#include "mc44s80x.h"
-#endif
+#include "mc44s803.h"
static int dvb_usb_af9015_debug;
module_param_named(debug, dvb_usb_af9015_debug, int, 0644);
@@ -280,6 +278,21 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate.
req.data = &msg[i+1].buf[0];
ret = af9015_ctrl_msg(d, &req);
i += 2;
+ } else if (msg[i].flags & I2C_M_RD) {
+ ret = -EINVAL;
+ if (msg[i].addr ==
+ af9015_af9013_config[0].demod_address)
+ goto error;
+ else
+ req.cmd = READ_I2C;
+ req.i2c_addr = msg[i].addr;
+ req.addr = addr;
+ req.mbox = mbox;
+ req.addr_len = addr_len;
+ req.data_len = msg[i].len;
+ req.data = &msg[i].buf[0];
+ ret = af9015_ctrl_msg(d, &req);
+ i += 1;
} else {
if (msg[i].addr ==
af9015_af9013_config[0].demod_address)
@@ -942,7 +955,6 @@ static int af9015_read_config(struct usb_device *udev)
switch (val) {
case AF9013_TUNER_ENV77H11D5:
case AF9013_TUNER_MT2060:
- case AF9013_TUNER_MC44S803:
case AF9013_TUNER_QT1010:
case AF9013_TUNER_UNKNOWN:
case AF9013_TUNER_MT2060_2:
@@ -955,6 +967,10 @@ static int af9015_read_config(struct usb_device *udev)
case AF9013_TUNER_MXL5005R:
af9015_af9013_config[i].rf_spec_inv = 0;
break;
+ case AF9013_TUNER_MC44S803:
+ af9015_af9013_config[i].gpio[1] = AF9013_GPIO_LO;
+ af9015_af9013_config[i].rf_spec_inv = 1;
+ break;
default:
warn("tuner id:%d not supported, please report!", val);
return -ENODEV;
@@ -1142,6 +1158,11 @@ static struct mxl5005s_config af9015_mxl5005_config = {
.AgcMasterByte = 0x00,
};
+static struct mc44s803_config af9015_mc44s803_config = {
+ .i2c_address = 0xc0,
+ .dig_out = 1,
+};
+
static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
{
struct af9015_state *state = adap->dev->priv;
@@ -1186,15 +1207,8 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
DVB_PLL_TDA665X) == NULL ? -ENODEV : 0;
break;
case AF9013_TUNER_MC44S803:
-#if 0 /* keep */
- ret = dvb_attach(mc44s80x_attach, adap->fe, i2c_adap)
- == NULL ? -ENODEV : 0;
-#else
- ret = -ENODEV;
- info("Freescale MC44S803 tuner found but no driver for that" \
- "tuner. Look at the Linuxtv.org for tuner driver" \
- "status.");
-#endif
+ ret = dvb_attach(mc44s803_attach, adap->fe, i2c_adap,
+ &af9015_mc44s803_config) == NULL ? -ENODEV : 0;
break;
case AF9013_TUNER_UNKNOWN:
default:
diff --git a/linux/drivers/media/radio/dsbr100.c b/linux/drivers/media/radio/dsbr100.c
index 0516711f8..155a75341 100644
--- a/linux/drivers/media/radio/dsbr100.c
+++ b/linux/drivers/media/radio/dsbr100.c
@@ -455,7 +455,10 @@ static int vidioc_s_frequency(struct file *file, void *priv,
if (radio->removed)
return -EIO;
+ mutex_lock(&radio->lock);
radio->curfreq = f->frequency;
+ mutex_unlock(&radio->lock);
+
retval = dsbr100_setfreq(radio, radio->curfreq);
if (retval < 0)
dev_warn(&radio->usbdev->dev, "Set frequency failed\n");
@@ -606,7 +609,10 @@ static int usb_dsbr100_close(struct file *file)
if (!radio)
return -ENODEV;
+ mutex_lock(&radio->lock);
radio->users = 0;
+ mutex_unlock(&radio->lock);
+
if (!radio->removed) {
retval = dsbr100_stop(radio);
if (retval < 0) {
diff --git a/linux/drivers/media/radio/radio-mr800.c b/linux/drivers/media/radio/radio-mr800.c
index 4aa51a282..c04c8887e 100644
--- a/linux/drivers/media/radio/radio-mr800.c
+++ b/linux/drivers/media/radio/radio-mr800.c
@@ -22,7 +22,7 @@
*/
/*
- * Big thanks to authors of dsbr100.c and radio-si470x.c
+ * Big thanks to authors and contributors of dsbr100.c and radio-si470x.c
*
* When work was looked pretty good, i discover this:
* http://av-usbradio.sourceforge.net/index.php
@@ -30,18 +30,23 @@
* Latest release of theirs project was in 2005.
* Probably, this driver could be improved trough using their
* achievements (specifications given).
- * So, we have smth to begin with.
+ * Also, Faidon Liambotis <paravoid@debian.org> wrote nice driver for this radio
+ * in 2007. He allowed to use his driver to improve current mr800 radio driver.
+ * http://kerneltrap.org/mailarchive/linux-usb-devel/2007/10/11/342492
*
- * History:
* Version 0.01: First working version.
* It's required to blacklist AverMedia USB Radio
* in usbhid/hid-quirks.c
+ * Version 0.10: A lot of cleanups and fixes: unpluging the device,
+ * few mutex locks were added, codinstyle issues, etc.
+ * Added stereo support. Thanks to
+ * Douglas Schilling Landgraf <dougsland@gmail.com> and
+ * David Ellingsworth <david@identd.dyndns.org>
+ * for discussion, help and support.
*
* Many things to do:
* - Correct power managment of device (suspend & resume)
- * - Make x86 independance (little-endian and big-endian stuff)
* - Add code for scanning and smooth tuning
- * - Checked and add stereo&mono stuff
* - Add code for sensitivity value
* - Correct mistakes
* - In Japan another FREQ_MIN and FREQ_MAX
@@ -63,8 +68,8 @@
/* driver and module definitions */
#define DRIVER_AUTHOR "Alexey Klimov <klimov.linux@gmail.com>"
#define DRIVER_DESC "AverMedia MR 800 USB FM radio driver"
-#define DRIVER_VERSION "0.01"
-#define RADIO_VERSION KERNEL_VERSION(0, 0, 1)
+#define DRIVER_VERSION "0.10"
+#define RADIO_VERSION KERNEL_VERSION(0, 1, 0)
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
@@ -88,6 +93,22 @@ devices, that would be 76 and 91. */
#define FREQ_MAX 108.0
#define FREQ_MUL 16000
+/*
+ * Commands that device should understand
+ * List isnt full and will be updated with implementation of new functions
+ */
+#define AMRADIO_SET_FREQ 0xa4
+#define AMRADIO_SET_MUTE 0xab
+#define AMRADIO_SET_MONO 0xae
+
+/* Comfortable defines for amradio_set_mute */
+#define AMRADIO_START 0x00
+#define AMRADIO_STOP 0x01
+
+/* Comfortable defines for amradio_set_stereo */
+#define WANT_STEREO 0x00
+#define WANT_MONO 0x01
+
/* module parameter */
static int radio_nr = -1;
module_param(radio_nr, int, 0);
@@ -172,43 +193,48 @@ static struct usb_driver usb_amradio_driver = {
.supports_autosuspend = 0,
};
-/* switch on radio. Send 8 bytes to device. */
-static int amradio_start(struct amradio_device *radio)
+/* switch on/off the radio. Send 8 bytes to device */
+static int amradio_set_mute(struct amradio_device *radio, char argument)
{
int retval;
int size;
+ /* safety check */
+ if (radio->removed)
+ return -EIO;
+
mutex_lock(&radio->lock);
radio->buffer[0] = 0x00;
radio->buffer[1] = 0x55;
radio->buffer[2] = 0xaa;
radio->buffer[3] = 0x00;
- radio->buffer[4] = 0xab;
- radio->buffer[5] = 0x00;
+ radio->buffer[4] = AMRADIO_SET_MUTE;
+ radio->buffer[5] = argument;
radio->buffer[6] = 0x00;
radio->buffer[7] = 0x00;
retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
(void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
- if (retval) {
+ if (retval < 0 || size != BUFFER_LENGTH) {
mutex_unlock(&radio->lock);
return retval;
}
- radio->muted = 0;
+ radio->muted = argument;
mutex_unlock(&radio->lock);
return retval;
}
-/* switch off radio */
-static int amradio_stop(struct amradio_device *radio)
+/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
+static int amradio_setfreq(struct amradio_device *radio, int freq)
{
int retval;
int size;
+ unsigned short freq_send = 0x10 + (freq >> 3) / 25;
/* safety check */
if (radio->removed)
@@ -219,33 +245,46 @@ static int amradio_stop(struct amradio_device *radio)
radio->buffer[0] = 0x00;
radio->buffer[1] = 0x55;
radio->buffer[2] = 0xaa;
- radio->buffer[3] = 0x00;
- radio->buffer[4] = 0xab;
- radio->buffer[5] = 0x01;
+ radio->buffer[3] = 0x03;
+ radio->buffer[4] = AMRADIO_SET_FREQ;
+ radio->buffer[5] = 0x00;
radio->buffer[6] = 0x00;
- radio->buffer[7] = 0x00;
+ radio->buffer[7] = 0x08;
retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
(void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
- if (retval) {
+ if (retval < 0 || size != BUFFER_LENGTH) {
mutex_unlock(&radio->lock);
return retval;
}
- radio->muted = 1;
+ /* frequency is calculated from freq_send and placed in first 2 bytes */
+ radio->buffer[0] = (freq_send >> 8) & 0xff;
+ radio->buffer[1] = freq_send & 0xff;
+ radio->buffer[2] = 0x01;
+ radio->buffer[3] = 0x00;
+ radio->buffer[4] = 0x00;
+ /* 5 and 6 bytes of buffer already = 0x00 */
+ radio->buffer[7] = 0x00;
+
+ retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
+ (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
+
+ if (retval < 0 || size != BUFFER_LENGTH) {
+ mutex_unlock(&radio->lock);
+ return retval;
+ }
mutex_unlock(&radio->lock);
return retval;
}
-/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
-static int amradio_setfreq(struct amradio_device *radio, int freq)
+static int amradio_set_stereo(struct amradio_device *radio, char argument)
{
int retval;
int size;
- unsigned short freq_send = 0x13 + (freq >> 3) / 25;
/* safety check */
if (radio->removed)
@@ -256,50 +295,33 @@ static int amradio_setfreq(struct amradio_device *radio, int freq)
radio->buffer[0] = 0x00;
radio->buffer[1] = 0x55;
radio->buffer[2] = 0xaa;
- radio->buffer[3] = 0x03;
- radio->buffer[4] = 0xa4;
- radio->buffer[5] = 0x00;
- radio->buffer[6] = 0x00;
- radio->buffer[7] = 0x08;
-
- retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
- (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
-
- if (retval) {
- mutex_unlock(&radio->lock);
- return retval;
- }
-
- /* frequency is calculated from freq_send and placed in first 2 bytes */
- radio->buffer[0] = (freq_send >> 8) & 0xff;
- radio->buffer[1] = freq_send & 0xff;
- radio->buffer[2] = 0x01;
radio->buffer[3] = 0x00;
- radio->buffer[4] = 0x00;
- /* 5 and 6 bytes of buffer already = 0x00 */
+ radio->buffer[4] = AMRADIO_SET_MONO;
+ radio->buffer[5] = argument;
+ radio->buffer[6] = 0x00;
radio->buffer[7] = 0x00;
retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
(void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
- if (retval) {
+ if (retval < 0 || size != BUFFER_LENGTH) {
+ radio->stereo = -1;
mutex_unlock(&radio->lock);
return retval;
}
- radio->stereo = 0;
+ radio->stereo = 1;
mutex_unlock(&radio->lock);
return retval;
}
-/* USB subsystem interface begins here */
-
-/* handle unplugging of the device, release data structures
-if nothing keeps us from doing it. If something is still
-keeping us busy, the release callback of v4l will take care
-of releasing it. */
+/* Handle unplugging the device.
+ * We call video_unregister_device in any case.
+ * The last function called in this procedure is
+ * usb_amradio_device_release.
+ */
static void usb_amradio_disconnect(struct usb_interface *intf)
{
struct amradio_device *radio = usb_get_intfdata(intf);
@@ -331,6 +353,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
struct v4l2_tuner *v)
{
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
+ int retval;
/* safety check */
if (radio->removed)
@@ -342,7 +365,16 @@ static int vidioc_g_tuner(struct file *file, void *priv,
/* TODO: Add function which look is signal stereo or not
* amradio_getstat(radio);
*/
- radio->stereo = -1;
+
+/* we call amradio_set_stereo to set radio->stereo
+ * Honestly, amradio_getstat should cover this in future and
+ * amradio_set_stereo shouldn't be here
+ */
+ retval = amradio_set_stereo(radio, WANT_STEREO);
+ if (retval < 0)
+ amradio_dev_warn(&radio->videodev->dev,
+ "set stereo failed\n");
+
strcpy(v->name, "FM");
v->type = V4L2_TUNER_RADIO;
v->rangelow = FREQ_MIN * FREQ_MUL;
@@ -363,6 +395,7 @@ static int vidioc_s_tuner(struct file *file, void *priv,
struct v4l2_tuner *v)
{
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
+ int retval;
/* safety check */
if (radio->removed)
@@ -370,6 +403,25 @@ static int vidioc_s_tuner(struct file *file, void *priv,
if (v->index > 0)
return -EINVAL;
+
+ /* mono/stereo selector */
+ switch (v->audmode) {
+ case V4L2_TUNER_MODE_MONO:
+ retval = amradio_set_stereo(radio, WANT_MONO);
+ if (retval < 0)
+ amradio_dev_warn(&radio->videodev->dev,
+ "set mono failed\n");
+ break;
+ case V4L2_TUNER_MODE_STEREO:
+ retval = amradio_set_stereo(radio, WANT_STEREO);
+ if (retval < 0)
+ amradio_dev_warn(&radio->videodev->dev,
+ "set stereo failed\n");
+ break;
+ default:
+ return -EINVAL;
+ }
+
return 0;
}
@@ -378,13 +430,18 @@ static int vidioc_s_frequency(struct file *file, void *priv,
struct v4l2_frequency *f)
{
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
+ int retval;
/* safety check */
if (radio->removed)
return -EIO;
+ mutex_lock(&radio->lock);
radio->curfreq = f->frequency;
- if (amradio_setfreq(radio, radio->curfreq) < 0)
+ mutex_unlock(&radio->lock);
+
+ retval = amradio_setfreq(radio, radio->curfreq);
+ if (retval < 0)
amradio_dev_warn(&radio->videodev->dev,
"set frequency failed\n");
return 0;
@@ -443,6 +500,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
struct v4l2_control *ctrl)
{
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
+ int retval;
/* safety check */
if (radio->removed)
@@ -451,13 +509,15 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
if (ctrl->value) {
- if (amradio_stop(radio) < 0) {
+ retval = amradio_set_mute(radio, AMRADIO_STOP);
+ if (retval < 0) {
amradio_dev_warn(&radio->videodev->dev,
"amradio_stop failed\n");
return -1;
}
} else {
- if (amradio_start(radio) < 0) {
+ retval = amradio_set_mute(radio, AMRADIO_START);
+ if (retval < 0) {
amradio_dev_warn(&radio->videodev->dev,
"amradio_start failed\n");
return -1;
@@ -508,20 +568,29 @@ static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
static int usb_amradio_open(struct file *file)
{
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
+ int retval;
lock_kernel();
radio->users = 1;
radio->muted = 1;
- if (amradio_start(radio) < 0) {
+ retval = amradio_set_mute(radio, AMRADIO_START);
+ if (retval < 0) {
amradio_dev_warn(&radio->videodev->dev,
"radio did not start up properly\n");
radio->users = 0;
unlock_kernel();
return -EIO;
}
- if (amradio_setfreq(radio, radio->curfreq) < 0)
+
+ retval = amradio_set_stereo(radio, WANT_STEREO);
+ if (retval < 0)
+ amradio_dev_warn(&radio->videodev->dev,
+ "set stereo failed\n");
+
+ retval = amradio_setfreq(radio, radio->curfreq);
+ if (retval < 0)
amradio_dev_warn(&radio->videodev->dev,
"set frequency failed\n");
@@ -538,10 +607,12 @@ static int usb_amradio_close(struct file *file)
if (!radio)
return -ENODEV;
+ mutex_lock(&radio->lock);
radio->users = 0;
+ mutex_unlock(&radio->lock);
if (!radio->removed) {
- retval = amradio_stop(radio);
+ retval = amradio_set_mute(radio, AMRADIO_STOP);
if (retval < 0)
amradio_dev_warn(&radio->videodev->dev,
"amradio_stop failed\n");
@@ -554,8 +625,10 @@ static int usb_amradio_close(struct file *file)
static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message)
{
struct amradio_device *radio = usb_get_intfdata(intf);
+ int retval;
- if (amradio_stop(radio) < 0)
+ retval = amradio_set_mute(radio, AMRADIO_STOP);
+ if (retval < 0)
dev_warn(&intf->dev, "amradio_stop failed\n");
dev_info(&intf->dev, "going into suspend..\n");
@@ -567,8 +640,10 @@ static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message)
static int usb_amradio_resume(struct usb_interface *intf)
{
struct amradio_device *radio = usb_get_intfdata(intf);
+ int retval;
- if (amradio_start(radio) < 0)
+ retval = amradio_set_mute(radio, AMRADIO_START);
+ if (retval < 0)
dev_warn(&intf->dev, "amradio_start failed\n");
dev_info(&intf->dev, "coming out of suspend..\n");
@@ -619,28 +694,32 @@ static struct video_device amradio_videodev_template = {
.release = usb_amradio_device_release,
};
-/* check if the device is present and register with v4l and
-usb if it is */
+/* check if the device is present and register with v4l and usb if it is */
static int usb_amradio_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct amradio_device *radio;
+ int retval;
radio = kmalloc(sizeof(struct amradio_device), GFP_KERNEL);
- if (!(radio))
+ if (!radio) {
+ dev_err(&intf->dev, "kmalloc for amradio_device failed\n");
return -ENOMEM;
+ }
radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL);
- if (!(radio->buffer)) {
+ if (!radio->buffer) {
+ dev_err(&intf->dev, "kmalloc for radio->buffer failed\n");
kfree(radio);
return -ENOMEM;
}
radio->videodev = video_device_alloc();
- if (!(radio->videodev)) {
+ if (!radio->videodev) {
+ dev_err(&intf->dev, "video_device_alloc failed\n");
kfree(radio->buffer);
kfree(radio);
return -ENOMEM;
@@ -653,12 +732,14 @@ static int usb_amradio_probe(struct usb_interface *intf,
radio->users = 0;
radio->usbdev = interface_to_usbdev(intf);
radio->curfreq = 95.16 * FREQ_MUL;
+ radio->stereo = -1;
mutex_init(&radio->lock);
video_set_drvdata(radio->videodev, radio);
- if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
- dev_warn(&intf->dev, "could not register video device\n");
+ retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr);
+ if (retval < 0) {
+ dev_err(&intf->dev, "could not register video device\n");
video_device_release(radio->videodev);
kfree(radio->buffer);
kfree(radio);
diff --git a/linux/drivers/media/radio/radio-si470x.c b/linux/drivers/media/radio/radio-si470x.c
index f3cdf3af4..f77a65d2a 100644
--- a/linux/drivers/media/radio/radio-si470x.c
+++ b/linux/drivers/media/radio/radio-si470x.c
@@ -1202,9 +1202,11 @@ static struct v4l2_queryctrl si470x_v4l2_queryctrl[] = {
static int si470x_vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *capability)
{
+ struct si470x_device *radio = video_drvdata(file);
+
strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
- sprintf(capability->bus_info, "USB");
+ usb_make_path(radio->usbdev, capability->bus_info, sizeof(capability->bus_info));
capability->version = DRIVER_KERNEL_VERSION;
capability->capabilities = V4L2_CAP_HW_FREQ_SEEK |
V4L2_CAP_TUNER | V4L2_CAP_RADIO;
diff --git a/linux/drivers/media/video/cx18/cx18-audio.c b/linux/drivers/media/video/cx18/cx18-audio.c
index 57beddf0a..d19bd778c 100644
--- a/linux/drivers/media/video/cx18/cx18-audio.c
+++ b/linux/drivers/media/video/cx18/cx18-audio.c
@@ -64,8 +64,7 @@ int cx18_audio_set_io(struct cx18 *cx)
val = cx18_read_reg(cx, CX18_AUDIO_ENABLE) & ~0x30;
val |= (audio_input > CX18_AV_AUDIO_SERIAL2) ? 0x20 :
(audio_input << 4);
- cx18_write_reg(cx, val | 0xb00, CX18_AUDIO_ENABLE);
- cx18_vapi(cx, CX18_APU_RESETAI, 1, 0);
+ cx18_write_reg_expect(cx, val | 0xb00, CX18_AUDIO_ENABLE, val, 0x30);
return 0;
}
diff --git a/linux/drivers/media/video/cx18/cx18-av-core.c b/linux/drivers/media/video/cx18/cx18-av-core.c
index 780125002..a3bd2c95f 100644
--- a/linux/drivers/media/video/cx18/cx18-av-core.c
+++ b/linux/drivers/media/video/cx18/cx18-av-core.c
@@ -169,9 +169,14 @@ static void cx18_av_initialize(struct cx18 *cx)
/* Set VGA_TRACK_RANGE to 0x20 */
cx18_av_and_or4(cx, CXADEC_DFE_CTRL2, 0xFFFF00FF, 0x00002000);
- /* Enable VBI capture */
- cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4010253F);
- /* cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4010253E); */
+ /*
+ * Initial VBI setup
+ * VIP-1.1, 10 bit mode, enable Raw, disable sliced,
+ * don't clamp raw samples when codes are in use, 1 byte user D-words,
+ * IDID0 has line #, RP code V bit transition on VBLANK, data during
+ * blanking intervals
+ */
+ cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4013252e);
/* Set the video input.
The setting in MODE_CTRL gets lost when we do the above setup */
@@ -213,6 +218,7 @@ void cx18_av_std_setup(struct cx18 *cx)
cx18_av_write(cx, 0x49f, 0x14);
if (std & V4L2_STD_625_50) {
+ /* FIXME - revisit these for Sliced VBI */
hblank = 132;
hactive = 720;
burst = 93;
@@ -236,13 +242,34 @@ void cx18_av_std_setup(struct cx18 *cx)
sc = 672351;
}
} else {
+ /*
+ * The following relationships of half line counts should hold:
+ * 525 = vsync + vactive + vblank656
+ * 12 = vblank656 - vblank
+ *
+ * vsync: always 6 half-lines of vsync pulses
+ * vactive: half lines of active video
+ * vblank656: half lines, after line 3, of blanked video
+ * vblank: half lines, after line 9, of blanked video
+ *
+ * vblank656 starts counting from the falling edge of the first
+ * vsync pulse (start of line 4)
+ * vblank starts counting from the after the 6 vsync pulses and
+ * 6 equalization pulses (start of line 10)
+ *
+ * For 525 line systems the driver will extract VBI information
+ * from lines 10 through 21. To avoid the EAV RP code from
+ * toggling at the start of hblank at line 22, where sliced VBI
+ * data from line 21 is stuffed, also treat line 22 as blanked.
+ */
+ vblank656 = 38; /* lines 4 through 22 */
+ vblank = 26; /* lines 10 through 22 */
+ vactive = 481; /* lines 23 through 262.5 */
+
hactive = 720;
hblank = 122;
- vactive = 487;
luma_lpf = 1;
uv_lpf = 1;
- vblank = 26;
- vblank656 = 26;
src_decimation = 0x21f;
if (std == V4L2_STD_PAL_60) {
@@ -325,14 +352,14 @@ void cx18_av_std_setup(struct cx18 *cx)
cx18_av_write(cx, 0x47d, 0xff & sc >> 8);
cx18_av_write(cx, 0x47e, 0xff & sc >> 16);
- /* Sets VBI parameters */
if (std & V4L2_STD_625_50) {
- cx18_av_write(cx, 0x47f, 0x01);
- state->vbi_line_offset = 5;
+ state->slicer_line_delay = 1;
+ state->slicer_line_offset = (6 + state->slicer_line_delay - 2);
} else {
- cx18_av_write(cx, 0x47f, 0x00);
- state->vbi_line_offset = 8;
+ state->slicer_line_delay = 0;
+ state->slicer_line_offset = (10 + state->slicer_line_delay - 2);
}
+ cx18_av_write(cx, 0x47f, state->slicer_line_delay);
}
/* ----------------------------------------------------------------------- */
@@ -680,19 +707,45 @@ static int set_v4lfmt(struct cx18 *cx, struct v4l2_format *fmt)
/* ----------------------------------------------------------------------- */
+static int valid_av_cmd(unsigned int cmd)
+{
+ switch (cmd) {
+ /* All commands supported by cx18_av_cmd() */
+ case VIDIOC_INT_DECODE_VBI_LINE:
+ case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+ case VIDIOC_STREAMON:
+ case VIDIOC_STREAMOFF:
+ case VIDIOC_LOG_STATUS:
+ case VIDIOC_G_CTRL:
+ case VIDIOC_S_CTRL:
+ case VIDIOC_QUERYCTRL:
+ case VIDIOC_G_STD:
+ case VIDIOC_S_STD:
+ case AUDC_SET_RADIO:
+ case VIDIOC_INT_G_VIDEO_ROUTING:
+ case VIDIOC_INT_S_VIDEO_ROUTING:
+ case VIDIOC_INT_G_AUDIO_ROUTING:
+ case VIDIOC_INT_S_AUDIO_ROUTING:
+ case VIDIOC_S_FREQUENCY:
+ case VIDIOC_G_TUNER:
+ case VIDIOC_S_TUNER:
+ case VIDIOC_G_FMT:
+ case VIDIOC_S_FMT:
+ case VIDIOC_INT_RESET:
+ return 1;
+ default:
+ return 0;
+ }
+ return 0;
+}
+
int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg)
{
struct cx18_av_state *state = &cx->av_state;
struct v4l2_tuner *vt = arg;
struct v4l2_routing *route = arg;
- /* ignore these commands */
- switch (cmd) {
- case TUNER_SET_TYPE_ADDR:
- return 0;
- }
-
- if (!state->is_initialized) {
+ if (!state->is_initialized && valid_av_cmd(cmd)) {
CX18_DEBUG_INFO("cmd %08x triggered fw load\n", cmd);
/* initialize on first use */
state->is_initialized = 1;
diff --git a/linux/drivers/media/video/cx18/cx18-av-core.h b/linux/drivers/media/video/cx18/cx18-av-core.h
index cf68a6039..d83760cae 100644
--- a/linux/drivers/media/video/cx18/cx18-av-core.h
+++ b/linux/drivers/media/video/cx18/cx18-av-core.h
@@ -79,11 +79,28 @@ struct cx18_av_state {
enum cx18_av_audio_input aud_input;
u32 audclk_freq;
int audmode;
- int vbi_line_offset;
int default_volume;
u32 id;
u32 rev;
int is_initialized;
+
+ /*
+ * The VBI slicer starts operating and counting lines, begining at
+ * slicer line count of 1, at D lines after the deassertion of VRESET
+ * This staring field line, S, is 6 or 10 for 625 or 525 line systems.
+ * Sliced ancillary data captured on VBI slicer line M is sent at the
+ * beginning of the next VBI slicer line, VBI slicer line count N = M+1.
+ * Thus when the VBI slicer reports a VBI slicer line number with
+ * ancillary data, the IDID0 byte indicates VBI slicer line N.
+ * The actual field line that the captured data comes from is
+ * L = M+(S+D-1) = N-1+(S+D-1) = N + (S+D-2).
+ *
+ * D is the slicer_line_delay value programmed into register 0x47f.
+ * (S+D-2) is the slicer_line_offset used to convert slicer reported
+ * line counts to actual field lines.
+ */
+ int slicer_line_delay;
+ int slicer_line_offset;
};
diff --git a/linux/drivers/media/video/cx18/cx18-av-firmware.c b/linux/drivers/media/video/cx18/cx18-av-firmware.c
index b374c74d3..940ea9352 100644
--- a/linux/drivers/media/video/cx18/cx18-av-firmware.c
+++ b/linux/drivers/media/video/cx18/cx18-av-firmware.c
@@ -131,7 +131,8 @@ int cx18_av_loadfw(struct cx18 *cx)
v = cx18_read_reg(cx, CX18_AUDIO_ENABLE);
/* If bit 11 is 1, clear bit 10 */
if (v & 0x800)
- cx18_write_reg(cx, v & 0xFFFFFBFF, CX18_AUDIO_ENABLE);
+ cx18_write_reg_expect(cx, v & 0xFFFFFBFF, CX18_AUDIO_ENABLE,
+ 0, 0x400);
/* Enable WW auto audio standard detection */
v = cx18_av_read4(cx, CXADEC_STD_DET_CTL);
diff --git a/linux/drivers/media/video/cx18/cx18-av-vbi.c b/linux/drivers/media/video/cx18/cx18-av-vbi.c
index 1527ea4f6..43267d1af 100644
--- a/linux/drivers/media/video/cx18/cx18-av-vbi.c
+++ b/linux/drivers/media/video/cx18/cx18-av-vbi.c
@@ -24,6 +24,52 @@
#include "cx18-driver.h"
+/*
+ * For sliced VBI output, we set up to use VIP-1.1, 8-bit mode,
+ * NN counts 1 byte Dwords, an IDID with the VBI line # in it.
+ * Thus, according to the VIP-2 Spec, our VBI ancillary data lines
+ * (should!) look like:
+ * 4 byte EAV code: 0xff 0x00 0x00 0xRP
+ * unknown number of possible idle bytes
+ * 3 byte Anc data preamble: 0x00 0xff 0xff
+ * 1 byte data identifier: ne010iii (parity bits, 010, DID bits)
+ * 1 byte secondary data id: nessssss (parity bits, SDID bits)
+ * 1 byte data word count: necccccc (parity bits, NN Dword count)
+ * 2 byte Internal DID: VBI-line-# 0x80
+ * NN data bytes
+ * 1 byte checksum
+ * Fill bytes needed to fil out to 4*NN bytes of payload
+ *
+ * The RP codes for EAVs when in VIP-1.1 mode, not in raw mode, &
+ * in the vertical blanking interval are:
+ * 0xb0 (Task 0 VerticalBlank HorizontalBlank 0 0 0 0)
+ * 0xf0 (Task EvenField VerticalBlank HorizontalBlank 0 0 0 0)
+ *
+ * Since the V bit is only allowed to toggle in the EAV RP code, just
+ * before the first active region line and for active lines, they are:
+ * 0x90 (Task 0 0 HorizontalBlank 0 0 0 0)
+ * 0xd0 (Task EvenField 0 HorizontalBlank 0 0 0 0)
+ *
+ * The user application DID bytes we care about are:
+ * 0x91 (1 0 010 0 !ActiveLine AncDataPresent)
+ * 0x55 (0 1 010 2ndField !ActiveLine AncDataPresent)
+ *
+ */
+static const u8 sliced_vbi_did[2] = { 0x91, 0x55 };
+
+struct vbi_anc_data {
+ /* u8 eav[4]; */
+ /* u8 idle[]; Variable number of idle bytes */
+ u8 preamble[3];
+ u8 did;
+ u8 sdid;
+ u8 data_count;
+ u8 idid[2];
+ u8 payload[1]; /* data_count of payload */
+ /* u8 checksum; */
+ /* u8 fill[]; Variable number of fill bytes */
+};
+
static int odd_parity(u8 c)
{
c ^= (c >> 4);
@@ -96,7 +142,7 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */
0, V4L2_SLICED_WSS_625, 0, /* 4 */
V4L2_SLICED_CAPTION_525, /* 6 */
- 0, 0, V4L2_SLICED_VPS, 0, 0, /* 9 */
+ V4L2_SLICED_VPS, 0, 0, 0, 0, /* 7 - unlike cx25840 */
0, 0, 0, 0
};
int is_pal = !(state->std & V4L2_STD_525_60);
@@ -136,7 +182,6 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
case VIDIOC_S_FMT:
{
int is_pal = !(state->std & V4L2_STD_525_60);
- int vbi_offset = is_pal ? 1 : 0;
int i, x;
u8 lcr[24];
@@ -153,7 +198,7 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
cx18_av_std_setup(cx);
/* VBI Offset */
- cx18_av_write(cx, 0x47f, vbi_offset);
+ cx18_av_write(cx, 0x47f, state->slicer_line_delay);
cx18_av_write(cx, 0x404, 0x2e);
break;
}
@@ -167,8 +212,9 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
/* Sliced VBI */
cx18_av_write(cx, 0x404, 0x32); /* Ancillary data */
cx18_av_write(cx, 0x406, 0x13);
- cx18_av_write(cx, 0x47f, vbi_offset);
+ cx18_av_write(cx, 0x47f, state->slicer_line_delay);
+ /* Force impossible lines to 0 */
if (is_pal) {
for (i = 0; i <= 6; i++)
svbi->service_lines[0][i] =
@@ -183,6 +229,7 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
svbi->service_lines[1][i] = 0;
}
+ /* Build register values for requested service lines */
for (i = 7; i <= 23; i++) {
for (x = 0; x <= 1; x++) {
switch (svbi->service_lines[1-x][i]) {
@@ -196,7 +243,7 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
lcr[i] |= 6 << (4 * x);
break;
case V4L2_SLICED_VPS:
- lcr[i] |= 9 << (4 * x);
+ lcr[i] |= 7 << (4 * x); /*'840 differs*/
break;
}
}
@@ -213,54 +260,61 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
}
cx18_av_write(cx, 0x43c, 0x16);
- cx18_av_write(cx, 0x474, is_pal ? 0x2a : 0x22);
+ /* FIXME - should match vblank set in cx18_av_std_setup() */
+ cx18_av_write(cx, 0x474, is_pal ? 0x2a : 26);
break;
}
case VIDIOC_INT_DECODE_VBI_LINE:
{
struct v4l2_decode_vbi_line *vbi = arg;
- u8 *p = vbi->p;
- int id1, id2, l, err = 0;
-
- if (p[0] || p[1] != 0xff || p[2] != 0xff ||
- (p[3] != 0x55 && p[3] != 0x91)) {
+ u8 *p;
+ struct vbi_anc_data *anc = (struct vbi_anc_data *) vbi->p;
+ int did, sdid, l, err = 0;
+
+ /*
+ * Check for the ancillary data header for sliced VBI
+ */
+ if (anc->preamble[0] ||
+ anc->preamble[1] != 0xff || anc->preamble[2] != 0xff ||
+ (anc->did != sliced_vbi_did[0] &&
+ anc->did != sliced_vbi_did[1])) {
vbi->line = vbi->type = 0;
break;
}
- p += 4;
- id1 = p[-1];
- id2 = p[0] & 0xf;
- l = p[2] & 0x3f;
- l += state->vbi_line_offset;
- p += 4;
+ did = anc->did;
+ sdid = anc->sdid & 0xf;
+ l = anc->idid[0] & 0x3f;
+ l += state->slicer_line_offset;
+ p = anc->payload;
- switch (id2) {
+ /* Decode the SDID set by the slicer */
+ switch (sdid) {
case 1:
- id2 = V4L2_SLICED_TELETEXT_B;
+ sdid = V4L2_SLICED_TELETEXT_B;
break;
case 4:
- id2 = V4L2_SLICED_WSS_625;
+ sdid = V4L2_SLICED_WSS_625;
break;
case 6:
- id2 = V4L2_SLICED_CAPTION_525;
+ sdid = V4L2_SLICED_CAPTION_525;
err = !odd_parity(p[0]) || !odd_parity(p[1]);
break;
- case 9:
- id2 = V4L2_SLICED_VPS;
+ case 7: /* Differs from cx25840 */
+ sdid = V4L2_SLICED_VPS;
if (decode_vps(p, p) != 0)
err = 1;
break;
default:
- id2 = 0;
+ sdid = 0;
err = 1;
break;
}
- vbi->type = err ? 0 : id2;
+ vbi->type = err ? 0 : sdid;
vbi->line = err ? 0 : l;
- vbi->is_second_field = err ? 0 : (id1 == 0x55);
+ vbi->is_second_field = err ? 0 : (did == sliced_vbi_did[1]);
vbi->p = p;
break;
}
diff --git a/linux/drivers/media/video/cx18/cx18-cards.c b/linux/drivers/media/video/cx18/cx18-cards.c
index 53217cf45..c0177ce39 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 = "Raw VBI supported; Sliced VBI is not yet supported\n",
+ .comment = "Simultaneous Digital and Analog TV capture 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 = "Raw VBI supported; Sliced VBI is not yet supported\n",
+ .comment = "Simultaneous Digital and Analog TV capture 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 = "Raw VBI supported; Sliced VBI is not yet supported\n",
+ .comment = "Analog TV capture 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 = "Raw VBI supported; Sliced VBI is not yet supported\n",
+ .comment = "Analog TV capture 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 6fa7bcb42..f8ee29f10 100644
--- a/linux/drivers/media/video/cx18/cx18-cards.h
+++ b/linux/drivers/media/video/cx18/cx18-cards.h
@@ -49,8 +49,7 @@
/* 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_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE)
struct cx18_card_video_input {
u8 video_type; /* video input type */
diff --git a/linux/drivers/media/video/cx18/cx18-controls.c b/linux/drivers/media/video/cx18/cx18-controls.c
index 17edf305d..6af4d5c19 100644
--- a/linux/drivers/media/video/cx18/cx18-controls.c
+++ b/linux/drivers/media/video/cx18/cx18-controls.c
@@ -178,8 +178,8 @@ static int cx18_setup_vbi_fmt(struct cx18 *cx, enum v4l2_mpeg_stream_vbi_fmt fmt
int i;
for (i = 0; i < CX18_VBI_FRAMES; i++) {
- /* Yuck, hardcoded. Needs to be a define */
- cx->vbi.sliced_mpeg_data[i] = kmalloc(2049, GFP_KERNEL);
+ cx->vbi.sliced_mpeg_data[i] =
+ kmalloc(CX18_SLICED_MPEG_DATA_BUFSZ, GFP_KERNEL);
if (cx->vbi.sliced_mpeg_data[i] == NULL) {
while (--i >= 0) {
kfree(cx->vbi.sliced_mpeg_data[i]);
diff --git a/linux/drivers/media/video/cx18/cx18-driver.c b/linux/drivers/media/video/cx18/cx18-driver.c
index fe2324ef2..f78566bcd 100644
--- a/linux/drivers/media/video/cx18/cx18-driver.c
+++ b/linux/drivers/media/video/cx18/cx18-driver.c
@@ -448,34 +448,38 @@ static void cx18_process_options(struct cx18 *cx)
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_VBI] = vbi_active_samples * 36;
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 */
+ /* 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) {
+ if (cx->stream_buffers[i] == 0 || /* User said 0 buffers */
+ cx->options.megabytes[i] <= 0 || /* User said 0 MB total */
+ cx->stream_buf_size[i] <= 0) { /* User said buf size 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;
+ /*
+ * VBI is a special case where the stream_buf_size is fixed
+ * and already in bytes
+ */
+ if (i == CX18_ENC_STREAM_TYPE_VBI) {
+ if (cx->stream_buffers[i] < 0) {
+ cx->stream_buffers[i] =
+ cx->options.megabytes[i] * 1024 * 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 * 1024);
}
continue;
}
+ /* All other streams have stream_buf_size in kB at this point */
if (cx->stream_buffers[i] < 0) {
cx->stream_buffers[i] = cx->options.megabytes[i] * 1024
/ cx->stream_buf_size[i];
@@ -563,8 +567,6 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
mutex_init(&cx->epu2apu_mb_lock);
mutex_init(&cx->epu2cpu_mb_lock);
- 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");
@@ -593,7 +595,8 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
(cx->params.video_temporal_filter_mode << 1) |
(cx->params.video_median_filter_type << 2);
cx->params.port = CX2341X_PORT_MEMORY;
- cx->params.capabilities = CX2341X_CAP_HAS_TS | CX2341X_CAP_HAS_AC3;
+ cx->params.capabilities =
+ CX2341X_CAP_HAS_TS | CX2341X_CAP_HAS_AC3 | CX2341X_CAP_HAS_SLICED_VBI;
init_waitqueue_head(&cx->cap_w);
init_waitqueue_head(&cx->mb_apu_waitq);
init_waitqueue_head(&cx->mb_cpu_waitq);
@@ -603,49 +606,6 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
cx->vbi.sliced_in = &cx->vbi.in.fmt.sliced;
- /*
- * 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 systems that use a 15.734 kHz horizontal rate, such as
- * NTSC-M, PAL-M, PAL-60, and other 60 Hz/525 line systems, we have:
- *
- * (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 systems that use a 15.625 kHz horizontal rate, such as
- * PAL-B/G/H, PAL-I, SECAM-L and other 50 Hz/625 line systems, we have:
- *
- * (1/15.625 kHz) * 2 * 13.5 MHz = 1728 samples/line =
- * 4 bytes SAV + 280 bytes anc data + 4 bytes SAV + 1440 active samples
- *
- */
-
- /* FIXME: init these based on tuner std & modify when std changes */
- /* 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;
}
@@ -678,8 +638,9 @@ 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;
+ cx->av_state.slicer_line_delay = 0;
+ cx->av_state.slicer_line_offset =
+ (10 + cx->av_state.slicer_line_delay - 2);
}
static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *pci_dev,
@@ -782,7 +743,6 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
{
int retval = 0;
int i;
- int vbi_buf_size;
u32 devtype;
struct cx18 *cx;
@@ -938,23 +898,6 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
}
cx->params.video_gop_size = cx->is_60hz ? 15 : 12;
- /*
- * FIXME: setting the buffer size based on the tuner standard is
- * suboptimal, as the CVBS and SVideo inputs could use a different std
- * and the buffer could end up being too small in that case.
- */
- 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;
@@ -1085,6 +1028,19 @@ int cx18_init_on_first_open(struct cx18 *cx)
return -ENXIO;
}
+ /*
+ * The second firmware load requires us to normalize the APU state,
+ * or the audio for the first analog capture will be badly incorrect.
+ *
+ * I can't seem to call APU_RESETAI and have it succeed without the
+ * APU capturing audio, so we start and stop it here to do the reset
+ */
+
+ /* MPEG Encoding, 224 kbps, MPEG Layer II, 48 ksps */
+ cx18_vapi(cx, CX18_APU_START, 2, CX18_APU_ENCODING_METHOD_MPEG|0xb9, 0);
+ cx18_vapi(cx, CX18_APU_RESETAI, 0);
+ cx18_vapi(cx, CX18_APU_STOP, 1, CX18_APU_ENCODING_METHOD_MPEG);
+
vf.tuner = 0;
vf.type = V4L2_TUNER_ANALOG_TV;
vf.frequency = 6400; /* the tuner 'baseline' frequency */
diff --git a/linux/drivers/media/video/cx18/cx18-driver.h b/linux/drivers/media/video/cx18/cx18-driver.h
index 3a21013cd..7fc914c52 100644
--- a/linux/drivers/media/video/cx18/cx18-driver.h
+++ b/linux/drivers/media/video/cx18/cx18-driver.h
@@ -293,7 +293,6 @@ struct cx18_stream {
int dma; /* can be PCI_DMA_TODEVICE,
PCI_DMA_FROMDEVICE or
PCI_DMA_NONE */
- u64 dma_pts;
wait_queue_head_t waitq;
/* Buffer Stats */
@@ -319,59 +318,121 @@ struct cx18_open_id {
/* forward declaration of struct defined in cx18-cards.h */
struct cx18_card;
+/*
+ * A note about "sliced" VBI data as implemented in this driver:
+ *
+ * Currently we collect the sliced VBI in the form of Ancillary Data
+ * packets, inserted by the AV core decoder/digitizer/slicer in the
+ * horizontal blanking region of the VBI lines, in "raw" mode as far as
+ * the Encoder is concerned. We don't ever tell the Encoder itself
+ * to provide sliced VBI. (AV Core: sliced mode - Encoder: raw mode)
+ *
+ * We then process the ancillary data ourselves to send the sliced data
+ * to the user application directly or build up MPEG-2 private stream 1
+ * packets to splice into (only!) MPEG-2 PS streams for the user app.
+ *
+ * (That's how ivtv essentially does it.)
+ *
+ * The Encoder should be able to extract certain sliced VBI data for
+ * us and provide it in a separate stream or splice it into any type of
+ * MPEG PS or TS stream, but this isn't implemented yet.
+ */
+
+/*
+ * Number of "raw" VBI samples per horizontal line we tell the Encoder to
+ * grab from the decoder/digitizer/slicer output for raw or sliced VBI.
+ * It depends 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 data 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 systems that use a 15.734 kHz horizontal rate, such as
+ * NTSC-M, PAL-M, PAL-60, and other 60 Hz/525 line systems, we have:
+ *
+ * (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 systems that use a 15.625 kHz horizontal rate, such as
+ * PAL-B/G/H, PAL-I, SECAM-L and other 50 Hz/625 line systems, we have:
+ *
+ * (1/15.625 kHz) * 2 * 13.5 MHz = 1728 samples/line =
+ * 4 bytes SAV + 280 bytes anc data + 4 bytes SAV + 1440 active samples
+ */
+static const u32 vbi_active_samples = 1444; /* 4 byte SAV + 720 Y + 720 U/V */
+static const u32 vbi_hblank_samples_60Hz = 272; /* 4 byte EAV + 268 anc/fill */
+static const u32 vbi_hblank_samples_50Hz = 284; /* 4 byte EAV + 280 anc/fill */
#define CX18_VBI_FRAMES 32
-/* VBI data */
struct vbi_info {
- u32 enc_size;
- u32 frame;
- u8 cc_data_odd[256];
- u8 cc_data_even[256];
- int cc_pos;
- u8 cc_no_update;
- u8 vps[5];
- u8 vps_found;
- int wss;
- u8 wss_found;
- u8 wss_no_update;
- u32 raw_decoder_line_size;
- u8 raw_decoder_sav_odd_field;
- u8 raw_decoder_sav_even_field;
- u32 sliced_decoder_line_size;
- u8 sliced_decoder_sav_odd_field;
- u8 sliced_decoder_sav_even_field;
+ /* Current state of v4l2 VBI settings for this device */
struct v4l2_format in;
- /* convenience pointer to sliced struct in vbi_in union */
- struct v4l2_sliced_vbi_format *sliced_in;
- u32 service_set_in;
- int insert_mpeg;
+ struct v4l2_sliced_vbi_format *sliced_in; /* pointer to in.fmt.sliced */
+ u32 count; /* Count of VBI data lines: 60 Hz: 12 or 50 Hz: 18 */
+ u32 start[2]; /* First VBI data line per field: 10 & 273 or 6 & 318 */
- /* Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines.
- One for /dev/vbi0 and one for /dev/vbi8 */
- struct v4l2_sliced_vbi_data sliced_data[36];
+ u32 frame; /* Count of VBI buffers/frames received from Encoder */
+
+ /*
+ * Vars for creation and insertion of MPEG Private Stream 1 packets
+ * of sliced VBI data into an MPEG PS
+ */
- /* Buffer for VBI data inserted into MPEG stream.
- The first byte is a dummy byte that's never used.
- The next 16 bytes contain the MPEG header for the VBI data,
- the remainder is the actual VBI data.
- The max size accepted by the MPEG VBI reinsertion turns out
- to be 1552 bytes, which happens to be 4 + (1 + 42) * (2 * 18) bytes,
- where 4 is a four byte header, 42 is the max sliced VBI payload, 1 is
- a single line header byte and 2 * 18 is the number of VBI lines per frame.
+ /* Boolean: create and insert Private Stream 1 packets into the PS */
+ int insert_mpeg;
- However, it seems that the data must be 1K aligned, so we have to
- pad the data until the 1 or 2 K boundary.
+ /*
+ * Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines.
+ * Used in cx18-vbi.c only for collecting sliced data, and as a source
+ * during conversion of sliced VBI data into MPEG Priv Stream 1 packets.
+ * We don't need to save state here, but the array may have been a bit
+ * too big (2304 bytes) to alloc from the stack.
+ */
+ struct v4l2_sliced_vbi_data sliced_data[36];
- This pointer array will allocate 2049 bytes to store each VBI frame. */
+ /*
+ * A ring buffer of driver-generated MPEG-2 PS
+ * Program Pack/Private Stream 1 packets for sliced VBI data insertion
+ * into the MPEG PS stream.
+ *
+ * In each sliced_mpeg_data[] buffer is:
+ * 16 byte MPEG-2 PS Program Pack Header
+ * 16 byte MPEG-2 Private Stream 1 PES Header
+ * 4 byte magic number: "itv0" or "ITV0"
+ * 4 byte first field line mask, if "itv0"
+ * 4 byte second field line mask, if "itv0"
+ * 36 lines, if "ITV0"; or <36 lines, if "itv0"; of sliced VBI data
+ *
+ * Each line in the payload is
+ * 1 byte line header derived from the SDID (WSS, CC, VPS, etc.)
+ * 42 bytes of line data
+ *
+ * That's a maximum 1552 bytes of payload in the Private Stream 1 packet
+ * which is the payload size a PVR-350 (CX23415) MPEG decoder will
+ * accept for VBI data. So, including the headers, it's a maximum 1584
+ * bytes total.
+ */
+#define CX18_SLICED_MPEG_DATA_MAXSZ 1584
+ /* copy_vbi_buf() needs 8 temp bytes on the end for the worst case */
+#define CX18_SLICED_MPEG_DATA_BUFSZ (CX18_SLICED_MPEG_DATA_MAXSZ+8)
u8 *sliced_mpeg_data[CX18_VBI_FRAMES];
u32 sliced_mpeg_size[CX18_VBI_FRAMES];
- struct cx18_buffer sliced_mpeg_buf;
+
+ /* Count of Program Pack/Program Stream 1 packets inserted into PS */
u32 inserted_frame;
- u32 start[2], count;
- u32 raw_size;
- u32 sliced_size;
+ /*
+ * A dummy driver stream transfer buffer with a copy of the next
+ * sliced_mpeg_data[] buffer for output to userland apps.
+ * Only used in cx18-fileops.c, but its state needs to persist at times.
+ */
+ struct cx18_buffer sliced_mpeg_buf;
};
/* Per cx23418, per I2C bus private algo callback data */
@@ -418,9 +479,6 @@ struct cx18 {
unsigned long dualwatch_jiffies;
u32 dualwatch_stereo_mode;
- /* Digitizer type */
- int digitizer; /* 0x00EF = saa7114 0x00FO = saa7115 0x0106 = mic */
-
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 */
@@ -429,7 +487,6 @@ struct cx18 {
unsigned long i_flags; /* global cx18 flags */
atomic_t ana_capturing; /* count number of active analog capture streams */
atomic_t tot_capturing; /* total count number of active capture streams */
- spinlock_t lock; /* lock access to this struct */
int search_pack_header;
int open_id; /* incremented each time an open occurs, used as
diff --git a/linux/drivers/media/video/cx18/cx18-fileops.c b/linux/drivers/media/video/cx18/cx18-fileops.c
index 36c380b66..c73fbe65b 100644
--- a/linux/drivers/media/video/cx18/cx18-fileops.c
+++ b/linux/drivers/media/video/cx18/cx18-fileops.c
@@ -209,9 +209,9 @@ static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block,
*err = 0;
while (1) {
if (s->type == CX18_ENC_STREAM_TYPE_MPG) {
-#if 0
/* Process pending program info updates and pending
VBI data */
+#if 0
cx18_update_pgm_info(cx);
#endif
@@ -224,7 +224,6 @@ static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block,
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_stream_put_buf_fw(s_vbi, buf);
}
@@ -245,8 +244,7 @@ static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block,
cx18_buf_swap(buf);
else {
/* byteswap and process VBI data */
- cx18_process_vbi_data(cx, buf,
- s->dma_pts, s->type);
+ cx18_process_vbi_data(cx, buf, s->type);
}
return buf;
}
@@ -298,6 +296,20 @@ static size_t cx18_copy_buf_to_user(struct cx18_stream *s,
len = ucount;
if (cx->vbi.insert_mpeg && s->type == CX18_ENC_STREAM_TYPE_MPG &&
!cx18_raw_vbi(cx) && buf != &cx->vbi.sliced_mpeg_buf) {
+ /*
+ * Try to find a good splice point in the PS, just before
+ * an MPEG-2 Program Pack start code, and provide only
+ * up to that point to the user, so it's easy to insert VBI data
+ * the next time around.
+ */
+ /* FIXME - This only works for an MPEG-2 PS, not a TS */
+ /*
+ * An MPEG-2 Program Stream (PS) is a series of
+ * MPEG-2 Program Packs terminated by an
+ * MPEG Program End Code after the last Program Pack.
+ * A Program Pack may hold a PS System Header packet and any
+ * number of Program Elementary Stream (PES) Packets
+ */
const char *start = buf->buf + buf->readpos;
const char *p = start + 1;
const u8 *q;
@@ -305,38 +317,54 @@ static size_t cx18_copy_buf_to_user(struct cx18_stream *s,
int stuffing, i;
while (start + len > p) {
+ /* Scan for a 0 to find a potential MPEG-2 start code */
q = memchr(p, 0, start + len - p);
if (q == NULL)
break;
p = q + 1;
+ /*
+ * Keep looking if not a
+ * MPEG-2 Pack header start code: 0x00 0x00 0x01 0xba
+ * or MPEG-2 video PES start code: 0x00 0x00 0x01 0xe0
+ */
if ((char *)q + 15 >= buf->buf + buf->bytesused ||
q[1] != 0 || q[2] != 1 || q[3] != ch)
continue;
+
+ /* If expecting the primary video PES */
if (!cx->search_pack_header) {
+ /* Continue if it couldn't be a PES packet */
if ((q[6] & 0xc0) != 0x80)
continue;
- if (((q[7] & 0xc0) == 0x80 &&
- (q[9] & 0xf0) == 0x20) ||
- ((q[7] & 0xc0) == 0xc0 &&
- (q[9] & 0xf0) == 0x30)) {
- ch = 0xba;
+ /* Check if a PTS or PTS & DTS follow */
+ if (((q[7] & 0xc0) == 0x80 && /* PTS only */
+ (q[9] & 0xf0) == 0x20) || /* PTS only */
+ ((q[7] & 0xc0) == 0xc0 && /* PTS & DTS */
+ (q[9] & 0xf0) == 0x30)) { /* DTS follows */
+ /* Assume we found the video PES hdr */
+ ch = 0xba; /* next want a Program Pack*/
cx->search_pack_header = 1;
- p = q + 9;
+ p = q + 9; /* Skip this video PES hdr */
}
continue;
}
+
+ /* We may have found a Program Pack start code */
+
+ /* Get the count of stuffing bytes & verify them */
stuffing = q[13] & 7;
/* all stuffing bytes must be 0xff */
for (i = 0; i < stuffing; i++)
if (q[14 + i] != 0xff)
break;
- if (i == stuffing &&
- (q[4] & 0xc4) == 0x44 &&
- (q[12] & 3) == 3 &&
- q[14 + stuffing] == 0 &&
+ if (i == stuffing && /* right number of stuffing bytes*/
+ (q[4] & 0xc4) == 0x44 && /* marker check */
+ (q[12] & 3) == 3 && /* marker check */
+ q[14 + stuffing] == 0 && /* PES Pack or Sys Hdr */
q[15 + stuffing] == 0 &&
q[16 + stuffing] == 1) {
- cx->search_pack_header = 0;
+ /* We declare we actually found a Program Pack*/
+ cx->search_pack_header = 0; /* expect vid PES */
len = (char *)q - start;
cx18_setup_sliced_vbi_buf(cx);
break;
diff --git a/linux/drivers/media/video/cx18/cx18-ioctl.c b/linux/drivers/media/video/cx18/cx18-ioctl.c
index 4a49b0819..995e19c23 100644
--- a/linux/drivers/media/video/cx18/cx18-ioctl.c
+++ b/linux/drivers/media/video/cx18/cx18-ioctl.c
@@ -58,12 +58,21 @@ u16 cx18_service2vbi(int type)
}
}
+/* Check if VBI services are allowed on the (field, line) for the video std */
static int valid_service_line(int field, int line, int is_pal)
{
- return (is_pal && line >= 6 && (line != 23 || field == 0)) ||
+ return (is_pal && line >= 6 &&
+ ((field == 0 && line <= 23) || (field == 1 && line <= 22))) ||
(!is_pal && line >= 10 && line < 22);
}
+/*
+ * For a (field, line, std) and inbound potential set of services for that line,
+ * return the first valid service of those passed in the incoming set for that
+ * line in priority order:
+ * CC, VPS, or WSS over TELETEXT for well known lines
+ * TELETEXT, before VPS, before CC, before WSS, for other lines
+ */
static u16 select_service_from_set(int field, int line, u16 set, int is_pal)
{
u16 valid_set = (is_pal ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525);
@@ -90,6 +99,10 @@ static u16 select_service_from_set(int field, int line, u16 set, int is_pal)
return 0;
}
+/*
+ * Expand the service_set of *fmt into valid service_lines for the std,
+ * and clear the passed in fmt->service_set
+ */
void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
{
u16 set = fmt->service_set;
@@ -102,7 +115,10 @@ void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
}
}
-#if 0
+/*
+ * Sanitize the service_lines in *fmt per the video std, and return 1
+ * if any service_line is left as valid after santization
+ */
static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
{
int f, l;
@@ -116,8 +132,8 @@ static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
}
return set != 0;
}
-#endif
+/* Compute the service_set from the assumed valid service_lines of *fmt */
u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt)
{
int f, l;
@@ -144,10 +160,8 @@ static int cx18_g_fmt_vid_cap(struct file *file, void *fh,
pixfmt->priv = 0;
if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
pixfmt->pixelformat = V4L2_PIX_FMT_HM12;
- /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
- pixfmt->sizeimage =
- pixfmt->height * pixfmt->width +
- pixfmt->height * (pixfmt->width / 2);
+ /* YUV size is (Y=(h*720) + UV=(h*(720/2))) */
+ pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2;
pixfmt->bytesperline = 720;
} else {
pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
@@ -164,8 +178,8 @@ static int cx18_g_fmt_vbi_cap(struct file *file, void *fh,
struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi;
vbifmt->sampling_rate = 27000000;
- vbifmt->offset = 248;
- vbifmt->samples_per_line = cx->vbi.raw_decoder_line_size - 4;
+ vbifmt->offset = 248; /* FIXME - slightly wrong for both 50 & 60 Hz */
+ vbifmt->samples_per_line = vbi_active_samples - 4;
vbifmt->sample_format = V4L2_PIX_FMT_GREY;
vbifmt->start[0] = cx->vbi.start[0];
vbifmt->start[1] = cx->vbi.start[1];
@@ -179,22 +193,30 @@ static int cx18_g_fmt_vbi_cap(struct file *file, void *fh,
static int cx18_g_fmt_sliced_vbi_cap(struct file *file, void *fh,
struct v4l2_format *fmt)
{
-#if 0
- /* Supported by the cx23418 but not yet implemented. */
struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+ /* sane, V4L2 spec compliant, defaults */
vbifmt->reserved[0] = 0;
vbifmt->reserved[1] = 0;
vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines));
+ vbifmt->service_set = 0;
+
+ /*
+ * Fetch the configured service_lines and total service_set from the
+ * digitizer/slicer. Note, cx18_av_vbi() wipes the passed in
+ * fmt->fmt.sliced under valid calling conditions
+ */
+ if (cx18_av_cmd(cx, VIDIOC_G_FMT, fmt))
+ return -EINVAL;
- cx18_av_cmd(cx, VIDIOC_G_FMT, fmt);
+ /* Ensure V4L2 spec compliant output */
+ vbifmt->reserved[0] = 0;
+ vbifmt->reserved[1] = 0;
+ vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
vbifmt->service_set = cx18_get_service_set(vbifmt);
return 0;
-#else
- return -EINVAL;
-#endif
}
static int cx18_try_fmt_vid_cap(struct file *file, void *fh,
@@ -204,11 +226,18 @@ static int cx18_try_fmt_vid_cap(struct file *file, void *fh,
struct cx18 *cx = id->cx;
int w = fmt->fmt.pix.width;
int h = fmt->fmt.pix.height;
+ int min_h = 2;
w = min(w, 720);
- w = max(w, 1);
+ w = max(w, 2);
+ if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
+ /* YUV height must be a multiple of 32 */
+ h &= ~0x1f;
+ min_h = 32;
+ }
h = min(h, cx->is_50hz ? 576 : 480);
- h = max(h, 2);
+ h = max(h, min_h);
+
cx18_g_fmt_vid_cap(file, fh, fmt);
fmt->fmt.pix.width = w;
fmt->fmt.pix.height = h;
@@ -224,8 +253,6 @@ static int cx18_try_fmt_vbi_cap(struct file *file, void *fh,
static int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh,
struct v4l2_format *fmt)
{
-#if 0
- /* Supported by the cx23418 but not yet implemented. */
struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
@@ -233,14 +260,13 @@ static int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh,
vbifmt->reserved[0] = 0;
vbifmt->reserved[1] = 0;
+ /* If given a service set, expand it validly & clear passed in set */
if (vbifmt->service_set)
cx18_expand_service_set(vbifmt, cx->is_50hz);
- check_service_set(vbifmt, cx->is_50hz);
- vbifmt->service_set = cx18_get_service_set(vbifmt);
+ /* Sanitize the service_lines, and compute the new set if any valid */
+ if (check_service_set(vbifmt, cx->is_50hz))
+ vbifmt->service_set = cx18_get_service_set(vbifmt);
return 0;
-#else
- return -EINVAL;
-#endif
}
static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
@@ -284,20 +310,32 @@ static int cx18_s_fmt_vbi_cap(struct file *file, void *fh,
if (ret)
return ret;
+ /*
+ * Changing the Encoder's Raw VBI parameters won't have any effect
+ * if any analog capture is ongoing
+ */
if (!cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0)
return -EBUSY;
+ /*
+ * Set the digitizer registers for raw active VBI.
+ * Note cx18_av_vbi_wipes out alot of the passed in fmt under valid
+ * calling conditions
+ */
+ ret = cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
+ if (ret)
+ return ret;
+
+ /* Store our new v4l2 (non-)sliced VBI state */
cx->vbi.sliced_in->service_set = 0;
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);
}
static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh,
struct v4l2_format *fmt)
{
-#if 0
- /* Supported by the cx23418 but not yet implemented. */
struct cx18_open_id *id = fh;
struct cx18 *cx = id->cx;
int ret;
@@ -307,22 +345,27 @@ static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh,
if (ret)
return ret;
- ret = cx18_try_fmt_sliced_vbi_cap(file, fh, fmt);
- if (ret)
- return ret;
-
- if (check_service_set(vbifmt, cx->is_50hz) == 0)
- return -EINVAL;
+ cx18_try_fmt_sliced_vbi_cap(file, fh, fmt);
+ /*
+ * Changing the Encoder's Raw VBI parameters won't have any effect
+ * if any analog capture is ongoing
+ */
if (cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0)
return -EBUSY;
+
+ /*
+ * Set the service_lines requested in the digitizer/slicer registers.
+ * Note, cx18_av_vbi() wipes some "impossible" service lines in the
+ * passed in fmt->fmt.sliced under valid calling conditions
+ */
+ ret = cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
+ if (ret)
+ return ret;
+ /* Store our current v4l2 sliced VBI settings */
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;
-#else
- return -EINVAL;
-#endif
}
static int cx18_g_chip_ident(struct file *file, void *fh,
@@ -620,7 +663,6 @@ int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std)
cx->vbi.count = cx->is_50hz ? 18 : 12;
cx->vbi.start[0] = cx->is_50hz ? 6 : 10;
cx->vbi.start[1] = cx->is_50hz ? 318 : 273;
- cx->vbi.sliced_decoder_line_size = cx->is_60hz ? 272 : 284;
CX18_DEBUG_INFO("Switching standard to %llx.\n",
(unsigned long long) cx->std);
@@ -671,23 +713,30 @@ static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
static int cx18_g_sliced_vbi_cap(struct file *file, void *fh,
struct v4l2_sliced_vbi_cap *cap)
{
-#if 0
- /* Supported by the cx23418 but not yet implemented. */
struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
int set = cx->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
int f, l;
- if (cap->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
- for (f = 0; f < 2; f++) {
- for (l = 0; l < 24; l++) {
- if (valid_service_line(f, l, cx->is_50hz))
- cap->service_lines[f][l] = set;
- }
+ if (cap->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+ return -EINVAL;
+
+ cap->service_set = 0;
+ for (f = 0; f < 2; f++) {
+ for (l = 0; l < 24; l++) {
+ if (valid_service_line(f, l, cx->is_50hz)) {
+ /*
+ * We can find all v4l2 supported vbi services
+ * for the standard, on a valid line for the std
+ */
+ cap->service_lines[f][l] = set;
+ cap->service_set |= set;
+ } else
+ cap->service_lines[f][l] = 0;
}
- return 0;
}
-#endif
- return -EINVAL;
+ for (f = 0; f < 3; f++)
+ cap->reserved[f] = 0;
+ return 0;
}
static int cx18_g_enc_index(struct file *file, void *fh,
diff --git a/linux/drivers/media/video/cx18/cx18-streams.c b/linux/drivers/media/video/cx18/cx18-streams.c
index 88b101401..e4a70cefc 100644
--- a/linux/drivers/media/video/cx18/cx18-streams.c
+++ b/linux/drivers/media/video/cx18/cx18-streams.c
@@ -349,44 +349,87 @@ static void cx18_vbi_setup(struct cx18_stream *s)
/* setup VBI registers */
cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in);
- /* determine number of lines and total number of VBI bytes.
- 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) */
+ /*
+ * Send the CX18_CPU_SET_RAW_VBI_PARAM API command to setup Encoder Raw
+ * VBI when the first analog capture channel starts, as once it starts
+ * (e.g. MPEG), we can't effect any change in the Encoder Raw VBI setup
+ * (i.e. for the VBI capture channels). We also send it for each
+ * analog capture channel anyway just to make sure we get the proper
+ * behavior
+ */
if (raw) {
lines = cx->vbi.count * 2;
} else {
- lines = cx->is_60hz ? 24 : 38;
- if (cx->is_60hz)
- lines += 2;
+ /*
+ * For 525/60 systems, according to the VIP 2 & BT.656 std:
+ * The EAV RP code's Field bit toggles on line 4, a few lines
+ * after the Vertcal Blank bit has already toggled.
+ * Tell the encoder to capture 21-4+1=18 lines per field,
+ * since we want lines 10 through 21.
+ *
+ * FIXME - revisit for 625/50 systems
+ */
+ lines = cx->is_60hz ? (21 - 4 + 1) * 2 : 38;
}
- cx->vbi.enc_size = lines *
- (raw ? cx->vbi.raw_size : cx->vbi.sliced_size);
-
data[0] = s->handle;
/* Lines per field */
data[1] = (lines / 2) | ((lines / 2) << 16);
/* bytes per line */
- data[2] = (raw ? cx->vbi.raw_decoder_line_size
- : cx->vbi.sliced_decoder_line_size);
+ data[2] = (raw ? vbi_active_samples
+ : (cx->is_60hz ? vbi_hblank_samples_60Hz
+ : vbi_hblank_samples_50Hz));
/* 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 */
+ /*
+ * Set the SAV/EAV RP codes to look for as start/stop points
+ * when in VIP-1.1 mode
+ */
if (raw) {
+ /*
+ * Start codes for beginning of "active" line in vertical blank
+ * 0x20 ( VerticalBlank )
+ * 0x60 ( EvenField VerticalBlank )
+ */
data[4] = 0x20602060;
+ /*
+ * End codes for end of "active" raw lines and regular lines
+ * 0x30 ( VerticalBlank HorizontalBlank)
+ * 0x70 ( EvenField VerticalBlank HorizontalBlank)
+ * 0x90 (Task HorizontalBlank)
+ * 0xd0 (Task EvenField HorizontalBlank)
+ */
data[5] = 0x307090d0;
} else {
+ /*
+ * End codes for active video, we want data in the hblank region
+ * 0xb0 (Task 0 VerticalBlank HorizontalBlank)
+ * 0xf0 (Task EvenField VerticalBlank HorizontalBlank)
+ *
+ * Since the V bit is only allowed to toggle in the EAV RP code,
+ * just before the first active region line, these two
+ * are problematic:
+ * 0x90 (Task HorizontalBlank)
+ * 0xd0 (Task EvenField HorizontalBlank)
+ *
+ * We have set the digitzer to consider the first active line
+ * as part of VerticalBlank as well so we don't have to look for
+ * these problem codes nor lose the last line of sliced data.
+ */
data[4] = 0xB0F0B0F0;
+ /*
+ * Start codes for beginning of active line in vertical blank
+ * 0xa0 (Task VerticalBlank )
+ * 0xe0 (Task EvenField VerticalBlank )
+ */
data[5] = 0xA0E0A0E0;
}
CX18_DEBUG_INFO("Setup VBI h: %d lines %x bpl %d fr %d %x %x\n",
data[0], data[1], data[2], data[3], data[4], data[5]);
- if (s->type == CX18_ENC_STREAM_TYPE_VBI)
- cx18_api(cx, CX18_CPU_SET_RAW_VBI_PARAM, 6, data);
+ cx18_api(cx, CX18_CPU_SET_RAW_VBI_PARAM, 6, data);
}
struct cx18_queue *cx18_stream_put_buf_fw(struct cx18_stream *s,
@@ -435,8 +478,8 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
u32 data[MAX_MB_ARGUMENTS];
struct cx18 *cx = s->cx;
struct cx18_buffer *buf;
- int ts = 0;
int captype = 0;
+ struct cx18_api_func_private priv;
if (s->video_dev == NULL && s->dvb.enabled == 0)
return -EINVAL;
@@ -454,7 +497,6 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
case CX18_ENC_STREAM_TYPE_TS:
captype = CAPTURE_CHANNEL_TYPE_TS;
- ts = 1;
break;
case CX18_ENC_STREAM_TYPE_YUV:
captype = CAPTURE_CHANNEL_TYPE_YUV;
@@ -463,8 +505,16 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
captype = CAPTURE_CHANNEL_TYPE_PCM;
break;
case CX18_ENC_STREAM_TYPE_VBI:
+#ifdef CX18_ENCODER_PARSES_SLICED
captype = cx18_raw_vbi(cx) ?
CAPTURE_CHANNEL_TYPE_VBI : CAPTURE_CHANNEL_TYPE_SLICED_VBI;
+#else
+ /*
+ * Currently we set things up so that Sliced VBI from the
+ * digitizer is handled as Raw VBI by the encoder
+ */
+ captype = CAPTURE_CHANNEL_TYPE_VBI;
+#endif
cx->vbi.frame = 0;
cx->vbi.inserted_frame = 0;
memset(cx->vbi.sliced_mpeg_size,
@@ -474,10 +524,6 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
return -EINVAL;
}
- /* mute/unmute video */
- cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2,
- s->handle, !!test_bit(CX18_F_I_RADIO_USER, &cx->i_flags));
-
/* Clear Streamoff flags in case left from last capture */
clear_bit(CX18_F_S_STREAMOFF, &s->s_flags);
@@ -485,31 +531,63 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
s->handle = data[0];
cx18_vapi(cx, CX18_CPU_SET_CHANNEL_TYPE, 2, s->handle, captype);
- if (atomic_read(&cx->ana_capturing) == 0 && !ts) {
- struct cx18_api_func_private priv;
-
- /* Stuff from Windows, we don't know what it is */
+ /*
+ * For everything but CAPTURE_CHANNEL_TYPE_TS, play it safe and
+ * set up all the parameters, as it is not obvious which parameters the
+ * firmware shares across capture channel types and which it does not.
+ *
+ * Some of the cx18_vapi() calls below apply to only certain capture
+ * channel types. We're hoping there's no harm in calling most of them
+ * anyway, as long as the values are all consistent. Setting some
+ * shared parameters will have no effect once an analog capture channel
+ * has started streaming.
+ */
+ if (captype != CAPTURE_CHANNEL_TYPE_TS) {
cx18_vapi(cx, CX18_CPU_SET_VER_CROP_LINE, 2, s->handle, 0);
cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 3, 1);
cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 8, 0);
cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 4, 1);
- cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2, s->handle, 12);
+ /*
+ * Audio related reset according to
+ * Documentation/video4linux/cx2341x/fw-encoder-api.txt
+ */
+ if (atomic_read(&cx->ana_capturing) == 0)
+ cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2,
+ s->handle, 12);
+
+ /*
+ * Number of lines for Field 1 & Field 2 according to
+ * Documentation/video4linux/cx2341x/fw-encoder-api.txt
+ * Field 1 is 312 for 625 line systems in BT.656
+ * Field 2 is 313 for 625 line systems in BT.656
+ */
cx18_vapi(cx, CX18_CPU_SET_CAPTURE_LINE_NO, 3,
- s->handle, cx->digitizer, cx->digitizer);
+ s->handle, 312, 313);
- /* Setup VBI */
if (cx->v4l2_cap & V4L2_CAP_VBI_CAPTURE)
cx18_vbi_setup(s);
- /* assign program index info.
- Mask 7: select I/P/B, Num_req: 400 max */
+ /*
+ * assign program index info.
+ * Mask 7: select I/P/B, Num_req: 400 max
+ * FIXME - currently we have this hardcoded as disabled
+ */
cx18_vapi_result(cx, data, CX18_CPU_SET_INDEXTABLE, 1, 0);
- /* Setup API for Stream */
+ /* Call out to the common CX2341x API setup for user controls */
priv.cx = cx;
priv.s = s;
cx2341x_update(&priv, cx18_api_func, NULL, &cx->params);
+
+ /*
+ * When starting a capture and we're set for radio,
+ * ensure the video is muted, despite the user control.
+ */
+ if (!cx->params.video_mute &&
+ test_bit(CX18_F_I_RADIO_USER, &cx->i_flags))
+ cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle,
+ (cx->params.video_mute_yuv << 8) | 1);
}
if (atomic_read(&cx->tot_capturing) == 0) {
@@ -553,7 +631,7 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
}
/* you're live! sit back and await interrupts :) */
- if (!ts)
+ if (captype != CAPTURE_CHANNEL_TYPE_TS)
atomic_inc(&cx->ana_capturing);
atomic_inc(&cx->tot_capturing);
return 0;
diff --git a/linux/drivers/media/video/cx18/cx18-vbi.c b/linux/drivers/media/video/cx18/cx18-vbi.c
index fb595bd54..8e6f4d4af 100644
--- a/linux/drivers/media/video/cx18/cx18-vbi.c
+++ b/linux/drivers/media/video/cx18/cx18-vbi.c
@@ -27,6 +27,16 @@
#include "cx18-queue.h"
#include "cx18-av-core.h"
+/*
+ * Raster Reference/Protection (RP) bytes, used in Start/End Active
+ * Video codes emitted from the digitzer in VIP 1.x mode, that flag the start
+ * of VBI sample or VBI ancilliary data regions in the digitial ratser line.
+ *
+ * Task FieldEven VerticalBlank HorizontalBlank 0 0 0 0
+ */
+static const u8 raw_vbi_sav_rp[2] = { 0x20, 0x60 }; /* __V_, _FV_ */
+static const u8 sliced_vbi_eav_rp[2] = { 0xb0, 0xf0 }; /* T_VH, TFVH */
+
static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp)
{
int line = 0;
@@ -34,10 +44,17 @@ static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp)
u32 linemask[2] = { 0, 0 };
unsigned short size;
static const u8 mpeg_hdr_data[] = {
- 0x00, 0x00, 0x01, 0xba, 0x44, 0x00, 0x0c, 0x66,
- 0x24, 0x01, 0x01, 0xd1, 0xd3, 0xfa, 0xff, 0xff,
- 0x00, 0x00, 0x01, 0xbd, 0x00, 0x1a, 0x84, 0x80,
- 0x07, 0x21, 0x00, 0x5d, 0x63, 0xa7, 0xff, 0xff
+ /* MPEG-2 Program Pack */
+ 0x00, 0x00, 0x01, 0xba, /* Prog Pack start code */
+ 0x44, 0x00, 0x0c, 0x66, 0x24, 0x01, /* SCR, SCR Ext, markers */
+ 0x01, 0xd1, 0xd3, /* Mux Rate, markers */
+ 0xfa, 0xff, 0xff, /* Res, Suff cnt, Stuff */
+ /* MPEG-2 Private Stream 1 PES Packet */
+ 0x00, 0x00, 0x01, 0xbd, /* Priv Stream 1 start */
+ 0x00, 0x1a, /* length */
+ 0x84, 0x80, 0x07, /* flags, hdr data len */
+ 0x21, 0x00, 0x5d, 0x63, 0xa7, /* PTS, markers */
+ 0xff, 0xff /* stuffing */
};
const int sd = sizeof(mpeg_hdr_data); /* start of vbi data */
int idx = cx->vbi.frame % CX18_VBI_FRAMES;
@@ -71,7 +88,7 @@ static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp)
memcpy(dst + sd + 4, dst + sd + 12, line * 43);
size = 4 + ((43 * line + 3) & ~3);
} else {
- memcpy(dst + sd, "cx0", 4);
+ memcpy(dst + sd, "itv0", 4);
memcpy(dst + sd + 4, &linemask[0], 8);
size = 12 + ((43 * line + 3) & ~3);
}
@@ -86,14 +103,13 @@ static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp)
}
/* Compress raw VBI format, removes leading SAV codes and surplus space
- after the field.
- Returns new compressed size. */
+ after the frame. Returns new compressed size. */
static u32 compress_raw_buf(struct cx18 *cx, u8 *buf, u32 size)
{
- u32 line_size = cx->vbi.raw_decoder_line_size;
- u32 lines = cx->vbi.count;
- u8 sav1 = cx->vbi.raw_decoder_sav_odd_field;
- u8 sav2 = cx->vbi.raw_decoder_sav_even_field;
+ u32 line_size = vbi_active_samples;
+ u32 lines = cx->vbi.count * 2;
+ u8 sav1 = raw_vbi_sav_rp[0];
+ u8 sav2 = raw_vbi_sav_rp[1];
u8 *q = buf;
u8 *p;
int i;
@@ -115,15 +131,16 @@ static u32 compress_raw_buf(struct cx18 *cx, u8 *buf, u32 size)
/* Compressed VBI format, all found sliced blocks put next to one another
Returns new compressed size */
static u32 compress_sliced_buf(struct cx18 *cx, u32 line, u8 *buf,
- u32 size, u8 sav)
+ u32 size, u8 eav)
{
- u32 line_size = cx->vbi.sliced_decoder_line_size;
struct v4l2_decode_vbi_line vbi;
int i;
+ u32 line_size = cx->is_60hz ? vbi_hblank_samples_60Hz
+ : vbi_hblank_samples_50Hz;
/* find the first valid line */
for (i = 0; i < size; i++, buf++) {
- if (buf[0] == 0xff && !buf[1] && !buf[2] && buf[3] == sav)
+ if (buf[0] == 0xff && !buf[1] && !buf[2] && buf[3] == eav)
break;
}
@@ -133,8 +150,8 @@ static u32 compress_sliced_buf(struct cx18 *cx, u32 line, u8 *buf,
for (i = 0; i < size / line_size; i++) {
u8 *p = buf + i * line_size;
- /* Look for SAV code */
- if (p[0] != 0xff || p[1] || p[2] || p[3] != sav)
+ /* Look for EAV code */
+ if (p[0] != 0xff || p[1] || p[2] || p[3] != eav)
continue;
vbi.p = p + 4;
cx18_av_cmd(cx, VIDIOC_INT_DECODE_VBI_LINE, &vbi);
@@ -150,51 +167,78 @@ static u32 compress_sliced_buf(struct cx18 *cx, u32 line, u8 *buf,
}
void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
- u64 pts_stamp, int streamtype)
+ int streamtype)
{
u8 *p = (u8 *) buf->buf;
+ u32 *q = (u32 *) buf->buf;
u32 size = buf->bytesused;
+ u32 pts;
int lines;
if (streamtype != CX18_ENC_STREAM_TYPE_VBI)
return;
+ /*
+ * The CX23418 sends us data that is 32 bit LE swapped, but we want
+ * the raw VBI bytes in the order they were in the raster line
+ */
+ cx18_buf_swap(buf);
+
+ /*
+ * The CX23418 provides a 12 byte header in it's raw VBI buffers to us:
+ * 0x3fffffff [4 bytes of something] [4 byte presentation time stamp?]
+ */
+
/* Raw VBI data */
if (cx18_raw_vbi(cx)) {
u8 type;
- cx18_buf_swap(buf);
-
- /* Skip 12 bytes of header that gets stuffed in */
+ /*
+ * We've set up to get a frame's worth of VBI data at a time.
+ * Skip 12 bytes of header prefixing the first field.
+ */
size -= 12;
memcpy(p, &buf->buf[12], size);
type = p[3];
+ /* Extrapolate the last 12 bytes of the frame's last line */
+ memset(&p[size], (int) p[size - 1], 12);
+ size += 12;
+
size = buf->bytesused = compress_raw_buf(cx, p, size);
- /* second field of the frame? */
- if (type == cx->vbi.raw_decoder_sav_even_field) {
- /* Dirty hack needed for backwards
- compatibility of old VBI software. */
- p += size - 4;
- memcpy(p, &cx->vbi.frame, 4);
- cx->vbi.frame++;
- }
+ /*
+ * Hack needed for compatibility with old VBI software.
+ * Write the frame # at the last 4 bytes of the frame
+ */
+ p += size - 4;
+ memcpy(p, &cx->vbi.frame, 4);
+ cx->vbi.frame++;
return;
}
/* Sliced VBI data with data insertion */
- cx18_buf_swap(buf);
+
+ pts = (be32_to_cpu(q[0] == 0x3fffffff)) ? be32_to_cpu(q[2]) : 0;
+
+ /*
+ * For calls to compress_sliced_buf(), ensure there are an integral
+ * number of lines by shifting the real data up over the 12 bytes header
+ * that got stuffed in.
+ * FIXME - there's a smarter way to do this with pointers, but for some
+ * reason I can't get it to work correctly right now.
+ */
+ memcpy(p, &buf->buf[12], size-12);
/* first field */
- lines = compress_sliced_buf(cx, 0, p, size / 2,
- cx->vbi.sliced_decoder_sav_odd_field);
- /* second field */
- /* experimentation shows that the second half does not always
- begin at the exact address. So start a bit earlier
- (hence 32). */
+ lines = compress_sliced_buf(cx, 0, p, size / 2, sliced_vbi_eav_rp[0]);
+ /*
+ * second field
+ * In case the second half does not always begin at the exact address,
+ * start a bit earlier (hence 32).
+ */
lines = compress_sliced_buf(cx, lines, p + size / 2 - 32,
- size / 2 + 32, cx->vbi.sliced_decoder_sav_even_field);
+ size / 2 + 32, sliced_vbi_eav_rp[1]);
/* always return at least one empty line */
if (lines == 0) {
cx->vbi.sliced_data[0].id = 0;
@@ -206,6 +250,6 @@ void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
memcpy(p, &cx->vbi.sliced_data[0], size);
if (cx->vbi.insert_mpeg)
- copy_vbi_data(cx, lines, pts_stamp);
+ copy_vbi_data(cx, lines, pts);
cx->vbi.frame++;
}
diff --git a/linux/drivers/media/video/cx18/cx18-vbi.h b/linux/drivers/media/video/cx18/cx18-vbi.h
index c56ff7d28..e7e1ae427 100644
--- a/linux/drivers/media/video/cx18/cx18-vbi.h
+++ b/linux/drivers/media/video/cx18/cx18-vbi.h
@@ -22,5 +22,5 @@
*/
void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
- u64 pts_stamp, int streamtype);
+ int streamtype);
int cx18_used_line(struct cx18 *cx, int line, int field);
diff --git a/linux/drivers/media/video/ivtv/ivtv-driver.c b/linux/drivers/media/video/ivtv/ivtv-driver.c
index 05bba3928..5e90897a2 100644
--- a/linux/drivers/media/video/ivtv/ivtv-driver.c
+++ b/linux/drivers/media/video/ivtv/ivtv-driver.c
@@ -357,7 +357,7 @@ void ivtv_read_eeprom(struct ivtv *itv, struct tveeprom *tv)
static void ivtv_process_eeprom(struct ivtv *itv)
{
struct tveeprom tv;
- int pci_slot = PCI_SLOT(itv->dev->devfn);
+ int pci_slot = PCI_SLOT(itv->pdev->devfn);
ivtv_read_eeprom(itv, &tv);
@@ -604,7 +604,7 @@ static void ivtv_process_options(struct ivtv *itv)
itv->std = ivtv_parse_std(itv);
if (itv->std == 0 && tunertype >= 0)
itv->std = tunertype ? V4L2_STD_MN : (V4L2_STD_ALL & ~V4L2_STD_MN);
- itv->has_cx23415 = (itv->dev->device == PCI_DEVICE_ID_IVTV15);
+ itv->has_cx23415 = (itv->pdev->device == PCI_DEVICE_ID_IVTV15);
chipname = itv->has_cx23415 ? "cx23415" : "cx23416";
if (itv->options.cardtype == -1) {
IVTV_INFO("Ignore card (detected %s based chip)\n", chipname);
@@ -617,9 +617,9 @@ static void ivtv_process_options(struct ivtv *itv)
IVTV_ERR("Unknown user specified type, trying to autodetect card\n");
}
if (itv->card == NULL) {
- if (itv->dev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE ||
- itv->dev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE_ALT1 ||
- itv->dev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE_ALT2) {
+ if (itv->pdev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE ||
+ itv->pdev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE_ALT1 ||
+ itv->pdev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE_ALT2) {
itv->card = ivtv_get_card(itv->has_cx23415 ? IVTV_CARD_PVR_350 : IVTV_CARD_PVR_150);
IVTV_INFO("Autodetected Hauppauge card (%s based)\n",
chipname);
@@ -630,13 +630,13 @@ static void ivtv_process_options(struct ivtv *itv)
if (itv->card->pci_list == NULL)
continue;
for (j = 0; itv->card->pci_list[j].device; j++) {
- if (itv->dev->device !=
+ if (itv->pdev->device !=
itv->card->pci_list[j].device)
continue;
- if (itv->dev->subsystem_vendor !=
+ if (itv->pdev->subsystem_vendor !=
itv->card->pci_list[j].subsystem_vendor)
continue;
- if (itv->dev->subsystem_device !=
+ if (itv->pdev->subsystem_device !=
itv->card->pci_list[j].subsystem_device)
continue;
IVTV_INFO("Autodetected %s card (%s based)\n",
@@ -650,9 +650,9 @@ done:
if (itv->card == NULL) {
itv->card = ivtv_get_card(IVTV_CARD_PVR_150);
IVTV_ERR("Unknown card: vendor/device: [%04x:%04x]\n",
- itv->dev->vendor, itv->dev->device);
+ itv->pdev->vendor, itv->pdev->device);
IVTV_ERR(" subsystem vendor/device: [%04x:%04x]\n",
- itv->dev->subsystem_vendor, itv->dev->subsystem_device);
+ itv->pdev->subsystem_vendor, itv->pdev->subsystem_device);
IVTV_ERR(" %s based\n", chipname);
IVTV_ERR("Defaulting to %s card\n", itv->card->name);
IVTV_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n");
@@ -671,7 +671,7 @@ done:
*/
static int __devinit ivtv_init_struct1(struct ivtv *itv)
{
- itv->base_addr = pci_resource_start(itv->dev, 0);
+ itv->base_addr = pci_resource_start(itv->pdev, 0);
itv->enc_mbox.max_mbox = 2; /* the encoder has 3 mailboxes (0-2) */
itv->dec_mbox.max_mbox = 1; /* the decoder has 2 mailboxes (0-1) */
@@ -682,7 +682,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv)
spin_lock_init(&itv->lock);
spin_lock_init(&itv->dma_reg_lock);
- itv->irq_work_queues = create_singlethread_workqueue(itv->device.name);
+ itv->irq_work_queues = create_singlethread_workqueue(itv->v4l2_dev.name);
if (itv->irq_work_queues == NULL) {
IVTV_ERR("Could not create ivtv workqueue\n");
return -1;
@@ -770,7 +770,7 @@ static void __devinit ivtv_init_struct2(struct ivtv *itv)
itv->audio_input = itv->card->video_inputs[i].audio_index;
}
-static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
+static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *pdev,
const struct pci_device_id *pci_id)
{
u16 cmd;
@@ -779,11 +779,11 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
IVTV_DEBUG_INFO("Enabling pci device\n");
- if (pci_enable_device(dev)) {
+ if (pci_enable_device(pdev)) {
IVTV_ERR("Can't enable device!\n");
return -EIO;
}
- if (pci_set_dma_mask(dev, 0xffffffff)) {
+ if (pci_set_dma_mask(pdev, 0xffffffff)) {
IVTV_ERR("No suitable DMA available.\n");
return -EIO;
}
@@ -809,11 +809,11 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
}
/* Check for bus mastering */
- pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ pci_read_config_word(pdev, PCI_COMMAND, &cmd);
if (!(cmd & PCI_COMMAND_MASTER)) {
IVTV_DEBUG_INFO("Attempting to enable Bus Mastering\n");
- pci_set_master(dev);
- pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ pci_set_master(pdev);
+ pci_read_config_word(pdev, PCI_COMMAND, &cmd);
if (!(cmd & PCI_COMMAND_MASTER)) {
IVTV_ERR("Bus Mastering is not enabled\n");
return -ENXIO;
@@ -821,26 +821,26 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
}
IVTV_DEBUG_INFO("Bus Mastering Enabled.\n");
- pci_read_config_byte(dev, PCI_CLASS_REVISION, &card_rev);
- pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency);
+ pci_read_config_byte(pdev, PCI_CLASS_REVISION, &card_rev);
+ pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency);
if (pci_latency < 64 && ivtv_pci_latency) {
IVTV_INFO("Unreasonably low latency timer, "
"setting to 64 (was %d)\n", pci_latency);
- pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
- pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency);
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
+ pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency);
}
/* This config space value relates to DMA latencies. The
default value 0x8080 is too low however and will lead
to DMA errors. 0xffff is the max value which solves
these problems. */
- pci_write_config_dword(dev, 0x40, 0xffff);
+ pci_write_config_dword(pdev, 0x40, 0xffff);
IVTV_DEBUG_INFO("%d (rev %d) at %02x:%02x.%x, "
"irq: %d, latency: %d, memory: 0x%lx\n",
- itv->dev->device, card_rev, dev->bus->number,
- PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
- itv->dev->irq, pci_latency, (unsigned long)itv->base_addr);
+ pdev->device, card_rev, pdev->bus->number,
+ PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
+ pdev->irq, pci_latency, (unsigned long)itv->base_addr);
return 0;
}
@@ -939,7 +939,7 @@ static void ivtv_load_and_init_modules(struct ivtv *itv)
}
}
-static int __devinit ivtv_probe(struct pci_dev *dev,
+static int __devinit ivtv_probe(struct pci_dev *pdev,
const struct pci_device_id *pci_id)
{
int retval = 0;
@@ -949,17 +949,17 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
itv = kzalloc(sizeof(struct ivtv), GFP_ATOMIC);
if (itv == NULL)
return -ENOMEM;
- itv->dev = dev;
+ itv->pdev = pdev;
itv->instance = atomic_inc_return(&ivtv_instance) - 1;
- retval = v4l2_device_register(&dev->dev, &itv->device);
+ retval = v4l2_device_register(&pdev->dev, &itv->v4l2_dev);
if (retval) {
kfree(itv);
return retval;
}
/* "ivtv + PCI ID" is a bit of a mouthful, so use
"ivtv + instance" instead. */
- snprintf(itv->device.name, sizeof(itv->device.name),
+ snprintf(itv->v4l2_dev.name, sizeof(itv->v4l2_dev.name),
"ivtv%d", itv->instance);
IVTV_INFO("Initializing card %d\n", itv->instance);
@@ -976,12 +976,11 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
IVTV_DEBUG_INFO("base addr: 0x%08x\n", itv->base_addr);
/* PCI Device Setup */
- if ((retval = ivtv_setup_pci(itv, dev, pci_id)) != 0) {
- if (retval == -EIO)
- goto free_workqueue;
- else if (retval == -ENXIO)
- goto free_mem;
- }
+ retval = ivtv_setup_pci(itv, pdev, pci_id);
+ if (retval == -EIO)
+ goto free_workqueue;
+ if (retval == -ENXIO)
+ goto free_mem;
/* map io memory */
IVTV_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n",
@@ -1158,8 +1157,8 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
ivtv_set_irq_mask(itv, 0xffffffff);
/* Register IRQ */
- retval = request_irq(itv->dev->irq, ivtv_irq_handler,
- IRQF_SHARED | IRQF_DISABLED, itv->device.name, (void *)itv);
+ retval = request_irq(itv->pdev->irq, ivtv_irq_handler,
+ IRQF_SHARED | IRQF_DISABLED, itv->v4l2_dev.name, (void *)itv);
if (retval) {
IVTV_ERR("Failed to register irq %d\n", retval);
goto free_i2c;
@@ -1181,7 +1180,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
free_streams:
ivtv_streams_cleanup(itv, 1);
free_irq:
- free_irq(itv->dev->irq, (void *)itv);
+ free_irq(itv->pdev->irq, (void *)itv);
free_i2c:
exit_ivtv_i2c(itv);
free_io:
@@ -1198,7 +1197,7 @@ err:
retval = -ENODEV;
IVTV_ERR("Error %d on initialization\n", retval);
- v4l2_device_unregister(&itv->device);
+ v4l2_device_unregister(&itv->v4l2_dev);
kfree(itv);
return retval;
}
@@ -1296,10 +1295,10 @@ int ivtv_init_on_first_open(struct ivtv *itv)
return 0;
}
-static void ivtv_remove(struct pci_dev *pci_dev)
+static void ivtv_remove(struct pci_dev *pdev)
{
- struct v4l2_device *dev = dev_get_drvdata(&pci_dev->dev);
- struct ivtv *itv = to_ivtv(dev);
+ struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
+ struct ivtv *itv = to_ivtv(v4l2_dev);
int i;
IVTV_DEBUG_INFO("Removing card\n");
@@ -1340,11 +1339,9 @@ static void ivtv_remove(struct pci_dev *pci_dev)
ivtv_streams_cleanup(itv, 1);
ivtv_udma_free(itv);
- v4l2_device_unregister(&itv->device);
-
exit_ivtv_i2c(itv);
- free_irq(itv->dev->irq, (void *)itv);
+ free_irq(itv->pdev->irq, (void *)itv);
ivtv_iounmap(itv);
release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
@@ -1352,11 +1349,13 @@ static void ivtv_remove(struct pci_dev *pci_dev)
if (itv->has_cx23415)
release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE);
- pci_disable_device(itv->dev);
+ pci_disable_device(itv->pdev);
for (i = 0; i < IVTV_VBI_FRAMES; i++)
kfree(itv->vbi.sliced_mpeg_data[i]);
printk(KERN_INFO "ivtv: Removed %s\n", itv->card_name);
+
+ v4l2_device_unregister(&itv->v4l2_dev);
kfree(itv);
}
diff --git a/linux/drivers/media/video/ivtv/ivtv-driver.h b/linux/drivers/media/video/ivtv/ivtv-driver.h
index 03df1cb7d..15779519a 100644
--- a/linux/drivers/media/video/ivtv/ivtv-driver.h
+++ b/linux/drivers/media/video/ivtv/ivtv-driver.h
@@ -134,7 +134,7 @@ extern int ivtv_debug;
#define IVTV_DEBUG(x, type, fmt, args...) \
do { \
if ((x) & ivtv_debug) \
- v4l2_info(&itv->device, " " type ": " fmt , ##args); \
+ v4l2_info(&itv->v4l2_dev, " " type ": " fmt , ##args); \
} while (0)
#define IVTV_DEBUG_WARN(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_WARN, "warn", fmt , ## args)
#define IVTV_DEBUG_INFO(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_INFO, "info", fmt , ## args)
@@ -150,7 +150,7 @@ extern int ivtv_debug;
#define IVTV_DEBUG_HIGH_VOL(x, type, fmt, args...) \
do { \
if (((x) & ivtv_debug) && (ivtv_debug & IVTV_DBGFLG_HIGHVOL)) \
- v4l2_info(&itv->device, " " type ": " fmt , ##args); \
+ v4l2_info(&itv->v4l2_dev, " " type ": " fmt , ##args); \
} while (0)
#define IVTV_DEBUG_HI_WARN(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_WARN, "warn", fmt , ## args)
#define IVTV_DEBUG_HI_INFO(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_INFO, "info", fmt , ## args)
@@ -164,9 +164,9 @@ extern int ivtv_debug;
#define IVTV_DEBUG_HI_YUV(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_YUV, "yuv", fmt , ## args)
/* Standard kernel messages */
-#define IVTV_ERR(fmt, args...) v4l2_err(&itv->device, fmt , ## args)
-#define IVTV_WARN(fmt, args...) v4l2_warn(&itv->device, fmt , ## args)
-#define IVTV_INFO(fmt, args...) v4l2_info(&itv->device, fmt , ## args)
+#define IVTV_ERR(fmt, args...) v4l2_err(&itv->v4l2_dev, fmt , ## args)
+#define IVTV_WARN(fmt, args...) v4l2_warn(&itv->v4l2_dev, fmt , ## args)
+#define IVTV_INFO(fmt, args...) v4l2_info(&itv->v4l2_dev, fmt , ## args)
/* output modes (cx23415 only) */
#define OUT_NONE 0
@@ -316,7 +316,7 @@ struct ivtv; /* forward reference */
struct ivtv_stream {
/* These first four fields are always set, even if the stream
is not actually created. */
- struct video_device *v4l2dev; /* NULL when stream not created */
+ struct video_device *vdev; /* NULL when stream not created */
struct ivtv *itv; /* for ease of use */
const char *name; /* name of the stream */
int type; /* stream type */
@@ -593,7 +593,7 @@ struct ivtv_card;
/* Struct to hold info about ivtv cards */
struct ivtv {
/* General fixed card data */
- struct pci_dev *dev; /* PCI device */
+ struct pci_dev *pdev; /* PCI device */
const struct ivtv_card *card; /* card information */
const char *card_name; /* full name of the card */
const struct ivtv_card_tuner_i2c *card_i2c; /* i2c addresses to probe for tuner */
@@ -613,7 +613,7 @@ struct ivtv {
volatile void __iomem *reg_mem; /* pointer to mapped registers */
struct ivtv_options options; /* user options */
- struct v4l2_device device;
+ struct v4l2_device v4l2_dev;
struct v4l2_subdev sd_gpio; /* GPIO sub-device */
u16 instance;
@@ -720,9 +720,9 @@ struct ivtv {
struct osd_info *osd_info; /* ivtvfb private OSD info */
};
-static inline struct ivtv *to_ivtv(struct v4l2_device *dev)
+static inline struct ivtv *to_ivtv(struct v4l2_device *v4l2_dev)
{
- return container_of(dev, struct ivtv, device);
+ return container_of(v4l2_dev, struct ivtv, v4l2_dev);
}
/* Globals */
@@ -789,7 +789,7 @@ static inline int ivtv_raw_vbi(const struct ivtv *itv)
/* Call the specified callback for all subdevs matching hw (if 0, then
match them all). Ignore any errors. */
#define ivtv_call_hw(itv, hw, o, f, args...) \
- __v4l2_device_call_subdevs(&(itv)->device, !(hw) || (sd->grp_id & (hw)), o, f , ##args)
+ __v4l2_device_call_subdevs(&(itv)->v4l2_dev, !(hw) || (sd->grp_id & (hw)), o, f , ##args)
#define ivtv_call_all(itv, o, f, args...) ivtv_call_hw(itv, 0, o, f , ##args)
@@ -797,7 +797,7 @@ static inline int ivtv_raw_vbi(const struct ivtv *itv)
match them all). If the callback returns an error other than 0 or
-ENOIOCTLCMD, then return with that error code. */
#define ivtv_call_hw_err(itv, hw, o, f, args...) \
- __v4l2_device_call_subdevs_until_err(&(itv)->device, !(hw) || (sd->grp_id & (hw)), o, f , ##args)
+ __v4l2_device_call_subdevs_until_err(&(itv)->v4l2_dev, !(hw) || (sd->grp_id & (hw)), o, f , ##args)
#define ivtv_call_all_err(itv, o, f, args...) ivtv_call_hw_err(itv, 0, o, f , ##args)
diff --git a/linux/drivers/media/video/ivtv/ivtv-fileops.c b/linux/drivers/media/video/ivtv/ivtv-fileops.c
index 617667d1c..cfaacf609 100644
--- a/linux/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/linux/drivers/media/video/ivtv/ivtv-fileops.c
@@ -991,7 +991,7 @@ int ivtv_v4l2_open(struct file *filp)
mutex_lock(&itv->serialize_lock);
if (ivtv_init_on_first_open(itv)) {
IVTV_ERR("Failed to initialize on minor %d\n",
- s->v4l2dev->minor);
+ vdev->minor);
mutex_unlock(&itv->serialize_lock);
return -ENXIO;
}
diff --git a/linux/drivers/media/video/ivtv/ivtv-firmware.c b/linux/drivers/media/video/ivtv/ivtv-firmware.c
index 6dba55b7e..c1b7ec475 100644
--- a/linux/drivers/media/video/ivtv/ivtv-firmware.c
+++ b/linux/drivers/media/video/ivtv/ivtv-firmware.c
@@ -52,7 +52,7 @@ static int load_fw_direct(const char *fn, volatile u8 __iomem *mem, struct ivtv
int retries = 3;
retry:
- if (retries && request_firmware(&fw, fn, &itv->dev->dev) == 0) {
+ if (retries && request_firmware(&fw, fn, &itv->pdev->dev) == 0) {
int i;
volatile u32 __iomem *dst = (volatile u32 __iomem *)mem;
const u32 *src = (const u32 *)fw->data;
diff --git a/linux/drivers/media/video/ivtv/ivtv-gpio.c b/linux/drivers/media/video/ivtv/ivtv-gpio.c
index dc2850e87..3321983d8 100644
--- a/linux/drivers/media/video/ivtv/ivtv-gpio.c
+++ b/linux/drivers/media/video/ivtv/ivtv-gpio.c
@@ -384,7 +384,7 @@ int ivtv_gpio_init(struct ivtv *itv)
write_reg(itv->card->gpio_init.initial_value | pin, IVTV_REG_GPIO_OUT);
write_reg(itv->card->gpio_init.direction | pin, IVTV_REG_GPIO_DIR);
v4l2_subdev_init(&itv->sd_gpio, &subdev_ops);
- snprintf(itv->sd_gpio.name, sizeof(itv->sd_gpio.name), "%s-gpio", itv->device.name);
+ snprintf(itv->sd_gpio.name, sizeof(itv->sd_gpio.name), "%s-gpio", itv->v4l2_dev.name);
itv->sd_gpio.grp_id = IVTV_HW_GPIO;
- return v4l2_device_register_subdev(&itv->device, &itv->sd_gpio);
+ return v4l2_device_register_subdev(&itv->v4l2_dev, &itv->sd_gpio);
}
diff --git a/linux/drivers/media/video/ivtv/ivtv-i2c.c b/linux/drivers/media/video/ivtv/ivtv-i2c.c
index 41452e111..682377c1a 100644
--- a/linux/drivers/media/video/ivtv/ivtv-i2c.c
+++ b/linux/drivers/media/video/ivtv/ivtv-i2c.c
@@ -198,14 +198,14 @@ struct v4l2_subdev *ivtv_find_hw(struct ivtv *itv, u32 hw)
struct v4l2_subdev *result = NULL;
struct v4l2_subdev *sd;
- spin_lock(&itv->device.lock);
- v4l2_device_for_each_subdev(sd, &itv->device) {
+ spin_lock(&itv->v4l2_dev.lock);
+ v4l2_device_for_each_subdev(sd, &itv->v4l2_dev) {
if (sd->grp_id == hw) {
result = sd;
break;
}
}
- spin_unlock(&itv->device.lock);
+ spin_unlock(&itv->v4l2_dev.lock);
return result;
}
@@ -476,8 +476,8 @@ static int ivtv_read(struct ivtv *itv, unsigned char addr, unsigned char *data,
intervening stop condition */
static int ivtv_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
{
- struct v4l2_device *drv = i2c_get_adapdata(i2c_adap);
- struct ivtv *itv = to_ivtv(drv);
+ struct v4l2_device *v4l2_dev = i2c_get_adapdata(i2c_adap);
+ struct ivtv *itv = to_ivtv(v4l2_dev);
int retval;
int i;
@@ -617,13 +617,13 @@ int init_ivtv_i2c(struct ivtv *itv)
sprintf(itv->i2c_adap.name + strlen(itv->i2c_adap.name), " #%d",
itv->instance);
- i2c_set_adapdata(&itv->i2c_adap, &itv->device);
+ i2c_set_adapdata(&itv->i2c_adap, &itv->v4l2_dev);
memcpy(&itv->i2c_client, &ivtv_i2c_client_template,
sizeof(struct i2c_client));
itv->i2c_client.adapter = &itv->i2c_adap;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
- itv->i2c_adap.dev.parent = &itv->dev->dev;
+ itv->i2c_adap.dev.parent = &itv->pdev->dev;
#endif
IVTV_DEBUG_I2C("setting scl and sda to 1\n");
diff --git a/linux/drivers/media/video/ivtv/ivtv-ioctl.c b/linux/drivers/media/video/ivtv/ivtv-ioctl.c
index f6b3ef6e6..aa55a3cc4 100644
--- a/linux/drivers/media/video/ivtv/ivtv-ioctl.c
+++ b/linux/drivers/media/video/ivtv/ivtv-ioctl.c
@@ -345,10 +345,8 @@ static int ivtv_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f
pixfmt->priv = 0;
if (id->type == IVTV_ENC_STREAM_TYPE_YUV) {
pixfmt->pixelformat = V4L2_PIX_FMT_HM12;
- /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
- pixfmt->sizeimage =
- pixfmt->height * pixfmt->width +
- pixfmt->height * (pixfmt->width / 2);
+ /* YUV size is (Y=(h*720) + UV=(h*(720/2))) */
+ pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2;
pixfmt->bytesperline = 720;
} else {
pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
@@ -469,11 +467,17 @@ static int ivtv_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format
struct ivtv *itv = id->itv;
int w = fmt->fmt.pix.width;
int h = fmt->fmt.pix.height;
+ int min_h = 2;
w = min(w, 720);
w = max(w, 2);
+ if (id->type == IVTV_ENC_STREAM_TYPE_YUV) {
+ /* YUV height must be a multiple of 32 */
+ h &= ~0x1f;
+ min_h = 32;
+ }
h = min(h, itv->is_50hz ? 576 : 480);
- h = max(h, 2);
+ h = max(h, min_h);
ivtv_g_fmt_vid_cap(file, fh, fmt);
fmt->fmt.pix.width = w;
fmt->fmt.pix.height = h;
@@ -766,7 +770,7 @@ static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vc
strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver));
strlcpy(vcap->card, itv->card_name, sizeof(vcap->card));
- snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(itv->dev));
+ snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(itv->pdev));
vcap->version = IVTV_DRIVER_VERSION; /* version */
vcap->capabilities = itv->v4l2_cap; /* capabilities */
return 0;
@@ -1513,12 +1517,12 @@ static int ivtv_log_status(struct file *file, void *fh)
}
IVTV_INFO("Tuner: %s\n",
test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV");
- cx2341x_log_status(&itv->params, itv->device.name);
+ cx2341x_log_status(&itv->params, itv->v4l2_dev.name);
IVTV_INFO("Status flags: 0x%08lx\n", itv->i_flags);
for (i = 0; i < IVTV_MAX_STREAMS; i++) {
struct ivtv_stream *s = &itv->streams[i];
- if (s->v4l2dev == NULL || s->buffers == 0)
+ if (s->vdev == NULL || s->buffers == 0)
continue;
IVTV_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", s->name, s->s_flags,
(s->buffers - s->q_free.buffers) * 100 / s->buffers,
diff --git a/linux/drivers/media/video/ivtv/ivtv-irq.c b/linux/drivers/media/video/ivtv/ivtv-irq.c
index 20e758d29..6dda1dd03 100644
--- a/linux/drivers/media/video/ivtv/ivtv-irq.c
+++ b/linux/drivers/media/video/ivtv/ivtv-irq.c
@@ -46,7 +46,7 @@ static void ivtv_pio_work_handler(struct ivtv *itv)
IVTV_DEBUG_HI_DMA("ivtv_pio_work_handler\n");
if (itv->cur_pio_stream < 0 || itv->cur_pio_stream >= IVTV_MAX_STREAMS ||
- s->v4l2dev == NULL || !ivtv_use_pio(s)) {
+ s->vdev == NULL || !ivtv_use_pio(s)) {
itv->cur_pio_stream = -1;
/* trigger PIO complete user interrupt */
write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44);
@@ -115,7 +115,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA
int rc;
/* sanity checks */
- if (s->v4l2dev == NULL) {
+ if (s->vdev == NULL) {
IVTV_DEBUG_WARN("Stream %s not started\n", s->name);
return -1;
}
diff --git a/linux/drivers/media/video/ivtv/ivtv-queue.c b/linux/drivers/media/video/ivtv/ivtv-queue.c
index 71bd13e22..ff7b7dede 100644
--- a/linux/drivers/media/video/ivtv/ivtv-queue.c
+++ b/linux/drivers/media/video/ivtv/ivtv-queue.c
@@ -230,7 +230,7 @@ int ivtv_stream_alloc(struct ivtv_stream *s)
return -ENOMEM;
}
if (ivtv_might_use_dma(s)) {
- s->sg_handle = pci_map_single(itv->dev, s->sg_dma, sizeof(struct ivtv_sg_element), s->dma);
+ s->sg_handle = pci_map_single(itv->pdev, s->sg_dma, sizeof(struct ivtv_sg_element), s->dma);
ivtv_stream_sync_for_cpu(s);
}
@@ -248,7 +248,7 @@ int ivtv_stream_alloc(struct ivtv_stream *s)
}
INIT_LIST_HEAD(&buf->list);
if (ivtv_might_use_dma(s)) {
- buf->dma_handle = pci_map_single(s->itv->dev,
+ buf->dma_handle = pci_map_single(s->itv->pdev,
buf->buf, s->buf_size + 256, s->dma);
ivtv_buf_sync_for_cpu(s, buf);
}
@@ -271,7 +271,7 @@ void ivtv_stream_free(struct ivtv_stream *s)
/* empty q_free */
while ((buf = ivtv_dequeue(s, &s->q_free))) {
if (ivtv_might_use_dma(s))
- pci_unmap_single(s->itv->dev, buf->dma_handle,
+ pci_unmap_single(s->itv->pdev, buf->dma_handle,
s->buf_size + 256, s->dma);
kfree(buf->buf);
kfree(buf);
@@ -280,7 +280,7 @@ void ivtv_stream_free(struct ivtv_stream *s)
/* Free SG Array/Lists */
if (s->sg_dma != NULL) {
if (s->sg_handle != IVTV_DMA_UNMAPPED) {
- pci_unmap_single(s->itv->dev, s->sg_handle,
+ pci_unmap_single(s->itv->pdev, s->sg_handle,
sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE);
s->sg_handle = IVTV_DMA_UNMAPPED;
}
diff --git a/linux/drivers/media/video/ivtv/ivtv-queue.h b/linux/drivers/media/video/ivtv/ivtv-queue.h
index 476556afd..91233839a 100644
--- a/linux/drivers/media/video/ivtv/ivtv-queue.h
+++ b/linux/drivers/media/video/ivtv/ivtv-queue.h
@@ -53,14 +53,14 @@ static inline int ivtv_use_dma(struct ivtv_stream *s)
static inline void ivtv_buf_sync_for_cpu(struct ivtv_stream *s, struct ivtv_buffer *buf)
{
if (ivtv_use_dma(s))
- pci_dma_sync_single_for_cpu(s->itv->dev, buf->dma_handle,
+ pci_dma_sync_single_for_cpu(s->itv->pdev, buf->dma_handle,
s->buf_size + 256, s->dma);
}
static inline void ivtv_buf_sync_for_device(struct ivtv_stream *s, struct ivtv_buffer *buf)
{
if (ivtv_use_dma(s))
- pci_dma_sync_single_for_device(s->itv->dev, buf->dma_handle,
+ pci_dma_sync_single_for_device(s->itv->pdev, buf->dma_handle,
s->buf_size + 256, s->dma);
}
@@ -82,14 +82,14 @@ void ivtv_stream_free(struct ivtv_stream *s);
static inline void ivtv_stream_sync_for_cpu(struct ivtv_stream *s)
{
if (ivtv_use_dma(s))
- pci_dma_sync_single_for_cpu(s->itv->dev, s->sg_handle,
+ pci_dma_sync_single_for_cpu(s->itv->pdev, s->sg_handle,
sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE);
}
static inline void ivtv_stream_sync_for_device(struct ivtv_stream *s)
{
if (ivtv_use_dma(s))
- pci_dma_sync_single_for_device(s->itv->dev, s->sg_handle,
+ pci_dma_sync_single_for_device(s->itv->pdev, s->sg_handle,
sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE);
}
diff --git a/linux/drivers/media/video/ivtv/ivtv-streams.c b/linux/drivers/media/video/ivtv/ivtv-streams.c
index 854a950af..15da01710 100644
--- a/linux/drivers/media/video/ivtv/ivtv-streams.c
+++ b/linux/drivers/media/video/ivtv/ivtv-streams.c
@@ -137,11 +137,11 @@ static struct {
static void ivtv_stream_init(struct ivtv *itv, int type)
{
struct ivtv_stream *s = &itv->streams[type];
- struct video_device *dev = s->v4l2dev;
+ struct video_device *vdev = s->vdev;
- /* we need to keep v4l2dev, so restore it afterwards */
+ /* we need to keep vdev, so restore it afterwards */
memset(s, 0, sizeof(*s));
- s->v4l2dev = dev;
+ s->vdev = vdev;
/* initialize ivtv_stream fields */
s->itv = itv;
@@ -172,10 +172,10 @@ static int ivtv_prep_dev(struct ivtv *itv, int type)
int num_offset = ivtv_stream_info[type].num_offset;
int num = itv->instance + ivtv_first_minor + num_offset;
- /* These four fields are always initialized. If v4l2dev == NULL, then
+ /* These four fields are always initialized. If vdev == NULL, then
this stream is not in use. In that case no other fields but these
four can be used. */
- s->v4l2dev = NULL;
+ s->vdev = NULL;
s->itv = itv;
s->type = type;
s->name = ivtv_stream_info[type].name;
@@ -197,21 +197,21 @@ static int ivtv_prep_dev(struct ivtv *itv, int type)
ivtv_stream_init(itv, type);
/* allocate and initialize the v4l2 video device structure */
- s->v4l2dev = video_device_alloc();
- if (s->v4l2dev == NULL) {
+ s->vdev = video_device_alloc();
+ if (s->vdev == NULL) {
IVTV_ERR("Couldn't allocate v4l2 video_device for %s\n", s->name);
return -ENOMEM;
}
- snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "%s %s",
- itv->device.name, s->name);
+ snprintf(s->vdev->name, sizeof(s->vdev->name), "%s %s",
+ itv->v4l2_dev.name, s->name);
- s->v4l2dev->num = num;
- s->v4l2dev->v4l2_dev = &itv->device;
- s->v4l2dev->fops = ivtv_stream_info[type].fops;
- s->v4l2dev->release = video_device_release;
- s->v4l2dev->tvnorms = V4L2_STD_ALL;
- ivtv_set_funcs(s->v4l2dev);
+ s->vdev->num = num;
+ s->vdev->v4l2_dev = &itv->v4l2_dev;
+ s->vdev->fops = ivtv_stream_info[type].fops;
+ s->vdev->release = video_device_release;
+ s->vdev->tvnorms = V4L2_STD_ALL;
+ ivtv_set_funcs(s->vdev);
return 0;
}
@@ -226,7 +226,7 @@ int ivtv_streams_setup(struct ivtv *itv)
if (ivtv_prep_dev(itv, type))
break;
- if (itv->streams[type].v4l2dev == NULL)
+ if (itv->streams[type].vdev == NULL)
continue;
/* Allocate Stream */
@@ -247,28 +247,28 @@ static int ivtv_reg_dev(struct ivtv *itv, int type)
int vfl_type = ivtv_stream_info[type].vfl_type;
int num;
- if (s->v4l2dev == NULL)
+ if (s->vdev == NULL)
return 0;
- num = s->v4l2dev->num;
+ num = s->vdev->num;
/* card number + user defined offset + device offset */
if (type != IVTV_ENC_STREAM_TYPE_MPG) {
struct ivtv_stream *s_mpg = &itv->streams[IVTV_ENC_STREAM_TYPE_MPG];
- if (s_mpg->v4l2dev)
- num = s_mpg->v4l2dev->num + ivtv_stream_info[type].num_offset;
+ if (s_mpg->vdev)
+ num = s_mpg->vdev->num + ivtv_stream_info[type].num_offset;
}
- video_set_drvdata(s->v4l2dev, s);
+ video_set_drvdata(s->vdev, s);
/* Register device. First try the desired minor, then any free one. */
- if (video_register_device(s->v4l2dev, vfl_type, num)) {
+ if (video_register_device(s->vdev, vfl_type, num)) {
IVTV_ERR("Couldn't register v4l2 device for %s kernel number %d\n",
s->name, num);
- video_device_release(s->v4l2dev);
- s->v4l2dev = NULL;
+ video_device_release(s->vdev);
+ s->vdev = NULL;
return -ENOMEM;
}
- num = s->v4l2dev->num;
+ num = s->vdev->num;
switch (vfl_type) {
case VFL_TYPE_GRABBER:
@@ -316,9 +316,9 @@ void ivtv_streams_cleanup(struct ivtv *itv, int unregister)
/* Teardown all streams */
for (type = 0; type < IVTV_MAX_STREAMS; type++) {
- struct video_device *vdev = itv->streams[type].v4l2dev;
+ struct video_device *vdev = itv->streams[type].vdev;
- itv->streams[type].v4l2dev = NULL;
+ itv->streams[type].vdev = NULL;
if (vdev == NULL)
continue;
@@ -449,7 +449,7 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
int captype = 0, subtype = 0;
int enable_passthrough = 0;
- if (s->v4l2dev == NULL)
+ if (s->vdev == NULL)
return -EINVAL;
IVTV_DEBUG_INFO("Start encoder stream %s\n", s->name);
@@ -611,7 +611,7 @@ static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s)
struct cx2341x_mpeg_params *p = &itv->params;
int datatype;
- if (s->v4l2dev == NULL)
+ if (s->vdev == NULL)
return -EINVAL;
IVTV_DEBUG_INFO("Setting some initial decoder settings\n");
@@ -657,7 +657,7 @@ int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset)
{
struct ivtv *itv = s->itv;
- if (s->v4l2dev == NULL)
+ if (s->vdev == NULL)
return -EINVAL;
if (test_and_set_bit(IVTV_F_S_STREAMING, &s->s_flags))
@@ -705,7 +705,7 @@ void ivtv_stop_all_captures(struct ivtv *itv)
for (i = IVTV_MAX_STREAMS - 1; i >= 0; i--) {
struct ivtv_stream *s = &itv->streams[i];
- if (s->v4l2dev == NULL)
+ if (s->vdev == NULL)
continue;
if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
ivtv_stop_v4l2_encode_stream(s, 0);
@@ -720,7 +720,7 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
int cap_type;
int stopmode;
- if (s->v4l2dev == NULL)
+ if (s->vdev == NULL)
return -EINVAL;
/* This function assumes that you are allowed to stop the capture
@@ -834,7 +834,7 @@ int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts)
{
struct ivtv *itv = s->itv;
- if (s->v4l2dev == NULL)
+ if (s->vdev == NULL)
return -EINVAL;
if (s->type != IVTV_DEC_STREAM_TYPE_YUV && s->type != IVTV_DEC_STREAM_TYPE_MPG)
@@ -895,7 +895,7 @@ int ivtv_passthrough_mode(struct ivtv *itv, int enable)
struct ivtv_stream *yuv_stream = &itv->streams[IVTV_ENC_STREAM_TYPE_YUV];
struct ivtv_stream *dec_stream = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV];
- if (yuv_stream->v4l2dev == NULL || dec_stream->v4l2dev == NULL)
+ if (yuv_stream->vdev == NULL || dec_stream->vdev == NULL)
return -EINVAL;
IVTV_DEBUG_INFO("ivtv ioctl: Select passthrough mode\n");
diff --git a/linux/drivers/media/video/ivtv/ivtv-udma.c b/linux/drivers/media/video/ivtv/ivtv-udma.c
index 5d4964b24..c3f8a5eac 100644
--- a/linux/drivers/media/video/ivtv/ivtv-udma.c
+++ b/linux/drivers/media/video/ivtv/ivtv-udma.c
@@ -94,7 +94,7 @@ void ivtv_udma_alloc(struct ivtv *itv)
{
if (itv->udma.SG_handle == 0) {
/* Map DMA Page Array Buffer */
- itv->udma.SG_handle = pci_map_single(itv->dev, itv->udma.SGarray,
+ itv->udma.SG_handle = pci_map_single(itv->pdev, itv->udma.SGarray,
sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE);
ivtv_udma_sync_for_cpu(itv);
}
@@ -148,7 +148,7 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr,
}
/* Map SG List */
- dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
+ dma->SG_length = pci_map_sg(itv->pdev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
/* Fill SG Array with new values */
ivtv_udma_fill_sg_array (dma, ivtv_dest_addr, 0, -1);
@@ -173,7 +173,7 @@ void ivtv_udma_unmap(struct ivtv *itv)
/* Unmap Scatterlist */
if (dma->SG_length) {
- pci_unmap_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
+ pci_unmap_sg(itv->pdev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
dma->SG_length = 0;
}
/* sync DMA */
@@ -192,13 +192,13 @@ void ivtv_udma_free(struct ivtv *itv)
/* Unmap SG Array */
if (itv->udma.SG_handle) {
- pci_unmap_single(itv->dev, itv->udma.SG_handle,
+ pci_unmap_single(itv->pdev, itv->udma.SG_handle,
sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE);
}
/* Unmap Scatterlist */
if (itv->udma.SG_length) {
- pci_unmap_sg(itv->dev, itv->udma.SGlist, itv->udma.page_count, PCI_DMA_TODEVICE);
+ pci_unmap_sg(itv->pdev, itv->udma.SGlist, itv->udma.page_count, PCI_DMA_TODEVICE);
}
for (i = 0; i < IVTV_DMA_SG_OSD_ENT; i++) {
diff --git a/linux/drivers/media/video/ivtv/ivtv-udma.h b/linux/drivers/media/video/ivtv/ivtv-udma.h
index df727e23b..ee3c9efb5 100644
--- a/linux/drivers/media/video/ivtv/ivtv-udma.h
+++ b/linux/drivers/media/video/ivtv/ivtv-udma.h
@@ -35,13 +35,13 @@ void ivtv_udma_start(struct ivtv *itv);
static inline void ivtv_udma_sync_for_device(struct ivtv *itv)
{
- pci_dma_sync_single_for_device((struct pci_dev *)itv->dev, itv->udma.SG_handle,
+ pci_dma_sync_single_for_device(itv->pdev, itv->udma.SG_handle,
sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE);
}
static inline void ivtv_udma_sync_for_cpu(struct ivtv *itv)
{
- pci_dma_sync_single_for_cpu((struct pci_dev *)itv->dev, itv->udma.SG_handle,
+ pci_dma_sync_single_for_cpu(itv->pdev, itv->udma.SG_handle,
sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE);
}
diff --git a/linux/drivers/media/video/ivtv/ivtv-yuv.c b/linux/drivers/media/video/ivtv/ivtv-yuv.c
index ee9110737..7912ed6b7 100644
--- a/linux/drivers/media/video/ivtv/ivtv-yuv.c
+++ b/linux/drivers/media/video/ivtv/ivtv-yuv.c
@@ -103,7 +103,7 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
dma->page_count = 0;
return -ENOMEM;
}
- dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
+ dma->SG_length = pci_map_sg(itv->pdev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
/* Fill SG Array with new values */
ivtv_udma_fill_sg_array(dma, y_buffer_offset, uv_buffer_offset, y_size);
@@ -910,7 +910,7 @@ static void ivtv_yuv_init(struct ivtv *itv)
/* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */
yi->blanking_ptr = kzalloc(720 * 16, GFP_KERNEL|__GFP_NOWARN);
if (yi->blanking_ptr) {
- yi->blanking_dmaptr = pci_map_single(itv->dev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE);
+ yi->blanking_dmaptr = pci_map_single(itv->pdev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE);
} else {
yi->blanking_dmaptr = 0;
IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n");
@@ -1237,7 +1237,7 @@ void ivtv_yuv_close(struct ivtv *itv)
if (yi->blanking_ptr) {
kfree(yi->blanking_ptr);
yi->blanking_ptr = NULL;
- pci_unmap_single(itv->dev, yi->blanking_dmaptr, 720*16, PCI_DMA_TODEVICE);
+ pci_unmap_single(itv->pdev, yi->blanking_dmaptr, 720*16, PCI_DMA_TODEVICE);
}
/* Invalidate the old dimension information */
diff --git a/linux/drivers/media/video/ivtv/ivtvfb.c b/linux/drivers/media/video/ivtv/ivtvfb.c
index 26b91d2c8..a48fe216b 100644
--- a/linux/drivers/media/video/ivtv/ivtvfb.c
+++ b/linux/drivers/media/video/ivtv/ivtvfb.c
@@ -1201,12 +1201,12 @@ static int ivtvfb_init_card(struct ivtv *itv)
static int __init ivtvfb_callback_init(struct device *dev, void *p)
{
struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
- struct ivtv *itv = container_of(v4l2_dev, struct ivtv, device);
+ struct ivtv *itv = container_of(v4l2_dev, struct ivtv, v4l2_dev);
if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
if (ivtvfb_init_card(itv) == 0) {
IVTVFB_INFO("Framebuffer registered on %s\n",
- itv->device.name);
+ itv->v4l2_dev.name);
(*(int *)p)++;
}
}
@@ -1216,7 +1216,7 @@ static int __init ivtvfb_callback_init(struct device *dev, void *p)
static int ivtvfb_callback_cleanup(struct device *dev, void *p)
{
struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
- struct ivtv *itv = container_of(v4l2_dev, struct ivtv, device);
+ struct ivtv *itv = container_of(v4l2_dev, struct ivtv, v4l2_dev);
if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
if (unregister_framebuffer(&itv->osd_info->ivtvfb_info)) {
diff --git a/linux/drivers/media/video/v4l2-ioctl.c b/linux/drivers/media/video/v4l2-ioctl.c
index 165bc9005..ec139df5c 100644
--- a/linux/drivers/media/video/v4l2-ioctl.c
+++ b/linux/drivers/media/video/v4l2-ioctl.c
@@ -24,6 +24,7 @@
#endif
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
#include <linux/video_decoder.h>
#include "compat.h"
@@ -1746,6 +1747,8 @@ static long __video_do_ioctl(struct file *file,
if (!ops->vidioc_g_chip_ident)
break;
+ p->ident = V4L2_IDENT_NONE;
+ p->revision = 0;
ret = ops->vidioc_g_chip_ident(file, fh, p);
if (!ret)
dbgarg(cmd, "chip_ident=%u, revision=0x%x\n", p->ident, p->revision);