From 2c2ea316cae4b14ff5b6ba6bf95d50e9692a72fd Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Sat, 6 Sep 2008 18:31:58 +0200 Subject: Fix support for Hauppauge Nova-S SE From: Patrick Boettcher Different backends have different input busses (saa7146, flexcop). To reflect that a config-option to the s5h1420-driver was added which makes the output mode selectable. Furthermore the s5h1420-driver is now doing the same i2c-method as it was done before adding support for other i2c-users. This patch needs to go into the current release of the kernel, as this driver is currently broken. (Thanks to Eberhard Kaltenhaeuser for helping out to debug this issue.) Priority: high Signed-off-by: Patrick Boettcher --- linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c | 1 + linux/drivers/media/dvb/frontends/s5h1420.c | 9 ++++++--- linux/drivers/media/dvb/frontends/s5h1420.h | 8 +++++--- 3 files changed, 12 insertions(+), 6 deletions(-) (limited to 'linux') diff --git a/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c index 4eed783f4..a127a4175 100644 --- a/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c +++ b/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c @@ -491,6 +491,7 @@ static struct s5h1420_config skystar2_rev2_7_s5h1420_config = { .demod_address = 0x53, .invert = 1, .repeated_start_workaround = 1, + .serial_mpeg = 1, }; static struct itd1000_config skystar2_rev2_7_itd1000_config = { diff --git a/linux/drivers/media/dvb/frontends/s5h1420.c b/linux/drivers/media/dvb/frontends/s5h1420.c index b768da972..31fc7c313 100644 --- a/linux/drivers/media/dvb/frontends/s5h1420.c +++ b/linux/drivers/media/dvb/frontends/s5h1420.c @@ -94,8 +94,11 @@ static u8 s5h1420_readreg(struct s5h1420_state *state, u8 reg) if (ret != 3) return ret; } else { - ret = i2c_transfer(state->i2c, &msg[1], 2); - if (ret != 2) + ret = i2c_transfer(state->i2c, &msg[1], 1); + if (ret != 1) + return ret; + ret = i2c_transfer(state->i2c, &msg[2], 1); + if (ret != 1) return ret; } @@ -854,7 +857,7 @@ static int s5h1420_init (struct dvb_frontend* fe) struct s5h1420_state* state = fe->demodulator_priv; /* disable power down and do reset */ - state->CON_1_val = 0x10; + state->CON_1_val = state->config->serial_mpeg << 4; s5h1420_writereg(state, 0x02, state->CON_1_val); msleep(10); s5h1420_reset(state); diff --git a/linux/drivers/media/dvb/frontends/s5h1420.h b/linux/drivers/media/dvb/frontends/s5h1420.h index 4c913f142..ff308136d 100644 --- a/linux/drivers/media/dvb/frontends/s5h1420.h +++ b/linux/drivers/media/dvb/frontends/s5h1420.h @@ -32,10 +32,12 @@ struct s5h1420_config u8 demod_address; /* does the inversion require inversion? */ - u8 invert : 1; + u8 invert:1; - u8 repeated_start_workaround : 1; - u8 cdclk_polarity : 1; /* 1 == falling edge, 0 == raising edge */ + u8 repeated_start_workaround:1; + u8 cdclk_polarity:1; /* 1 == falling edge, 0 == raising edge */ + + u8 serial_mpeg:1; }; #if defined(CONFIG_DVB_S5H1420) || (defined(CONFIG_DVB_S5H1420_MODULE) && defined(MODULE)) -- cgit v1.2.3 From f6b31c86cbf9e9833b40bded9ba5b31bf882fd2e Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Sat, 6 Sep 2008 18:42:47 +0200 Subject: Add support for the Gigabyte R8000-HT USB DVB-T adapter. From: Finn Thain Thanks to Ilia Penev for the tip-off that this device is much the same as (identical to?) a Terratec Cinergy HT USB XE, and for the firmware hints: http://linuxtv.org/pipermail/linux-dvb/2008-August/028108.html DVB functionality tested OK with xine using the usual dib0700 firmware. This diff is based on the latest latest linuxtv.org v4l-dvb mercurial repo. Priority: normal Signed-off-by: Finn Thain Signed-off-by: Patrick Boettcher --- linux/drivers/media/dvb/dvb-usb/dib0700_devices.c | 7 ++++++- linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'linux') diff --git a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c index 6c0e5c5f4..110d9344b 100644 --- a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -1119,6 +1119,7 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P_2) }, /* 35 */{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009) }, { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_3) }, + { USB_DEVICE(USB_VID_GIGABYTE, USB_PID_GIGABYTE_U8000) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -1408,7 +1409,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { }, }, - .num_device_descs = 3, + .num_device_descs = 4, .devices = { { "Terratec Cinergy HT USB XE", { &dib0700_usb_id_table[27], NULL }, @@ -1422,6 +1423,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[32], NULL }, { NULL }, }, + { "Gigabyte U8000-RH", + { &dib0700_usb_id_table[37], NULL }, + { NULL }, + }, }, .rc_interval = DEFAULT_RC_INTERVAL, .rc_key_map = dib0700_rc_keys, diff --git a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 81369b79e..d4c38b11d 100644 --- a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -205,6 +205,7 @@ #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_COLD 0x0514 #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM 0x0513 #define USB_PID_GIGABYTE_U7000 0x7001 +#define USB_PID_GIGABYTE_U8000 0x7002 #define USB_PID_ASUS_U3000 0x171f #define USB_PID_ASUS_U3100 0x173f #define USB_PID_YUAN_EC372S 0x1edc -- cgit v1.2.3 From e57c2bd89fdf14fd8cf07a300289c3af4b303594 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Sat, 6 Sep 2008 18:45:27 +0200 Subject: Add support for new i2c API provided in firmware version 1.20 From: Devin Heitmueller The Pinnacle PCTV HD Pro has an xc5000, which exposed a bug in the dib0700's i2c implementation where it did not properly support a single i2c read request (sending it as an i2c write request instead). Version 1.20 of the firmware added support for a new i2c API which supported such requests. This change defaults to fw 1.20 for all devices, but does not default to using the new i2c API (since initial testing suggests problems interacting with the mt2060). Maintainers can enable the use of the new i2c API by putting the following into their frontend initialization: struct dib0700_state *st = adap->dev->priv; st->fw_use_new_i2c_api = 1; Also note that the code expects i2c repeated start to be supported. If the i2c slave does not support repeated start, i2c messsages should have the I2C_M_NOSTART flag set. Thanks to Patrick Boettcher for providing new firmware fixing the issue as well as example i2c code utilizing the interface. Priority: normal Signed-off-by: Devin Heitmueller Signed-off-by: Patrick Boettcher --- linux/drivers/media/dvb/dvb-usb/dib0700.h | 3 + linux/drivers/media/dvb/dvb-usb/dib0700_core.c | 108 +++++++++++++++++++++- linux/drivers/media/dvb/dvb-usb/dib0700_devices.c | 2 +- 3 files changed, 110 insertions(+), 3 deletions(-) (limited to 'linux') diff --git a/linux/drivers/media/dvb/dvb-usb/dib0700.h b/linux/drivers/media/dvb/dvb-usb/dib0700.h index 66d4dc6ba..cc0c51d82 100644 --- a/linux/drivers/media/dvb/dvb-usb/dib0700.h +++ b/linux/drivers/media/dvb/dvb-usb/dib0700.h @@ -31,6 +31,8 @@ extern int dvb_usb_dib0700_debug; // 2 Byte: MPEG2 mode: 4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1) // 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines) 4LSB( " " ) #define REQUEST_SET_RC 0x11 +#define REQUEST_NEW_I2C_READ 0x12 +#define REQUEST_NEW_I2C_WRITE 0x13 #define REQUEST_GET_VERSION 0x15 struct dib0700_state { @@ -39,6 +41,7 @@ struct dib0700_state { u8 rc_toggle; u8 rc_counter; u8 is_dib7000pc; + u8 fw_use_new_i2c_api; }; extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val); diff --git a/linux/drivers/media/dvb/dvb-usb/dib0700_core.c b/linux/drivers/media/dvb/dvb-usb/dib0700_core.c index a2162fda5..ac89da344 100644 --- a/linux/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/linux/drivers/media/dvb/dvb-usb/dib0700_core.c @@ -82,9 +82,98 @@ int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_ } /* - * I2C master xfer function + * I2C master xfer function (supported in 1.20 firmware) */ -static int dib0700_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg *msg,int num) +static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg, + int num) +{ + /* The new i2c firmware messages are more reliable and in particular + properly support i2c read calls not preceded by a write */ + + struct dvb_usb_device *d = i2c_get_adapdata(adap); + uint8_t bus_mode = 1; /* 0=eeprom bus, 1=frontend bus */ + uint8_t gen_mode = 0; /* 0=master i2c, 1=gpio i2c */ + uint8_t en_start = 0; + uint8_t en_stop = 0; + uint8_t buf[255]; /* TBV: malloc ? */ + int result, i; + + /* Ensure nobody else hits the i2c bus while we're sending our + sequence of messages, (such as the remote control thread) */ + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + for (i = 0; i < num; i++) { + if (i == 0) { + /* First message in the transaction */ + en_start = 1; + } else if (!(msg[i].flags & I2C_M_NOSTART)) { + /* Device supports repeated-start */ + en_start = 1; + } else { + /* Not the first packet and device doesn't support + repeated start */ + en_start = 0; + } + if (i == (num - 1)) { + /* Last message in the transaction */ + en_stop = 1; + } + + if (msg[i].flags & I2C_M_RD) { + /* Read request */ + u16 index, value; + uint8_t i2c_dest; + + i2c_dest = (msg[i].addr << 1); + value = ((en_start << 7) | (en_stop << 6) | + (msg[i].len & 0x3F)) << 8 | i2c_dest; + /* I2C ctrl + FE bus; */ + index = ((gen_mode<<6)&0xC0) | ((bus_mode<<4)&0x30); + + result = usb_control_msg(d->udev, + usb_rcvctrlpipe(d->udev, 0), + REQUEST_NEW_I2C_READ, + USB_TYPE_VENDOR | USB_DIR_IN, + value, index, msg[i].buf, + msg[i].len, + USB_CTRL_GET_TIMEOUT); + if (result < 0) { + err("i2c read error (status = %d)\n", result); + break; + } + } else { + /* Write request */ + buf[0] = REQUEST_NEW_I2C_WRITE; + buf[1] = (msg[i].addr << 1); + buf[2] = (en_start << 7) | (en_stop << 6) | + (msg[i].len & 0x3F); + /* I2C ctrl + FE bus; */ + buf[3] = ((gen_mode<<6)&0xC0) | ((bus_mode<<4)&0x30); + /* The Actual i2c payload */ + memcpy(&buf[4], msg[i].buf, msg[i].len); + + result = usb_control_msg(d->udev, + usb_sndctrlpipe(d->udev, 0), + REQUEST_NEW_I2C_WRITE, + USB_TYPE_VENDOR | USB_DIR_OUT, + 0, 0, buf, msg[i].len + 4, + USB_CTRL_GET_TIMEOUT); + if (result < 0) { + err("i2c write error (status = %d)\n", result); + break; + } + } + } + mutex_unlock(&d->i2c_mutex); + return i; +} + +/* + * I2C master xfer function (pre-1.20 firmware) + */ +static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap, + struct i2c_msg *msg, int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); int i,len; @@ -124,6 +213,21 @@ static int dib0700_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg *msg,int num return i; } +static int dib0700_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + struct dib0700_state *st = d->priv; + + if (st->fw_use_new_i2c_api == 1) { + /* User running at least fw 1.20 */ + return dib0700_i2c_xfer_new(adap, msg, num); + } else { + /* Use legacy calls */ + return dib0700_i2c_xfer_legacy(adap, msg, num); + } +} + static u32 dib0700_i2c_func(struct i2c_adapter *adapter) { return I2C_FUNC_I2C; diff --git a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c index 110d9344b..2555e53b3 100644 --- a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -1127,7 +1127,7 @@ MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); #define DIB0700_DEFAULT_DEVICE_PROPERTIES \ .caps = DVB_USB_IS_AN_I2C_ADAPTER, \ .usb_ctrl = DEVICE_SPECIFIC, \ - .firmware = "dvb-usb-dib0700-1.10.fw", \ + .firmware = "dvb-usb-dib0700-1.20.fw", \ .download_firmware = dib0700_download_firmware, \ .no_reconnect = 1, \ .size_of_priv = sizeof(struct dib0700_state), \ -- cgit v1.2.3 From 57a7e7f304515be9abbcf4eb0f81f217c19676fe Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Sat, 6 Sep 2008 18:54:06 +0200 Subject: TTUSB-DEC DVB-S: claim to have lock From: Peter Beutner As reported by BOUWSMA Barry the readout of the signal status doesn't work on dec3000-s models. Since we don't know how to do it better, revert back to the old behaviour and always report a signal lock. Reported by Barry Bouwsma Priority: normal Signed-off-by: Peter Beutner Signed-off-by: Patrick Boettcher --- linux/drivers/media/dvb/ttusb-dec/ttusbdecfe.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'linux') diff --git a/linux/drivers/media/dvb/ttusb-dec/ttusbdecfe.c b/linux/drivers/media/dvb/ttusb-dec/ttusbdecfe.c index 443af2409..21260aad1 100644 --- a/linux/drivers/media/dvb/ttusb-dec/ttusbdecfe.c +++ b/linux/drivers/media/dvb/ttusb-dec/ttusbdecfe.c @@ -38,7 +38,17 @@ struct ttusbdecfe_state { }; -static int ttusbdecfe_read_status(struct dvb_frontend* fe, fe_status_t* status) +static int ttusbdecfe_dvbs_read_status(struct dvb_frontend *fe, + fe_status_t *status) +{ + *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | + FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK; + return 0; +} + + +static int ttusbdecfe_dvbt_read_status(struct dvb_frontend *fe, + fe_status_t *status) { struct ttusbdecfe_state* state = fe->demodulator_priv; u8 b[] = { 0x00, 0x00, 0x00, 0x00, @@ -251,7 +261,7 @@ static struct dvb_frontend_ops ttusbdecfe_dvbt_ops = { .get_tune_settings = ttusbdecfe_dvbt_get_tune_settings, - .read_status = ttusbdecfe_read_status, + .read_status = ttusbdecfe_dvbt_read_status, }; static struct dvb_frontend_ops ttusbdecfe_dvbs_ops = { @@ -273,7 +283,7 @@ static struct dvb_frontend_ops ttusbdecfe_dvbs_ops = { .set_frontend = ttusbdecfe_dvbs_set_frontend, - .read_status = ttusbdecfe_read_status, + .read_status = ttusbdecfe_dvbs_read_status, .diseqc_send_master_cmd = ttusbdecfe_dvbs_diseqc_send_master_cmd, .set_voltage = ttusbdecfe_dvbs_set_voltage, -- cgit v1.2.3 From a8c47d6fe59867e3b3f6ee4ed672eb434b375188 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Sun, 7 Sep 2008 17:39:44 +0200 Subject: Add support YUAN High-Tech STK7700D (1164:1f08) From: Daniel Oliveira Nascimento This patch extends the dib0700 driver to support the DVB-part of the Asus notebook M51Sn tv-tunner (USB-ID 1164:1f08). Priority: normal Signed-off-by: Patrick Boettcher --- linux/drivers/media/dvb/dvb-usb/dib0700_devices.c | 7 ++++++- linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'linux') diff --git a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c index 2555e53b3..a5e970eca 100644 --- a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -1120,6 +1120,7 @@ struct usb_device_id dib0700_usb_id_table[] = { /* 35 */{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009) }, { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_3) }, { USB_DEVICE(USB_VID_GIGABYTE, USB_PID_GIGABYTE_U8000) }, + { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700PH) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -1409,7 +1410,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { }, }, - .num_device_descs = 4, + .num_device_descs = 5, .devices = { { "Terratec Cinergy HT USB XE", { &dib0700_usb_id_table[27], NULL }, @@ -1427,6 +1428,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[37], NULL }, { NULL }, }, + { "YUAN High-Tech STK7700PH", + { &dib0700_usb_id_table[38], NULL }, + { NULL }, + }, }, .rc_interval = DEFAULT_RC_INTERVAL, .rc_key_map = dib0700_rc_keys, diff --git a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index d4c38b11d..cd0af6a97 100644 --- a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -209,6 +209,7 @@ #define USB_PID_ASUS_U3000 0x171f #define USB_PID_ASUS_U3100 0x173f #define USB_PID_YUAN_EC372S 0x1edc +#define USB_PID_YUAN_STK7700PH 0x1f08 #define USB_PID_DW2102 0x2102 #endif -- cgit v1.2.3 From 06999cfa3758e3e88f071bea68bc44a962f737fb Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Sun, 7 Sep 2008 17:43:33 +0200 Subject: Add support for Asus My Cinema U3000 Hybrid From: Albert Comerma This patch introduces support for dvb-t for the following dibcom based cards: Asus My Cinema U3000 Hybrid (USB-ID: 0b05:1736) Priority: normal Signed-off-by: Albert Comerma Signed-off-by: Patrick Boettcher --- linux/drivers/media/dvb/dvb-usb/dib0700_devices.c | 5 +++++ linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + 2 files changed, 6 insertions(+) (limited to 'linux') diff --git a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c index a5e970eca..d08cd4562 100644 --- a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -1121,6 +1121,7 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_3) }, { USB_DEVICE(USB_VID_GIGABYTE, USB_PID_GIGABYTE_U8000) }, { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700PH) }, + { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3000H) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -1432,6 +1433,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[38], NULL }, { NULL }, }, + { "Asus My Cinema-U3000Hybrid", + { &dib0700_usb_id_table[39], NULL }, + { NULL }, + }, }, .rc_interval = DEFAULT_RC_INTERVAL, .rc_key_map = dib0700_rc_keys, diff --git a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index cd0af6a97..f0fd47d84 100644 --- a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -207,6 +207,7 @@ #define USB_PID_GIGABYTE_U7000 0x7001 #define USB_PID_GIGABYTE_U8000 0x7002 #define USB_PID_ASUS_U3000 0x171f +#define USB_PID_ASUS_U3000H 0x1736 #define USB_PID_ASUS_U3100 0x173f #define USB_PID_YUAN_EC372S 0x1edc #define USB_PID_YUAN_STK7700PH 0x1f08 -- cgit v1.2.3 From c28e7446b370682d03bca416af6451c35a6ee538 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Sun, 7 Sep 2008 21:04:38 +0200 Subject: S5H1420: Fix size of shadow-array to avoid overflow From: Patrick Boettcher The array size of 'shadow' still needs to be fixed in order to not overflow when reading register 0x00. Thanks to Oliver Endriss for pointing that out. Priority: high Signed-off-by: Patrick Boettcher --- linux/drivers/media/dvb/frontends/s5h1420.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux') diff --git a/linux/drivers/media/dvb/frontends/s5h1420.c b/linux/drivers/media/dvb/frontends/s5h1420.c index 31fc7c313..46d55e393 100644 --- a/linux/drivers/media/dvb/frontends/s5h1420.c +++ b/linux/drivers/media/dvb/frontends/s5h1420.c @@ -59,7 +59,7 @@ struct s5h1420_state { * it does not support repeated-start, workaround: write addr-1 * and then read */ - u8 shadow[255]; + u8 shadow[256]; }; static u32 s5h1420_getsymbolrate(struct s5h1420_state* state); -- cgit v1.2.3 From ad9201bcf79af9e49eeba6aeed6c68a9c258d945 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Mon, 8 Sep 2008 10:42:42 +0200 Subject: Add support for Pinnacle PCTV HD Pro 801e (ATSC only) From: Devin Heitmueller Add digital support for the Pinnacle PCTV HD Pro 801e (usb id 2304:023a) Thanks to Patrick Boettcher for providing new firmware fixing the issue with the i2c that prevented the xc5000 from working. Priority: normal Signed-off-by: Devin Heitmueller Signed-off-by: Patrick Boettcher --- linux/drivers/media/dvb/dvb-usb/dib0700.h | 1 + linux/drivers/media/dvb/dvb-usb/dib0700_core.c | 7 +- linux/drivers/media/dvb/dvb-usb/dib0700_devices.c | 111 ++++++++++++++++++++++ linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + 4 files changed, 119 insertions(+), 1 deletion(-) (limited to 'linux') diff --git a/linux/drivers/media/dvb/dvb-usb/dib0700.h b/linux/drivers/media/dvb/dvb-usb/dib0700.h index cc0c51d82..739193943 100644 --- a/linux/drivers/media/dvb/dvb-usb/dib0700.h +++ b/linux/drivers/media/dvb/dvb-usb/dib0700.h @@ -42,6 +42,7 @@ struct dib0700_state { u8 rc_counter; u8 is_dib7000pc; u8 fw_use_new_i2c_api; + u8 disable_streaming_master_mode; }; extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val); diff --git a/linux/drivers/media/dvb/dvb-usb/dib0700_core.c b/linux/drivers/media/dvb/dvb-usb/dib0700_core.c index ac89da344..3c7bdef28 100644 --- a/linux/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/linux/drivers/media/dvb/dvb-usb/dib0700_core.c @@ -350,7 +350,12 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) b[0] = REQUEST_ENABLE_VIDEO; b[1] = (onoff << 4) | 0x00; /* this bit gives a kind of command, rather than enabling something or not */ - b[2] = (0x01 << 4); /* Master mode */ + + if (st->disable_streaming_master_mode == 1) + b[2] = 0x00; + else + b[2] = (0x01 << 4); /* Master mode */ + b[3] = 0x00; deb_info("modifying (%d) streaming state for %d\n", onoff, adap->id); diff --git a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c index d08cd4562..7d9efd702 100644 --- a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -14,6 +14,8 @@ #include "mt2060.h" #include "mt2266.h" #include "tuner-xc2028.h" +#include "xc5000.h" +#include "s5h1411.h" #include "dib0070.h" static int force_lna_activation; @@ -1078,6 +1080,89 @@ static int stk7070pd_frontend_attach1(struct dvb_usb_adapter *adap) return adap->fe == NULL ? -ENODEV : 0; } +/* S5H1411 */ +static struct s5h1411_config pinnacle_801e_config = { + .output_mode = S5H1411_PARALLEL_OUTPUT, + .gpio = S5H1411_GPIO_OFF, + .mpeg_timing = S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK, + .qam_if = S5H1411_IF_44000, + .vsb_if = S5H1411_IF_44000, + .inversion = S5H1411_INVERSION_OFF, + .status_mode = S5H1411_DEMODLOCKING +}; + +/* Pinnacle PCTV HD Pro 801e GPIOs map: + GPIO0 - currently unknown + GPIO1 - xc5000 tuner reset + GPIO2 - CX25843 sleep + GPIO3 - currently unknown + GPIO4 - currently unknown + GPIO6 - currently unknown + GPIO7 - currently unknown + GPIO9 - currently unknown + GPIO10 - CX25843 reset + */ +static int s5h1411_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_state *st = adap->dev->priv; + + /* Make use of the new i2c functions from FW 1.20 */ + st->fw_use_new_i2c_api = 1; + + /* The s5h1411 requires the dib0700 to not be in master mode */ + st->disable_streaming_master_mode = 1; + + /* All msleep values taken from Windows USB trace */ + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 0); + dib0700_set_gpio(adap->dev, GPIO3, GPIO_OUT, 0); + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(400); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + msleep(60); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(30); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 0); + msleep(30); + + /* Put the CX25843 to sleep for now since we're in digital mode */ + dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 1); + + /* GPIOs are initialized, do the attach */ + adap->fe = dvb_attach(s5h1411_attach, &pinnacle_801e_config, + &adap->dev->i2c_adap); + return adap->fe == NULL ? -ENODEV : 0; +} + +int dib0700_xc5000_tuner_callback(void *priv, int command, int arg) +{ + struct dvb_usb_adapter *adap = priv; + + /* Reset the tuner */ + dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 0); + msleep(330); /* from Windows USB trace */ + dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 1); + msleep(330); /* from Windows USB trace */ + + return 0; +} + +static struct xc5000_config s5h1411_xc5000_tunerconfig = { + .i2c_address = 0x64, + .if_khz = 5380, + .tuner_callback = dib0700_xc5000_tuner_callback +}; + +static int xc5000_tuner_attach(struct dvb_usb_adapter *adap) +{ + return dvb_attach(xc5000_attach, adap->fe, &adap->dev->i2c_adap, + &s5h1411_xc5000_tunerconfig, adap) + == NULL ? -ENODEV : 0; +} + /* DVB-USB and USB stuff follows */ struct usb_device_id dib0700_usb_id_table[] = { /* 0 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P) }, @@ -1122,6 +1207,7 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_GIGABYTE, USB_PID_GIGABYTE_U8000) }, { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700PH) }, { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3000H) }, +/* 40 */{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV801E) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -1442,6 +1528,31 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_key_map = dib0700_rc_keys, .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), .rc_query = dib0700_rc_query + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .frontend_attach = s5h1411_frontend_attach, + .tuner_attach = xc5000_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + .size_of_priv = sizeof(struct + dib0700_adapter_state), + }, + }, + + .num_device_descs = 1, + .devices = { + { "Pinnacle PCTV HD Pro USB Stick", + { &dib0700_usb_id_table[40], NULL }, + { NULL }, + }, + }, + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_key_map = dib0700_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), + .rc_query = dib0700_rc_query }, }; diff --git a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index f0fd47d84..3a5956c51 100644 --- a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -157,6 +157,7 @@ #define USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T 0x0229 #define USB_PID_PINNACLE_PCTV72E 0x0236 #define USB_PID_PINNACLE_PCTV73E 0x0237 +#define USB_PID_PINNACLE_PCTV801E 0x023a #define USB_PID_PCTV_200E 0x020e #define USB_PID_PCTV_400E 0x020f #define USB_PID_PCTV_450E 0x0222 -- cgit v1.2.3 From 458d337d90095b5d546c442e37de79db65fc9dfd Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Wed, 10 Sep 2008 00:39:20 -0400 Subject: add a general-purpose callback pointer to struct dvb_frontend From: Michael Krufky Remove tuner_callback pointers from tuner driver configuration and private state structures, replaced with a general-purpose callback pointer within struct dvb_frontend. A new parameter is added to the callback function, called component. This allows us to use this callback pointer by frontend components other than the tuner, if need be. So far, this is only used by tuner drivers. Priority: normal Signed-off-by: Michael Krufky --- linux/drivers/media/dvb/dvb-core/dvb_frontend.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'linux') diff --git a/linux/drivers/media/dvb/dvb-core/dvb_frontend.h b/linux/drivers/media/dvb/dvb-core/dvb_frontend.h index 1207f29f2..a0c591b3b 100644 --- a/linux/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/linux/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -234,6 +234,8 @@ struct dvb_frontend { void *sec_priv; void *analog_demod_priv; struct dtv_frontend_properties dtv_property_cache; +#define DVB_FRONTEND_COMPONENT_TUNER 0 + int (*callback)(void *adapter_priv, int component, int cmd, int arg); }; extern int dvb_register_frontend(struct dvb_adapter *dvb, -- cgit v1.2.3 From 9385e4874ef72f62d77800fe2eb47429d0854125 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 12 Sep 2008 12:31:45 -0400 Subject: convert tuner drivers to use dvb_frontend->callback From: Michael Krufky Priority: normal Signed-off-by: Michael Krufky --- linux/drivers/media/common/tuners/tda827x.c | 12 ++++--- linux/drivers/media/common/tuners/tda827x.h | 1 - linux/drivers/media/common/tuners/tda8290.c | 4 +-- linux/drivers/media/common/tuners/tda8290.h | 1 - linux/drivers/media/common/tuners/tuner-xc2028.c | 41 ++++++++++++----------- linux/drivers/media/common/tuners/tuner-xc2028.h | 2 -- linux/drivers/media/common/tuners/xc5000.c | 8 ++--- linux/drivers/media/common/tuners/xc5000.h | 2 -- linux/drivers/media/dvb/dvb-usb/cxusb.c | 7 ++-- linux/drivers/media/dvb/dvb-usb/dib0700_devices.c | 8 +++-- linux/drivers/media/video/au0828/au0828-cards.c | 2 +- linux/drivers/media/video/au0828/au0828-dvb.c | 3 +- linux/drivers/media/video/au0828/au0828.h | 3 +- linux/drivers/media/video/cx18/cx18-gpio.c | 2 +- linux/drivers/media/video/cx18/cx18-gpio.h | 2 +- linux/drivers/media/video/cx23885/cx23885-cards.c | 2 +- linux/drivers/media/video/cx23885/cx23885-dvb.c | 12 ++----- linux/drivers/media/video/cx23885/cx23885.h | 2 +- linux/drivers/media/video/cx88/cx88-cards.c | 24 ++++++++++--- linux/drivers/media/video/cx88/cx88-dvb.c | 40 ++-------------------- linux/drivers/media/video/cx88/cx88.h | 2 +- linux/drivers/media/video/em28xx/em28xx-cards.c | 2 +- linux/drivers/media/video/em28xx/em28xx-dvb.c | 3 +- linux/drivers/media/video/em28xx/em28xx.h | 2 +- linux/drivers/media/video/ivtv/ivtv-gpio.c | 2 +- linux/drivers/media/video/ivtv/ivtv-gpio.h | 2 +- linux/drivers/media/video/saa7134/saa7134-cards.c | 2 +- linux/drivers/media/video/saa7134/saa7134-dvb.c | 7 ++-- linux/drivers/media/video/saa7134/saa7134.h | 2 +- linux/drivers/media/video/tuner-core.c | 10 ++---- linux/include/media/tuner.h | 2 +- 31 files changed, 90 insertions(+), 124 deletions(-) (limited to 'linux') diff --git a/linux/drivers/media/common/tuners/tda827x.c b/linux/drivers/media/common/tuners/tda827x.c index 763b0dd95..83a017c53 100644 --- a/linux/drivers/media/common/tuners/tda827x.c +++ b/linux/drivers/media/common/tuners/tda827x.c @@ -448,17 +448,19 @@ static void tda827xa_lna_gain(struct dvb_frontend *fe, int high, else arg = 0; } - if (priv->cfg->tuner_callback) - priv->cfg->tuner_callback(priv->i2c_adap->algo_data, - gp_func, arg); + if (fe->callback) + fe->callback(priv->i2c_adap->algo_data, + DVB_FRONTEND_COMPONENT_TUNER, + gp_func, arg); buf[1] = high ? 0 : 1; if (priv->cfg->config == 2) buf[1] = high ? 1 : 0; i2c_transfer(priv->i2c_adap, &msg, 1); break; case 3: /* switch with GPIO of saa713x */ - if (priv->cfg->tuner_callback) - priv->cfg->tuner_callback(priv->i2c_adap->algo_data, 0, high); + if (fe->callback) + fe->callback(priv->i2c_adap->algo_data, + DVB_FRONTEND_COMPONENT_TUNER, 0, high); break; } } diff --git a/linux/drivers/media/common/tuners/tda827x.h b/linux/drivers/media/common/tuners/tda827x.h index 7850a9a1d..7d72ce0a0 100644 --- a/linux/drivers/media/common/tuners/tda827x.h +++ b/linux/drivers/media/common/tuners/tda827x.h @@ -36,7 +36,6 @@ struct tda827x_config /* interface to tda829x driver */ unsigned int config; int switch_addr; - int (*tuner_callback) (void *dev, int command, int arg); void (*agcf)(struct dvb_frontend *fe); }; diff --git a/linux/drivers/media/common/tuners/tda8290.c b/linux/drivers/media/common/tuners/tda8290.c index 751845554..637849ec8 100644 --- a/linux/drivers/media/common/tuners/tda8290.c +++ b/linux/drivers/media/common/tuners/tda8290.c @@ -695,10 +695,8 @@ struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, priv->i2c_props.addr = i2c_addr; priv->i2c_props.adap = i2c_adap; priv->i2c_props.name = "tda829x"; - if (cfg) { + if (cfg) priv->cfg.config = cfg->lna_cfg; - priv->cfg.tuner_callback = cfg->tuner_callback; - } if (tda8290_probe(&priv->i2c_props) == 0) { priv->ver = TDA8290; diff --git a/linux/drivers/media/common/tuners/tda8290.h b/linux/drivers/media/common/tuners/tda8290.h index aa074f3f0..7e288b26f 100644 --- a/linux/drivers/media/common/tuners/tda8290.h +++ b/linux/drivers/media/common/tuners/tda8290.h @@ -22,7 +22,6 @@ struct tda829x_config { unsigned int lna_cfg; - int (*tuner_callback) (void *dev, int command, int arg); unsigned int probe_tuner:1; #define TDA829X_PROBE_TUNER 0 diff --git a/linux/drivers/media/common/tuners/tuner-xc2028.c b/linux/drivers/media/common/tuners/tuner-xc2028.c index a3272e81e..6af6bc599 100644 --- a/linux/drivers/media/common/tuners/tuner-xc2028.c +++ b/linux/drivers/media/common/tuners/tuner-xc2028.c @@ -75,9 +75,6 @@ struct firmware_properties { struct xc2028_data { struct list_head hybrid_tuner_instance_list; struct tuner_i2c_props i2c_props; - int (*tuner_callback) (void *dev, - int command, int arg); - void *video_dev; __u32 frequency; struct firmware_description *firm; @@ -496,6 +493,23 @@ ret: return i; } +static inline int do_tuner_callback(struct dvb_frontend *fe, int cmd, int arg) +{ + struct xc2028_data *priv = fe->tuner_priv; + + /* analog side (tuner-core) uses i2c_adap->algo_data. + * digital side is not guaranteed to have algo_data defined. + * + * digital side will always have fe->dvb defined. + * analog side (tuner-core) doesn't (yet) define fe->dvb. + */ + + return (!fe->callback) ? -EINVAL : + fe->callback(((fe->dvb) && (fe->dvb->priv)) ? + fe->dvb->priv : priv->i2c_props.adap->algo_data, + DVB_FRONTEND_COMPONENT_TUNER, cmd, arg); +} + static int load_firmware(struct dvb_frontend *fe, unsigned int type, v4l2_std_id *id) { @@ -534,8 +548,7 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type, if (!size) { /* Special callback command received */ - rc = priv->tuner_callback(priv->video_dev, - XC2028_TUNER_RESET, 0); + rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0); if (rc < 0) { tuner_err("Error at RESET code %d\n", (*p) & 0x7f); @@ -546,8 +559,7 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type, if (size >= 0xff00) { switch (size) { case 0xff00: - rc = priv->tuner_callback(priv->video_dev, - XC2028_RESET_CLK, 0); + rc = do_tuner_callback(fe, XC2028_RESET_CLK, 0); if (rc < 0) { tuner_err("Error at RESET code %d\n", (*p) & 0x7f); @@ -719,8 +731,7 @@ retry: memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); /* Reset is needed before loading firmware */ - rc = priv->tuner_callback(priv->video_dev, - XC2028_TUNER_RESET, 0); + rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0); if (rc < 0) goto fail; @@ -937,7 +948,7 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, The reset CLK is needed only with tm6000. Driver should work fine even if this fails. */ - priv->tuner_callback(priv->video_dev, XC2028_RESET_CLK, 1); + do_tuner_callback(fe, XC2028_RESET_CLK, 1); msleep(10); @@ -1213,20 +1224,10 @@ struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, break; case 1: /* new tuner instance */ - priv->tuner_callback = cfg->callback; priv->ctrl.max_len = 13; mutex_init(&priv->lock); - /* analog side (tuner-core) uses i2c_adap->algo_data. - * digital side is not guaranteed to have algo_data defined. - * - * digital side will always have fe->dvb defined. - * analog side (tuner-core) doesn't (yet) define fe->dvb. - */ - priv->video_dev = ((fe->dvb) && (fe->dvb->priv)) ? - fe->dvb->priv : cfg->i2c_adap->algo_data; - fe->tuner_priv = priv; break; case 2: diff --git a/linux/drivers/media/common/tuners/tuner-xc2028.h b/linux/drivers/media/common/tuners/tuner-xc2028.h index 2c5b6282b..1af69f49f 100644 --- a/linux/drivers/media/common/tuners/tuner-xc2028.h +++ b/linux/drivers/media/common/tuners/tuner-xc2028.h @@ -39,9 +39,7 @@ struct xc2028_ctrl { struct xc2028_config { struct i2c_adapter *i2c_adap; u8 i2c_addr; - void *video_dev; struct xc2028_ctrl *ctrl; - int (*callback) (void *dev, int command, int arg); }; /* xc2028 commands for callback */ diff --git a/linux/drivers/media/common/tuners/xc5000.c b/linux/drivers/media/common/tuners/xc5000.c index 7d4d82d23..f3a3c47fe 100644 --- a/linux/drivers/media/common/tuners/xc5000.c +++ b/linux/drivers/media/common/tuners/xc5000.c @@ -58,8 +58,6 @@ struct xc5000_priv { u32 bandwidth; u8 video_standard; u8 rf_mode; - - int (*tuner_callback) (void *priv, int command, int arg); }; /* Misc Defines */ @@ -232,10 +230,11 @@ static void xc5000_TunerReset(struct dvb_frontend *fe) dprintk(1, "%s()\n", __func__); - if (priv->tuner_callback) { - ret = priv->tuner_callback(((fe->dvb) && (fe->dvb->priv)) ? + if (fe->callback) { + ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ? fe->dvb->priv : priv->i2c_props.adap->algo_data, + DVB_FRONTEND_COMPONENT_TUNER, XC5000_TUNER_RESET, 0); if (ret) printk(KERN_ERR "xc5000: reset failed\n"); @@ -994,7 +993,6 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, /* new tuner instance */ priv->bandwidth = BANDWIDTH_6_MHZ; priv->if_khz = cfg->if_khz; - priv->tuner_callback = cfg->tuner_callback; fe->tuner_priv = priv; break; diff --git a/linux/drivers/media/common/tuners/xc5000.h b/linux/drivers/media/common/tuners/xc5000.h index fa0321cfd..cf1a558e0 100644 --- a/linux/drivers/media/common/tuners/xc5000.h +++ b/linux/drivers/media/common/tuners/xc5000.h @@ -30,8 +30,6 @@ struct i2c_adapter; struct xc5000_config { u8 i2c_address; u32 if_khz; - - int (*tuner_callback) (void *priv, int command, int arg); }; /* xc5000 callback command */ diff --git a/linux/drivers/media/dvb/dvb-usb/cxusb.c b/linux/drivers/media/dvb/dvb-usb/cxusb.c index 1a746127c..406d7fba3 100644 --- a/linux/drivers/media/dvb/dvb-usb/cxusb.c +++ b/linux/drivers/media/dvb/dvb-usb/cxusb.c @@ -742,7 +742,8 @@ static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap) return 0; } -static int dvico_bluebird_xc2028_callback(void *ptr, int command, int arg) +static int dvico_bluebird_xc2028_callback(void *ptr, int component, + int command, int arg) { struct dvb_usb_adapter *adap = ptr; struct dvb_usb_device *d = adap->dev; @@ -770,7 +771,6 @@ static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap) struct xc2028_config cfg = { .i2c_adap = &adap->dev->i2c_adap, .i2c_addr = 0x61, - .callback = dvico_bluebird_xc2028_callback, }; static struct xc2028_ctrl ctl = { .fname = XC2028_DEFAULT_FIRMWARE, @@ -778,6 +778,9 @@ static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap) .demod = XC3028_FE_ZARLINK456, }; + /* FIXME: generalize & move to common area */ + adap->fe->callback = dvico_bluebird_xc2028_callback; + fe = dvb_attach(xc2028_attach, adap->fe, &cfg); if (fe == NULL || fe->ops.tuner_ops.set_config == NULL) return -EIO; diff --git a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c index 6c0e5c5f4..88925c9ba 100644 --- a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -366,7 +366,8 @@ static struct dib7000p_config stk7700ph_dib7700_xc3028_config = { .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, }; -static int stk7700ph_xc3028_callback(void *ptr, int command, int arg) +static int stk7700ph_xc3028_callback(void *ptr, int component, + int command, int arg) { struct dvb_usb_adapter *adap = ptr; @@ -394,7 +395,6 @@ static struct xc2028_ctrl stk7700ph_xc3028_ctrl = { static struct xc2028_config stk7700ph_xc3028_config = { .i2c_addr = 0x61, - .callback = stk7700ph_xc3028_callback, .ctrl = &stk7700ph_xc3028_ctrl, }; @@ -435,7 +435,9 @@ static int stk7700ph_tuner_attach(struct dvb_usb_adapter *adap) DIBX000_I2C_INTERFACE_TUNER, 1); stk7700ph_xc3028_config.i2c_adap = tun_i2c; - stk7700ph_xc3028_config.video_dev = adap; + + /* FIXME: generalize & move to common area */ + adap->fe->callback = stk7700ph_xc3028_callback; return dvb_attach(xc2028_attach, adap->fe, &stk7700ph_xc3028_config) == NULL ? -ENODEV : 0; diff --git a/linux/drivers/media/video/au0828/au0828-cards.c b/linux/drivers/media/video/au0828/au0828-cards.c index ed48908a9..5f07a8a07 100644 --- a/linux/drivers/media/video/au0828/au0828-cards.c +++ b/linux/drivers/media/video/au0828/au0828-cards.c @@ -46,7 +46,7 @@ struct au0828_board au0828_boards[] = { /* Tuner callback function for au0828 boards. Currently only needed * for HVR1500Q, which has an xc5000 tuner. */ -int au0828_tuner_callback(void *priv, int command, int arg) +int au0828_tuner_callback(void *priv, int component, int command, int arg) { struct au0828_dev *dev = priv; diff --git a/linux/drivers/media/video/au0828/au0828-dvb.c b/linux/drivers/media/video/au0828/au0828-dvb.c index 24160ca59..82474a4a8 100644 --- a/linux/drivers/media/video/au0828/au0828-dvb.c +++ b/linux/drivers/media/video/au0828/au0828-dvb.c @@ -54,7 +54,6 @@ static struct au8522_config hauppauge_woodbury_config = { static struct xc5000_config hauppauge_hvr950q_tunerconfig = { .i2c_address = 0x61, .if_khz = 6000, - .tuner_callback = au0828_tuner_callback }; static struct mxl5007t_config mxl5007t_hvr950q_config = { @@ -394,6 +393,8 @@ int au0828_dvb_register(struct au0828_dev *dev) __func__); return -1; } + /* define general-purpose callback pointer */ + dvb->frontend->callback = au0828_tuner_callback; /* register everything */ ret = dvb_register(dev); diff --git a/linux/drivers/media/video/au0828/au0828.h b/linux/drivers/media/video/au0828/au0828.h index 4f10ff300..9d6a1161d 100644 --- a/linux/drivers/media/video/au0828/au0828.h +++ b/linux/drivers/media/video/au0828/au0828.h @@ -103,7 +103,8 @@ extern int au0828_debug; extern struct au0828_board au0828_boards[]; extern struct usb_device_id au0828_usb_id_table[]; extern void au0828_gpio_setup(struct au0828_dev *dev); -extern int au0828_tuner_callback(void *priv, int command, int arg); +extern int au0828_tuner_callback(void *priv, int component, + int command, int arg); extern void au0828_card_setup(struct au0828_dev *dev); /* ----------------------------------------------------------- */ diff --git a/linux/drivers/media/video/cx18/cx18-gpio.c b/linux/drivers/media/video/cx18/cx18-gpio.c index 3bdffbf7a..0e5604219 100644 --- a/linux/drivers/media/video/cx18/cx18-gpio.c +++ b/linux/drivers/media/video/cx18/cx18-gpio.c @@ -152,7 +152,7 @@ void cx18_gpio_init(struct cx18 *cx) } /* Xceive tuner reset function */ -int cx18_reset_tuner_gpio(void *dev, int cmd, int value) +int cx18_reset_tuner_gpio(void *dev, int component, int cmd, int value) { struct i2c_algo_bit_data *algo = dev; struct cx18_i2c_algo_callback_data *cb_data = algo->data; diff --git a/linux/drivers/media/video/cx18/cx18-gpio.h b/linux/drivers/media/video/cx18/cx18-gpio.h index 22cd7ddf8..beb7424b9 100644 --- a/linux/drivers/media/video/cx18/cx18-gpio.h +++ b/linux/drivers/media/video/cx18/cx18-gpio.h @@ -23,5 +23,5 @@ void cx18_gpio_init(struct cx18 *cx); void cx18_reset_i2c_slaves_gpio(struct cx18 *cx); void cx18_reset_ir_gpio(void *data); -int cx18_reset_tuner_gpio(void *dev, int cmd, int value); +int cx18_reset_tuner_gpio(void *dev, int component, int cmd, int value); int cx18_gpio(struct cx18 *cx, unsigned int command, void *arg); diff --git a/linux/drivers/media/video/cx23885/cx23885-cards.c b/linux/drivers/media/video/cx23885/cx23885-cards.c index be9a6d8ec..2b497b28b 100644 --- a/linux/drivers/media/video/cx23885/cx23885-cards.c +++ b/linux/drivers/media/video/cx23885/cx23885-cards.c @@ -338,7 +338,7 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) dev->name, tv.model); } -int cx23885_tuner_callback(void *priv, int command, int arg) +int cx23885_tuner_callback(void *priv, int component, int command, int arg) { struct cx23885_tsport *port = priv; struct cx23885_dev *dev = port->dev; diff --git a/linux/drivers/media/video/cx23885/cx23885-dvb.c b/linux/drivers/media/video/cx23885/cx23885-dvb.c index c84688aba..78dfb13ca 100644 --- a/linux/drivers/media/video/cx23885/cx23885-dvb.c +++ b/linux/drivers/media/video/cx23885/cx23885-dvb.c @@ -190,13 +190,11 @@ static struct s5h1411_config dvico_s5h1411_config = { static struct xc5000_config hauppauge_hvr1500q_tunerconfig = { .i2c_address = 0x61, .if_khz = 5380, - .tuner_callback = cx23885_tuner_callback, }; static struct xc5000_config dvico_xc5000_tunerconfig = { .i2c_address = 0x64, .if_khz = 5380, - .tuner_callback = cx23885_tuner_callback, }; static struct tda829x_config tda829x_no_probe = { @@ -404,8 +402,6 @@ static int dvb_register(struct cx23885_tsport *port) struct xc2028_config cfg = { .i2c_adap = &i2c_bus->i2c_adap, .i2c_addr = 0x61, - .video_dev = port, - .callback = cx23885_tuner_callback, }; static struct xc2028_ctrl ctl = { .fname = XC2028_DEFAULT_FIRMWARE, @@ -444,8 +440,6 @@ static int dvb_register(struct cx23885_tsport *port) struct xc2028_config cfg = { .i2c_adap = &dev->i2c_bus[1].i2c_adap, .i2c_addr = 0x64, - .video_dev = port, - .callback = cx23885_tuner_callback, }; static struct xc2028_ctrl ctl = { .fname = XC3028L_DEFAULT_FIRMWARE, @@ -486,8 +480,6 @@ static int dvb_register(struct cx23885_tsport *port) struct xc2028_config cfg = { .i2c_adap = &i2c_bus->i2c_adap, .i2c_addr = 0x61, - .video_dev = port, - .callback = cx23885_tuner_callback, }; static struct xc2028_ctrl ctl = { .fname = XC2028_DEFAULT_FIRMWARE, @@ -513,8 +505,6 @@ static int dvb_register(struct cx23885_tsport *port) struct xc2028_config cfg = { .i2c_adap = &dev->i2c_bus[1].i2c_adap, .i2c_addr = 0x61, - .video_dev = port, - .callback = cx23885_tuner_callback, }; static struct xc2028_ctrl ctl = { .fname = XC2028_DEFAULT_FIRMWARE, @@ -537,6 +527,8 @@ static int dvb_register(struct cx23885_tsport *port) printk("%s: frontend initialization failed\n", dev->name); return -1; } + /* define general-purpose callback pointer */ + port->dvb.frontend->callback = cx23885_tuner_callback; /* Put the analog decoder in standby to keep it quiet */ cx23885_call_i2c_clients(i2c_bus, TUNER_SET_STANDBY, NULL); diff --git a/linux/drivers/media/video/cx23885/cx23885.h b/linux/drivers/media/video/cx23885/cx23885.h index 49e3eaec7..dea1798f7 100644 --- a/linux/drivers/media/video/cx23885/cx23885.h +++ b/linux/drivers/media/video/cx23885/cx23885.h @@ -412,7 +412,7 @@ extern const unsigned int cx23885_bcount; extern struct cx23885_subid cx23885_subids[]; extern const unsigned int cx23885_idcount; -extern int cx23885_tuner_callback(void *priv, int command, int arg); +extern int cx23885_tuner_callback(void *priv, int component, int command, int arg); extern void cx23885_card_list(struct cx23885_dev *dev); extern int cx23885_ir_init(struct cx23885_dev *dev); extern void cx23885_gpio_setup(struct cx23885_dev *dev); diff --git a/linux/drivers/media/video/cx88/cx88-cards.c b/linux/drivers/media/video/cx88/cx88-cards.c index 95b2ff5d9..87e1b6ced 100644 --- a/linux/drivers/media/video/cx88/cx88-cards.c +++ b/linux/drivers/media/video/cx88/cx88-cards.c @@ -2345,9 +2345,21 @@ static int cx88_dvico_xc2028_callback(struct cx88_core *core, { switch (command) { case XC2028_TUNER_RESET: - cx_write(MO_GP0_IO, 0x101000); - mdelay(5); - cx_set(MO_GP0_IO, 0x101010); + switch (core->boardnr) { + case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO: + /* GPIO-4 xc3028 tuner */ + + cx_set(MO_GP0_IO, 0x00001000); + cx_clear(MO_GP0_IO, 0x00000010); + msleep(100); + cx_set(MO_GP0_IO, 0x00000010); + msleep(100); + break; + default: + cx_write(MO_GP0_IO, 0x101000); + mdelay(5); + cx_set(MO_GP0_IO, 0x101010); + } break; default: return -EINVAL; @@ -2456,6 +2468,7 @@ static int cx88_xc2028_tuner_callback(struct cx88_core *core, case CX88_BOARD_PROLINK_PV_8000GT: return cx88_pv_8000gt_callback(core, command, arg); case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO: + case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO: return cx88_dvico_xc2028_callback(core, command, arg); } @@ -2523,7 +2536,7 @@ static int cx88_xc5000_tuner_callback(struct cx88_core *core, return 0; /* Should never be here */ } -int cx88_tuner_callback(void *priv, int command, int arg) +int cx88_tuner_callback(void *priv, int component, int command, int arg) { struct i2c_algo_bit_data *i2c_algo = priv; struct cx88_core *core; @@ -2540,6 +2553,9 @@ int cx88_tuner_callback(void *priv, int command, int arg) return -EINVAL; } + if (component != DVB_FRONTEND_COMPONENT_TUNER) + return -EINVAL; + switch (core->board.tuner_type) { case TUNER_XC2028: info_printk(core, "Calling XC2028/3028 callback\n"); diff --git a/linux/drivers/media/video/cx88/cx88-dvb.c b/linux/drivers/media/video/cx88/cx88-dvb.c index 64c799500..a65ea03a0 100644 --- a/linux/drivers/media/video/cx88/cx88-dvb.c +++ b/linux/drivers/media/video/cx88/cx88-dvb.c @@ -406,40 +406,6 @@ static int tevii_dvbs_set_voltage(struct dvb_frontend *fe, return 0; } -static int cx88_pci_nano_callback(void *ptr, int command, int arg) -{ - struct cx88_core *core = ptr; - - switch (command) { - case XC2028_TUNER_RESET: - /* Send the tuner in then out of reset */ - dprintk(1, "%s: XC2028_TUNER_RESET %d\n", __func__, arg); - - switch (core->boardnr) { - case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO: - /* GPIO-4 xc3028 tuner */ - - cx_set(MO_GP0_IO, 0x00001000); - cx_clear(MO_GP0_IO, 0x00000010); - msleep(100); - cx_set(MO_GP0_IO, 0x00000010); - msleep(100); - break; - } - - break; - case XC2028_RESET_CLK: - dprintk(1, "%s: XC2028_RESET_CLK %d\n", __func__, arg); - break; - default: - dprintk(1, "%s: unknown command %d, arg %d\n", __func__, - command, arg); - return -EINVAL; - } - - return 0; -} - static struct cx24123_config geniatech_dvbs_config = { .demod_address = 0x55, .set_ts_params = cx24123_set_ts_param, @@ -487,7 +453,6 @@ static struct s5h1409_config kworld_atsc_120_config = { static struct xc5000_config pinnacle_pctv_hd_800i_tuner_config = { .i2c_address = 0x64, .if_khz = 5380, - .tuner_callback = cx88_tuner_callback, }; static struct zl10353_config cx88_geniatech_x8000_mt = { @@ -514,7 +479,6 @@ static struct s5h1411_config dvico_fusionhdtv7_config = { static struct xc5000_config dvico_fusionhdtv7_tuner_config = { .i2c_address = 0xc2 >> 1, .if_khz = 5380, - .tuner_callback = cx88_tuner_callback, }; static int attach_xc3028(u8 addr, struct cx8802_dev *dev) @@ -525,7 +489,6 @@ static int attach_xc3028(u8 addr, struct cx8802_dev *dev) .i2c_adap = &dev->core->i2c_adap, .i2c_addr = addr, .ctrl = &ctl, - .callback = cx88_tuner_callback, }; if (!dev->dvb.frontend) { @@ -919,7 +882,6 @@ static int dvb_register(struct cx8802_dev *dev) struct xc2028_config cfg = { .i2c_adap = &core->i2c_adap, .i2c_addr = 0x61, - .callback = cx88_pci_nano_callback, }; static struct xc2028_ctrl ctl = { .fname = XC2028_DEFAULT_FIRMWARE, @@ -1042,6 +1004,8 @@ static int dvb_register(struct cx8802_dev *dev) core->name); return -EINVAL; } + /* define general-purpose callback pointer */ + dev->dvb.frontend->callback = cx88_tuner_callback; /* Ensure all frontends negotiate bus access */ dev->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl; diff --git a/linux/drivers/media/video/cx88/cx88.h b/linux/drivers/media/video/cx88/cx88.h index 238370681..6f5b2963b 100644 --- a/linux/drivers/media/video/cx88/cx88.h +++ b/linux/drivers/media/video/cx88/cx88.h @@ -628,7 +628,7 @@ extern void cx88_call_i2c_clients(struct cx88_core *core, /* ----------------------------------------------------------- */ /* cx88-cards.c */ -extern int cx88_tuner_callback(void *dev, int command, int arg); +extern int cx88_tuner_callback(void *dev, int component, int command, int arg); extern int cx88_get_resources(const struct cx88_core *core, struct pci_dev *pci); extern struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr); diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c index 5abdefdf0..38874e024 100644 --- a/linux/drivers/media/video/em28xx/em28xx-cards.c +++ b/linux/drivers/media/video/em28xx/em28xx-cards.c @@ -1273,7 +1273,7 @@ static struct em28xx_hash_table em28xx_i2c_hash[] = { {0x1ba50080, EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA, TUNER_ABSENT}, }; -int em28xx_tuner_callback(void *ptr, int command, int arg) +int em28xx_tuner_callback(void *ptr, int component, int command, int arg) { int rc = 0; struct em28xx *dev = ptr; diff --git a/linux/drivers/media/video/em28xx/em28xx-dvb.c b/linux/drivers/media/video/em28xx/em28xx-dvb.c index 79c11b1d0..03c212e5a 100644 --- a/linux/drivers/media/video/em28xx/em28xx-dvb.c +++ b/linux/drivers/media/video/em28xx/em28xx-dvb.c @@ -250,7 +250,6 @@ static int attach_xc3028(u8 addr, struct em28xx *dev) memset(&cfg, 0, sizeof(cfg)); cfg.i2c_adap = &dev->i2c_adap; cfg.i2c_addr = addr; - cfg.callback = em28xx_tuner_callback; if (!dev->dvb->frontend) { printk(KERN_ERR "%s/2: dvb frontend not attached. " @@ -466,6 +465,8 @@ static int dvb_init(struct em28xx *dev) result = -EINVAL; goto out_free; } + /* define general-purpose callback pointer */ + dvb->frontend->callback = em28xx_tuner_callback; /* register everything */ result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev); diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h index 4bdff9619..d73b8c983 100644 --- a/linux/drivers/media/video/em28xx/em28xx.h +++ b/linux/drivers/media/video/em28xx/em28xx.h @@ -541,7 +541,7 @@ extern struct em28xx_board em28xx_boards[]; extern struct usb_device_id em28xx_id_table[]; extern const unsigned int em28xx_bcount; void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir); -int em28xx_tuner_callback(void *ptr, int command, int arg); +int em28xx_tuner_callback(void *ptr, int component, int command, int arg); /* Provided by em28xx-input.c */ /* TODO: Check if the standard get_key handlers on ir-common can be used */ diff --git a/linux/drivers/media/video/ivtv/ivtv-gpio.c b/linux/drivers/media/video/ivtv/ivtv-gpio.c index bc22905ea..74a44844c 100644 --- a/linux/drivers/media/video/ivtv/ivtv-gpio.c +++ b/linux/drivers/media/video/ivtv/ivtv-gpio.c @@ -124,7 +124,7 @@ void ivtv_reset_ir_gpio(struct ivtv *itv) } /* Xceive tuner reset function */ -int ivtv_reset_tuner_gpio(void *dev, int cmd, int value) +int ivtv_reset_tuner_gpio(void *dev, int component, int cmd, int value) { struct i2c_algo_bit_data *algo = dev; struct ivtv *itv = algo->data; diff --git a/linux/drivers/media/video/ivtv/ivtv-gpio.h b/linux/drivers/media/video/ivtv/ivtv-gpio.h index 964a265d9..48b629161 100644 --- a/linux/drivers/media/video/ivtv/ivtv-gpio.h +++ b/linux/drivers/media/video/ivtv/ivtv-gpio.h @@ -24,7 +24,7 @@ /* GPIO stuff */ void ivtv_gpio_init(struct ivtv *itv); void ivtv_reset_ir_gpio(struct ivtv *itv); -int ivtv_reset_tuner_gpio(void *dev, int cmd, int value); +int ivtv_reset_tuner_gpio(void *dev, int component, int cmd, int value); int ivtv_gpio(struct ivtv *itv, unsigned int command, void *arg); #endif diff --git a/linux/drivers/media/video/saa7134/saa7134-cards.c b/linux/drivers/media/video/saa7134/saa7134-cards.c index 3fbf9dfc7..9280fb314 100644 --- a/linux/drivers/media/video/saa7134/saa7134-cards.c +++ b/linux/drivers/media/video/saa7134/saa7134-cards.c @@ -5671,7 +5671,7 @@ static int saa7134_tda8290_callback(struct saa7134_dev *dev, return 0; } -int saa7134_tuner_callback(void *priv, int command, int arg) +int saa7134_tuner_callback(void *priv, int component, int command, int arg) { struct saa7134_dev *dev = priv; if (dev != NULL) { diff --git a/linux/drivers/media/video/saa7134/saa7134-dvb.c b/linux/drivers/media/video/saa7134/saa7134-dvb.c index d61ab4e10..4fb5c0d41 100644 --- a/linux/drivers/media/video/saa7134/saa7134-dvb.c +++ b/linux/drivers/media/video/saa7134/saa7134-dvb.c @@ -553,7 +553,6 @@ static int configure_tda827x_fe(struct saa7134_dev *dev, /* ------------------------------------------------------------------ */ static struct tda827x_config tda827x_cfg_0 = { - .tuner_callback = saa7134_tuner_callback, .init = philips_tda827x_tuner_init, .sleep = philips_tda827x_tuner_sleep, .config = 0, @@ -561,7 +560,6 @@ static struct tda827x_config tda827x_cfg_0 = { }; static struct tda827x_config tda827x_cfg_1 = { - .tuner_callback = saa7134_tuner_callback, .init = philips_tda827x_tuner_init, .sleep = philips_tda827x_tuner_sleep, .config = 1, @@ -569,7 +567,6 @@ static struct tda827x_config tda827x_cfg_1 = { }; static struct tda827x_config tda827x_cfg_2 = { - .tuner_callback = saa7134_tuner_callback, .init = philips_tda827x_tuner_init, .sleep = philips_tda827x_tuner_sleep, .config = 2, @@ -577,7 +574,6 @@ static struct tda827x_config tda827x_cfg_2 = { }; static struct tda827x_config tda827x_cfg_2_sw42 = { - .tuner_callback = saa7134_tuner_callback, .init = philips_tda827x_tuner_init, .sleep = philips_tda827x_tuner_sleep, .config = 2, @@ -836,7 +832,6 @@ static int ads_duo_tuner_sleep(struct dvb_frontend *fe) } static struct tda827x_config ads_duo_cfg = { - .tuner_callback = saa7134_tuner_callback, .init = ads_duo_tuner_init, .sleep = ads_duo_tuner_sleep, .config = 0 @@ -1370,6 +1365,8 @@ static int dvb_init(struct saa7134_dev *dev) printk(KERN_ERR "%s/dvb: frontend initialization failed\n", dev->name); return -1; } + /* define general-purpose callback pointer */ + dev->dvb.frontend->callback = saa7134_tuner_callback; /* register everything else */ ret = videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev, diff --git a/linux/drivers/media/video/saa7134/saa7134.h b/linux/drivers/media/video/saa7134/saa7134.h index 168cc7dfd..1e7fcf3fd 100644 --- a/linux/drivers/media/video/saa7134/saa7134.h +++ b/linux/drivers/media/video/saa7134/saa7134.h @@ -658,7 +658,7 @@ extern struct pci_device_id __devinitdata saa7134_pci_tbl[]; extern int saa7134_board_init1(struct saa7134_dev *dev); extern int saa7134_board_init2(struct saa7134_dev *dev); -int saa7134_tuner_callback(void *priv, int command, int arg); +int saa7134_tuner_callback(void *priv, int component, int command, int arg); /* ----------------------------------------------------------- */ diff --git a/linux/drivers/media/video/tuner-core.c b/linux/drivers/media/video/tuner-core.c index d6ce6f6a5..5dd4bd660 100644 --- a/linux/drivers/media/video/tuner-core.c +++ b/linux/drivers/media/video/tuner-core.c @@ -93,7 +93,6 @@ struct tuner { unsigned int type; /* chip type id */ unsigned int config; - int (*tuner_callback) (void *dev, int command, int arg); const char *name; }; @@ -347,7 +346,7 @@ static struct xc5000_config xc5000_cfg; static void set_type(struct i2c_client *c, unsigned int type, unsigned int new_mode_mask, unsigned int new_config, - int (*tuner_callback) (void *dev, int command,int arg)) + int (*tuner_callback) (void *dev, int component, int cmd, int arg)) { struct tuner *t = i2c_get_clientdata(c); struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; @@ -363,7 +362,7 @@ static void set_type(struct i2c_client *c, unsigned int type, t->config = new_config; if (tuner_callback != NULL) { tuner_dbg("defining GPIO callback\n"); - t->tuner_callback = tuner_callback; + t->fe.callback = tuner_callback; } if (t->mode == T_UNINITIALIZED) { @@ -386,7 +385,6 @@ static void set_type(struct i2c_client *c, unsigned int type, { struct tda829x_config cfg = { .lna_cfg = t->config, - .tuner_callback = t->tuner_callback, }; if (!dvb_attach(tda829x_attach, &t->fe, t->i2c->adapter, t->i2c->addr, &cfg)) @@ -434,7 +432,6 @@ static void set_type(struct i2c_client *c, unsigned int type, struct xc2028_config cfg = { .i2c_adap = t->i2c->adapter, .i2c_addr = t->i2c->addr, - .callback = t->tuner_callback, }; if (!dvb_attach(xc2028_attach, &t->fe, &cfg)) goto attach_failed; @@ -451,7 +448,6 @@ static void set_type(struct i2c_client *c, unsigned int type, xc5000_cfg.i2c_address = t->i2c->addr; xc5000_cfg.if_khz = 5380; - xc5000_cfg.tuner_callback = t->tuner_callback; if (!dvb_attach(xc5000_attach, &t->fe, t->i2c->adapter, &xc5000_cfg)) goto attach_failed; @@ -1234,7 +1230,7 @@ register_client: } else { t->mode = V4L2_TUNER_DIGITAL_TV; } - set_type(client, t->type, t->mode_mask, t->config, t->tuner_callback); + set_type(client, t->type, t->mode_mask, t->config, t->fe.callback); list_add_tail(&t->list, &tuner_list); return 0; } diff --git a/linux/include/media/tuner.h b/linux/include/media/tuner.h index ba818985c..67c1f514d 100644 --- a/linux/include/media/tuner.h +++ b/linux/include/media/tuner.h @@ -179,7 +179,7 @@ struct tuner_setup { unsigned int type; /* Tuner type */ unsigned int mode_mask; /* Allowed tuner modes */ unsigned int config; /* configuraion for more complex tuners */ - int (*tuner_callback) (void *dev, int command,int arg); + int (*tuner_callback) (void *dev, int component, int cmd, int arg); }; #endif /* __KERNEL__ */ -- cgit v1.2.3 From c4cf46815549e8414d732d62f7d1deaf5a97473d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 16 Sep 2008 01:19:46 +0000 Subject: uvcvideo : Add support for Advent 4211 integrated webcam From: Laurent Pinchart Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/uvc/uvc_driver.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'linux') diff --git a/linux/drivers/media/video/uvc/uvc_driver.c b/linux/drivers/media/video/uvc/uvc_driver.c index b2482502a..5364417de 100644 --- a/linux/drivers/media/video/uvc/uvc_driver.c +++ b/linux/drivers/media/video/uvc/uvc_driver.c @@ -1941,6 +1941,15 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_PROBE_MINMAX }, + /* Advent 4211 - Bison Electronics */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x5986, + .idProduct = 0x0203, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_QUIRK_PROBE_MINMAX }, /* Bison Electronics */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, -- cgit v1.2.3 From 1252343c32470785b0e37b5736ce4064f8af3506 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 16 Sep 2008 01:24:29 +0000 Subject: uvcvideo: Fix incomplete frame drop when switching to a variable size format. From: Laurent Pinchart When streaming in a fixed size format the driver sets a flag in the uvc_queue structure to drop incomplete incoming frames. The flag wasn't cleared when switching to a variable size format, which resulted in a broken 'MJPEG after YUV'. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/uvc/uvc_v4l2.c | 4 ---- linux/drivers/media/video/uvc/uvc_video.c | 5 +++++ 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'linux') diff --git a/linux/drivers/media/video/uvc/uvc_v4l2.c b/linux/drivers/media/video/uvc/uvc_v4l2.c index d4758c8e1..78e4c4e09 100644 --- a/linux/drivers/media/video/uvc/uvc_v4l2.c +++ b/linux/drivers/media/video/uvc/uvc_v4l2.c @@ -842,10 +842,6 @@ static int uvc_v4l2_do_ioctl(struct inode *inode, struct file *file, if (ret < 0) return ret; - if (!(video->streaming->cur_format->flags & - UVC_FMT_FLAG_COMPRESSED)) - video->queue.flags |= UVC_QUEUE_DROP_INCOMPLETE; - rb->count = ret; ret = 0; break; diff --git a/linux/drivers/media/video/uvc/uvc_video.c b/linux/drivers/media/video/uvc/uvc_video.c index 593aebffe..b7bb23820 100644 --- a/linux/drivers/media/video/uvc/uvc_video.c +++ b/linux/drivers/media/video/uvc/uvc_video.c @@ -971,6 +971,11 @@ int uvc_video_enable(struct uvc_video_device *video, int enable) return 0; } + if (video->streaming->cur_format->flags & UVC_FMT_FLAG_COMPRESSED) + video->queue.flags &= ~UVC_QUEUE_DROP_INCOMPLETE; + else + video->queue.flags |= UVC_QUEUE_DROP_INCOMPLETE; + if ((ret = uvc_queue_enable(&video->queue, 1)) < 0) return ret; -- cgit v1.2.3 From afe823da08720ab728a75ac4d12a830d1cc73549 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 16 Sep 2008 06:32:20 +0000 Subject: V4L/DVB:usbvideo:don't use part of buffer for USB transfer #4 From: Ming Lei The status[] is part of uvc_device structure. We can't make sure the address of status is at a cache-line boundary in all archs,so status[] might share a cache-line with some fields in uvc_structure. This can lead to some cache coherence issues(http://lwn.net/Articles/2265/). Use dynamically allocated buffer instead. Signed-off-by: Ming Lei Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/uvc/uvc_status.c | 11 +++++++++-- linux/drivers/media/video/uvc/uvcvideo.h | 4 +++- 2 files changed, 12 insertions(+), 3 deletions(-) (limited to 'linux') diff --git a/linux/drivers/media/video/uvc/uvc_status.c b/linux/drivers/media/video/uvc/uvc_status.c index 75e678ac5..5d60b264d 100644 --- a/linux/drivers/media/video/uvc/uvc_status.c +++ b/linux/drivers/media/video/uvc/uvc_status.c @@ -177,9 +177,15 @@ int uvc_status_init(struct uvc_device *dev) uvc_input_init(dev); + dev->status = kzalloc(UVC_MAX_STATUS_SIZE, GFP_KERNEL); + if (dev->status == NULL) + return -ENOMEM; + dev->int_urb = usb_alloc_urb(0, GFP_KERNEL); - if (dev->int_urb == NULL) + if (dev->int_urb == NULL) { + kfree(dev->status); return -ENOMEM; + } pipe = usb_rcvintpipe(dev->udev, ep->desc.bEndpointAddress); @@ -192,7 +198,7 @@ int uvc_status_init(struct uvc_device *dev) interval = fls(interval) - 1; usb_fill_int_urb(dev->int_urb, dev->udev, pipe, - dev->status, sizeof dev->status, uvc_status_complete, + dev->status, UVC_MAX_STATUS_SIZE, uvc_status_complete, dev, interval); return usb_submit_urb(dev->int_urb, GFP_KERNEL); @@ -202,6 +208,7 @@ void uvc_status_cleanup(struct uvc_device *dev) { usb_kill_urb(dev->int_urb); usb_free_urb(dev->int_urb); + kfree(dev->status); uvc_input_cleanup(dev); } diff --git a/linux/drivers/media/video/uvc/uvcvideo.h b/linux/drivers/media/video/uvc/uvcvideo.h index bafe3406e..9a6bc1aaf 100644 --- a/linux/drivers/media/video/uvc/uvcvideo.h +++ b/linux/drivers/media/video/uvc/uvcvideo.h @@ -303,6 +303,8 @@ struct uvc_xu_control { #define UVC_MAX_FRAME_SIZE (16*1024*1024) /* Maximum number of video buffers. */ #define UVC_MAX_VIDEO_BUFFERS 32 +/* Maximum status buffer size in bytes of interrupt URB. */ +#define UVC_MAX_STATUS_SIZE 16 #define UVC_CTRL_CONTROL_TIMEOUT 300 #define UVC_CTRL_STREAMING_TIMEOUT 1000 @@ -634,7 +636,7 @@ struct uvc_device { /* Status Interrupt Endpoint */ struct usb_host_endpoint *int_ep; struct urb *int_urb; - __u8 status[16]; + __u8 *status; struct input_dev *input; /* Video Streaming interfaces */ -- cgit v1.2.3 From 7e2816a102e8c58b190688cd96930d9c5c84f7f4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 19 Sep 2008 02:26:35 +0000 Subject: drivers/media/video/tda9840.c: unbreak From: Andrew Morton drivers/media/video/tda9840.c: In function 'tda9840_command': drivers/media/video/tda9840.c:152: warning: 'result' is used uninitialized in this function Priority: normal Signed-off-by: Andrew Morton [mchehab@redhat.com: Fix conflict with another patch that were meant to solve the warning] Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/tda9840.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'linux') diff --git a/linux/drivers/media/video/tda9840.c b/linux/drivers/media/video/tda9840.c index 72adcb450..31dde7516 100644 --- a/linux/drivers/media/video/tda9840.c +++ b/linux/drivers/media/video/tda9840.c @@ -72,7 +72,6 @@ static void tda9840_write(struct i2c_client *client, u8 reg, u8 val) static int tda9840_command(struct i2c_client *client, unsigned cmd, void *arg) { - int result = 0; int byte = *(int *)arg; switch (cmd) { @@ -177,9 +176,6 @@ static int tda9840_command(struct i2c_client *client, unsigned cmd, void *arg) return -ENOIOCTLCMD; } - if (result) - return -EIO; - return 0; } -- cgit v1.2.3 From 01743e6f42125b8c56b589f07799f514ca96a196 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 21 Sep 2008 04:12:03 -0300 Subject: With the recent patch to v4l2 titled "v4l2: use register_chrdev_region From: David Ellingsworth instead of register_chrdev", the internal reference count is no longer necessary in order to free the internal stk_webcam struct. This patch removes the reference counter from the stk_webcam struct and frees the struct via the video_device release callback. It also fixes an associated bug in stk_camera_probe which could result from video_unregister_device being called before video_register_device. Lastly, it simplifies access to the stk_webcam struct in several places. This patch should apply cleanly against the "working" branch of the v4l-dvb git repository. This patch is identical to the patch I sent a couple of months back titled "stk-webcam: Fix video_device handling" except that it has been rebased against current modifications to stk-webcam and it no longer depends on any other outstanding patches. Acked-by: Jaime Velasco Juan Signed-off-by: David Ellingsworth Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/stk-webcam.c | 84 ++++++++++------------------------ linux/drivers/media/video/stk-webcam.h | 2 - 2 files changed, 23 insertions(+), 63 deletions(-) (limited to 'linux') diff --git a/linux/drivers/media/video/stk-webcam.c b/linux/drivers/media/video/stk-webcam.c index 055e92549..8c1817a47 100644 --- a/linux/drivers/media/video/stk-webcam.c +++ b/linux/drivers/media/video/stk-webcam.c @@ -66,22 +66,6 @@ static struct usb_device_id stkwebcam_table[] = { }; MODULE_DEVICE_TABLE(usb, stkwebcam_table); -static void stk_camera_cleanup(struct kref *kref) -{ - struct stk_camera *dev = to_stk_camera(kref); - - STK_INFO("Syntek USB2.0 Camera release resources" - " video device /dev/video%d\n", dev->vdev.minor); - video_unregister_device(&dev->vdev); - video_set_drvdata(&dev->vdev, NULL); - - if (dev->sio_bufs != NULL || dev->isobufs != NULL) - STK_ERROR("We are leaking memory\n"); - usb_put_intf(dev->interface); - kfree(dev); -} - - /* * Basic stuff */ @@ -695,8 +679,7 @@ static int v4l_stk_open(struct inode *inode, struct file *fp) unlock_kernel(); return -ENXIO; } - fp->private_data = vdev; - kref_get(&dev->kref); + fp->private_data = dev; usb_autopm_get_interface(dev->interface); unlock_kernel(); @@ -705,23 +688,10 @@ static int v4l_stk_open(struct inode *inode, struct file *fp) static int v4l_stk_release(struct inode *inode, struct file *fp) { - struct stk_camera *dev; - struct video_device *vdev; - - vdev = video_devdata(fp); - if (vdev == NULL) { - STK_ERROR("v4l_release called w/o video devdata\n"); - return -EFAULT; - } - dev = vdev_to_camera(vdev); - if (dev == NULL) { - STK_ERROR("v4l_release called on removed device\n"); - return -ENODEV; - } + struct stk_camera *dev = fp->private_data; if (dev->owner != fp) { usb_autopm_put_interface(dev->interface); - kref_put(&dev->kref, stk_camera_cleanup); return 0; } @@ -732,7 +702,6 @@ static int v4l_stk_release(struct inode *inode, struct file *fp) dev->owner = NULL; usb_autopm_put_interface(dev->interface); - kref_put(&dev->kref, stk_camera_cleanup); return 0; } @@ -743,14 +712,8 @@ static ssize_t v4l_stk_read(struct file *fp, char __user *buf, int i; int ret; unsigned long flags; - struct stk_camera *dev; - struct video_device *vdev; struct stk_sio_buffer *sbuf; - - vdev = video_devdata(fp); - if (vdev == NULL) - return -EFAULT; - dev = vdev_to_camera(vdev); + struct stk_camera *dev = fp->private_data; if (dev == NULL) return -EIO; @@ -809,15 +772,8 @@ static ssize_t v4l_stk_read(struct file *fp, char __user *buf, static unsigned int v4l_stk_poll(struct file *fp, poll_table *wait) { - struct stk_camera *dev; - struct video_device *vdev; - - vdev = video_devdata(fp); - - if (vdev == NULL) - return -EFAULT; + struct stk_camera *dev = fp->private_data; - dev = vdev_to_camera(vdev); if (dev == NULL) return -ENODEV; @@ -855,16 +811,12 @@ static int v4l_stk_mmap(struct file *fp, struct vm_area_struct *vma) unsigned int i; int ret; unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; - struct stk_camera *dev; - struct video_device *vdev; + struct stk_camera *dev = fp->private_data; struct stk_sio_buffer *sbuf = NULL; if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED)) return -EINVAL; - vdev = video_devdata(fp); - dev = vdev_to_camera(vdev); - for (i = 0; i < dev->n_sbufs; i++) { if (dev->sio_bufs[i].v4lbuf.m.offset == offset) { sbuf = dev->sio_bufs + i; @@ -1360,6 +1312,12 @@ static const struct v4l2_ioctl_ops v4l_stk_ioctl_ops = { static void stk_v4l_dev_release(struct video_device *vd) { + struct stk_camera *dev = vdev_to_camera(vd); + + if (dev->sio_bufs != NULL || dev->isobufs != NULL) + STK_ERROR("We are leaking memory\n"); + usb_put_intf(dev->interface); + kfree(dev); } static struct video_device stk_v4l_data = { @@ -1380,7 +1338,6 @@ static int stk_register_video_device(struct stk_camera *dev) dev->vdev = stk_v4l_data; dev->vdev.debug = debug; dev->vdev.parent = &dev->interface->dev; - video_set_drvdata(&dev->vdev, dev); err = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1); if (err) STK_ERROR("v4l registration failed\n"); @@ -1397,7 +1354,7 @@ static int stk_camera_probe(struct usb_interface *interface, const struct usb_device_id *id) { int i; - int err; + int err = 0; struct stk_camera *dev = NULL; struct usb_device *udev = interface_to_usbdev(interface); @@ -1410,7 +1367,6 @@ static int stk_camera_probe(struct usb_interface *interface, return -ENOMEM; } - kref_init(&dev->kref); spin_lock_init(&dev->spinlock); init_waitqueue_head(&dev->wait_frame); @@ -1443,8 +1399,8 @@ static int stk_camera_probe(struct usb_interface *interface, } if (!dev->isoc_ep) { STK_ERROR("Could not find isoc-in endpoint"); - kref_put(&dev->kref, stk_camera_cleanup); - return -ENODEV; + err = -ENODEV; + goto error; } dev->vsettings.brightness = 0x7fff; dev->vsettings.palette = V4L2_PIX_FMT_RGB565; @@ -1458,14 +1414,17 @@ static int stk_camera_probe(struct usb_interface *interface, err = stk_register_video_device(dev); if (err) { - kref_put(&dev->kref, stk_camera_cleanup); - return err; + goto error; } stk_create_sysfs_files(&dev->vdev); usb_autopm_enable(dev->interface); return 0; + +error: + kfree(dev); + return err; } static void stk_camera_disconnect(struct usb_interface *interface) @@ -1478,7 +1437,10 @@ static void stk_camera_disconnect(struct usb_interface *interface) wake_up_interruptible(&dev->wait_frame); stk_remove_sysfs_files(&dev->vdev); - kref_put(&dev->kref, stk_camera_cleanup); + STK_INFO("Syntek USB2.0 Camera release resources" + "video device /dev/video%d\n", dev->vdev.minor); + + video_unregister_device(&dev->vdev); } #ifdef CONFIG_PM diff --git a/linux/drivers/media/video/stk-webcam.h b/linux/drivers/media/video/stk-webcam.h index df4dfefc5..084a85bdd 100644 --- a/linux/drivers/media/video/stk-webcam.h +++ b/linux/drivers/media/video/stk-webcam.h @@ -99,7 +99,6 @@ struct stk_camera { u8 isoc_ep; - struct kref kref; /* Not sure if this is right */ atomic_t urbs_used; @@ -121,7 +120,6 @@ struct stk_camera { unsigned sequence; }; -#define to_stk_camera(d) container_of(d, struct stk_camera, kref) #define vdev_to_camera(d) container_of(d, struct stk_camera, vdev) void stk_camera_delete(struct kref *); -- cgit v1.2.3 From 3f7c87cad1eaa1b5274ee30258cd5862c3adfb98 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 22 Sep 2008 16:14:59 +0000 Subject: uvcvideo: Declare missing camera and processing unit controls. From: Laurent Pinchart This declares all missing UVC camera and processing unit controls. V4L2 mappings are not supported yet for those controls. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/uvc/uvc_ctrl.c | 164 +++++++++++++++++++++++++++---- 1 file changed, 145 insertions(+), 19 deletions(-) (limited to 'linux') diff --git a/linux/drivers/media/video/uvc/uvc_ctrl.c b/linux/drivers/media/video/uvc/uvc_ctrl.c index 6ef3e5297..6da37cdda 100644 --- a/linux/drivers/media/video/uvc/uvc_ctrl.c +++ b/linux/drivers/media/video/uvc/uvc_ctrl.c @@ -81,6 +81,22 @@ static struct uvc_control_info uvc_ctrls[] = { .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE | UVC_CONTROL_RESTORE, }, + { + .entity = UVC_GUID_UVC_PROCESSING, + .selector = PU_WHITE_BALANCE_TEMPERATURE_CONTROL, + .index = 6, + .size = 2, + .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE + | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE, + }, + { + .entity = UVC_GUID_UVC_PROCESSING, + .selector = PU_WHITE_BALANCE_COMPONENT_CONTROL, + .index = 7, + .size = 4, + .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE + | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE, + }, { .entity = UVC_GUID_UVC_PROCESSING, .selector = PU_BACKLIGHT_COMPENSATION_CONTROL, @@ -113,6 +129,60 @@ static struct uvc_control_info uvc_ctrls[] = { .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE, }, + { + .entity = UVC_GUID_UVC_PROCESSING, + .selector = PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL, + .index = 12, + .size = 1, + .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR + | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE, + }, + { + .entity = UVC_GUID_UVC_PROCESSING, + .selector = PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL, + .index = 13, + .size = 1, + .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR + | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE, + }, + { + .entity = UVC_GUID_UVC_PROCESSING, + .selector = PU_DIGITAL_MULTIPLIER_CONTROL, + .index = 14, + .size = 2, + .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE + | UVC_CONTROL_RESTORE, + }, + { + .entity = UVC_GUID_UVC_PROCESSING, + .selector = PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL, + .index = 15, + .size = 2, + .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE + | UVC_CONTROL_RESTORE, + }, + { + .entity = UVC_GUID_UVC_PROCESSING, + .selector = PU_ANALOG_VIDEO_STANDARD_CONTROL, + .index = 16, + .size = 1, + .flags = UVC_CONTROL_GET_CUR, + }, + { + .entity = UVC_GUID_UVC_PROCESSING, + .selector = PU_ANALOG_LOCK_STATUS_CONTROL, + .index = 17, + .size = 1, + .flags = UVC_CONTROL_GET_CUR, + }, + { + .entity = UVC_GUID_UVC_CAMERA, + .selector = CT_SCANNING_MODE_CONTROL, + .index = 0, + .size = 1, + .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR + | UVC_CONTROL_RESTORE, + }, { .entity = UVC_GUID_UVC_CAMERA, .selector = CT_AE_MODE_CONTROL, @@ -138,6 +208,14 @@ static struct uvc_control_info uvc_ctrls[] = { .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE | UVC_CONTROL_RESTORE, }, + { + .entity = UVC_GUID_UVC_CAMERA, + .selector = CT_EXPOSURE_TIME_RELATIVE_CONTROL, + .index = 4, + .size = 1, + .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR + | UVC_CONTROL_RESTORE, + }, { .entity = UVC_GUID_UVC_CAMERA, .selector = CT_FOCUS_ABSOLUTE_CONTROL, @@ -148,42 +226,90 @@ static struct uvc_control_info uvc_ctrls[] = { }, { .entity = UVC_GUID_UVC_CAMERA, - .selector = CT_FOCUS_AUTO_CONTROL, - .index = 17, - .size = 1, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR - | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE, + .selector = CT_FOCUS_RELATIVE_CONTROL, + .index = 6, + .size = 2, + .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE + | UVC_CONTROL_AUTO_UPDATE, }, { - .entity = UVC_GUID_UVC_PROCESSING, - .selector = PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL, - .index = 12, + .entity = UVC_GUID_UVC_CAMERA, + .selector = CT_IRIS_ABSOLUTE_CONTROL, + .index = 7, + .size = 2, + .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE + | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE, + }, + { + .entity = UVC_GUID_UVC_CAMERA, + .selector = CT_IRIS_RELATIVE_CONTROL, + .index = 8, .size = 1, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR - | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE, + | UVC_CONTROL_AUTO_UPDATE, }, { - .entity = UVC_GUID_UVC_PROCESSING, - .selector = PU_WHITE_BALANCE_TEMPERATURE_CONTROL, - .index = 6, + .entity = UVC_GUID_UVC_CAMERA, + .selector = CT_ZOOM_ABSOLUTE_CONTROL, + .index = 9, .size = 2, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE, }, { - .entity = UVC_GUID_UVC_PROCESSING, - .selector = PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL, + .entity = UVC_GUID_UVC_CAMERA, + .selector = CT_ZOOM_RELATIVE_CONTROL, + .index = 10, + .size = 3, + .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE + | UVC_CONTROL_AUTO_UPDATE, + }, + { + .entity = UVC_GUID_UVC_CAMERA, + .selector = CT_PANTILT_ABSOLUTE_CONTROL, + .index = 11, + .size = 8, + .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE + | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE, + }, + { + .entity = UVC_GUID_UVC_CAMERA, + .selector = CT_PANTILT_RELATIVE_CONTROL, + .index = 12, + .size = 4, + .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE + | UVC_CONTROL_AUTO_UPDATE, + }, + { + .entity = UVC_GUID_UVC_CAMERA, + .selector = CT_ROLL_ABSOLUTE_CONTROL, .index = 13, + .size = 2, + .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE + | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE, + }, + { + .entity = UVC_GUID_UVC_CAMERA, + .selector = CT_ROLL_RELATIVE_CONTROL, + .index = 14, + .size = 2, + .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE + | UVC_CONTROL_AUTO_UPDATE, + }, + { + .entity = UVC_GUID_UVC_CAMERA, + .selector = CT_FOCUS_AUTO_CONTROL, + .index = 17, .size = 1, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE, }, { - .entity = UVC_GUID_UVC_PROCESSING, - .selector = PU_WHITE_BALANCE_COMPONENT_CONTROL, - .index = 7, - .size = 4, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE + .entity = UVC_GUID_UVC_CAMERA, + .selector = CT_PRIVACY_CONTROL, + .index = 18, + .size = 1, + .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE, }, }; -- cgit v1.2.3 From d6a5eef9322793ef300fea2bf45b7bdb504e4dbd Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 25 Sep 2008 11:21:11 +0200 Subject: Add Pinnacle 801e dependencies to KConfig From: Devin Heitmueller Support for the Pinnacle PCTV HD Pro 801e creates a dib0700 dependency on the xc5000 tuner and s5h1411 demodulator drivers. Update KConfig accordingly. Priority: normal Signed-off-by: Devin Heitmueller Signed-off-by: Patrick Boettcher --- linux/drivers/media/dvb/dvb-usb/Kconfig | 2 ++ 1 file changed, 2 insertions(+) (limited to 'linux') diff --git a/linux/drivers/media/dvb/dvb-usb/Kconfig b/linux/drivers/media/dvb/dvb-usb/Kconfig index 1d9e98cee..33d63643f 100644 --- a/linux/drivers/media/dvb/dvb-usb/Kconfig +++ b/linux/drivers/media/dvb/dvb-usb/Kconfig @@ -72,9 +72,11 @@ config DVB_USB_DIB0700 select DVB_DIB7000P select DVB_DIB7000M select DVB_DIB3000MC + select DVB_S5H1411 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_MT2266 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE select DVB_TUNER_DIB0070 help Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The -- cgit v1.2.3 From c99f53fab2622236cdf79ce4433361aaf267745a Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 25 Sep 2008 11:22:23 +0200 Subject: Add support for Non-Pro version of Pinnacle PCTV HD USB Stick From: Devin Heitmueller Add USB ID for Pinnacle PCTV HD USB Stick. According to the USB trace and photos, the only difference is the removal of the port for the analog S-video/audio input. Thanks to Mike Pringle for providing the USB trace of the device starting up, and testing the support. Priority: normal Signed-off-by: Devin Heitmueller Signed-off-by: Patrick Boettcher --- linux/drivers/media/dvb/dvb-usb/dib0700_devices.c | 7 ++++++- linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'linux') diff --git a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c index 7d9efd702..7e692b3b0 100644 --- a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -1208,6 +1208,7 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700PH) }, { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3000H) }, /* 40 */{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV801E) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV801E_SE) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -1542,12 +1543,16 @@ struct dvb_usb_device_properties dib0700_devices[] = { }, }, - .num_device_descs = 1, + .num_device_descs = 2, .devices = { { "Pinnacle PCTV HD Pro USB Stick", { &dib0700_usb_id_table[40], NULL }, { NULL }, }, + { "Pinnacle PCTV HD USB Stick", + { &dib0700_usb_id_table[41], NULL }, + { NULL }, + }, }, .rc_interval = DEFAULT_RC_INTERVAL, .rc_key_map = dib0700_rc_keys, diff --git a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 3a5956c51..cc8593ea7 100644 --- a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -158,6 +158,7 @@ #define USB_PID_PINNACLE_PCTV72E 0x0236 #define USB_PID_PINNACLE_PCTV73E 0x0237 #define USB_PID_PINNACLE_PCTV801E 0x023a +#define USB_PID_PINNACLE_PCTV801E_SE 0x023b #define USB_PID_PCTV_200E 0x020e #define USB_PID_PCTV_400E 0x020f #define USB_PID_PCTV_450E 0x0222 -- cgit v1.2.3 From 968c43076f37c9f65df65fe50a1c643a82b1192b Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 25 Sep 2008 11:52:24 +0200 Subject: [PATCH] Add remote control support to Nova-TD (52009) From: Chris Rankin This patch adds remote control support for the Hauppauge WinTV Nova-TD (Diversity) model. (That's the 52009 version.) It also adds the key-codes for the credit-card style remote control that comes with this particular adapter. Priority: normal Signed-off-by: Chris Rankin Signed-off-by: Patrick Boettcher --- linux/drivers/media/dvb/dvb-usb/dib0700_devices.c | 44 ++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) (limited to 'linux') diff --git a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c index 7e692b3b0..565563e68 100644 --- a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -679,6 +679,43 @@ static struct dvb_usb_rc_key dib0700_rc_keys[] = { { 0x01, 0x7d, KEY_VOLUMEDOWN }, { 0x02, 0x42, KEY_CHANNELUP }, { 0x00, 0x7d, KEY_CHANNELDOWN }, + + /* Key codes for Nova-TD "credit card" remote control. */ + { 0x1d, 0x00, KEY_0 }, + { 0x1d, 0x01, KEY_1 }, + { 0x1d, 0x02, KEY_2 }, + { 0x1d, 0x03, KEY_3 }, + { 0x1d, 0x04, KEY_4 }, + { 0x1d, 0x05, KEY_5 }, + { 0x1d, 0x06, KEY_6 }, + { 0x1d, 0x07, KEY_7 }, + { 0x1d, 0x08, KEY_8 }, + { 0x1d, 0x09, KEY_9 }, + { 0x1d, 0x0a, KEY_TEXT }, + { 0x1d, 0x0d, KEY_MENU }, + { 0x1d, 0x0f, KEY_MUTE }, + { 0x1d, 0x10, KEY_VOLUMEUP }, + { 0x1d, 0x11, KEY_VOLUMEDOWN }, + { 0x1d, 0x12, KEY_CHANNEL }, + { 0x1d, 0x14, KEY_UP }, + { 0x1d, 0x15, KEY_DOWN }, + { 0x1d, 0x16, KEY_LEFT }, + { 0x1d, 0x17, KEY_RIGHT }, + { 0x1d, 0x1c, KEY_TV }, + { 0x1d, 0x1e, KEY_NEXT }, + { 0x1d, 0x1f, KEY_BACK }, + { 0x1d, 0x20, KEY_CHANNELUP }, + { 0x1d, 0x21, KEY_CHANNELDOWN }, + { 0x1d, 0x24, KEY_LAST }, + { 0x1d, 0x25, KEY_OK }, + { 0x1d, 0x30, KEY_PAUSE }, + { 0x1d, 0x32, KEY_REWIND }, + { 0x1d, 0x34, KEY_FASTFORWARD }, + { 0x1d, 0x35, KEY_PLAY }, + { 0x1d, 0x36, KEY_STOP }, + { 0x1d, 0x37, KEY_RECORD }, + { 0x1d, 0x3b, KEY_GOTO }, + { 0x1d, 0x3d, KEY_POWER }, }; /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */ @@ -1383,7 +1420,12 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[31], NULL }, { NULL }, } - } + }, + + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_key_map = dib0700_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), + .rc_query = dib0700_rc_query }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, .num_adapters = 1, -- cgit v1.2.3 From b21333aab210fe38e84f8311a9d921e696bf8f9b Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 25 Sep 2008 08:47:07 -0400 Subject: dib0700: use dvb_frontend->callback for xc5000 gpio reset From: Michael Krufky The tuner_callback function pointer from struct xc5000_config has been removed. Use dvb_frontend->callback instead. Also, mark function dib0700_xc5000_tuner_callback as static int. Priority: normal Signed-off-by: Michael Krufky --- linux/drivers/media/dvb/dvb-usb/dib0700_devices.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'linux') diff --git a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c index 8b74e13a6..9891ca092 100644 --- a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -1176,7 +1176,8 @@ static int s5h1411_frontend_attach(struct dvb_usb_adapter *adap) return adap->fe == NULL ? -ENODEV : 0; } -int dib0700_xc5000_tuner_callback(void *priv, int command, int arg) +static int dib0700_xc5000_tuner_callback(void *priv, int component, + int command, int arg) { struct dvb_usb_adapter *adap = priv; @@ -1192,14 +1193,16 @@ int dib0700_xc5000_tuner_callback(void *priv, int command, int arg) static struct xc5000_config s5h1411_xc5000_tunerconfig = { .i2c_address = 0x64, .if_khz = 5380, - .tuner_callback = dib0700_xc5000_tuner_callback }; static int xc5000_tuner_attach(struct dvb_usb_adapter *adap) { return dvb_attach(xc5000_attach, adap->fe, &adap->dev->i2c_adap, - &s5h1411_xc5000_tunerconfig, adap) + &s5h1411_xc5000_tunerconfig) == NULL ? -ENODEV : 0; + + /* FIXME: generalize & move to common area */ + adap->fe->callback = dib0700_xc5000_tuner_callback; } /* DVB-USB and USB stuff follows */ -- cgit v1.2.3 From cfd49e1a2492fe52c02e75c2e2a82eceb3385ff8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 27 Sep 2008 23:54:02 +0000 Subject: uvcvideo: Fix control cache access when setting composite auto-update controls From: Laurent Pinchart Auto-update controls are never marked is loaded to prevent uvc_get_ctrl from loading the control value from the cache. When setting a composite (mapped to several V4L2 controls) auto-update UVC control, the driver updates the control cache value before processing each V4L2 control, overwriting the previously set V4L2 control. This fixes the problem by marking all controls as loaded in uvc_set_ctrl regardless of their type and resetting the loaded flag in uvc_commit_ctrl for auto-update controls. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/uvc/uvc_ctrl.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'linux') diff --git a/linux/drivers/media/video/uvc/uvc_ctrl.c b/linux/drivers/media/video/uvc/uvc_ctrl.c index 6da37cdda..b66c95ffd 100644 --- a/linux/drivers/media/video/uvc/uvc_ctrl.c +++ b/linux/drivers/media/video/uvc/uvc_ctrl.c @@ -837,7 +837,17 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev, for (i = 0; i < entity->ncontrols; ++i) { ctrl = &entity->controls[i]; - if (ctrl->info == NULL || !ctrl->dirty) + if (ctrl->info == NULL) + continue; + + /* Reset the loaded flag for auto-update controls that were + * marked as loaded in uvc_ctrl_get/uvc_ctrl_set to prevent + * uvc_ctrl_get from using the cached value. + */ + if (ctrl->info->flags & UVC_CONTROL_AUTO_UPDATE) + ctrl->loaded = 0; + + if (!ctrl->dirty) continue; if (!rollback) @@ -853,9 +863,6 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev, uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP), ctrl->info->size); - if ((ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0) - ctrl->loaded = 0; - ctrl->dirty = 0; if (ret < 0) @@ -913,8 +920,7 @@ int uvc_ctrl_get(struct uvc_video_device *video, if (ret < 0) return ret; - if ((ctrl->info->flags & UVC_CONTROL_AUTO_UPDATE) == 0) - ctrl->loaded = 1; + ctrl->loaded = 1; } xctrl->value = uvc_get_le_value( @@ -965,8 +971,7 @@ int uvc_ctrl_set(struct uvc_video_device *video, return ret; } - if ((ctrl->info->flags & UVC_CONTROL_AUTO_UPDATE) == 0) - ctrl->loaded = 1; + ctrl->loaded = 1; } if (!ctrl->dirty) { -- cgit v1.2.3 From 64c3e9edd4ec8939176b23508522c913333d4464 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 23 Sep 2008 00:06:48 +0000 Subject: fix buffer overflow in uvc-video From: Ralph Loader There is a buffer overflow in drivers/media/video/uvc/uvc_ctrl.c: INFO: 0xf2c5ce08-0xf2c5ce0b. First byte 0xa1 instead of 0xcc INFO: Allocated in uvc_query_v4l2_ctrl+0x3c/0x239 [uvcvideo] age=13 cpu=1 pid=4975 ... A fixed size 8-byte buffer is allocated, and a variable size field is read into it; there is no particular bound on the size of the field (it is dependent on hardware and configuration) and it can overflow [also verified by inserting printk's.] The patch attempts to size the buffer to the correctly. Signed-off-by: Andrew Morton Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/uvc/uvc_ctrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux') diff --git a/linux/drivers/media/video/uvc/uvc_ctrl.c b/linux/drivers/media/video/uvc/uvc_ctrl.c index b66c95ffd..f16aafe9c 100644 --- a/linux/drivers/media/video/uvc/uvc_ctrl.c +++ b/linux/drivers/media/video/uvc/uvc_ctrl.c @@ -718,7 +718,7 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video, if (ctrl == NULL) return -EINVAL; - data = kmalloc(8, GFP_KERNEL); + data = kmalloc(ctrl->info->size, GFP_KERNEL); if (data == NULL) return -ENOMEM; -- cgit v1.2.3 From c20af2106a755d11b45e19ade56a98fa8bf6ca29 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 26 Sep 2008 11:29:03 +0200 Subject: implement proper locking in the dvb ca en50221 driver From: Matthias Dahl Concurrent access to a single DVB CA 50221 interface slot is generally discouraged. The underlying drivers (budget-av, budget-ci) do not implement proper locking and thus two transactions could (and do) interfere with on another. This fixes the following problems seen by others and myself: - sudden i/o errors when writing to the ci device which usually would result in an undefined state of the hw and require a software restart - errors about the CAM trying to send a buffer larger than the agreed size usually also resulting in an undefined state of the hw Due the to design of the DVB CA 50221 driver, implementing the locks in the underlying drivers would not be enough and still leave some race conditions, even though they were harder to trigger. Signed-off-by: Matthias Dahl Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.c | 24 ++++++++++++++++++++--- linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.h | 6 ++++-- 2 files changed, 25 insertions(+), 5 deletions(-) (limited to 'linux') diff --git a/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.c index f6016feab..19965a055 100644 --- a/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ b/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.c @@ -94,6 +94,9 @@ struct dvb_ca_slot { /* current state of the CAM */ int slot_state; + /* mutex used for serializing access to one CI slot */ + struct mutex slot_lock; + /* Number of CAMCHANGES that have occurred since last processing */ atomic_t camchange_count; @@ -712,14 +715,20 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * b dprintk("%s\n", __func__); - // sanity check + /* sanity check */ if (bytes_write > ca->slot_info[slot].link_buf_size) return -EINVAL; - /* check if interface is actually waiting for us to read from it, or if a read is in progress */ + /* it is possible we are dealing with a single buffer implementation, + thus if there is data available for read or if there is even a read + already in progress, we do nothing but awake the kernel thread to + process the data if necessary. */ if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) goto exitnowrite; if (status & (STATUSREG_DA | STATUSREG_RE)) { + if (status & STATUSREG_DA) + dvb_ca_en50221_thread_wakeup(ca); + status = -EAGAIN; goto exitnowrite; } @@ -988,6 +997,8 @@ static int dvb_ca_en50221_thread(void *data) /* go through all the slots processing them */ for (slot = 0; slot < ca->slot_count; slot++) { + mutex_lock(&ca->slot_info[slot].slot_lock); + // check the cam status + deal with CAMCHANGEs while (dvb_ca_en50221_check_camstatus(ca, slot)) { /* clear down an old CI slot if necessary */ @@ -1123,7 +1134,7 @@ static int dvb_ca_en50221_thread(void *data) case DVB_CA_SLOTSTATE_RUNNING: if (!ca->open) - continue; + break; // poll slots for data pktcount = 0; @@ -1147,6 +1158,8 @@ static int dvb_ca_en50221_thread(void *data) } break; } + + mutex_unlock(&ca->slot_info[slot].slot_lock); } } @@ -1182,6 +1195,7 @@ static int dvb_ca_en50221_io_do_ioctl(struct inode *inode, struct file *file, switch (cmd) { case CA_RESET: for (slot = 0; slot < ca->slot_count; slot++) { + mutex_lock(&ca->slot_info[slot].slot_lock); if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE) { dvb_ca_en50221_slot_shutdown(ca, slot); if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE) @@ -1189,6 +1203,7 @@ static int dvb_ca_en50221_io_do_ioctl(struct inode *inode, struct file *file, slot, DVB_CA_EN50221_CAMCHANGE_INSERTED); } + mutex_unlock(&ca->slot_info[slot].slot_lock); } ca->next_read_slot = 0; dvb_ca_en50221_thread_wakeup(ca); @@ -1309,7 +1324,9 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file, goto exit; } + mutex_lock(&ca->slot_info[slot].slot_lock); status = dvb_ca_en50221_write_data(ca, slot, fragbuf, fraglen + 2); + mutex_unlock(&ca->slot_info[slot].slot_lock); if (status == (fraglen + 2)) { written = 1; break; @@ -1665,6 +1682,7 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, ca->slot_info[i].slot_state = DVB_CA_SLOTSTATE_NONE; atomic_set(&ca->slot_info[i].camchange_count, 0); ca->slot_info[i].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED; + mutex_init(&ca->slot_info[i].slot_lock); } if (signal_pending(current)) { diff --git a/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.h b/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.h index 8467e63dd..7df2e1411 100644 --- a/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.h +++ b/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.h @@ -45,8 +45,10 @@ struct dvb_ca_en50221 { /* the module owning this structure */ struct module* owner; - /* NOTE: the read_*, write_* and poll_slot_status functions must use locks as - * they may be called from several threads at once */ + /* NOTE: the read_*, write_* and poll_slot_status functions will be + * called for different slots concurrently and need to use locks where + * and if appropriate. There will be no concurrent access to one slot. + */ /* functions for accessing attribute memory on the CAM */ int (*read_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address); -- cgit v1.2.3 From ac5d49924a0ab6a492457817a7a08d952961ab67 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Sun, 28 Sep 2008 20:46:02 -0400 Subject: cx18: Add default behavior of checking and retrying PCI MMIO accesses From: Andy Walls cx18: Add default behavior of checking and retrying PCI MMIO accesses. The concept of checking and retrying PCI MMIO accesses for better reliability in older motherboards was suggested by Steve Toth . This change implements MMIO retries and the retry_mmio module parameter that is enabled by default. Limited experiments have shown this is more reliable than the mmio_ndelay parameter. mmio_ndelay has insignificant effect with retries enabled. Priority: high Signed-off-by: Andy Walls --- linux/drivers/media/video/cx18/cx18-av-core.c | 11 + linux/drivers/media/video/cx18/cx18-av-core.h | 2 + linux/drivers/media/video/cx18/cx18-av-firmware.c | 18 +- linux/drivers/media/video/cx18/cx18-driver.c | 7 + linux/drivers/media/video/cx18/cx18-driver.h | 11 + linux/drivers/media/video/cx18/cx18-io.c | 135 ++++++++++- linux/drivers/media/video/cx18/cx18-io.h | 278 ++++++++++++++++++++-- linux/drivers/media/video/cx18/cx18-ioctl.c | 1 + 8 files changed, 427 insertions(+), 36 deletions(-) (limited to 'linux') diff --git a/linux/drivers/media/video/cx18/cx18-av-core.c b/linux/drivers/media/video/cx18/cx18-av-core.c index d8626e354..73f5141a4 100644 --- a/linux/drivers/media/video/cx18/cx18-av-core.c +++ b/linux/drivers/media/video/cx18/cx18-av-core.c @@ -42,6 +42,12 @@ int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value) return 0; } +int cx18_av_write4_noretry(struct cx18 *cx, u16 addr, u32 value) +{ + cx18_write_reg_noretry(cx, value, 0xc40000 + addr); + return 0; +} + u8 cx18_av_read(struct cx18 *cx, u16 addr) { u32 x = cx18_read_reg(cx, 0xc40000 + (addr & ~3)); @@ -55,6 +61,11 @@ u32 cx18_av_read4(struct cx18 *cx, u16 addr) return cx18_read_reg(cx, 0xc40000 + addr); } +u32 cx18_av_read4_noretry(struct cx18 *cx, u16 addr) +{ + return cx18_read_reg_noretry(cx, 0xc40000 + addr); +} + int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned and_mask, u8 or_value) { diff --git a/linux/drivers/media/video/cx18/cx18-av-core.h b/linux/drivers/media/video/cx18/cx18-av-core.h index eb61fa1e0..b67d8df20 100644 --- a/linux/drivers/media/video/cx18/cx18-av-core.h +++ b/linux/drivers/media/video/cx18/cx18-av-core.h @@ -301,8 +301,10 @@ struct cx18_av_state { /* cx18_av-core.c */ int cx18_av_write(struct cx18 *cx, u16 addr, u8 value); int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value); +int cx18_av_write4_noretry(struct cx18 *cx, u16 addr, u32 value); u8 cx18_av_read(struct cx18 *cx, u16 addr); u32 cx18_av_read4(struct cx18 *cx, u16 addr); +u32 cx18_av_read4_noretry(struct cx18 *cx, u16 addr); int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned mask, u8 value); int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 mask, u32 value); int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg); diff --git a/linux/drivers/media/video/cx18/cx18-av-firmware.c b/linux/drivers/media/video/cx18/cx18-av-firmware.c index 0488b6297..522a035b2 100644 --- a/linux/drivers/media/video/cx18/cx18-av-firmware.c +++ b/linux/drivers/media/video/cx18/cx18-av-firmware.c @@ -50,7 +50,7 @@ int cx18_av_loadfw(struct cx18 *cx) cx18_av_write4(cx, 0x8100, 0x00010000); /* Put the 8051 in reset and enable firmware upload */ - cx18_av_write4(cx, CXADEC_DL_CTL, 0x0F000000); + cx18_av_write4_noretry(cx, CXADEC_DL_CTL, 0x0F000000); ptr = fw->data; size = fw->size; @@ -59,22 +59,28 @@ int cx18_av_loadfw(struct cx18 *cx) u32 dl_control = 0x0F000000 | i | ((u32)ptr[i] << 16); u32 value = 0; int retries2; + int unrec_err = 0; - for (retries2 = 0; retries2 < 5; retries2++) { - cx18_av_write4(cx, CXADEC_DL_CTL, dl_control); + for (retries2 = 0; retries2 < CX18_MAX_MMIO_RETRIES; + retries2++) { + cx18_av_write4_noretry(cx, CXADEC_DL_CTL, + dl_control); udelay(10); - value = cx18_av_read4(cx, CXADEC_DL_CTL); + value = cx18_av_read4_noretry(cx, + CXADEC_DL_CTL); if (value == dl_control) break; /* Check if we can correct the byte by changing the address. We can only write the lower address byte of the address. */ if ((value & 0x3F00) != (dl_control & 0x3F00)) { - retries2 = 5; + unrec_err = 1; break; } } - if (retries2 >= 5) + cx18_log_write_retries(cx, retries2, + cx->reg_mem + 0xc40000 + CXADEC_DL_CTL); + if (unrec_err || retries2 >= CX18_MAX_MMIO_RETRIES) break; } if (i == size) diff --git a/linux/drivers/media/video/cx18/cx18-driver.c b/linux/drivers/media/video/cx18/cx18-driver.c index 4de7b501f..df5531709 100644 --- a/linux/drivers/media/video/cx18/cx18-driver.c +++ b/linux/drivers/media/video/cx18/cx18-driver.c @@ -96,6 +96,7 @@ static int enc_pcm_buffers = CX18_DEFAULT_ENC_PCM_BUFFERS; static int cx18_pci_latency = 1; +int cx18_retry_mmio = 1; int cx18_debug; module_param_array(tuner, int, &tuner_c, 0644); @@ -106,6 +107,7 @@ module_param_string(pal, pal, sizeof(pal), 0644); module_param_string(secam, secam, sizeof(secam), 0644); module_param_string(ntsc, ntsc, sizeof(ntsc), 0644); module_param_named(debug, cx18_debug, int, 0644); +module_param_named(retry_mmio, cx18_retry_mmio, int, 0644); module_param(cx18_pci_latency, int, 0644); module_param(cx18_first_minor, int, 0644); @@ -147,6 +149,9 @@ MODULE_PARM_DESC(debug, MODULE_PARM_DESC(cx18_pci_latency, "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n" "\t\t\tDefault: Yes"); +MODULE_PARM_DESC(retry_mmio, + "Check and retry memory mapped IO accesses\n" + "\t\t\tDefault: 1 [Yes]"); MODULE_PARM_DESC(mmio_ndelay, "Delay (ns) for each CX23418 memory mapped IO access.\n" "\t\t\tTry larger values that are close to a multiple of the\n" @@ -827,6 +832,7 @@ err: if (retval == 0) retval = -ENODEV; CX18_ERR("Error %d on initialization\n", retval); + cx18_log_statistics(cx); kfree(cx18_cards[cx18_cards_active]); cx18_cards[cx18_cards_active] = NULL; @@ -931,6 +937,7 @@ static void cx18_remove(struct pci_dev *pci_dev) pci_disable_device(cx->dev); + cx18_log_statistics(cx); CX18_INFO("Removed %s, card #%d\n", cx->card_name, cx->num); } diff --git a/linux/drivers/media/video/cx18/cx18-driver.h b/linux/drivers/media/video/cx18/cx18-driver.h index 66cb74887..80f5f563d 100644 --- a/linux/drivers/media/video/cx18/cx18-driver.h +++ b/linux/drivers/media/video/cx18/cx18-driver.h @@ -171,6 +171,7 @@ #define CX18_MAX_PGM_INDEX (400) +extern int cx18_retry_mmio; /* enable check & retry of mmio accesses */ extern int cx18_debug; @@ -344,6 +345,13 @@ struct cx18_i2c_algo_callback_data { int bus_index; /* 0 or 1 for the cx23418's 1st or 2nd I2C bus */ }; +#define CX18_MAX_MMIO_RETRIES 10 + +struct cx18_mmio_stats { + atomic_t retried_write[CX18_MAX_MMIO_RETRIES+1]; + atomic_t retried_read[CX18_MAX_MMIO_RETRIES+1]; +}; + /* Struct to hold info about cx18 cards */ struct cx18 { int num; /* board number, -1 during init! */ @@ -433,6 +441,9 @@ struct cx18 { u32 gpio_val; struct mutex gpio_lock; + /* Statistics */ + struct cx18_mmio_stats mmio_stats; + /* v4l2 and User settings */ /* codec settings */ diff --git a/linux/drivers/media/video/cx18/cx18-io.c b/linux/drivers/media/video/cx18/cx18-io.c index 55d1df932..700ab9439 100644 --- a/linux/drivers/media/video/cx18/cx18-io.c +++ b/linux/drivers/media/video/cx18/cx18-io.c @@ -24,6 +24,131 @@ #include "cx18-io.h" #include "cx18-irq.h" +void cx18_log_statistics(struct cx18 *cx) +{ + int i; + + if (!(cx18_debug & CX18_DBGFLG_INFO)) + return; + + for (i = 0; i <= CX18_MAX_MMIO_RETRIES; i++) + CX18_DEBUG_INFO("retried_write[%d] = %d\n", i, + atomic_read(&cx->mmio_stats.retried_write[i])); + for (i = 0; i <= CX18_MAX_MMIO_RETRIES; i++) + CX18_DEBUG_INFO("retried_read[%d] = %d\n", i, + atomic_read(&cx->mmio_stats.retried_read[i])); + return; +} + +void cx18_raw_writel_retry(struct cx18 *cx, u32 val, void __iomem *addr) +{ + int i; + for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) { + cx18_raw_writel_noretry(cx, val, addr); + if (val == cx18_raw_readl_noretry(cx, addr)) + break; + } + cx18_log_write_retries(cx, i, addr); +} + +u32 cx18_raw_readl_retry(struct cx18 *cx, const void __iomem *addr) +{ + int i; + u32 val; + for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) { + val = cx18_raw_readl_noretry(cx, addr); + if (val != 0xffffffff) /* PCI bus read error */ + break; + } + cx18_log_read_retries(cx, i, addr); + return val; +} + +u16 cx18_raw_readw_retry(struct cx18 *cx, const void __iomem *addr) +{ + int i; + u16 val; + for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) { + val = cx18_raw_readw_noretry(cx, addr); + if (val != 0xffff) /* PCI bus read error */ + break; + } + cx18_log_read_retries(cx, i, addr); + return val; +} + +void cx18_writel_retry(struct cx18 *cx, u32 val, void __iomem *addr) +{ + int i; + for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) { + cx18_writel_noretry(cx, val, addr); + if (val == cx18_readl_noretry(cx, addr)) + break; + } + cx18_log_write_retries(cx, i, addr); +} + +void cx18_writew_retry(struct cx18 *cx, u16 val, void __iomem *addr) +{ + int i; + for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) { + cx18_writew_noretry(cx, val, addr); + if (val == cx18_readw_noretry(cx, addr)) + break; + } + cx18_log_write_retries(cx, i, addr); +} + +void cx18_writeb_retry(struct cx18 *cx, u8 val, void __iomem *addr) +{ + int i; + for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) { + cx18_writeb_noretry(cx, val, addr); + if (val == cx18_readb_noretry(cx, addr)) + break; + } + cx18_log_write_retries(cx, i, addr); +} + +u32 cx18_readl_retry(struct cx18 *cx, const void __iomem *addr) +{ + int i; + u32 val; + for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) { + val = cx18_readl_noretry(cx, addr); + if (val != 0xffffffff) /* PCI bus read error */ + break; + } + cx18_log_read_retries(cx, i, addr); + return val; +} + +u16 cx18_readw_retry(struct cx18 *cx, const void __iomem *addr) +{ + int i; + u16 val; + for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) { + val = cx18_readw_noretry(cx, addr); + if (val != 0xffff) /* PCI bus read error */ + break; + } + cx18_log_read_retries(cx, i, addr); + return val; +} + +u8 cx18_readb_retry(struct cx18 *cx, const void __iomem *addr) +{ + int i; + u8 val; + for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) { + val = cx18_readb_noretry(cx, addr); + if (val != 0xff) /* PCI bus read error */ + break; + } + cx18_log_read_retries(cx, i, addr); + return val; +} + void cx18_memcpy_fromio(struct cx18 *cx, void *to, const void __iomem *from, unsigned int len) { @@ -127,13 +252,3 @@ void cx18_setup_page(struct cx18 *cx, u32 addr) val = (val & ~0x1f00) | ((addr >> 17) & 0x1f00); cx18_write_reg(cx, val, 0xD000F8); } - -/* Tries to recover from the CX23418 responding improperly on the PCI bus */ -int cx18_pci_try_recover(struct cx18 *cx) -{ - u16 status; - - pci_read_config_word(cx->dev, PCI_STATUS, &status); - pci_write_config_word(cx->dev, PCI_STATUS, status); - return 0; -} diff --git a/linux/drivers/media/video/cx18/cx18-io.h b/linux/drivers/media/video/cx18/cx18-io.h index 7ab7be253..197d4fbd9 100644 --- a/linux/drivers/media/video/cx18/cx18-io.h +++ b/linux/drivers/media/video/cx18/cx18-io.h @@ -31,102 +31,343 @@ static inline void cx18_io_delay(struct cx18 *cx) ndelay(cx->options.mmio_ndelay); } +/* + * Readback and retry of MMIO access for reliability: + * The concept was suggested by Steve Toth . + * The implmentation is the fault of Andy Walls . + */ + +/* Statistics gathering */ +static inline +void cx18_log_write_retries(struct cx18 *cx, int i, const void *addr) +{ + if (i > CX18_MAX_MMIO_RETRIES) + i = CX18_MAX_MMIO_RETRIES; + atomic_inc(&cx->mmio_stats.retried_write[i]); + return; +} + +static inline +void cx18_log_read_retries(struct cx18 *cx, int i, const void *addr) +{ + if (i > CX18_MAX_MMIO_RETRIES) + i = CX18_MAX_MMIO_RETRIES; + atomic_inc(&cx->mmio_stats.retried_read[i]); + return; +} + +void cx18_log_statistics(struct cx18 *cx); + /* Non byteswapping memory mapped IO */ -static inline void cx18_raw_writel(struct cx18 *cx, u32 val, void __iomem *addr) +static inline +void cx18_raw_writel_noretry(struct cx18 *cx, u32 val, void __iomem *addr) { __raw_writel(val, addr); cx18_io_delay(cx); } -static inline u32 cx18_raw_readl(struct cx18 *cx, const void __iomem *addr) +void cx18_raw_writel_retry(struct cx18 *cx, u32 val, void __iomem *addr); + +static inline void cx18_raw_writel(struct cx18 *cx, u32 val, void __iomem *addr) +{ + if (cx18_retry_mmio) + cx18_raw_writel_retry(cx, val, addr); + else + cx18_raw_writel_noretry(cx, val, addr); +} + + +static inline +u32 cx18_raw_readl_noretry(struct cx18 *cx, const void __iomem *addr) { u32 ret = __raw_readl(addr); cx18_io_delay(cx); return ret; } -static inline u16 cx18_raw_readw(struct cx18 *cx, const void __iomem *addr) +u32 cx18_raw_readl_retry(struct cx18 *cx, const void __iomem *addr); + +static inline u32 cx18_raw_readl(struct cx18 *cx, const void __iomem *addr) +{ + if (cx18_retry_mmio) + return cx18_raw_readl_retry(cx, addr); + + return cx18_raw_readl_noretry(cx, addr); +} + + +static inline +u16 cx18_raw_readw_noretry(struct cx18 *cx, const void __iomem *addr) { u16 ret = __raw_readw(addr); cx18_io_delay(cx); return ret; } +u16 cx18_raw_readw_retry(struct cx18 *cx, const void __iomem *addr); + +static inline u16 cx18_raw_readw(struct cx18 *cx, const void __iomem *addr) +{ + if (cx18_retry_mmio) + return cx18_raw_readw_retry(cx, addr); + + return cx18_raw_readw_noretry(cx, addr); +} + + /* Normal memory mapped IO */ -static inline void cx18_writel(struct cx18 *cx, u32 val, void __iomem *addr) +static inline +void cx18_writel_noretry(struct cx18 *cx, u32 val, void __iomem *addr) { writel(val, addr); cx18_io_delay(cx); } -static inline void cx18_writew(struct cx18 *cx, u16 val, void __iomem *addr) +void cx18_writel_retry(struct cx18 *cx, u32 val, void __iomem *addr); + +static inline void cx18_writel(struct cx18 *cx, u32 val, void __iomem *addr) +{ + if (cx18_retry_mmio) + cx18_writel_retry(cx, val, addr); + else + cx18_writel_noretry(cx, val, addr); +} + + +static inline +void cx18_writew_noretry(struct cx18 *cx, u16 val, void __iomem *addr) { writew(val, addr); cx18_io_delay(cx); } -static inline void cx18_writeb(struct cx18 *cx, u8 val, void __iomem *addr) +void cx18_writew_retry(struct cx18 *cx, u16 val, void __iomem *addr); + +static inline void cx18_writew(struct cx18 *cx, u16 val, void __iomem *addr) +{ + if (cx18_retry_mmio) + cx18_writew_retry(cx, val, addr); + else + cx18_writew_noretry(cx, val, addr); +} + + +static inline +void cx18_writeb_noretry(struct cx18 *cx, u8 val, void __iomem *addr) { writeb(val, addr); cx18_io_delay(cx); } -static inline u32 cx18_readl(struct cx18 *cx, const void __iomem *addr) +void cx18_writeb_retry(struct cx18 *cx, u8 val, void __iomem *addr); + +static inline void cx18_writeb(struct cx18 *cx, u8 val, void __iomem *addr) +{ + if (cx18_retry_mmio) + cx18_writeb_retry(cx, val, addr); + else + cx18_writeb_noretry(cx, val, addr); +} + + +static inline u32 cx18_readl_noretry(struct cx18 *cx, const void __iomem *addr) { u32 ret = readl(addr); cx18_io_delay(cx); return ret; } -static inline u8 cx18_readb(struct cx18 *cx, const void __iomem *addr) +u32 cx18_readl_retry(struct cx18 *cx, const void __iomem *addr); + +static inline u32 cx18_readl(struct cx18 *cx, const void __iomem *addr) +{ + if (cx18_retry_mmio) + return cx18_readl_retry(cx, addr); + + return cx18_readl_noretry(cx, addr); +} + + +static inline u16 cx18_readw_noretry(struct cx18 *cx, const void __iomem *addr) +{ + u16 ret = readw(addr); + cx18_io_delay(cx); + return ret; +} + +u16 cx18_readw_retry(struct cx18 *cx, const void __iomem *addr); + +static inline u16 cx18_readw(struct cx18 *cx, const void __iomem *addr) +{ + if (cx18_retry_mmio) + return cx18_readw_retry(cx, addr); + + return cx18_readw_noretry(cx, addr); +} + + +static inline u8 cx18_readb_noretry(struct cx18 *cx, const void __iomem *addr) { u8 ret = readb(addr); cx18_io_delay(cx); return ret; } +u8 cx18_readb_retry(struct cx18 *cx, const void __iomem *addr); + +static inline u8 cx18_readb(struct cx18 *cx, const void __iomem *addr) +{ + if (cx18_retry_mmio) + return cx18_readb_retry(cx, addr); + + return cx18_readb_noretry(cx, addr); +} + + +static inline +u32 cx18_write_sync_noretry(struct cx18 *cx, u32 val, void __iomem *addr) +{ + cx18_writel_noretry(cx, val, addr); + return cx18_readl_noretry(cx, addr); +} + +static inline +u32 cx18_write_sync_retry(struct cx18 *cx, u32 val, void __iomem *addr) +{ + cx18_writel_retry(cx, val, addr); + return cx18_readl_retry(cx, addr); +} + static inline u32 cx18_write_sync(struct cx18 *cx, u32 val, void __iomem *addr) { - cx18_writel(cx, val, addr); - return cx18_readl(cx, addr); + if (cx18_retry_mmio) + return cx18_write_sync_retry(cx, val, addr); + + return cx18_write_sync_noretry(cx, val, addr); } + void cx18_memcpy_fromio(struct cx18 *cx, void *to, const void __iomem *from, unsigned int len); void cx18_memset_io(struct cx18 *cx, void __iomem *addr, int val, size_t count); + /* Access "register" region of CX23418 memory mapped I/O */ +static inline void cx18_write_reg_noretry(struct cx18 *cx, u32 val, u32 reg) +{ + cx18_writel_noretry(cx, val, cx->reg_mem + reg); +} + +static inline void cx18_write_reg_retry(struct cx18 *cx, u32 val, u32 reg) +{ + cx18_writel_retry(cx, val, cx->reg_mem + reg); +} + static inline void cx18_write_reg(struct cx18 *cx, u32 val, u32 reg) { - cx18_writel(cx, val, cx->reg_mem + reg); + if (cx18_retry_mmio) + cx18_write_reg_retry(cx, val, reg); + else + cx18_write_reg_noretry(cx, val, reg); +} + + +static inline u32 cx18_read_reg_noretry(struct cx18 *cx, u32 reg) +{ + return cx18_readl_noretry(cx, cx->reg_mem + reg); +} + +static inline u32 cx18_read_reg_retry(struct cx18 *cx, u32 reg) +{ + return cx18_readl_retry(cx, cx->reg_mem + reg); } static inline u32 cx18_read_reg(struct cx18 *cx, u32 reg) { - return cx18_readl(cx, cx->reg_mem + reg); + if (cx18_retry_mmio) + return cx18_read_reg_retry(cx, reg); + + return cx18_read_reg_noretry(cx, reg); +} + + +static inline u32 cx18_write_reg_sync_noretry(struct cx18 *cx, u32 val, u32 reg) +{ + return cx18_write_sync_noretry(cx, val, cx->reg_mem + reg); +} + +static inline u32 cx18_write_reg_sync_retry(struct cx18 *cx, u32 val, u32 reg) +{ + return cx18_write_sync_retry(cx, val, cx->reg_mem + reg); } static inline u32 cx18_write_reg_sync(struct cx18 *cx, u32 val, u32 reg) { - return cx18_write_sync(cx, val, cx->reg_mem + reg); + if (cx18_retry_mmio) + return cx18_write_reg_sync_retry(cx, val, reg); + + return cx18_write_reg_sync_noretry(cx, val, reg); } + /* Access "encoder memory" region of CX23418 memory mapped I/O */ +static inline void cx18_write_enc_noretry(struct cx18 *cx, u32 val, u32 addr) +{ + cx18_writel_noretry(cx, val, cx->enc_mem + addr); +} + +static inline void cx18_write_enc_retry(struct cx18 *cx, u32 val, u32 addr) +{ + cx18_writel_retry(cx, val, cx->enc_mem + addr); +} + static inline void cx18_write_enc(struct cx18 *cx, u32 val, u32 addr) { - cx18_writel(cx, val, cx->enc_mem + addr); + if (cx18_retry_mmio) + cx18_write_enc_retry(cx, val, addr); + else + cx18_write_enc_noretry(cx, val, addr); +} + + +static inline u32 cx18_read_enc_noretry(struct cx18 *cx, u32 addr) +{ + return cx18_readl_noretry(cx, cx->enc_mem + addr); +} + +static inline u32 cx18_read_enc_retry(struct cx18 *cx, u32 addr) +{ + return cx18_readl_retry(cx, cx->enc_mem + addr); } static inline u32 cx18_read_enc(struct cx18 *cx, u32 addr) { - return cx18_readl(cx, cx->enc_mem + addr); + if (cx18_retry_mmio) + return cx18_read_enc_retry(cx, addr); + + return cx18_read_enc_noretry(cx, addr); +} + +static inline +u32 cx18_write_enc_sync_noretry(struct cx18 *cx, u32 val, u32 addr) +{ + return cx18_write_sync_noretry(cx, val, cx->enc_mem + addr); } -static inline u32 cx18_write_enc_sync(struct cx18 *cx, u32 val, u32 addr) +static inline +u32 cx18_write_enc_sync_retry(struct cx18 *cx, u32 val, u32 addr) { - return cx18_write_sync(cx, val, cx->enc_mem + addr); + return cx18_write_sync_retry(cx, val, cx->enc_mem + addr); } +static inline +u32 cx18_write_enc_sync(struct cx18 *cx, u32 val, u32 addr) +{ + if (cx18_retry_mmio) + return cx18_write_enc_sync_retry(cx, val, addr); + + return cx18_write_enc_sync_noretry(cx, val, addr); +} void cx18_sw1_irq_enable(struct cx18 *cx, u32 val); void cx18_sw1_irq_disable(struct cx18 *cx, u32 val); @@ -134,7 +375,4 @@ void cx18_sw2_irq_enable(struct cx18 *cx, u32 val); void cx18_sw2_irq_disable(struct cx18 *cx, u32 val); void cx18_setup_page(struct cx18 *cx, u32 addr); -/* Tries to recover from the CX23418 responding improperly on the PCI bus */ -int cx18_pci_try_recover(struct cx18 *cx); - #endif /* CX18_IO_H */ diff --git a/linux/drivers/media/video/cx18/cx18-ioctl.c b/linux/drivers/media/video/cx18/cx18-ioctl.c index b909c78d3..77fd0249e 100644 --- a/linux/drivers/media/video/cx18/cx18-ioctl.c +++ b/linux/drivers/media/video/cx18/cx18-ioctl.c @@ -857,6 +857,7 @@ static int cx18_log_status(struct file *file, void *fh) CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n", (long long)cx->mpg_data_received, (long long)cx->vbi_data_inserted); + cx18_log_statistics(cx); CX18_INFO("================== END STATUS CARD #%d ==================\n", cx->num); return 0; } -- cgit v1.2.3 From ddfa2bbea3cb3a9f980e360f49a80643998cd4e0 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Fri, 3 Oct 2008 12:49:05 -0400 Subject: cx18: Up the version to 1.0.1 From: Andy Walls cx18: Up the version to 1.0.1. This will make it easy to tell if retries of MMIO access are implemented or not in trouble reports. First course of action for I2C and other initialization problem reports will be to have user upgrade to v1.0.1 of driver. Priority: high Signed-off-by: Andy Walls --- linux/drivers/media/video/cx18/cx18-version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux') diff --git a/linux/drivers/media/video/cx18/cx18-version.h b/linux/drivers/media/video/cx18/cx18-version.h index d5c7a6f96..9f6be2d45 100644 --- a/linux/drivers/media/video/cx18/cx18-version.h +++ b/linux/drivers/media/video/cx18/cx18-version.h @@ -25,7 +25,7 @@ #define CX18_DRIVER_NAME "cx18" #define CX18_DRIVER_VERSION_MAJOR 1 #define CX18_DRIVER_VERSION_MINOR 0 -#define CX18_DRIVER_VERSION_PATCHLEVEL 0 +#define CX18_DRIVER_VERSION_PATCHLEVEL 1 #define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL) #define CX18_DRIVER_VERSION KERNEL_VERSION(CX18_DRIVER_VERSION_MAJOR, \ -- cgit v1.2.3