diff options
Diffstat (limited to 'drivers/media/usb/dvb-usb-v2/rtl28xxu.c')
| -rw-r--r-- | drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 209 |
1 files changed, 130 insertions, 79 deletions
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index e16ca07acf1d..487c6ab784ab 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c @@ -1,23 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Realtek RTL28xxU DVB USB driver * * Copyright (C) 2009 Antti Palosaari <crope@iki.fi> * Copyright (C) 2011 Antti Palosaari <crope@iki.fi> * Copyright (C) 2012 Thomas Mair <thomas.mair86@googlemail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "rtl28xxu.h" @@ -50,7 +37,16 @@ static int rtl28xxu_ctrl_msg(struct dvb_usb_device *d, struct rtl28xxu_req *req) } else { /* read */ requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); - pipe = usb_rcvctrlpipe(d->udev, 0); + + /* + * Zero-length transfers must use usb_sndctrlpipe() and + * rtl28xxu_identify_state() uses a zero-length i2c read + * command to determine the chip type. + */ + if (req->size) + pipe = usb_rcvctrlpipe(d->udev, 0); + else + pipe = usb_sndctrlpipe(d->udev, 0); } ret = usb_control_msg(d->udev, pipe, 0, requesttype, req->value, @@ -180,6 +176,10 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], ret = -EOPNOTSUPP; goto err_mutex_unlock; } else if (msg[0].addr == 0x10) { + if (msg[0].len < 1 || msg[1].len < 1) { + ret = -EOPNOTSUPP; + goto err_mutex_unlock; + } /* method 1 - integrated demod */ if (msg[0].buf[0] == 0x00) { /* return demod page from driver cache */ @@ -193,6 +193,10 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], ret = rtl28xxu_ctrl_msg(d, &req); } } else if (msg[0].len < 2) { + if (msg[0].len < 1) { + ret = -EOPNOTSUPP; + goto err_mutex_unlock; + } /* method 2 - old I2C */ req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1); req.index = CMD_I2C_RD; @@ -221,8 +225,16 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], ret = -EOPNOTSUPP; goto err_mutex_unlock; } else if (msg[0].addr == 0x10) { + if (msg[0].len < 1) { + ret = -EOPNOTSUPP; + goto err_mutex_unlock; + } /* method 1 - integrated demod */ if (msg[0].buf[0] == 0x00) { + if (msg[0].len < 2) { + ret = -EOPNOTSUPP; + goto err_mutex_unlock; + } /* save demod page for later demod access */ dev->page = msg[0].buf[1]; ret = 0; @@ -235,6 +247,10 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], ret = rtl28xxu_ctrl_msg(d, &req); } } else if ((msg[0].len < 23) && (!dev->new_i2c_write)) { + if (msg[0].len < 1) { + ret = -EOPNOTSUPP; + goto err_mutex_unlock; + } /* method 2 - old I2C */ req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1); req.index = CMD_I2C_WR; @@ -274,7 +290,7 @@ static u32 rtl28xxu_i2c_func(struct i2c_adapter *adapter) return I2C_FUNC_I2C; } -static struct i2c_algorithm rtl28xxu_i2c_algo = { +static const struct i2c_algorithm rtl28xxu_i2c_algo = { .master_xfer = rtl28xxu_i2c_xfer, .functionality = rtl28xxu_i2c_func, }; @@ -384,6 +400,7 @@ static int rtl2832u_read_config(struct dvb_usb_device *d) struct rtl28xxu_req req_r828d = {0x0074, CMD_I2C_RD, 1, buf}; struct rtl28xxu_req req_mn88472 = {0xff38, CMD_I2C_RD, 1, buf}; struct rtl28xxu_req req_mn88473 = {0xff38, CMD_I2C_RD, 1, buf}; + struct rtl28xxu_req req_cxd2837er = {0xfdd8, CMD_I2C_RD, 1, buf}; struct rtl28xxu_req req_si2157 = {0x00c0, CMD_I2C_RD, 1, buf}; struct rtl28xxu_req req_si2168 = {0x00c8, CMD_I2C_RD, 1, buf}; @@ -540,7 +557,18 @@ tuner_found: /* probe slave demod */ if (dev->tuner == TUNER_RTL2832_R828D) { - /* power on MN88472 demod on GPIO0 */ + /* power off slave demod on GPIO0 to reset CXD2837ER */ + ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_VAL, 0x00, 0x01); + if (ret) + goto err; + + ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_EN, 0x00, 0x01); + if (ret) + goto err; + + msleep(50); + + /* power on slave demod on GPIO0 */ ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_VAL, 0x01, 0x01); if (ret) goto err; @@ -553,7 +581,10 @@ tuner_found: if (ret) goto err; - /* check MN88472 answers */ + /* slave demod needs some time to wake up */ + msleep(20); + + /* check slave answers */ ret = rtl28xxu_ctrl_msg(d, &req_mn88472); if (ret == 0 && buf[0] == 0x02) { dev_dbg(&d->intf->dev, "MN88472 found\n"); @@ -567,6 +598,13 @@ tuner_found: dev->slave_demod = SLAVE_DEMOD_MN88473; goto demod_found; } + + ret = rtl28xxu_ctrl_msg(d, &req_cxd2837er); + if (ret == 0 && buf[0] == 0xb1) { + dev_dbg(&d->intf->dev, "CXD2837ER found\n"); + dev->slave_demod = SLAVE_DEMOD_CXD2837ER; + goto demod_found; + } } if (dev->tuner == TUNER_RTL2832_SI2157) { /* check Si2168 ID register; reg=c8 val=80 */ @@ -687,12 +725,12 @@ static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap) /* attach demodulator */ memset(&board_info, 0, sizeof(board_info)); - strlcpy(board_info.type, "rtl2830", I2C_NAME_SIZE); + strscpy(board_info.type, "rtl2830", I2C_NAME_SIZE); board_info.addr = 0x10; board_info.platform_data = pdata; request_module("%s", board_info.type); - client = i2c_new_device(&d->i2c_adap, &board_info); - if (client == NULL || client->dev.driver == NULL) { + client = i2c_new_client_device(&d->i2c_adap, &board_info); + if (!i2c_client_has_driver(client)) { ret = -ENODEV; goto err; } @@ -908,12 +946,12 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap) /* attach demodulator */ memset(&board_info, 0, sizeof(board_info)); - strlcpy(board_info.type, "rtl2832", I2C_NAME_SIZE); + strscpy(board_info.type, "rtl2832", I2C_NAME_SIZE); board_info.addr = 0x10; board_info.platform_data = pdata; request_module("%s", board_info.type); - client = i2c_new_device(&d->i2c_adap, &board_info); - if (client == NULL || client->dev.driver == NULL) { + client = i2c_new_client_device(&d->i2c_adap, &board_info); + if (!i2c_client_has_driver(client)) { ret = -ENODEV; goto err; } @@ -935,34 +973,25 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap) if (dev->slave_demod) { struct i2c_board_info info = {}; - /* - * We continue on reduced mode, without DVB-T2/C, using master - * demod, when slave demod fails. - */ - ret = 0; - /* attach slave demodulator */ if (dev->slave_demod == SLAVE_DEMOD_MN88472) { struct mn88472_config mn88472_config = {}; mn88472_config.fe = &adap->fe[1]; - mn88472_config.i2c_wr_max = 22, - strlcpy(info.type, "mn88472", I2C_NAME_SIZE); + mn88472_config.i2c_wr_max = 22; + strscpy(info.type, "mn88472", I2C_NAME_SIZE); mn88472_config.xtal = 20500000; mn88472_config.ts_mode = SERIAL_TS_MODE; mn88472_config.ts_clock = VARIABLE_TS_CLOCK; info.addr = 0x18; info.platform_data = &mn88472_config; request_module(info.type); - client = i2c_new_device(&d->i2c_adap, &info); - if (client == NULL || client->dev.driver == NULL) { - dev->slave_demod = SLAVE_DEMOD_NONE; + client = i2c_new_client_device(&d->i2c_adap, &info); + if (!i2c_client_has_driver(client)) goto err_slave_demod_failed; - } if (!try_module_get(client->dev.driver->owner)) { i2c_unregister_device(client); - dev->slave_demod = SLAVE_DEMOD_NONE; goto err_slave_demod_failed; } @@ -971,24 +1000,36 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap) struct mn88473_config mn88473_config = {}; mn88473_config.fe = &adap->fe[1]; - mn88473_config.i2c_wr_max = 22, - strlcpy(info.type, "mn88473", I2C_NAME_SIZE); + mn88473_config.i2c_wr_max = 22; + strscpy(info.type, "mn88473", I2C_NAME_SIZE); info.addr = 0x18; info.platform_data = &mn88473_config; request_module(info.type); - client = i2c_new_device(&d->i2c_adap, &info); - if (client == NULL || client->dev.driver == NULL) { - dev->slave_demod = SLAVE_DEMOD_NONE; + client = i2c_new_client_device(&d->i2c_adap, &info); + if (!i2c_client_has_driver(client)) goto err_slave_demod_failed; - } if (!try_module_get(client->dev.driver->owner)) { i2c_unregister_device(client); - dev->slave_demod = SLAVE_DEMOD_NONE; goto err_slave_demod_failed; } dev->i2c_client_slave_demod = client; + } else if (dev->slave_demod == SLAVE_DEMOD_CXD2837ER) { + struct cxd2841er_config cxd2837er_config = {}; + + cxd2837er_config.i2c_addr = 0xd8; + cxd2837er_config.xtal = SONY_XTAL_20500; + cxd2837er_config.flags = (CXD2841ER_AUTO_IFHZ | + CXD2841ER_NO_AGCNEG | CXD2841ER_TSBITS | + CXD2841ER_EARLY_TUNE | CXD2841ER_TS_SERIAL); + adap->fe[1] = dvb_attach(cxd2841er_attach_t_c, + &cxd2837er_config, + &d->i2c_adap); + if (!adap->fe[1]) + goto err_slave_demod_failed; + adap->fe[1]->id = 1; + dev->i2c_client_slave_demod = NULL; } else { struct si2168_config si2168_config = {}; struct i2c_adapter *adapter; @@ -998,19 +1039,16 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap) si2168_config.ts_mode = SI2168_TS_SERIAL; si2168_config.ts_clock_inv = false; si2168_config.ts_clock_gapped = true; - strlcpy(info.type, "si2168", I2C_NAME_SIZE); + strscpy(info.type, "si2168", I2C_NAME_SIZE); info.addr = 0x64; info.platform_data = &si2168_config; request_module(info.type); - client = i2c_new_device(&d->i2c_adap, &info); - if (client == NULL || client->dev.driver == NULL) { - dev->slave_demod = SLAVE_DEMOD_NONE; + client = i2c_new_client_device(&d->i2c_adap, &info); + if (!i2c_client_has_driver(client)) goto err_slave_demod_failed; - } if (!try_module_get(client->dev.driver->owner)) { i2c_unregister_device(client); - dev->slave_demod = SLAVE_DEMOD_NONE; goto err_slave_demod_failed; } @@ -1021,10 +1059,18 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap) } } return 0; -err_slave_demod_failed: + err: dev_dbg(&d->intf->dev, "failed=%d\n", ret); return ret; + +err_slave_demod_failed: + /* + * We continue on reduced mode, without DVB-T2/C, using master + * demod, when slave demod fails. + */ + dev->slave_demod = SLAVE_DEMOD_NONE; + return 0; } static int rtl28xxu_frontend_attach(struct dvb_usb_adapter *adap) @@ -1189,13 +1235,14 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) .clock = 28800000, }; - strlcpy(info.type, "e4000", I2C_NAME_SIZE); + strscpy(info.type, "e4000", I2C_NAME_SIZE); info.addr = 0x64; info.platform_data = &e4000_config; request_module(info.type); - client = i2c_new_device(dev->demod_i2c_adapter, &info); - if (client == NULL || client->dev.driver == NULL) + client = i2c_new_client_device(dev->demod_i2c_adapter, + &info); + if (!i2c_client_has_driver(client)) break; if (!try_module_get(client->dev.driver->owner)) { @@ -1213,13 +1260,13 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) }; struct i2c_board_info board_info = {}; - strlcpy(board_info.type, "fc2580", I2C_NAME_SIZE); + strscpy(board_info.type, "fc2580", I2C_NAME_SIZE); board_info.addr = 0x56; board_info.platform_data = &fc2580_pdata; request_module("fc2580"); - client = i2c_new_device(dev->demod_i2c_adapter, - &board_info); - if (client == NULL || client->dev.driver == NULL) + client = i2c_new_client_device(dev->demod_i2c_adapter, + &board_info); + if (!i2c_client_has_driver(client)) break; if (!try_module_get(client->dev.driver->owner)) { i2c_unregister_device(client); @@ -1244,12 +1291,13 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) if (ret) goto err; - strlcpy(board_info.type, "tua9001", I2C_NAME_SIZE); + strscpy(board_info.type, "tua9001", I2C_NAME_SIZE); board_info.addr = 0x60; board_info.platform_data = &tua9001_pdata; request_module("tua9001"); - client = i2c_new_device(dev->demod_i2c_adapter, &board_info); - if (client == NULL || client->dev.driver == NULL) + client = i2c_new_client_device(dev->demod_i2c_adapter, + &board_info); + if (!i2c_client_has_driver(client)) break; if (!try_module_get(client->dev.driver->owner)) { i2c_unregister_device(client); @@ -1289,12 +1337,12 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) .inversion = false, }; - strlcpy(info.type, "si2157", I2C_NAME_SIZE); + strscpy(info.type, "si2157", I2C_NAME_SIZE); info.addr = 0x60; info.platform_data = &si2157_config; request_module(info.type); - client = i2c_new_device(&d->i2c_adap, &info); - if (client == NULL || client->dev.driver == NULL) + client = i2c_new_client_device(&d->i2c_adap, &info); + if (!i2c_client_has_driver(client)) break; if (!try_module_get(client->dev.driver->owner)) { @@ -1598,7 +1646,7 @@ static int rtl2831u_rc_query(struct dvb_usb_device *d) struct rtl28xxu_dev *dev = d->priv; u8 buf[5]; u32 rc_code; - struct rtl28xxu_reg_val rc_nec_tab[] = { + static const struct rtl28xxu_reg_val rc_nec_tab[] = { { 0x3033, 0x80 }, { 0x3020, 0x43 }, { 0x3021, 0x16 }, @@ -1631,24 +1679,24 @@ static int rtl2831u_rc_query(struct dvb_usb_device *d) goto err; if (buf[4] & 0x01) { - enum rc_type proto; + enum rc_proto proto; if (buf[2] == (u8) ~buf[3]) { if (buf[0] == (u8) ~buf[1]) { /* NEC standard (16 bit) */ rc_code = RC_SCANCODE_NEC(buf[0], buf[2]); - proto = RC_TYPE_NEC; + proto = RC_PROTO_NEC; } else { /* NEC extended (24 bit) */ rc_code = RC_SCANCODE_NECX(buf[0] << 8 | buf[1], buf[2]); - proto = RC_TYPE_NECX; + proto = RC_PROTO_NECX; } } else { /* NEC full (32 bit) */ rc_code = RC_SCANCODE_NEC32(buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]); - proto = RC_TYPE_NEC32; + proto = RC_PROTO_NEC32; } rc_keydown(d->rc_dev, proto, rc_code, 0); @@ -1673,7 +1721,8 @@ static int rtl2831u_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) { rc->map_name = RC_MAP_EMPTY; - rc->allowed_protos = RC_BIT_NEC | RC_BIT_NECX | RC_BIT_NEC32; + rc->allowed_protos = RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX | + RC_PROTO_BIT_NEC32; rc->query = rtl2831u_rc_query; rc->interval = 400; @@ -1684,7 +1733,7 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d) { int ret, i, len; struct rtl28xxu_dev *dev = d->priv; - struct ir_raw_event ev; + struct ir_raw_event ev = {}; u8 buf[128]; static const struct rtl28xxu_reg_val_mask refresh_tab[] = { {IR_RX_IF, 0x03, 0xff}, @@ -1731,7 +1780,7 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d) goto exit; ret = rtl28xxu_rd_reg(d, IR_RX_BC, &buf[0]); - if (ret) + if (ret || buf[0] > sizeof(buf)) goto err; len = buf[0]; @@ -1750,16 +1799,13 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d) } /* pass data to Kernel IR decoder */ - init_ir_raw_event(&ev); - for (i = 0; i < len; i++) { ev.pulse = buf[i] >> 7; - ev.duration = 50800 * (buf[i] & 0x7f); + ev.duration = 51 * (buf[i] & 0x7f); ir_raw_event_store_with_filter(d->rc_dev, &ev); } - /* 'flush' ir_raw_event_store_with_filter() */ - ir_raw_event_set_idle(d->rc_dev, true); + /* 'flush' ir_raw_event_store_with_filter() */ ir_raw_event_handle(d->rc_dev); exit: return ret; @@ -1778,10 +1824,12 @@ static int rtl2832u_get_rc_config(struct dvb_usb_device *d, /* load empty to enable rc */ if (!rc->map_name) rc->map_name = RC_MAP_EMPTY; - rc->allowed_protos = RC_BIT_ALL_IR_DECODER; + rc->allowed_protos = RC_PROTO_BIT_ALL_IR_DECODER; rc->driver_type = RC_DRIVER_IR_RAW; rc->query = rtl2832u_rc_query; rc->interval = 200; + /* we program idle len to 0xc0, set timeout to one less */ + rc->timeout = 0xbf * 51; return 0; } @@ -1932,10 +1980,13 @@ static const struct usb_device_id rtl28xxu_id_table[] = { &rtl28xxu_props, "Sveon STV27", NULL) }, { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_TURBOX_DTT_2000, &rtl28xxu_props, "TURBO-X Pure TV Tuner DTT-2000", NULL) }, + { DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_PROLECTRIX_DV107669, + &rtl28xxu_props, "PROlectrix DV107669", NULL) }, /* RTL2832P devices: */ { DVB_USB_DEVICE(USB_VID_HANFTEK, 0x0131, - &rtl28xxu_props, "Astrometa DVB-T2", NULL) }, + &rtl28xxu_props, "Astrometa DVB-T2", + RC_MAP_ASTROMETA_T2HYBRID) }, { DVB_USB_DEVICE(0x5654, 0xca42, &rtl28xxu_props, "GoTView MasterHD 3", NULL) }, { } |
