diff options
Diffstat (limited to 'drivers/media/dvb/dvb-usb')
-rw-r--r-- | drivers/media/dvb/dvb-usb/Kconfig | 42 | ||||
-rw-r--r-- | drivers/media/dvb/dvb-usb/Makefile | 10 | ||||
-rw-r--r-- | drivers/media/dvb/dvb-usb/af9005-remote.c | 2 | ||||
-rw-r--r-- | drivers/media/dvb/dvb-usb/af9005-script.h | 2 | ||||
-rw-r--r-- | drivers/media/dvb/dvb-usb/af9005.c | 23 | ||||
-rw-r--r-- | drivers/media/dvb/dvb-usb/af9015.c | 1474 | ||||
-rw-r--r-- | drivers/media/dvb/dvb-usb/af9015.h | 524 | ||||
-rw-r--r-- | drivers/media/dvb/dvb-usb/anysee.c | 30 | ||||
-rw-r--r-- | drivers/media/dvb/dvb-usb/cinergyT2-core.c | 268 | ||||
-rw-r--r-- | drivers/media/dvb/dvb-usb/cinergyT2-fe.c | 351 | ||||
-rw-r--r-- | drivers/media/dvb/dvb-usb/cinergyT2.h | 95 | ||||
-rw-r--r-- | drivers/media/dvb/dvb-usb/cxusb.c | 504 | ||||
-rw-r--r-- | drivers/media/dvb/dvb-usb/dib0700.h | 4 | ||||
-rw-r--r-- | drivers/media/dvb/dvb-usb/dib0700_core.c | 115 | ||||
-rw-r--r-- | drivers/media/dvb/dvb-usb/dib0700_devices.c | 195 | ||||
-rw-r--r-- | drivers/media/dvb/dvb-usb/dtv5100.c | 240 | ||||
-rw-r--r-- | drivers/media/dvb/dvb-usb/dtv5100.h | 51 | ||||
-rw-r--r-- | drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 29 | ||||
-rw-r--r-- | drivers/media/dvb/dvb-usb/dw2102.c | 572 | ||||
-rw-r--r-- | drivers/media/dvb/dvb-usb/dw2102.h | 1 |
20 files changed, 4404 insertions, 128 deletions
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index e84152b7576..3c13bcfa638 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/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 @@ -108,6 +110,8 @@ config DVB_USB_CXUSB select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE + select DVB_DIB7000P if !DVB_FE_CUSTOMISE + select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE help Say Y here to support the Conexant USB2.0 hybrid reference design. Currently, only DVB and ATSC modes are supported, analog mode @@ -245,12 +249,25 @@ config DVB_USB_AF9005_REMOTE Afatech AF9005 based receiver. config DVB_USB_DW2102 - tristate "DvbWorld 2102 DVB-S USB2.0 receiver" + tristate "DvbWorld DVB-S/S2 USB2.0 support" depends on DVB_USB - select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_PLL if !DVB_FE_CUSTOMISE + select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_STV0288 if !DVB_FE_CUSTOMISE + select DVB_STB6000 if !DVB_FE_CUSTOMISE + select DVB_CX24116 if !DVB_FE_CUSTOMISE + select DVB_SI21XX if !DVB_FE_CUSTOMISE help - Say Y here to support the DvbWorld 2102 DVB-S USB2.0 receiver. + Say Y here to support the DvbWorld DVB-S/S2 USB2.0 receivers + and the TeVii S650. + +config DVB_USB_CINERGY_T2 + tristate "Terratec CinergyT2/qanu USB 2.0 DVB-T receiver" + depends on DVB_USB + help + Support for "TerraTec CinergyT2" USB2.0 Highspeed DVB Receivers + + Say Y if you own such a device and want to use it. config DVB_USB_ANYSEE tristate "Anysee DVB-T/C USB2.0 support" @@ -262,3 +279,22 @@ config DVB_USB_ANYSEE help Say Y here to support the Anysee E30, Anysee E30 Plus or Anysee E30 C Plus DVB USB2.0 receiver. + +config DVB_USB_DTV5100 + tristate "AME DTV-5100 USB2.0 DVB-T support" + depends on DVB_USB + select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE + help + Say Y here to support the AME DTV-5100 USB2.0 DVB-T receiver. + +config DVB_USB_AF9015 + tristate "Afatech AF9015 DVB-T USB2.0 support" + depends on DVB_USB && EXPERIMENTAL + select DVB_AF9013 + select DVB_PLL if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE + help + Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index e206f1ea002..3122b7cc2c2 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile @@ -67,6 +67,16 @@ obj-$(CONFIG_DVB_USB_ANYSEE) += dvb-usb-anysee.o dvb-usb-dw2102-objs = dw2102.o obj-$(CONFIG_DVB_USB_DW2102) += dvb-usb-dw2102.o +dvb-usb-dtv5100-objs = dtv5100.o +obj-$(CONFIG_DVB_USB_DTV5100) += dvb-usb-dtv5100.o + +dvb-usb-af9015-objs = af9015.o +obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o + +dvb-usb-cinergyT2-objs = cinergyT2-core.o cinergyT2-fe.o +obj-$(CONFIG_DVB_USB_CINERGY_T2) += dvb-usb-cinergyT2.o + + EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ # due to tuner-xc3028 EXTRA_CFLAGS += -Idrivers/media/common/tuners diff --git a/drivers/media/dvb/dvb-usb/af9005-remote.c b/drivers/media/dvb/dvb-usb/af9005-remote.c index ff00c0e8f4a..7c596f92676 100644 --- a/drivers/media/dvb/dvb-usb/af9005-remote.c +++ b/drivers/media/dvb/dvb-usb/af9005-remote.c @@ -25,7 +25,7 @@ */ #include "af9005.h" /* debug */ -int dvb_usb_af9005_remote_debug; +static int dvb_usb_af9005_remote_debug; module_param_named(debug, dvb_usb_af9005_remote_debug, int, 0644); MODULE_PARM_DESC(debug, "enable (1) or disable (0) debug messages." diff --git a/drivers/media/dvb/dvb-usb/af9005-script.h b/drivers/media/dvb/dvb-usb/af9005-script.h index 6eeaae51b1c..4d69045426d 100644 --- a/drivers/media/dvb/dvb-usb/af9005-script.h +++ b/drivers/media/dvb/dvb-usb/af9005-script.h @@ -14,7 +14,7 @@ typedef struct { u8 val; } RegDesc; -RegDesc script[] = { +static RegDesc script[] = { {0xa180, 0x0, 0x8, 0xa}, {0xa181, 0x0, 0x8, 0xd7}, {0xa182, 0x0, 0x8, 0xa3}, diff --git a/drivers/media/dvb/dvb-usb/af9005.c b/drivers/media/dvb/dvb-usb/af9005.c index cfe71feefca..ca5a0a4d2a4 100644 --- a/drivers/media/dvb/dvb-usb/af9005.c +++ b/drivers/media/dvb/dvb-usb/af9005.c @@ -35,17 +35,17 @@ module_param_named(led, dvb_usb_af9005_led, bool, 0644); MODULE_PARM_DESC(led, "enable led (default: 1)."); /* eeprom dump */ -int dvb_usb_af9005_dump_eeprom = 0; +static int dvb_usb_af9005_dump_eeprom; module_param_named(dump_eeprom, dvb_usb_af9005_dump_eeprom, int, 0); MODULE_PARM_DESC(dump_eeprom, "dump contents of the eeprom."); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); /* remote control decoder */ -int (*rc_decode) (struct dvb_usb_device * d, u8 * data, int len, u32 * event, - int *state); -void *rc_keys; -int *rc_keys_size; +static int (*rc_decode) (struct dvb_usb_device *d, u8 *data, int len, + u32 *event, int *state); +static void *rc_keys; +static int *rc_keys_size; u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; @@ -54,8 +54,8 @@ struct af9005_device_state { int led_state; }; -int af9005_usb_generic_rw(struct dvb_usb_device *d, u8 * wbuf, u16 wlen, - u8 * rbuf, u16 rlen, int delay_ms) +static int af9005_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, + u8 *rbuf, u16 rlen, int delay_ms) { int actlen, ret = -ENOMEM; @@ -98,12 +98,7 @@ int af9005_usb_generic_rw(struct dvb_usb_device *d, u8 * wbuf, u16 wlen, return ret; } -int af9005_usb_generic_write(struct dvb_usb_device *d, u8 * buf, u16 len) -{ - return af9005_usb_generic_rw(d, buf, len, NULL, 0, 0); -} - -int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg, +static int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg, int readwrite, int type, u8 * values, int len) { struct af9005_device_state *st = d->priv; @@ -765,7 +760,7 @@ static int af9005_boot_packet(struct usb_device *udev, int type, u8 * reply) return 0; } -int af9005_download_firmware(struct usb_device *udev, const struct firmware *fw) +static int af9005_download_firmware(struct usb_device *udev, const struct firmware *fw) { int i, packets, ret, act_len; diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c new file mode 100644 index 00000000000..cb0829c038c --- /dev/null +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -0,0 +1,1474 @@ +/* + * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver + * + * Copyright (C) 2007 Antti Palosaari <crope@iki.fi> + * + * Thanks to Afatech who kindly provided information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "af9015.h" +#include "af9013.h" +#include "mt2060.h" +#include "qt1010.h" +#include "tda18271.h" +#include "mxl5005s.h" +#if 0 +#include "mc44s80x.h" +#endif + +int dvb_usb_af9015_debug; +module_param_named(debug, dvb_usb_af9015_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); +int dvb_usb_af9015_remote; +module_param_named(remote, dvb_usb_af9015_remote, int, 0644); +MODULE_PARM_DESC(remote, "select remote"); +int dvb_usb_af9015_dual_mode; +module_param_named(dual_mode, dvb_usb_af9015_dual_mode, int, 0644); +MODULE_PARM_DESC(dual_mode, "enable dual mode"); +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static DEFINE_MUTEX(af9015_usb_mutex); + +static struct af9015_config af9015_config; +static struct dvb_usb_device_properties af9015_properties[2]; +int af9015_properties_count = ARRAY_SIZE(af9015_properties); + +static struct af9013_config af9015_af9013_config[] = { + { + .demod_address = AF9015_I2C_DEMOD, + .output_mode = AF9013_OUTPUT_MODE_USB, + .api_version = { 0, 1, 9, 0 }, + .gpio[0] = AF9013_GPIO_HI, + .gpio[3] = AF9013_GPIO_TUNER_ON, + + }, { + .output_mode = AF9013_OUTPUT_MODE_SERIAL, + .api_version = { 0, 1, 9, 0 }, + .gpio[0] = AF9013_GPIO_TUNER_ON, + .gpio[1] = AF9013_GPIO_LO, + } +}; + +static int af9015_rw_udev(struct usb_device *udev, struct req_t *req) +{ + int act_len, ret; + u8 buf[64]; + u8 write = 1; + u8 msg_len = 8; + static u8 seq; /* packet sequence number */ + + if (mutex_lock_interruptible(&af9015_usb_mutex) < 0) + return -EAGAIN; + + buf[0] = req->cmd; + buf[1] = seq++; + buf[2] = req->i2c_addr; + buf[3] = req->addr >> 8; + buf[4] = req->addr & 0xff; + buf[5] = req->mbox; + buf[6] = req->addr_len; + buf[7] = req->data_len; + + switch (req->cmd) { + case GET_CONFIG: + case BOOT: + case READ_MEMORY: + case RECONNECT_USB: + case GET_IR_CODE: + write = 0; + break; + case READ_I2C: + write = 0; + buf[2] |= 0x01; /* set I2C direction */ + case WRITE_I2C: + buf[0] = READ_WRITE_I2C; + break; + case WRITE_MEMORY: + if (((req->addr & 0xff00) == 0xff00) || + ((req->addr & 0xae00) == 0xae00)) + buf[0] = WRITE_VIRTUAL_MEMORY; + case WRITE_VIRTUAL_MEMORY: + case COPY_FIRMWARE: + case DOWNLOAD_FIRMWARE: + break; + default: + err("unknown command:%d", req->cmd); + ret = -1; + goto error_unlock; + } + + /* write requested */ + if (write) { + memcpy(&buf[8], req->data, req->data_len); + msg_len += req->data_len; + } + deb_xfer(">>> "); + debug_dump(buf, msg_len, deb_xfer); + + /* send req */ + ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x02), buf, msg_len, + &act_len, AF9015_USB_TIMEOUT); + if (ret) + err("bulk message failed:%d (%d/%d)", ret, msg_len, act_len); + else + if (act_len != msg_len) + ret = -1; /* all data is not send */ + if (ret) + goto error_unlock; + + /* no ack for those packets */ + if (req->cmd == DOWNLOAD_FIRMWARE || req->cmd == RECONNECT_USB) + goto exit_unlock; + + /* receive ack and data if read req */ + msg_len = 1 + 1 + req->data_len; /* seq + status + data len */ + ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, 0x81), buf, msg_len, + &act_len, AF9015_USB_TIMEOUT); + if (ret) { + err("recv bulk message failed:%d", ret); + ret = -1; + goto error_unlock; + } + + deb_xfer("<<< "); + debug_dump(buf, act_len, deb_xfer); + + /* remote controller query status is 1 if remote code is not received */ + if (req->cmd == GET_IR_CODE && buf[1] == 1) { + buf[1] = 0; /* clear command "error" status */ + memset(&buf[2], 0, req->data_len); + buf[3] = 1; /* no remote code received mark */ + } + + /* check status */ + if (buf[1]) { + err("command failed:%d", buf[1]); + ret = -1; + goto error_unlock; + } + + /* read request, copy returned data to return buf */ + if (!write) + memcpy(req->data, &buf[2], req->data_len); + +error_unlock: +exit_unlock: + mutex_unlock(&af9015_usb_mutex); + + return ret; +} + +static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) +{ + return af9015_rw_udev(d->udev, req); +} + +static int af9015_write_regs(struct dvb_usb_device *d, u16 addr, u8 *val, + u8 len) +{ + struct req_t req = {WRITE_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len, + val}; + return af9015_ctrl_msg(d, &req); +} + +static int af9015_write_reg(struct dvb_usb_device *d, u16 addr, u8 val) +{ + return af9015_write_regs(d, addr, &val, 1); +} + +static int af9015_read_reg(struct dvb_usb_device *d, u16 addr, u8 *val) +{ + struct req_t req = {READ_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, 1, val}; + return af9015_ctrl_msg(d, &req); +} + +static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, + u8 val) +{ + struct req_t req = {WRITE_I2C, addr, reg, 1, 1, 1, &val}; + + if (addr == af9015_af9013_config[0].demod_address || + addr == af9015_af9013_config[1].demod_address) + req.addr_len = 3; + + return af9015_ctrl_msg(d, &req); +} + +static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, + u8 *val) +{ + struct req_t req = {READ_I2C, addr, reg, 0, 1, 1, val}; + + if (addr == af9015_af9013_config[0].demod_address || + addr == af9015_af9013_config[1].demod_address) + req.addr_len = 3; + + return af9015_ctrl_msg(d, &req); +} + +static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int ret = 0, i = 0; + u16 addr; + u8 mbox, addr_len; + struct req_t req; + +/* TODO: implement bus lock + +The bus lock is needed because there is two tuners both using same I2C-address. +Due to that the only way to select correct tuner is use demodulator I2C-gate. + +................................................ +. AF9015 includes integrated AF9013 demodulator. +. ____________ ____________ . ____________ +.| uC | | demod | . | tuner | +.|------------| |------------| . |------------| +.| AF9015 | | AF9013/5 | . | MXL5003 | +.| |--+----I2C-------|-----/ -----|-.-----I2C-------| | +.| | | | addr 0x38 | . | addr 0xc6 | +.|____________| | |____________| . |____________| +.................|.............................. + | ____________ ____________ + | | demod | | tuner | + | |------------| |------------| + | | AF9013 | | MXL5003 | + +----I2C-------|-----/ -----|-------I2C-------| | + | addr 0x3a | | addr 0xc6 | + |____________| |____________| +*/ + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + while (i < num) { + if (msg[i].addr == af9015_af9013_config[0].demod_address || + msg[i].addr == af9015_af9013_config[1].demod_address) { + addr = msg[i].buf[0] << 8; + addr += msg[i].buf[1]; + mbox = msg[i].buf[2]; + addr_len = 3; + } else { + addr = msg[i].buf[0]; + addr_len = 1; + mbox = 0; + } + + if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { + if (msg[i].addr == + af9015_af9013_config[0].demod_address) + req.cmd = READ_MEMORY; + else + req.cmd = READ_I2C; + req.i2c_addr = msg[i].addr; + req.addr = addr; + req.mbox = mbox; + req.addr_len = addr_len; + req.data_len = msg[i+1].len; + req.data = &msg[i+1].buf[0]; + ret = af9015_ctrl_msg(d, &req); + i += 2; + } else { + if (msg[i].addr == + af9015_af9013_config[0].demod_address) + req.cmd = WRITE_MEMORY; + else + req.cmd = WRITE_I2C; + req.i2c_addr = msg[i].addr; + req.addr = addr; + req.mbox = mbox; + req.addr_len = addr_len; + req.data_len = msg[i].len-addr_len; + req.data = &msg[i].buf[addr_len]; + ret = af9015_ctrl_msg(d, &req); + i += 1; + } + if (ret) + goto error; + + } + ret = i; + +error: + mutex_unlock(&d->i2c_mutex); + + return ret; +} + +static u32 af9015_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm af9015_i2c_algo = { + .master_xfer = af9015_i2c_xfer, + .functionality = af9015_i2c_func, +}; + +static int af9015_do_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit, u8 op) +{ + int ret; + u8 val, mask = 0x01; + + ret = af9015_read_reg(d, addr, &val); + if (ret) + return ret; + + mask <<= bit; + if (op) { + /* set bit */ + val |= mask; + } else { + /* clear bit */ + mask ^= 0xff; + val &= mask; + } + + return af9015_write_reg(d, addr, val); +} + +static int af9015_set_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit) +{ + return af9015_do_reg_bit(d, addr, bit, 1); +} + +static int af9015_clear_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit) +{ + return af9015_do_reg_bit(d, addr, bit, 0); +} + +static int af9015_init_endpoint(struct dvb_usb_device *d) +{ + int ret; + u16 frame_size; + u8 packet_size; + deb_info("%s: USB speed:%d\n", __func__, d->udev->speed); + +#define TS_PACKET_SIZE 188 + +#define TS_USB20_PACKET_COUNT 348 +#define TS_USB20_FRAME_SIZE (TS_PACKET_SIZE*TS_USB20_PACKET_COUNT) + +#define TS_USB11_PACKET_COUNT 21 +#define TS_USB11_FRAME_SIZE (TS_PACKET_SIZE*TS_USB11_PACKET_COUNT) + +#define TS_USB20_MAX_PACKET_SIZE 512 +#define TS_USB11_MAX_PACKET_SIZE 64 + + if (d->udev->speed == USB_SPEED_FULL) { + frame_size = TS_USB11_FRAME_SIZE/4; + packet_size = TS_USB11_MAX_PACKET_SIZE/4; + } else { + frame_size = TS_USB20_FRAME_SIZE/4; + packet_size = TS_USB20_MAX_PACKET_SIZE/4; + } + + ret = af9015_set_reg_bit(d, 0xd507, 2); /* assert EP4 reset */ + if (ret) + goto error; + ret = af9015_set_reg_bit(d, 0xd50b, 1); /* assert EP5 reset */ + if (ret) + goto error; + ret = af9015_clear_reg_bit(d, 0xdd11, 5); /* disable EP4 */ + if (ret) + goto error; + ret = af9015_clear_reg_bit(d, 0xdd11, 6); /* disable EP5 */ + if (ret) + goto error; + ret = af9015_set_reg_bit(d, 0xdd11, 5); /* enable EP4 */ + if (ret) + goto error; + if (af9015_config.dual_mode) { + ret = af9015_set_reg_bit(d, 0xdd11, 6); /* enable EP5 */ + if (ret) + goto error; + } + ret = af9015_clear_reg_bit(d, 0xdd13, 5); /* disable EP4 NAK */ + if (ret) + goto error; + if (af9015_config.dual_mode) { + ret = af9015_clear_reg_bit(d, 0xdd13, 6); /* disable EP5 NAK */ + if (ret) + goto error; + } + /* EP4 xfer length */ + ret = af9015_write_reg(d, 0xdd88, frame_size & 0xff); + if (ret) + goto error; + ret = af9015_write_reg(d, 0xdd89, frame_size >> 8); + if (ret) + goto error; + /* EP5 xfer length */ + ret = af9015_write_reg(d, 0xdd8a, frame_size & 0xff); + if (ret) + goto error; + ret = af9015_write_reg(d, 0xdd8b, frame_size >> 8); + if (ret) + goto error; + ret = af9015_write_reg(d, 0xdd0c, packet_size); /* EP4 packet size */ + if (ret) + goto error; + ret = af9015_write_reg(d, 0xdd0d, packet_size); /* EP5 packet size */ + if (ret) + goto error; + ret = af9015_clear_reg_bit(d, 0xd507, 2); /* negate EP4 reset */ + if (ret) + goto error; + if (af9015_config.dual_mode) { + ret = af9015_clear_reg_bit(d, 0xd50b, 1); /* negate EP5 reset */ + if (ret) + goto error; + } + + /* enable / disable mp2if2 */ + if (af9015_config.dual_mode) + ret = af9015_set_reg_bit(d, 0xd50b, 0); + else + ret = af9015_clear_reg_bit(d, 0xd50b, 0); +error: + if (ret) + err("endpoint init failed:%d", ret); + return ret; +} + +static int af9015_copy_firmware(struct dvb_usb_device *d) +{ + int ret; + u8 fw_params[4]; + u8 val, i; + struct req_t req = {COPY_FIRMWARE, 0, 0x5100, 0, 0, sizeof(fw_params), + fw_params }; + deb_info("%s:\n", __func__); + + fw_params[0] = af9015_config.firmware_size >> 8; + fw_params[1] = af9015_config.firmware_size & 0xff; + fw_params[2] = af9015_config.firmware_checksum >> 8; + fw_params[3] = af9015_config.firmware_checksum & 0xff; + + /* wait 2nd demodulator ready */ + msleep(100); + + ret = af9015_read_reg_i2c(d, 0x3a, 0x98be, &val); + if (ret) + goto error; + else + deb_info("%s: firmware status:%02x\n", __func__, val); + + if (val == 0x0c) /* fw is running, no need for download */ + goto exit; + + /* set I2C master clock to fast (to speed up firmware copy) */ + ret = af9015_write_reg(d, 0xd416, 0x04); /* 0x04 * 400ns */ + if (ret) + goto error; + + msleep(50); + + /* copy firmware */ + ret = af9015_ctrl_msg(d, &req); + if (ret) + err("firmware copy cmd failed:%d", ret); + deb_info("%s: firmware copy done\n", __func__); + + /* set I2C master clock back to normal */ + ret = af9015_write_reg(d, 0xd416, 0x14); /* 0x14 * 400ns */ + if (ret) + goto error; + + /* request boot firmware */ + ret = af9015_write_reg_i2c(d, af9015_af9013_config[1].demod_address, + 0xe205, 1); + deb_info("%s: firmware boot cmd status:%d\n", __func__, ret); + if (ret) + goto error; + + for (i = 0; i < 15; i++) { + msleep(100); + + /* check firmware status */ + ret = af9015_read_reg_i2c(d, + af9015_af9013_config[1].demod_address, 0x98be, &val); + deb_info("%s: firmware status cmd status:%d fw status:%02x\n", + __func__, ret, val); + if (ret) + goto error; + + if (val == 0x0c || val == 0x04) /* success or fail */ + break; + } + + if (val == 0x04) { + err("firmware did not run"); + ret = -1; + } else if (val != 0x0c) { + err("firmware boot timeout"); + ret = -1; + } + +error: +exit: + return ret; +} + +/* dump eeprom */ +static int af9015_eeprom_dump(struct dvb_usb_device *d) +{ + char buf[52], buf2[4]; + u8 reg, val; + + for (reg = 0; ; reg++) { + if (reg % 16 == 0) { + if (reg) + deb_info("%s\n", buf); + sprintf(buf, "%02x: ", reg); + } + if (af9015_read_reg_i2c(d, AF9015_I2C_EEPROM, reg, &val) == 0) + sprintf(buf2, "%02x ", val); + else + strcpy(buf2, "-- "); + strcat(buf, buf2); + if (reg == 0xff) + break; + } + deb_info("%s\n", buf); + return 0; +} + +int af9015_download_ir_table(struct dvb_usb_device *d) +{ + int i, packets = 0, ret; + u16 addr = 0x9a56; /* ir-table start address */ + struct req_t req = {WRITE_MEMORY, 0, 0, 0, 0, 1, NULL}; + u8 *data = NULL; + deb_info("%s:\n", __func__); + + data = af9015_config.ir_table; + packets = af9015_config.ir_table_size; + + /* no remote */ + if (!packets) + goto exit; + + /* load remote ir-table */ + for (i = 0; i < packets; i++) { + req.addr = addr + i; + req.data = &data[i]; + ret = af9015_ctrl_msg(d, &req); + if (ret) { + err("ir-table download failed at packet %d with " \ + "code %d", i, ret); + return ret; + } + } + +exit: + return 0; +} + +static int af9015_init(struct dvb_usb_device *d) +{ + int ret; + deb_info("%s:\n", __func__); + + ret = af9015_init_endpoint(d); + if (ret) + goto error; + + ret = af9015_download_ir_table(d); + if (ret) + goto error; + +error: + return ret; +} + +static int af9015_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + int ret; + deb_info("%s: onoff:%d\n", __func__, onoff); + + if (onoff) + ret = af9015_set_reg_bit(adap->dev, 0xd503, 0); + else + ret = af9015_clear_reg_bit(adap->dev, 0xd503, 0); + + return ret; +} + +static int af9015_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, + int onoff) +{ + int ret; + u8 idx; + + deb_info("%s: set pid filter, index %d, pid %x, onoff %d\n", + __func__, index, pid, onoff); + + ret = af9015_write_reg(adap->dev, 0xd505, (pid & 0xff)); + if (ret) + goto error; + + ret = af9015_write_reg(adap->dev, 0xd506, (pid >> 8)); + if (ret) + goto error; + + idx = ((index & 0x1f) | (1 << 5)); + ret = af9015_write_reg(adap->dev, 0xd504, idx); + +error: + return ret; +} + +static int af9015_download_firmware(struct usb_device *udev, + const struct firmware *fw) +{ + int i, len, packets, remainder, ret; + struct req_t req = {DOWNLOAD_FIRMWARE, 0, 0, 0, 0, 0, NULL}; + u16 addr = 0x5100; /* firmware start address */ + u16 checksum = 0; + + deb_info("%s:\n", __func__); + + /* calc checksum */ + for (i = 0; i < fw->size; i++) + checksum += fw->data[i]; + + af9015_config.firmware_size = fw->size; + af9015_config.firmware_checksum = checksum; + + #define FW_PACKET_MAX_DATA 55 + + packets = fw->size / FW_PACKET_MAX_DATA; + remainder = fw->size % FW_PACKET_MAX_DATA; + len = FW_PACKET_MAX_DATA; + for (i = 0; i <= packets; i++) { + if (i == packets) /* set size of the last packet */ + len = remainder; + + req.data_len = len; + req.data = (u8 *)(fw->data + i * FW_PACKET_MAX_DATA); + req.addr = addr; + addr += FW_PACKET_MAX_DATA; + + ret = af9015_rw_udev(udev, &req); + if (ret) { + err("firmware download failed at packet %d with " \ + "code %d", i, ret); + goto error; + } + } + + /* firmware loaded, request boot */ + req.cmd = BOOT; + ret = af9015_rw_udev(udev, &req); + if (ret) { + err("firmware boot failed:%d", ret); + goto error; + } + + /* firmware is running, reconnect device in the usb bus */ + req.cmd = RECONNECT_USB; + ret = af9015_rw_udev(udev, &req); + if (ret) + err("reconnect failed: %d", ret); + +error: + return ret; +} + +static int af9015_read_config(struct usb_device *udev) +{ + int ret; + u8 val, i, offset = 0; + struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val}; + char manufacturer[10]; + + /* IR remote controller */ + req.addr = AF9015_EEPROM_IR_MODE; + ret = af9015_rw_udev(udev, &req); + if (ret) + goto error; + deb_info("%s: IR mode:%d\n", __func__, val); + for (i = 0; i < af9015_properties_count; i++) { + if (val == AF9015_IR_MODE_DISABLED || val == 0x04) { + af9015_properties[i].rc_key_map = NULL; + af9015_properties[i].rc_key_map_size = 0; + } else if (dvb_usb_af9015_remote) { + /* load remote defined as module param */ + switch (dvb_usb_af9015_remote) { + case AF9015_REMOTE_A_LINK_DTU_M: + af9015_properties[i].rc_key_map = + af9015_rc_keys_a_link; + af9015_properties[i].rc_key_map_size = + ARRAY_SIZE(af9015_rc_keys_a_link); + af9015_config.ir_table = af9015_ir_table_a_link; + af9015_config.ir_table_size = + ARRAY_SIZE(af9015_ir_table_a_link); + break; + case AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3: + af9015_properties[i].rc_key_map = + af9015_rc_keys_msi; + af9015_properties[i].rc_key_map_size = + ARRAY_SIZE(af9015_rc_keys_msi); + af9015_config.ir_table = af9015_ir_table_msi; + af9015_config.ir_table_size = + ARRAY_SIZE(af9015_ir_table_msi); + break; + case AF9015_REMOTE_MYGICTV_U718: + af9015_properties[i].rc_key_map = + af9015_rc_keys_mygictv; + af9015_properties[i].rc_key_map_size = + ARRAY_SIZE(af9015_rc_keys_mygictv); + af9015_config.ir_table = + af9015_ir_table_mygictv; + af9015_config.ir_table_size = + ARRAY_SIZE(af9015_ir_table_mygictv); + break; + } + } else { + switch (udev->descriptor.idVendor) { + case USB_VID_LEADTEK: + af9015_properties[i].rc_key_map = + af9015_rc_keys_leadtek; + af9015_properties[i].rc_key_map_size = + ARRAY_SIZE(af9015_rc_keys_leadtek); + af9015_config.ir_table = + af9015_ir_table_leadtek; + af9015_config.ir_table_size = + ARRAY_SIZE(af9015_ir_table_leadtek); + break; + case USB_VID_VISIONPLUS: + if (udev->descriptor.idProduct == + USB_PID_AZUREWAVE_AD_TU700) { + af9015_properties[i].rc_key_map = + af9015_rc_keys_twinhan; + af9015_properties[i].rc_key_map_size = + ARRAY_SIZE(af9015_rc_keys_twinhan); + af9015_config.ir_table = + af9015_ir_table_twinhan; + af9015_config.ir_table_size = + ARRAY_SIZE(af9015_ir_table_twinhan); + } + break; + case USB_VID_KWORLD_2: + /* TODO: use correct rc keys */ + af9015_properties[i].rc_key_map = + af9015_rc_keys_twinhan; + af9015_properties[i].rc_key_map_size = + ARRAY_SIZE(af9015_rc_keys_twinhan); + af9015_config.ir_table = af9015_ir_table_kworld; + af9015_config.ir_table_size = + ARRAY_SIZE(af9015_ir_table_kworld); + break; + /* Check USB manufacturer and product strings and try + to determine correct remote in case of chip vendor + reference IDs are used. */ + case USB_VID_AFATECH: + memset(manufacturer, 0, sizeof(manufacturer)); + usb_string(udev, udev->descriptor.iManufacturer, + manufacturer, sizeof(manufacturer)); + if (!strcmp("Geniatech", manufacturer)) { + /* iManufacturer 1 Geniatech + iProduct 2 AF9015 */ + af9015_properties[i].rc_key_map = + af9015_rc_keys_mygictv; + af9015_properties[i].rc_key_map_size = + ARRAY_SIZE(af9015_rc_keys_mygictv); + af9015_config.ir_table = + af9015_ir_table_mygi |