From: Mauro Carvalho Chehab Date: Sun, 12 Aug 2012 10:53:33 +0000 (-0300) Subject: [media] lmedm04: fix build X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=db6651a9ebb3;p=openwrt%2Fstaging%2Fblogic.git [media] lmedm04: fix build Those files were at the wrong place, probably due to the usage of a previous version of dvb-usb-v2 tree. Signed-off-by: Mauro Carvalho Chehab --- diff --git a/drivers/media/dvb/dvb-usb-v2/lmedm04.c b/drivers/media/dvb/dvb-usb-v2/lmedm04.c new file mode 100644 index 000000000000..c6bc1b8b58b8 --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/lmedm04.c @@ -0,0 +1,1373 @@ +/* DVB USB compliant linux driver for + * + * DM04/QQBOX DVB-S USB BOX LME2510C + SHARP:BS2F7HZ7395 + * LME2510C + LG TDQY-P001F + * LME2510C + BS2F7HZ0194 + * LME2510 + LG TDQY-P001F + * LME2510 + BS2F7HZ0194 + * + * MVB7395 (LME2510C+SHARP:BS2F7HZ7395) + * SHARP:BS2F7HZ7395 = (STV0288+Sharp IX2505V) + * + * MV001F (LME2510+LGTDQY-P001F) + * LG TDQY - P001F =(TDA8263 + TDA10086H) + * + * MVB0001F (LME2510C+LGTDQT-P001F) + * + * MV0194 (LME2510+SHARP:BS2F7HZ0194) + * SHARP:BS2F7HZ0194 = (STV0299+IX2410) + * + * MVB0194 (LME2510C+SHARP0194) + * + * LME2510C + M88RS2000 + * + * For firmware see Documentation/dvb/lmedm04.txt + * + * I2C addresses: + * 0xd0 - STV0288 - Demodulator + * 0xc0 - Sharp IX2505V - Tuner + * -- + * 0x1c - TDA10086 - Demodulator + * 0xc0 - TDA8263 - Tuner + * -- + * 0xd0 - STV0299 - Demodulator + * 0xc0 - IX2410 - Tuner + * + * + * VID = 3344 PID LME2510=1122 LME2510C=1120 + * + * Copyright (C) 2010 Malcolm Priestley (tvboxspy@gmail.com) + * LME2510(C)(C) Leaguerme (Shenzhen) MicroElectronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License Version 2, as + * published by the Free Software Foundation. + * + * 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. + * + * + * see Documentation/dvb/README.dvb-usb for more information + * + * Known Issues : + * LME2510: Non Intel USB chipsets fail to maintain High Speed on + * Boot or Hot Plug. + * + * QQbox suffers from noise on LNB voltage. + * + * LME2510: SHARP:BS2F7HZ0194(MV0194) cannot cold reset and share system + * with other tuners. After a cold reset streaming will not start. + * + * M88RS2000 suffers from loss of lock. + */ +#define DVB_USB_LOG_PREFIX "LME2510(C)" +#include +#include +#include + +#include "dvb_usb.h" +#include "lmedm04.h" +#include "tda826x.h" +#include "tda10086.h" +#include "stv0288.h" +#include "ix2505v.h" +#include "stv0299.h" +#include "dvb-pll.h" +#include "z0194a.h" +#include "m88rs2000.h" + + +#define LME2510_C_S7395 "dvb-usb-lme2510c-s7395.fw"; +#define LME2510_C_LG "dvb-usb-lme2510c-lg.fw"; +#define LME2510_C_S0194 "dvb-usb-lme2510c-s0194.fw"; +#define LME2510_C_RS2000 "dvb-usb-lme2510c-rs2000.fw"; +#define LME2510_LG "dvb-usb-lme2510-lg.fw"; +#define LME2510_S0194 "dvb-usb-lme2510-s0194.fw"; + +/* debug */ +static int dvb_usb_lme2510_debug; +#define lme_debug(var, level, args...) do { \ + if ((var >= level)) \ + pr_debug(DVB_USB_LOG_PREFIX": " args); \ +} while (0) +#define deb_info(level, args...) lme_debug(dvb_usb_lme2510_debug, level, args) +#define debug_data_snipet(level, name, p) \ + deb_info(level, name" (%02x%02x%02x%02x%02x%02x%02x%02x)", \ + *p, *(p+1), *(p+2), *(p+3), *(p+4), \ + *(p+5), *(p+6), *(p+7)); +#define info(args...) pr_info(DVB_USB_LOG_PREFIX": "args) + +module_param_named(debug, dvb_usb_lme2510_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."); + +static int dvb_usb_lme2510_firmware; +module_param_named(firmware, dvb_usb_lme2510_firmware, int, 0644); +MODULE_PARM_DESC(firmware, "set default firmware 0=Sharp7395 1=LG"); + +static int pid_filter; +module_param_named(pid, pid_filter, int, 0644); +MODULE_PARM_DESC(pid, "set default 0=default 1=off 2=on"); + + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define TUNER_DEFAULT 0x0 +#define TUNER_LG 0x1 +#define TUNER_S7395 0x2 +#define TUNER_S0194 0x3 +#define TUNER_RS2000 0x4 + +struct lme2510_state { + u8 id; + u8 tuner_config; + u8 signal_lock; + u8 signal_level; + u8 signal_sn; + u8 time_key; + u8 last_key; + u8 key_timeout; + u8 i2c_talk_onoff; + u8 i2c_gate; + u8 i2c_tuner_gate_w; + u8 i2c_tuner_gate_r; + u8 i2c_tuner_addr; + u8 stream_on; + u8 pid_size; + u8 pid_off; + void *buffer; + struct urb *lme_urb; + void *usb_buffer; + int (*fe_set_voltage)(struct dvb_frontend *, fe_sec_voltage_t); + u8 dvb_usb_lme2510_firmware; +}; + +static int lme2510_bulk_write(struct usb_device *dev, + u8 *snd, int len, u8 pipe) +{ + int ret, actual_l; + + ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, pipe), + snd, len , &actual_l, 100); + return ret; +} + +static int lme2510_bulk_read(struct usb_device *dev, + u8 *rev, int len, u8 pipe) +{ + int ret, actual_l; + + ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, pipe), + rev, len , &actual_l, 200); + return ret; +} + +static int lme2510_usb_talk(struct dvb_usb_device *d, + u8 *wbuf, int wlen, u8 *rbuf, int rlen) +{ + struct lme2510_state *st = d->priv; + u8 *buff; + int ret = 0; + + if (st->usb_buffer == NULL) { + st->usb_buffer = kmalloc(64, GFP_KERNEL); + if (st->usb_buffer == NULL) { + info("MEM Error no memory"); + return -ENOMEM; + } + } + buff = st->usb_buffer; + + ret = mutex_lock_interruptible(&d->usb_mutex); + + if (ret < 0) + return -EAGAIN; + + /* the read/write capped at 64 */ + memcpy(buff, wbuf, (wlen < 64) ? wlen : 64); + + ret |= lme2510_bulk_write(d->udev, buff, wlen , 0x01); + + ret |= lme2510_bulk_read(d->udev, buff, (rlen < 64) ? + rlen : 64 , 0x01); + + if (rlen > 0) + memcpy(rbuf, buff, rlen); + + mutex_unlock(&d->usb_mutex); + + return (ret < 0) ? -ENODEV : 0; +} + +static int lme2510_stream_restart(struct dvb_usb_device *d) +{ + struct lme2510_state *st = d->priv; + u8 all_pids[] = LME_ALL_PIDS; + u8 stream_on[] = LME_ST_ON_W; + int ret; + u8 rbuff[1]; + if (st->pid_off) + ret = lme2510_usb_talk(d, all_pids, sizeof(all_pids), + rbuff, sizeof(rbuff)); + /*Restart Stream Command*/ + ret = lme2510_usb_talk(d, stream_on, sizeof(stream_on), + rbuff, sizeof(rbuff)); + return ret; +} + +static int lme2510_enable_pid(struct dvb_usb_device *d, u8 index, u16 pid_out) +{ + struct lme2510_state *st = d->priv; + static u8 pid_buff[] = LME_ZERO_PID; + static u8 rbuf[1]; + u8 pid_no = index * 2; + u8 pid_len = pid_no + 2; + int ret = 0; + deb_info(1, "PID Setting Pid %04x", pid_out); + + if (st->pid_size == 0) + ret |= lme2510_stream_restart(d); + + pid_buff[2] = pid_no; + pid_buff[3] = (u8)pid_out & 0xff; + pid_buff[4] = pid_no + 1; + pid_buff[5] = (u8)(pid_out >> 8); + + if (pid_len > st->pid_size) + st->pid_size = pid_len; + pid_buff[7] = 0x80 + st->pid_size; + + ret |= lme2510_usb_talk(d, pid_buff , + sizeof(pid_buff) , rbuf, sizeof(rbuf)); + + if (st->stream_on) + ret |= lme2510_stream_restart(d); + + return ret; +} + +static void lme2510_int_response(struct urb *lme_urb) +{ + struct dvb_usb_adapter *adap = lme_urb->context; + struct lme2510_state *st = adap_to_priv(adap); + static u8 *ibuf, *rbuf; + int i = 0, offset; + u32 key; + + switch (lme_urb->status) { + case 0: + case -ETIMEDOUT: + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + return; + default: + info("Error %x", lme_urb->status); + break; + } + + rbuf = (u8 *) lme_urb->transfer_buffer; + + offset = ((lme_urb->actual_length/8) > 4) + ? 4 : (lme_urb->actual_length/8) ; + + for (i = 0; i < offset; ++i) { + ibuf = (u8 *)&rbuf[i*8]; + deb_info(5, "INT O/S C =%02x C/O=%02x Type =%02x%02x", + offset, i, ibuf[0], ibuf[1]); + + switch (ibuf[0]) { + case 0xaa: + debug_data_snipet(1, "INT Remote data snipet", ibuf); + if ((ibuf[4] + ibuf[5]) == 0xff) { + key = ibuf[5]; + key += (ibuf[3] > 0) + ? (ibuf[3] ^ 0xff) << 8 : 0; + key += (ibuf[2] ^ 0xff) << 16; + deb_info(1, "INT Key =%08x", key); + if (adap_to_d(adap)->rc_dev != NULL) + rc_keydown(adap_to_d(adap)->rc_dev, + key, 0); + } + break; + case 0xbb: + switch (st->tuner_config) { + case TUNER_LG: + if (ibuf[2] > 0) + st->signal_lock = ibuf[2]; + st->signal_level = ibuf[4]; + st->signal_sn = ibuf[3]; + st->time_key = ibuf[7]; + break; + case TUNER_S7395: + case TUNER_S0194: + /* Tweak for earlier firmware*/ + if (ibuf[1] == 0x03) { + if (ibuf[2] > 1) + st->signal_lock = ibuf[2]; + st->signal_level = ibuf[3]; + st->signal_sn = ibuf[4]; + } else { + st->signal_level = ibuf[4]; + st->signal_sn = ibuf[5]; + st->signal_lock = + (st->signal_lock & 0xf7) + + ((ibuf[2] & 0x01) << 0x03); + } + break; + case TUNER_RS2000: + if (ibuf[1] == 0x3 && ibuf[6] == 0xff) + st->signal_lock = 0xff; + else + st->signal_lock = 0x00; + st->signal_level = ibuf[5]; + st->signal_sn = ibuf[4]; + st->time_key = ibuf[7]; + default: + break; + } + debug_data_snipet(5, "INT Remote data snipet in", ibuf); + break; + case 0xcc: + debug_data_snipet(1, "INT Control data snipet", ibuf); + break; + default: + debug_data_snipet(1, "INT Unknown data snipet", ibuf); + break; + } + } + usb_submit_urb(lme_urb, GFP_ATOMIC); +} + +static int lme2510_int_read(struct dvb_usb_adapter *adap) +{ + struct dvb_usb_device *d = adap_to_d(adap); + struct lme2510_state *lme_int = adap_to_priv(adap); + + lme_int->lme_urb = usb_alloc_urb(0, GFP_ATOMIC); + + if (lme_int->lme_urb == NULL) + return -ENOMEM; + + lme_int->buffer = usb_alloc_coherent(d->udev, 128, GFP_ATOMIC, + &lme_int->lme_urb->transfer_dma); + + if (lme_int->buffer == NULL) + return -ENOMEM; + + usb_fill_int_urb(lme_int->lme_urb, + d->udev, + usb_rcvintpipe(d->udev, 0xa), + lme_int->buffer, + 128, + lme2510_int_response, + adap, + 8); + + lme_int->lme_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + usb_submit_urb(lme_int->lme_urb, GFP_ATOMIC); + info("INT Interrupt Service Started"); + + return 0; +} + +static int lme2510_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + struct dvb_usb_device *d = adap_to_d(adap); + struct lme2510_state *st = adap_to_priv(adap); + static u8 clear_pid_reg[] = LME_ALL_PIDS; + static u8 rbuf[1]; + int ret = 0; + + deb_info(1, "PID Clearing Filter"); + + mutex_lock(&d->i2c_mutex); + + if (!onoff) { + ret |= lme2510_usb_talk(d, clear_pid_reg, + sizeof(clear_pid_reg), rbuf, sizeof(rbuf)); + st->pid_off = true; + } else + st->pid_off = false; + + st->pid_size = 0; + + mutex_unlock(&d->i2c_mutex); + + return 0; +} + +static int lme2510_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, + int onoff) +{ + struct dvb_usb_device *d = adap_to_d(adap); + int ret = 0; + + deb_info(3, "%s PID=%04x Index=%04x onoff=%02x", __func__, + pid, index, onoff); + + if (onoff) { + mutex_lock(&d->i2c_mutex); + ret |= lme2510_enable_pid(d, index, pid); + mutex_unlock(&d->i2c_mutex); + } + + + return ret; +} + + +static int lme2510_return_status(struct dvb_usb_device *d) +{ + int ret = 0; + u8 *data; + + data = kzalloc(10, GFP_KERNEL); + if (!data) + return -ENOMEM; + + ret |= usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), + 0x06, 0x80, 0x0302, 0x00, data, 0x0006, 200); + info("Firmware Status: %x (%x)", ret , data[2]); + + ret = (ret < 0) ? -ENODEV : data[2]; + kfree(data); + return ret; +} + +static int lme2510_msg(struct dvb_usb_device *d, + u8 *wbuf, int wlen, u8 *rbuf, int rlen) +{ + int ret = 0; + struct lme2510_state *st = d->priv; + + if (st->i2c_talk_onoff == 1) { + + ret = lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); + + switch (st->tuner_config) { + case TUNER_LG: + if (wbuf[2] == 0x1c) { + if (wbuf[3] == 0x0e) { + st->signal_lock = rbuf[1]; + if ((st->stream_on & 1) && + (st->signal_lock & 0x10)) { + lme2510_stream_restart(d); + st->i2c_talk_onoff = 0; + } + msleep(80); + } + } + break; + case TUNER_S7395: + if (wbuf[2] == 0xd0) { + if (wbuf[3] == 0x24) { + st->signal_lock = rbuf[1]; + if ((st->stream_on & 1) && + (st->signal_lock & 0x8)) { + lme2510_stream_restart(d); + st->i2c_talk_onoff = 0; + } + } + } + break; + case TUNER_S0194: + if (wbuf[2] == 0xd0) { + if (wbuf[3] == 0x1b) { + st->signal_lock = rbuf[1]; + if ((st->stream_on & 1) && + (st->signal_lock & 0x8)) { + lme2510_stream_restart(d); + st->i2c_talk_onoff = 0; + } + } + } + break; + case TUNER_RS2000: + default: + break; + } + } else { + /* TODO rewrite this section */ + switch (st->tuner_config) { + case TUNER_LG: + switch (wbuf[3]) { + case 0x0e: + rbuf[0] = 0x55; + rbuf[1] = st->signal_lock; + break; + case 0x43: + rbuf[0] = 0x55; + rbuf[1] = st->signal_level; + break; + case 0x1c: + rbuf[0] = 0x55; + rbuf[1] = st->signal_sn; + break; + case 0x15: + case 0x16: + case 0x17: + case 0x18: + rbuf[0] = 0x55; + rbuf[1] = 0x00; + break; + default: + lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); + st->i2c_talk_onoff = 1; + break; + } + break; + case TUNER_S7395: + switch (wbuf[3]) { + case 0x10: + rbuf[0] = 0x55; + rbuf[1] = (st->signal_level & 0x80) + ? 0 : (st->signal_level * 2); + break; + case 0x2d: + rbuf[0] = 0x55; + rbuf[1] = st->signal_sn; + break; + case 0x24: + rbuf[0] = 0x55; + rbuf[1] = st->signal_lock; + break; + case 0x2e: + case 0x26: + case 0x27: + rbuf[0] = 0x55; + rbuf[1] = 0x00; + break; + default: + lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); + st->i2c_talk_onoff = 1; + break; + } + break; + case TUNER_S0194: + switch (wbuf[3]) { + case 0x18: + rbuf[0] = 0x55; + rbuf[1] = (st->signal_level & 0x80) + ? 0 : (st->signal_level * 2); + break; + case 0x24: + rbuf[0] = 0x55; + rbuf[1] = st->signal_sn; + break; + case 0x1b: + rbuf[0] = 0x55; + rbuf[1] = st->signal_lock; + break; + case 0x19: + case 0x25: + case 0x1e: + case 0x1d: + rbuf[0] = 0x55; + rbuf[1] = 0x00; + break; + default: + lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); + st->i2c_talk_onoff = 1; + break; + } + break; + case TUNER_RS2000: + switch (wbuf[3]) { + case 0x8c: + rbuf[0] = 0x55; + rbuf[1] = 0xff; + if (st->last_key == st->time_key) { + st->key_timeout++; + if (st->key_timeout > 5) + rbuf[1] = 0; + } else + st->key_timeout = 0; + st->last_key = st->time_key; + break; + default: + lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); + st->i2c_talk_onoff = 1; + break; + } + default: + break; + } + + deb_info(4, "I2C From Interrupt Message out(%02x) in(%02x)", + wbuf[3], rbuf[1]); + + } + + return ret; +} + + +static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + struct lme2510_state *st = d->priv; + static u8 obuf[64], ibuf[64]; + int i, read, read_o; + u16 len; + u8 gate = st->i2c_gate; + + mutex_lock(&d->i2c_mutex); + + if (gate == 0) + gate = 5; + + for (i = 0; i < num; i++) { + read_o = 1 & (msg[i].flags & I2C_M_RD); + read = i+1 < num && (msg[i+1].flags & I2C_M_RD); + read |= read_o; + gate = (msg[i].addr == st->i2c_tuner_addr) + ? (read) ? st->i2c_tuner_gate_r + : st->i2c_tuner_gate_w + : st->i2c_gate; + obuf[0] = gate | (read << 7); + + if (gate == 5) + obuf[1] = (read) ? 2 : msg[i].len + 1; + else + obuf[1] = msg[i].len + read + 1; + + obuf[2] = msg[i].addr; + if (read) { + if (read_o) + len = 3; + else { + memcpy(&obuf[3], msg[i].buf, msg[i].len); + obuf[msg[i].len+3] = msg[i+1].len; + len = msg[i].len+4; + } + } else { + memcpy(&obuf[3], msg[i].buf, msg[i].len); + len = msg[i].len+3; + } + + if (lme2510_msg(d, obuf, len, ibuf, 64) < 0) { + deb_info(1, "i2c transfer failed."); + mutex_unlock(&d->i2c_mutex); + return -EAGAIN; + } + + if (read) { + if (read_o) + memcpy(msg[i].buf, &ibuf[1], msg[i].len); + else { + memcpy(msg[i+1].buf, &ibuf[1], msg[i+1].len); + i++; + } + } + } + + mutex_unlock(&d->i2c_mutex); + return i; +} + +static u32 lme2510_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm lme2510_i2c_algo = { + .master_xfer = lme2510_i2c_xfer, + .functionality = lme2510_i2c_func, +}; + +static int lme2510_streaming_ctrl(struct dvb_frontend *fe, int onoff) +{ + struct dvb_usb_adapter *adap = fe_to_adap(fe); + struct dvb_usb_device *d = adap_to_d(adap); + struct lme2510_state *st = adap_to_priv(adap); + static u8 clear_reg_3[] = LME_ALL_PIDS; + static u8 rbuf[1]; + int ret = 0, rlen = sizeof(rbuf); + + deb_info(1, "STM (%02x)", onoff); + + /* Streaming is started by FE_HAS_LOCK */ + if (onoff == 1) + st->stream_on = 1; + else { + deb_info(1, "STM Steam Off"); + /* mutex is here only to avoid collision with I2C */ + mutex_lock(&d->i2c_mutex); + + ret = lme2510_usb_talk(d, clear_reg_3, + sizeof(clear_reg_3), rbuf, rlen); + st->stream_on = 0; + st->i2c_talk_onoff = 1; + + mutex_unlock(&d->i2c_mutex); + } + + return (ret < 0) ? -ENODEV : 0; +} + +static u8 check_sum(u8 *p, u8 len) +{ + u8 sum = 0; + while (len--) + sum += *p++; + return sum; +} + +static int lme2510_download_firmware(struct dvb_usb_device *d, + const struct firmware *fw) +{ + int ret = 0; + u8 *data; + u16 j, wlen, len_in, start, end; + u8 packet_size, dlen, i; + u8 *fw_data; + + packet_size = 0x31; + len_in = 1; + + data = kzalloc(128, GFP_KERNEL); + if (!data) { + info("FRM Could not start Firmware Download"\ + "(Buffer allocation failed)"); + return -ENOMEM; + } + + info("FRM Starting Firmware Download"); + + for (i = 1; i < 3; i++) { + start = (i == 1) ? 0 : 512; + end = (i == 1) ? 512 : fw->size; + for (j = start; j < end; j += (packet_size+1)) { + fw_data = (u8 *)(fw->data + j); + if ((end - j) > packet_size) { + data[0] = i; + dlen = packet_size; + } else { + data[0] = i | 0x80; + dlen = (u8)(end - j)-1; + } + data[1] = dlen; + memcpy(&data[2], fw_data, dlen+1); + wlen = (u8) dlen + 4; + data[wlen-1] = check_sum(fw_data, dlen+1); + deb_info(1, "Data S=%02x:E=%02x CS= %02x", data[3], + data[dlen+2], data[dlen+3]); + lme2510_usb_talk(d, data, wlen, data, len_in); + ret |= (data[0] == 0x88) ? 0 : -1; + } + } + + usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), + 0x06, 0x80, 0x0200, 0x00, data, 0x0109, 1000); + + + data[0] = 0x8a; + len_in = 1; + msleep(2000); + lme2510_usb_talk(d, data, len_in, data, len_in); + msleep(400); + + if (ret < 0) + info("FRM Firmware Download Failed (%04x)" , ret); + else + info("FRM Firmware Download Completed - Resetting Device"); + + kfree(data); + return RECONNECTS_USB; +} + +static void lme_coldreset(struct dvb_usb_device *d) +{ + u8 data[1] = {0}; + data[0] = 0x0a; + info("FRM Firmware Cold Reset"); + + lme2510_usb_talk(d, data, sizeof(data), data, sizeof(data)); + + return; +} + +static const char fw_c_s7395[] = LME2510_C_S7395; +static const char fw_c_lg[] = LME2510_C_LG; +static const char fw_c_s0194[] = LME2510_C_S0194; +static const char fw_c_rs2000[] = LME2510_C_RS2000; +static const char fw_lg[] = LME2510_LG; +static const char fw_s0194[] = LME2510_S0194; + +const char *lme_firmware_switch(struct dvb_usb_device *d, int cold) +{ + struct lme2510_state *st = d->priv; + struct usb_device *udev = d->udev; + const struct firmware *fw = NULL; + const char *fw_lme; + int ret = 0; + + cold = (cold > 0) ? (cold & 1) : 0; + + switch (le16_to_cpu(udev->descriptor.idProduct)) { + case 0x1122: + switch (st->dvb_usb_lme2510_firmware) { + default: + st->dvb_usb_lme2510_firmware = TUNER_S0194; + case TUNER_S0194: + fw_lme = fw_s0194; + ret = request_firmware(&fw, fw_lme, &udev->dev); + if (ret == 0) { + cold = 0; + break; + } + st->dvb_usb_lme2510_firmware = TUNER_LG; + case TUNER_LG: + fw_lme = fw_lg; + ret = request_firmware(&fw, fw_lme, &udev->dev); + if (ret == 0) + break; + st->dvb_usb_lme2510_firmware = TUNER_DEFAULT; + break; + } + break; + case 0x1120: + switch (st->dvb_usb_lme2510_firmware) { + default: + st->dvb_usb_lme2510_firmware = TUNER_S7395; + case TUNER_S7395: + fw_lme = fw_c_s7395; + ret = request_firmware(&fw, fw_lme, &udev->dev); + if (ret == 0) { + cold = 0; + break; + } + st->dvb_usb_lme2510_firmware = TUNER_LG; + case TUNER_LG: + fw_lme = fw_c_lg; + ret = request_firmware(&fw, fw_lme, &udev->dev); + if (ret == 0) + break; + st->dvb_usb_lme2510_firmware = TUNER_S0194; + case TUNER_S0194: + fw_lme = fw_c_s0194; + ret = request_firmware(&fw, fw_lme, &udev->dev); + if (ret == 0) + break; + st->dvb_usb_lme2510_firmware = TUNER_DEFAULT; + cold = 0; + break; + } + break; + case 0x22f0: + fw_lme = fw_c_rs2000; + st->dvb_usb_lme2510_firmware = TUNER_RS2000; + break; + default: + fw_lme = fw_c_s7395; + } + + release_firmware(fw); + + if (cold) { + dvb_usb_lme2510_firmware = st->dvb_usb_lme2510_firmware; + info("FRM Changing to %s firmware", fw_lme); + lme_coldreset(d); + return NULL; + } + + return fw_lme; +} + +static int lme2510_kill_urb(struct usb_data_stream *stream) +{ + int i; + + for (i = 0; i < stream->urbs_submitted; i++) { + deb_info(3, "killing URB no. %d.", i); + /* stop the URB */ + usb_kill_urb(stream->urb_list[i]); + } + stream->urbs_submitted = 0; + + return 0; +} + +static struct tda10086_config tda10086_config = { + .demod_address = 0x1c, + .invert = 0, + .diseqc_tone = 1, + .xtal_freq = TDA10086_XTAL_16M, +}; + +static struct stv0288_config lme_config = { + .demod_address = 0xd0, + .min_delay_ms = 15, + .inittab = s7395_inittab, +}; + +static struct ix2505v_config lme_tuner = { + .tuner_address = 0xc0, + .min_delay_ms = 100, + .tuner_gain = 0x0, + .tuner_chargepump = 0x3, +}; + +static struct stv0299_config sharp_z0194_config = { + .demod_address = 0xd0, + .inittab = sharp_z0194a_inittab, + .mclk = 88000000UL, + .invert = 0, + .skip_reinit = 0, + .lock_output = STV0299_LOCKOUTPUT_1, + .volt13_op0_op1 = STV0299_VOLT13_OP1, + .min_delay_ms = 100, + .set_symbol_rate = sharp_z0194a_set_symbol_rate, +}; + +static int dm04_rs2000_set_ts_param(struct dvb_frontend *fe, + int caller) +{ + struct dvb_usb_adapter *adap = fe_to_adap(fe); + struct dvb_usb_device *d = adap_to_d(adap); + struct lme2510_state *st = d->priv; + + mutex_lock(&d->i2c_mutex); + if ((st->i2c_talk_onoff == 1) && (st->stream_on & 1)) { + st->i2c_talk_onoff = 0; + lme2510_stream_restart(d); + } + mutex_unlock(&d->i2c_mutex); + + return 0; +} + +static struct m88rs2000_config m88rs2000_config = { + .demod_addr = 0xd0, + .tuner_addr = 0xc0, + .set_ts_params = dm04_rs2000_set_ts_param, +}; + +static int dm04_lme2510_set_voltage(struct dvb_frontend *fe, + fe_sec_voltage_t voltage) +{ + struct dvb_usb_device *d = fe_to_d(fe); + struct lme2510_state *st = fe_to_priv(fe); + static u8 voltage_low[] = LME_VOLTAGE_L; + static u8 voltage_high[] = LME_VOLTAGE_H; + static u8 rbuf[1]; + int ret = 0, len = 3, rlen = 1; + + mutex_lock(&d->i2c_mutex); + + switch (voltage) { + case SEC_VOLTAGE_18: + ret |= lme2510_usb_talk(d, + voltage_high, len, rbuf, rlen); + break; + + case SEC_VOLTAGE_OFF: + case SEC_VOLTAGE_13: + default: + ret |= lme2510_usb_talk(d, + voltage_low, len, rbuf, rlen); + break; + } + + mutex_unlock(&d->i2c_mutex); + + if (st->tuner_config == TUNER_RS2000) + if (st->fe_set_voltage) + st->fe_set_voltage(fe, voltage); + + + return (ret < 0) ? -ENODEV : 0; +} + +static int dm04_rs2000_read_signal_strength(struct dvb_frontend *fe, + u16 *strength) +{ + struct lme2510_state *st = fe_to_priv(fe); + + *strength = (u16)((u32)st->signal_level * 0xffff / 0xff); + + return 0; +} + +static int dm04_rs2000_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct lme2510_state *st = fe_to_priv(fe); + + *snr = (u16)((u32)st->signal_sn * 0xffff / 0x7f); + + return 0; +} + +static int dm04_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + *ber = 0; + + return 0; +} + +static int dm04_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + *ucblocks = 0; + + return 0; +} + +static int lme_name(struct dvb_usb_adapter *adap) +{ + struct dvb_usb_device *d = adap_to_d(adap); + struct lme2510_state *st = adap_to_priv(adap); + const char *desc = d->name; + char *fe_name[] = {"", " LG TDQY-P001F", " SHARP:BS2F7HZ7395", + " SHARP:BS2F7HZ0194", " RS2000"}; + char *name = adap->fe[0]->ops.info.name; + + strlcpy(name, desc, 128); + strlcat(name, fe_name[st->tuner_config], 128); + + return 0; +} + +static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_usb_device *d = adap_to_d(adap); + struct lme2510_state *st = d->priv; + int ret = 0; + + st->i2c_talk_onoff = 1; + switch (le16_to_cpu(d->udev->descriptor.idProduct)) { + case 0x1122: + case 0x1120: + st->i2c_gate = 4; + adap->fe[0] = dvb_attach(tda10086_attach, + &tda10086_config, &d->i2c_adap); + if (adap->fe[0]) { + info("TUN Found Frontend TDA10086"); + st->i2c_tuner_gate_w = 4; + st->i2c_tuner_gate_r = 4; + st->i2c_tuner_addr = 0xc0; + st->tuner_config = TUNER_LG; + if (st->dvb_usb_lme2510_firmware != TUNER_LG) { + st->dvb_usb_lme2510_firmware = TUNER_LG; + ret = lme_firmware_switch(d, 1) ? 0 : -ENODEV; + } + break; + } + + st->i2c_gate = 4; + adap->fe[0] = dvb_attach(stv0299_attach, + &sharp_z0194_config, &d->i2c_adap); + if (adap->fe[0]) { + info("FE Found Stv0299"); + st->i2c_tuner_gate_w = 4; + st->i2c_tuner_gate_r = 5; + st->i2c_tuner_addr = 0xc0; + st->tuner_config = TUNER_S0194; + if (st->dvb_usb_lme2510_firmware != TUNER_S0194) { + st->dvb_usb_lme2510_firmware = TUNER_S0194; + ret = lme_firmware_switch(d, 1) ? 0 : -ENODEV; + } + break; + } + + st->i2c_gate = 5; + adap->fe[0] = dvb_attach(stv0288_attach, &lme_config, + &d->i2c_adap); + + if (adap->fe[0]) { + info("FE Found Stv0288"); + st->i2c_tuner_gate_w = 4; + st->i2c_tuner_gate_r = 5; + st->i2c_tuner_addr = 0xc0; + st->tuner_config = TUNER_S7395; + if (st->dvb_usb_lme2510_firmware != TUNER_S7395) { + st->dvb_usb_lme2510_firmware = TUNER_S7395; + ret = lme_firmware_switch(d, 1) ? 0 : -ENODEV; + } + break; + } + case 0x22f0: + st->i2c_gate = 5; + adap->fe[0] = dvb_attach(m88rs2000_attach, + &m88rs2000_config, &d->i2c_adap); + + if (adap->fe[0]) { + info("FE Found M88RS2000"); + st->i2c_tuner_gate_w = 5; + st->i2c_tuner_gate_r = 5; + st->i2c_tuner_addr = 0xc0; + st->tuner_config = TUNER_RS2000; + st->fe_set_voltage = + adap->fe[0]->ops.set_voltage; + + adap->fe[0]->ops.read_signal_strength = + dm04_rs2000_read_signal_strength; + adap->fe[0]->ops.read_snr = + dm04_rs2000_read_snr; + adap->fe[0]->ops.read_ber = + dm04_read_ber; + adap->fe[0]->ops.read_ucblocks = + dm04_read_ucblocks; + } + break; + } + + if (adap->fe[0] == NULL) { + info("DM04/QQBOX Not Powered up or not Supported"); + return -ENODEV; + } + + if (ret) { + if (adap->fe[0]) { + dvb_frontend_detach(adap->fe[0]); + adap->fe[0] = NULL; + } + d->rc_map = NULL; + return -ENODEV; + } + + adap->fe[0]->ops.set_voltage = dm04_lme2510_set_voltage; + ret = lme_name(adap); + return ret; +} + +static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap) +{ + struct dvb_usb_device *d = adap_to_d(adap); + struct lme2510_state *st = adap_to_priv(adap); + char *tun_msg[] = {"", "TDA8263", "IX2505V", "DVB_PLL_OPERA", "RS2000"}; + int ret = 0; + + switch (st->tuner_config) { + case TUNER_LG: + if (dvb_attach(tda826x_attach, adap->fe[0], 0xc0, + &d->i2c_adap, 1)) + ret = st->tuner_config; + break; + case TUNER_S7395: + if (dvb_attach(ix2505v_attach , adap->fe[0], &lme_tuner, + &d->i2c_adap)) + ret = st->tuner_config; + break; + case TUNER_S0194: + if (dvb_attach(dvb_pll_attach , adap->fe[0], 0xc0, + &d->i2c_adap, DVB_PLL_OPERA1)) + ret = st->tuner_config; + break; + case TUNER_RS2000: + ret = st->tuner_config; + break; + default: + break; + } + + if (ret) + info("TUN Found %s tuner", tun_msg[ret]); + else { + info("TUN No tuner found --- resetting device"); + lme_coldreset(d); + return -ENODEV; + } + + /* Start the Interrupt*/ + ret = lme2510_int_read(adap); + if (ret < 0) { + info("INT Unable to start Interrupt Service"); + return -ENODEV; + } + + return ret; +} + +static int lme2510_powerup(struct dvb_usb_device *d, int onoff) +{ + struct lme2510_state *st = d->priv; + static u8 lnb_on[] = LNB_ON; + static u8 lnb_off[] = LNB_OFF; + static u8 rbuf[1]; + int ret = 0, len = 3, rlen = 1; + + mutex_lock(&d->i2c_mutex); + + if (onoff) + ret = lme2510_usb_talk(d, lnb_on, len, rbuf, rlen); + else + ret = lme2510_usb_talk(d, lnb_off, len, rbuf, rlen); + + st->i2c_talk_onoff = 1; + + mutex_unlock(&d->i2c_mutex); + + return ret; +} + +static int lme2510_get_adapter_count(struct dvb_usb_device *d) +{ + return 1; +} + +static int lme2510_identify_state(struct dvb_usb_device *d, const char **name) +{ + struct lme2510_state *st = d->priv; + + usb_reset_configuration(d->udev); + + usb_set_interface(d->udev, + d->intf->cur_altsetting->desc.bInterfaceNumber, 1); + + st->dvb_usb_lme2510_firmware = dvb_usb_lme2510_firmware; + + if (lme2510_return_status(d) == 0x44) { + *name = lme_firmware_switch(d, 0); + return COLD; + } + + return 0; +} + +static int lme2510_get_stream_config(struct dvb_frontend *fe, u8 *ts_type, + struct usb_data_stream_properties *stream) +{ + struct dvb_usb_adapter *adap = fe_to_adap(fe); + struct dvb_usb_device *d = adap_to_d(adap); + + if (adap == NULL) + return 0; + /* Turn PID filter on the fly by module option */ + if (pid_filter == 2) { + adap->pid_filtering = 1; + adap->max_feed_count = 15; + } + + if (!(le16_to_cpu(d->udev->descriptor.idProduct) + == 0x1122)) + stream->endpoint = 0x8; + + return 0; +} + +static int lme2510_get_rc_config(struct dvb_usb_device *d, + struct dvb_usb_rc *rc) +{ + rc->allowed_protos = RC_TYPE_NEC; + return 0; +} + +static void *lme2510_exit_int(struct dvb_usb_device *d) +{ + struct lme2510_state *st = d->priv; + struct dvb_usb_adapter *adap = &d->adapter[0]; + void *buffer = NULL; + + if (adap != NULL) { + lme2510_kill_urb(&adap->stream); + } + + if (st->usb_buffer != NULL) { + st->i2c_talk_onoff = 1; + st->signal_lock = 0; + st->signal_level = 0; + st->signal_sn = 0; + buffer = st->usb_buffer; + } + + if (st->lme_urb != NULL) { + usb_kill_urb(st->lme_urb); + usb_free_coherent(d->udev, 128, st->buffer, + st->lme_urb->transfer_dma); + info("Interrupt Service Stopped"); + } + + return buffer; +} + +static void lme2510_exit(struct dvb_usb_device *d) +{ + void *usb_buffer; + + if (d != NULL) { + usb_buffer = lme2510_exit_int(d); + if (usb_buffer != NULL) + kfree(usb_buffer); + } +} + +static struct dvb_usb_device_properties lme2510_props = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .bInterfaceNumber = 0, + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct lme2510_state), + + .download_firmware = lme2510_download_firmware, + + .power_ctrl = lme2510_powerup, + .identify_state = lme2510_identify_state, + .i2c_algo = &lme2510_i2c_algo, + + .frontend_attach = dm04_lme2510_frontend_attach, + .tuner_attach = dm04_lme2510_tuner, + .get_stream_config = lme2510_get_stream_config, + .get_adapter_count = lme2510_get_adapter_count, + .streaming_ctrl = lme2510_streaming_ctrl, + + .get_rc_config = lme2510_get_rc_config, + + .exit = lme2510_exit, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER| + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 15, + .pid_filter = lme2510_pid_filter, + .pid_filter_ctrl = lme2510_pid_filter_ctrl, + .stream = + DVB_USB_STREAM_BULK(0x86, 10, 4096), + }, + { + } + }, +}; + +static const struct usb_device_id lme2510_id_table[] = { + { DVB_USB_DEVICE(0x3344, 0x1122, &lme2510_props, + "DM04_LME2510_DVB-S", RC_MAP_LME2510) }, + { DVB_USB_DEVICE(0x3344, 0x1120, &lme2510_props, + "DM04_LME2510C_DVB-S", RC_MAP_LME2510) }, + { DVB_USB_DEVICE(0x3344, 0x22f0, &lme2510_props, + "DM04_LME2510C_DVB-S RS2000", RC_MAP_LME2510) }, + {} /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, lme2510_id_table); + +static struct usb_driver lme2510_driver = { + .name = KBUILD_MODNAME, + .probe = dvb_usbv2_probe, + .disconnect = dvb_usbv2_disconnect, + .id_table = lme2510_id_table, + .no_dynamic_id = 1, + .soft_unbind = 1, +}; + +module_usb_driver(lme2510_driver); + +MODULE_AUTHOR("Malcolm Priestley "); +MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0"); +MODULE_VERSION("2.06"); +MODULE_LICENSE("GPL"); +MODULE_FIRMWARE(LME2510_C_S7395); +MODULE_FIRMWARE(LME2510_C_LG); +MODULE_FIRMWARE(LME2510_C_S0194); +MODULE_FIRMWARE(LME2510_C_RS2000); +MODULE_FIRMWARE(LME2510_LG); +MODULE_FIRMWARE(LME2510_S0194); + diff --git a/drivers/media/dvb/dvb-usb-v2/lmedm04.h b/drivers/media/dvb/dvb-usb-v2/lmedm04.h new file mode 100644 index 000000000000..e9c207205c2f --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/lmedm04.h @@ -0,0 +1,175 @@ +/* DVB USB compliant linux driver for + * + * DM04/QQBOX DVB-S USB BOX LME2510C + SHARP:BS2F7HZ7395 + * LME2510C + LG TDQY-P001F + * LME2510 + LG TDQY-P001F + * + * MVB7395 (LME2510C+SHARP:BS2F7HZ7395) + * SHARP:BS2F7HZ7395 = (STV0288+Sharp IX2505V) + * + * MVB001F (LME2510+LGTDQT-P001F) + * LG TDQY - P001F =(TDA8263 + TDA10086H) + * + * MVB0001F (LME2510C+LGTDQT-P001F) + * + * 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, version 2. + * * + * see Documentation/dvb/README.dvb-usb for more information + */ +#ifndef _DVB_USB_LME2510_H_ +#define _DVB_USB_LME2510_H_ + +/* Streamer & PID + * + * Note: These commands do not actually stop the streaming + * but form some kind of packet filtering/stream count + * or tuning related functions. + * 06 XX + * offset 1 = 00 Enable Streaming + * + * + * PID + * 03 XX XX ----> reg number ---> setting....20 XX + * offset 1 = length + * offset 2 = start of data + * end byte -1 = 20 + * end byte = clear pid always a0, other wise 9c, 9a ?? + * +*/ +#define LME_ST_ON_W {0x06, 0x00} +#define LME_CLEAR_PID {0x03, 0x02, 0x20, 0xa0} +#define LME_ZERO_PID {0x03, 0x06, 0x00, 0x00, 0x01, 0x00, 0x20, 0x9c} +#define LME_ALL_PIDS {0x03, 0x06, 0x00, 0xff, 0x01, 0x1f, 0x20, 0x81} + +/* LNB Voltage + * 07 XX XX + * offset 1 = 01 + * offset 2 = 00=Voltage low 01=Voltage high + * + * LNB Power + * 03 01 XX + * offset 2 = 00=ON 01=OFF + */ + +#define LME_VOLTAGE_L {0x07, 0x01, 0x00} +#define LME_VOLTAGE_H {0x07, 0x01, 0x01} +#define LNB_ON {0x3a, 0x01, 0x00} +#define LNB_OFF {0x3a, 0x01, 0x01} + +/* Initial stv0288 settings for 7395 Frontend */ +static u8 s7395_inittab[] = { + 0x01, 0x15, + 0x02, 0x20, + 0x03, 0xa0, + 0x04, 0xa0, + 0x05, 0x12, + 0x06, 0x00, + 0x09, 0x00, + 0x0a, 0x04, + 0x0b, 0x00, + 0x0c, 0x00, + 0x0d, 0x00, + 0x0e, 0xc1, + 0x0f, 0x54, + 0x11, 0x7a, + 0x12, 0x03, + 0x13, 0x48, + 0x14, 0x84, + 0x15, 0xc5, + 0x16, 0xb8, + 0x17, 0x9c, + 0x18, 0x00, + 0x19, 0xa6, + 0x1a, 0x88, + 0x1b, 0x8f, + 0x1c, 0xf0, + 0x20, 0x0b, + 0x21, 0x54, + 0x22, 0xff, + 0x23, 0x01, + 0x28, 0x46, + 0x29, 0x66, + 0x2a, 0x90, + 0x2b, 0xfa, + 0x2c, 0xd9, + 0x30, 0x0, + 0x31, 0x1e, + 0x32, 0x14, + 0x33, 0x0f, + 0x34, 0x09, + 0x35, 0x0c, + 0x36, 0x05, + 0x37, 0x2f, + 0x38, 0x16, + 0x39, 0xbd, + 0x3a, 0x0, + 0x3b, 0x13, + 0x3c, 0x11, + 0x3d, 0x30, + 0x40, 0x63, + 0x41, 0x04, + 0x42, 0x20, + 0x43, 0x00, + 0x44, 0x00, + 0x45, 0x00, + 0x46, 0x00, + 0x47, 0x00, + 0x4a, 0x00, + 0x50, 0x10, + 0x51, 0x36, + 0x52, 0x21, + 0x53, 0x94, + 0x54, 0xb2, + 0x55, 0x29, + 0x56, 0x64, + 0x57, 0x2b, + 0x58, 0x54, + 0x59, 0x86, + 0x5a, 0x00, + 0x5b, 0x9b, + 0x5c, 0x08, + 0x5d, 0x7f, + 0x5e, 0xff, + 0x5f, 0x8d, + 0x70, 0x0, + 0x71, 0x0, + 0x72, 0x0, + 0x74, 0x0, + 0x75, 0x0, + 0x76, 0x0, + 0x81, 0x0, + 0x82, 0x3f, + 0x83, 0x3f, + 0x84, 0x0, + 0x85, 0x0, + 0x88, 0x0, + 0x89, 0x0, + 0x8a, 0x0, + 0x8b, 0x0, + 0x8c, 0x0, + 0x90, 0x0, + 0x91, 0x0, + 0x92, 0x0, + 0x93, 0x0, + 0x94, 0x1c, + 0x97, 0x0, + 0xa0, 0x48, + 0xa1, 0x0, + 0xb0, 0xb8, + 0xb1, 0x3a, + 0xb2, 0x10, + 0xb3, 0x82, + 0xb4, 0x80, + 0xb5, 0x82, + 0xb6, 0x82, + 0xb7, 0x82, + 0xb8, 0x20, + 0xb9, 0x0, + 0xf0, 0x0, + 0xf1, 0x0, + 0xf2, 0xc0, + 0xff, 0xff, +}; +#endif diff --git a/drivers/media/dvb/dvb-usb/lmedm04.c b/drivers/media/dvb/dvb-usb/lmedm04.c deleted file mode 100644 index c6bc1b8b58b8..000000000000 --- a/drivers/media/dvb/dvb-usb/lmedm04.c +++ /dev/null @@ -1,1373 +0,0 @@ -/* DVB USB compliant linux driver for - * - * DM04/QQBOX DVB-S USB BOX LME2510C + SHARP:BS2F7HZ7395 - * LME2510C + LG TDQY-P001F - * LME2510C + BS2F7HZ0194 - * LME2510 + LG TDQY-P001F - * LME2510 + BS2F7HZ0194 - * - * MVB7395 (LME2510C+SHARP:BS2F7HZ7395) - * SHARP:BS2F7HZ7395 = (STV0288+Sharp IX2505V) - * - * MV001F (LME2510+LGTDQY-P001F) - * LG TDQY - P001F =(TDA8263 + TDA10086H) - * - * MVB0001F (LME2510C+LGTDQT-P001F) - * - * MV0194 (LME2510+SHARP:BS2F7HZ0194) - * SHARP:BS2F7HZ0194 = (STV0299+IX2410) - * - * MVB0194 (LME2510C+SHARP0194) - * - * LME2510C + M88RS2000 - * - * For firmware see Documentation/dvb/lmedm04.txt - * - * I2C addresses: - * 0xd0 - STV0288 - Demodulator - * 0xc0 - Sharp IX2505V - Tuner - * -- - * 0x1c - TDA10086 - Demodulator - * 0xc0 - TDA8263 - Tuner - * -- - * 0xd0 - STV0299 - Demodulator - * 0xc0 - IX2410 - Tuner - * - * - * VID = 3344 PID LME2510=1122 LME2510C=1120 - * - * Copyright (C) 2010 Malcolm Priestley (tvboxspy@gmail.com) - * LME2510(C)(C) Leaguerme (Shenzhen) MicroElectronics Co., Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License Version 2, as - * published by the Free Software Foundation. - * - * 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. - * - * - * see Documentation/dvb/README.dvb-usb for more information - * - * Known Issues : - * LME2510: Non Intel USB chipsets fail to maintain High Speed on - * Boot or Hot Plug. - * - * QQbox suffers from noise on LNB voltage. - * - * LME2510: SHARP:BS2F7HZ0194(MV0194) cannot cold reset and share system - * with other tuners. After a cold reset streaming will not start. - * - * M88RS2000 suffers from loss of lock. - */ -#define DVB_USB_LOG_PREFIX "LME2510(C)" -#include -#include -#include - -#include "dvb_usb.h" -#include "lmedm04.h" -#include "tda826x.h" -#include "tda10086.h" -#include "stv0288.h" -#include "ix2505v.h" -#include "stv0299.h" -#include "dvb-pll.h" -#include "z0194a.h" -#include "m88rs2000.h" - - -#define LME2510_C_S7395 "dvb-usb-lme2510c-s7395.fw"; -#define LME2510_C_LG "dvb-usb-lme2510c-lg.fw"; -#define LME2510_C_S0194 "dvb-usb-lme2510c-s0194.fw"; -#define LME2510_C_RS2000 "dvb-usb-lme2510c-rs2000.fw"; -#define LME2510_LG "dvb-usb-lme2510-lg.fw"; -#define LME2510_S0194 "dvb-usb-lme2510-s0194.fw"; - -/* debug */ -static int dvb_usb_lme2510_debug; -#define lme_debug(var, level, args...) do { \ - if ((var >= level)) \ - pr_debug(DVB_USB_LOG_PREFIX": " args); \ -} while (0) -#define deb_info(level, args...) lme_debug(dvb_usb_lme2510_debug, level, args) -#define debug_data_snipet(level, name, p) \ - deb_info(level, name" (%02x%02x%02x%02x%02x%02x%02x%02x)", \ - *p, *(p+1), *(p+2), *(p+3), *(p+4), \ - *(p+5), *(p+6), *(p+7)); -#define info(args...) pr_info(DVB_USB_LOG_PREFIX": "args) - -module_param_named(debug, dvb_usb_lme2510_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."); - -static int dvb_usb_lme2510_firmware; -module_param_named(firmware, dvb_usb_lme2510_firmware, int, 0644); -MODULE_PARM_DESC(firmware, "set default firmware 0=Sharp7395 1=LG"); - -static int pid_filter; -module_param_named(pid, pid_filter, int, 0644); -MODULE_PARM_DESC(pid, "set default 0=default 1=off 2=on"); - - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define TUNER_DEFAULT 0x0 -#define TUNER_LG 0x1 -#define TUNER_S7395 0x2 -#define TUNER_S0194 0x3 -#define TUNER_RS2000 0x4 - -struct lme2510_state { - u8 id; - u8 tuner_config; - u8 signal_lock; - u8 signal_level; - u8 signal_sn; - u8 time_key; - u8 last_key; - u8 key_timeout; - u8 i2c_talk_onoff; - u8 i2c_gate; - u8 i2c_tuner_gate_w; - u8 i2c_tuner_gate_r; - u8 i2c_tuner_addr; - u8 stream_on; - u8 pid_size; - u8 pid_off; - void *buffer; - struct urb *lme_urb; - void *usb_buffer; - int (*fe_set_voltage)(struct dvb_frontend *, fe_sec_voltage_t); - u8 dvb_usb_lme2510_firmware; -}; - -static int lme2510_bulk_write(struct usb_device *dev, - u8 *snd, int len, u8 pipe) -{ - int ret, actual_l; - - ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, pipe), - snd, len , &actual_l, 100); - return ret; -} - -static int lme2510_bulk_read(struct usb_device *dev, - u8 *rev, int len, u8 pipe) -{ - int ret, actual_l; - - ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, pipe), - rev, len , &actual_l, 200); - return ret; -} - -static int lme2510_usb_talk(struct dvb_usb_device *d, - u8 *wbuf, int wlen, u8 *rbuf, int rlen) -{ - struct lme2510_state *st = d->priv; - u8 *buff; - int ret = 0; - - if (st->usb_buffer == NULL) { - st->usb_buffer = kmalloc(64, GFP_KERNEL); - if (st->usb_buffer == NULL) { - info("MEM Error no memory"); - return -ENOMEM; - } - } - buff = st->usb_buffer; - - ret = mutex_lock_interruptible(&d->usb_mutex); - - if (ret < 0) - return -EAGAIN; - - /* the read/write capped at 64 */ - memcpy(buff, wbuf, (wlen < 64) ? wlen : 64); - - ret |= lme2510_bulk_write(d->udev, buff, wlen , 0x01); - - ret |= lme2510_bulk_read(d->udev, buff, (rlen < 64) ? - rlen : 64 , 0x01); - - if (rlen > 0) - memcpy(rbuf, buff, rlen); - - mutex_unlock(&d->usb_mutex); - - return (ret < 0) ? -ENODEV : 0; -} - -static int lme2510_stream_restart(struct dvb_usb_device *d) -{ - struct lme2510_state *st = d->priv; - u8 all_pids[] = LME_ALL_PIDS; - u8 stream_on[] = LME_ST_ON_W; - int ret; - u8 rbuff[1]; - if (st->pid_off) - ret = lme2510_usb_talk(d, all_pids, sizeof(all_pids), - rbuff, sizeof(rbuff)); - /*Restart Stream Command*/ - ret = lme2510_usb_talk(d, stream_on, sizeof(stream_on), - rbuff, sizeof(rbuff)); - return ret; -} - -static int lme2510_enable_pid(struct dvb_usb_device *d, u8 index, u16 pid_out) -{ - struct lme2510_state *st = d->priv; - static u8 pid_buff[] = LME_ZERO_PID; - static u8 rbuf[1]; - u8 pid_no = index * 2; - u8 pid_len = pid_no + 2; - int ret = 0; - deb_info(1, "PID Setting Pid %04x", pid_out); - - if (st->pid_size == 0) - ret |= lme2510_stream_restart(d); - - pid_buff[2] = pid_no; - pid_buff[3] = (u8)pid_out & 0xff; - pid_buff[4] = pid_no + 1; - pid_buff[5] = (u8)(pid_out >> 8); - - if (pid_len > st->pid_size) - st->pid_size = pid_len; - pid_buff[7] = 0x80 + st->pid_size; - - ret |= lme2510_usb_talk(d, pid_buff , - sizeof(pid_buff) , rbuf, sizeof(rbuf)); - - if (st->stream_on) - ret |= lme2510_stream_restart(d); - - return ret; -} - -static void lme2510_int_response(struct urb *lme_urb) -{ - struct dvb_usb_adapter *adap = lme_urb->context; - struct lme2510_state *st = adap_to_priv(adap); - static u8 *ibuf, *rbuf; - int i = 0, offset; - u32 key; - - switch (lme_urb->status) { - case 0: - case -ETIMEDOUT: - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - return; - default: - info("Error %x", lme_urb->status); - break; - } - - rbuf = (u8 *) lme_urb->transfer_buffer; - - offset = ((lme_urb->actual_length/8) > 4) - ? 4 : (lme_urb->actual_length/8) ; - - for (i = 0; i < offset; ++i) { - ibuf = (u8 *)&rbuf[i*8]; - deb_info(5, "INT O/S C =%02x C/O=%02x Type =%02x%02x", - offset, i, ibuf[0], ibuf[1]); - - switch (ibuf[0]) { - case 0xaa: - debug_data_snipet(1, "INT Remote data snipet", ibuf); - if ((ibuf[4] + ibuf[5]) == 0xff) { - key = ibuf[5]; - key += (ibuf[3] > 0) - ? (ibuf[3] ^ 0xff) << 8 : 0; - key += (ibuf[2] ^ 0xff) << 16; - deb_info(1, "INT Key =%08x", key); - if (adap_to_d(adap)->rc_dev != NULL) - rc_keydown(adap_to_d(adap)->rc_dev, - key, 0); - } - break; - case 0xbb: - switch (st->tuner_config) { - case TUNER_LG: - if (ibuf[2] > 0) - st->signal_lock = ibuf[2]; - st->signal_level = ibuf[4]; - st->signal_sn = ibuf[3]; - st->time_key = ibuf[7]; - break; - case TUNER_S7395: - case TUNER_S0194: - /* Tweak for earlier firmware*/ - if (ibuf[1] == 0x03) { - if (ibuf[2] > 1) - st->signal_lock = ibuf[2]; - st->signal_level = ibuf[3]; - st->signal_sn = ibuf[4]; - } else { - st->signal_level = ibuf[4]; - st->signal_sn = ibuf[5]; - st->signal_lock = - (st->signal_lock & 0xf7) + - ((ibuf[2] & 0x01) << 0x03); - } - break; - case TUNER_RS2000: - if (ibuf[1] == 0x3 && ibuf[6] == 0xff) - st->signal_lock = 0xff; - else - st->signal_lock = 0x00; - st->signal_level = ibuf[5]; - st->signal_sn = ibuf[4]; - st->time_key = ibuf[7]; - default: - break; - } - debug_data_snipet(5, "INT Remote data snipet in", ibuf); - break; - case 0xcc: - debug_data_snipet(1, "INT Control data snipet", ibuf); - break; - default: - debug_data_snipet(1, "INT Unknown data snipet", ibuf); - break; - } - } - usb_submit_urb(lme_urb, GFP_ATOMIC); -} - -static int lme2510_int_read(struct dvb_usb_adapter *adap) -{ - struct dvb_usb_device *d = adap_to_d(adap); - struct lme2510_state *lme_int = adap_to_priv(adap); - - lme_int->lme_urb = usb_alloc_urb(0, GFP_ATOMIC); - - if (lme_int->lme_urb == NULL) - return -ENOMEM; - - lme_int->buffer = usb_alloc_coherent(d->udev, 128, GFP_ATOMIC, - &lme_int->lme_urb->transfer_dma); - - if (lme_int->buffer == NULL) - return -ENOMEM; - - usb_fill_int_urb(lme_int->lme_urb, - d->udev, - usb_rcvintpipe(d->udev, 0xa), - lme_int->buffer, - 128, - lme2510_int_response, - adap, - 8); - - lme_int->lme_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - - usb_submit_urb(lme_int->lme_urb, GFP_ATOMIC); - info("INT Interrupt Service Started"); - - return 0; -} - -static int lme2510_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - struct dvb_usb_device *d = adap_to_d(adap); - struct lme2510_state *st = adap_to_priv(adap); - static u8 clear_pid_reg[] = LME_ALL_PIDS; - static u8 rbuf[1]; - int ret = 0; - - deb_info(1, "PID Clearing Filter"); - - mutex_lock(&d->i2c_mutex); - - if (!onoff) { - ret |= lme2510_usb_talk(d, clear_pid_reg, - sizeof(clear_pid_reg), rbuf, sizeof(rbuf)); - st->pid_off = true; - } else - st->pid_off = false; - - st->pid_size = 0; - - mutex_unlock(&d->i2c_mutex); - - return 0; -} - -static int lme2510_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, - int onoff) -{ - struct dvb_usb_device *d = adap_to_d(adap); - int ret = 0; - - deb_info(3, "%s PID=%04x Index=%04x onoff=%02x", __func__, - pid, index, onoff); - - if (onoff) { - mutex_lock(&d->i2c_mutex); - ret |= lme2510_enable_pid(d, index, pid); - mutex_unlock(&d->i2c_mutex); - } - - - return ret; -} - - -static int lme2510_return_status(struct dvb_usb_device *d) -{ - int ret = 0; - u8 *data; - - data = kzalloc(10, GFP_KERNEL); - if (!data) - return -ENOMEM; - - ret |= usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), - 0x06, 0x80, 0x0302, 0x00, data, 0x0006, 200); - info("Firmware Status: %x (%x)", ret , data[2]); - - ret = (ret < 0) ? -ENODEV : data[2]; - kfree(data); - return ret; -} - -static int lme2510_msg(struct dvb_usb_device *d, - u8 *wbuf, int wlen, u8 *rbuf, int rlen) -{ - int ret = 0; - struct lme2510_state *st = d->priv; - - if (st->i2c_talk_onoff == 1) { - - ret = lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); - - switch (st->tuner_config) { - case TUNER_LG: - if (wbuf[2] == 0x1c) { - if (wbuf[3] == 0x0e) { - st->signal_lock = rbuf[1]; - if ((st->stream_on & 1) && - (st->signal_lock & 0x10)) { - lme2510_stream_restart(d); - st->i2c_talk_onoff = 0; - } - msleep(80); - } - } - break; - case TUNER_S7395: - if (wbuf[2] == 0xd0) { - if (wbuf[3] == 0x24) { - st->signal_lock = rbuf[1]; - if ((st->stream_on & 1) && - (st->signal_lock & 0x8)) { - lme2510_stream_restart(d); - st->i2c_talk_onoff = 0; - } - } - } - break; - case TUNER_S0194: - if (wbuf[2] == 0xd0) { - if (wbuf[3] == 0x1b) { - st->signal_lock = rbuf[1]; - if ((st->stream_on & 1) && - (st->signal_lock & 0x8)) { - lme2510_stream_restart(d); - st->i2c_talk_onoff = 0; - } - } - } - break; - case TUNER_RS2000: - default: - break; - } - } else { - /* TODO rewrite this section */ - switch (st->tuner_config) { - case TUNER_LG: - switch (wbuf[3]) { - case 0x0e: - rbuf[0] = 0x55; - rbuf[1] = st->signal_lock; - break; - case 0x43: - rbuf[0] = 0x55; - rbuf[1] = st->signal_level; - break; - case 0x1c: - rbuf[0] = 0x55; - rbuf[1] = st->signal_sn; - break; - case 0x15: - case 0x16: - case 0x17: - case 0x18: - rbuf[0] = 0x55; - rbuf[1] = 0x00; - break; - default: - lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); - st->i2c_talk_onoff = 1; - break; - } - break; - case TUNER_S7395: - switch (wbuf[3]) { - case 0x10: - rbuf[0] = 0x55; - rbuf[1] = (st->signal_level & 0x80) - ? 0 : (st->signal_level * 2); - break; - case 0x2d: - rbuf[0] = 0x55; - rbuf[1] = st->signal_sn; - break; - case 0x24: - rbuf[0] = 0x55; - rbuf[1] = st->signal_lock; - break; - case 0x2e: - case 0x26: - case 0x27: - rbuf[0] = 0x55; - rbuf[1] = 0x00; - break; - default: - lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); - st->i2c_talk_onoff = 1; - break; - } - break; - case TUNER_S0194: - switch (wbuf[3]) { - case 0x18: - rbuf[0] = 0x55; - rbuf[1] = (st->signal_level & 0x80) - ? 0 : (st->signal_level * 2); - break; - case 0x24: - rbuf[0] = 0x55; - rbuf[1] = st->signal_sn; - break; - case 0x1b: - rbuf[0] = 0x55; - rbuf[1] = st->signal_lock; - break; - case 0x19: - case 0x25: - case 0x1e: - case 0x1d: - rbuf[0] = 0x55; - rbuf[1] = 0x00; - break; - default: - lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); - st->i2c_talk_onoff = 1; - break; - } - break; - case TUNER_RS2000: - switch (wbuf[3]) { - case 0x8c: - rbuf[0] = 0x55; - rbuf[1] = 0xff; - if (st->last_key == st->time_key) { - st->key_timeout++; - if (st->key_timeout > 5) - rbuf[1] = 0; - } else - st->key_timeout = 0; - st->last_key = st->time_key; - break; - default: - lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); - st->i2c_talk_onoff = 1; - break; - } - default: - break; - } - - deb_info(4, "I2C From Interrupt Message out(%02x) in(%02x)", - wbuf[3], rbuf[1]); - - } - - return ret; -} - - -static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - struct lme2510_state *st = d->priv; - static u8 obuf[64], ibuf[64]; - int i, read, read_o; - u16 len; - u8 gate = st->i2c_gate; - - mutex_lock(&d->i2c_mutex); - - if (gate == 0) - gate = 5; - - for (i = 0; i < num; i++) { - read_o = 1 & (msg[i].flags & I2C_M_RD); - read = i+1 < num && (msg[i+1].flags & I2C_M_RD); - read |= read_o; - gate = (msg[i].addr == st->i2c_tuner_addr) - ? (read) ? st->i2c_tuner_gate_r - : st->i2c_tuner_gate_w - : st->i2c_gate; - obuf[0] = gate | (read << 7); - - if (gate == 5) - obuf[1] = (read) ? 2 : msg[i].len + 1; - else - obuf[1] = msg[i].len + read + 1; - - obuf[2] = msg[i].addr; - if (read) { - if (read_o) - len = 3; - else { - memcpy(&obuf[3], msg[i].buf, msg[i].len); - obuf[msg[i].len+3] = msg[i+1].len; - len = msg[i].len+4; - } - } else { - memcpy(&obuf[3], msg[i].buf, msg[i].len); - len = msg[i].len+3; - } - - if (lme2510_msg(d, obuf, len, ibuf, 64) < 0) { - deb_info(1, "i2c transfer failed."); - mutex_unlock(&d->i2c_mutex); - return -EAGAIN; - } - - if (read) { - if (read_o) - memcpy(msg[i].buf, &ibuf[1], msg[i].len); - else { - memcpy(msg[i+1].buf, &ibuf[1], msg[i+1].len); - i++; - } - } - } - - mutex_unlock(&d->i2c_mutex); - return i; -} - -static u32 lme2510_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm lme2510_i2c_algo = { - .master_xfer = lme2510_i2c_xfer, - .functionality = lme2510_i2c_func, -}; - -static int lme2510_streaming_ctrl(struct dvb_frontend *fe, int onoff) -{ - struct dvb_usb_adapter *adap = fe_to_adap(fe); - struct dvb_usb_device *d = adap_to_d(adap); - struct lme2510_state *st = adap_to_priv(adap); - static u8 clear_reg_3[] = LME_ALL_PIDS; - static u8 rbuf[1]; - int ret = 0, rlen = sizeof(rbuf); - - deb_info(1, "STM (%02x)", onoff); - - /* Streaming is started by FE_HAS_LOCK */ - if (onoff == 1) - st->stream_on = 1; - else { - deb_info(1, "STM Steam Off"); - /* mutex is here only to avoid collision with I2C */ - mutex_lock(&d->i2c_mutex); - - ret = lme2510_usb_talk(d, clear_reg_3, - sizeof(clear_reg_3), rbuf, rlen); - st->stream_on = 0; - st->i2c_talk_onoff = 1; - - mutex_unlock(&d->i2c_mutex); - } - - return (ret < 0) ? -ENODEV : 0; -} - -static u8 check_sum(u8 *p, u8 len) -{ - u8 sum = 0; - while (len--) - sum += *p++; - return sum; -} - -static int lme2510_download_firmware(struct dvb_usb_device *d, - const struct firmware *fw) -{ - int ret = 0; - u8 *data; - u16 j, wlen, len_in, start, end; - u8 packet_size, dlen, i; - u8 *fw_data; - - packet_size = 0x31; - len_in = 1; - - data = kzalloc(128, GFP_KERNEL); - if (!data) { - info("FRM Could not start Firmware Download"\ - "(Buffer allocation failed)"); - return -ENOMEM; - } - - info("FRM Starting Firmware Download"); - - for (i = 1; i < 3; i++) { - start = (i == 1) ? 0 : 512; - end = (i == 1) ? 512 : fw->size; - for (j = start; j < end; j += (packet_size+1)) { - fw_data = (u8 *)(fw->data + j); - if ((end - j) > packet_size) { - data[0] = i; - dlen = packet_size; - } else { - data[0] = i | 0x80; - dlen = (u8)(end - j)-1; - } - data[1] = dlen; - memcpy(&data[2], fw_data, dlen+1); - wlen = (u8) dlen + 4; - data[wlen-1] = check_sum(fw_data, dlen+1); - deb_info(1, "Data S=%02x:E=%02x CS= %02x", data[3], - data[dlen+2], data[dlen+3]); - lme2510_usb_talk(d, data, wlen, data, len_in); - ret |= (data[0] == 0x88) ? 0 : -1; - } - } - - usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), - 0x06, 0x80, 0x0200, 0x00, data, 0x0109, 1000); - - - data[0] = 0x8a; - len_in = 1; - msleep(2000); - lme2510_usb_talk(d, data, len_in, data, len_in); - msleep(400); - - if (ret < 0) - info("FRM Firmware Download Failed (%04x)" , ret); - else - info("FRM Firmware Download Completed - Resetting Device"); - - kfree(data); - return RECONNECTS_USB; -} - -static void lme_coldreset(struct dvb_usb_device *d) -{ - u8 data[1] = {0}; - data[0] = 0x0a; - info("FRM Firmware Cold Reset"); - - lme2510_usb_talk(d, data, sizeof(data), data, sizeof(data)); - - return; -} - -static const char fw_c_s7395[] = LME2510_C_S7395; -static const char fw_c_lg[] = LME2510_C_LG; -static const char fw_c_s0194[] = LME2510_C_S0194; -static const char fw_c_rs2000[] = LME2510_C_RS2000; -static const char fw_lg[] = LME2510_LG; -static const char fw_s0194[] = LME2510_S0194; - -const char *lme_firmware_switch(struct dvb_usb_device *d, int cold) -{ - struct lme2510_state *st = d->priv; - struct usb_device *udev = d->udev; - const struct firmware *fw = NULL; - const char *fw_lme; - int ret = 0; - - cold = (cold > 0) ? (cold & 1) : 0; - - switch (le16_to_cpu(udev->descriptor.idProduct)) { - case 0x1122: - switch (st->dvb_usb_lme2510_firmware) { - default: - st->dvb_usb_lme2510_firmware = TUNER_S0194; - case TUNER_S0194: - fw_lme = fw_s0194; - ret = request_firmware(&fw, fw_lme, &udev->dev); - if (ret == 0) { - cold = 0; - break; - } - st->dvb_usb_lme2510_firmware = TUNER_LG; - case TUNER_LG: - fw_lme = fw_lg; - ret = request_firmware(&fw, fw_lme, &udev->dev); - if (ret == 0) - break; - st->dvb_usb_lme2510_firmware = TUNER_DEFAULT; - break; - } - break; - case 0x1120: - switch (st->dvb_usb_lme2510_firmware) { - default: - st->dvb_usb_lme2510_firmware = TUNER_S7395; - case TUNER_S7395: - fw_lme = fw_c_s7395; - ret = request_firmware(&fw, fw_lme, &udev->dev); - if (ret == 0) { - cold = 0; - break; - } - st->dvb_usb_lme2510_firmware = TUNER_LG; - case TUNER_LG: - fw_lme = fw_c_lg; - ret = request_firmware(&fw, fw_lme, &udev->dev); - if (ret == 0) - break; - st->dvb_usb_lme2510_firmware = TUNER_S0194; - case TUNER_S0194: - fw_lme = fw_c_s0194; - ret = request_firmware(&fw, fw_lme, &udev->dev); - if (ret == 0) - break; - st->dvb_usb_lme2510_firmware = TUNER_DEFAULT; - cold = 0; - break; - } - break; - case 0x22f0: - fw_lme = fw_c_rs2000; - st->dvb_usb_lme2510_firmware = TUNER_RS2000; - break; - default: - fw_lme = fw_c_s7395; - } - - release_firmware(fw); - - if (cold) { - dvb_usb_lme2510_firmware = st->dvb_usb_lme2510_firmware; - info("FRM Changing to %s firmware", fw_lme); - lme_coldreset(d); - return NULL; - } - - return fw_lme; -} - -static int lme2510_kill_urb(struct usb_data_stream *stream) -{ - int i; - - for (i = 0; i < stream->urbs_submitted; i++) { - deb_info(3, "killing URB no. %d.", i); - /* stop the URB */ - usb_kill_urb(stream->urb_list[i]); - } - stream->urbs_submitted = 0; - - return 0; -} - -static struct tda10086_config tda10086_config = { - .demod_address = 0x1c, - .invert = 0, - .diseqc_tone = 1, - .xtal_freq = TDA10086_XTAL_16M, -}; - -static struct stv0288_config lme_config = { - .demod_address = 0xd0, - .min_delay_ms = 15, - .inittab = s7395_inittab, -}; - -static struct ix2505v_config lme_tuner = { - .tuner_address = 0xc0, - .min_delay_ms = 100, - .tuner_gain = 0x0, - .tuner_chargepump = 0x3, -}; - -static struct stv0299_config sharp_z0194_config = { - .demod_address = 0xd0, - .inittab = sharp_z0194a_inittab, - .mclk = 88000000UL, - .invert = 0, - .skip_reinit = 0, - .lock_output = STV0299_LOCKOUTPUT_1, - .volt13_op0_op1 = STV0299_VOLT13_OP1, - .min_delay_ms = 100, - .set_symbol_rate = sharp_z0194a_set_symbol_rate, -}; - -static int dm04_rs2000_set_ts_param(struct dvb_frontend *fe, - int caller) -{ - struct dvb_usb_adapter *adap = fe_to_adap(fe); - struct dvb_usb_device *d = adap_to_d(adap); - struct lme2510_state *st = d->priv; - - mutex_lock(&d->i2c_mutex); - if ((st->i2c_talk_onoff == 1) && (st->stream_on & 1)) { - st->i2c_talk_onoff = 0; - lme2510_stream_restart(d); - } - mutex_unlock(&d->i2c_mutex); - - return 0; -} - -static struct m88rs2000_config m88rs2000_config = { - .demod_addr = 0xd0, - .tuner_addr = 0xc0, - .set_ts_params = dm04_rs2000_set_ts_param, -}; - -static int dm04_lme2510_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) -{ - struct dvb_usb_device *d = fe_to_d(fe); - struct lme2510_state *st = fe_to_priv(fe); - static u8 voltage_low[] = LME_VOLTAGE_L; - static u8 voltage_high[] = LME_VOLTAGE_H; - static u8 rbuf[1]; - int ret = 0, len = 3, rlen = 1; - - mutex_lock(&d->i2c_mutex); - - switch (voltage) { - case SEC_VOLTAGE_18: - ret |= lme2510_usb_talk(d, - voltage_high, len, rbuf, rlen); - break; - - case SEC_VOLTAGE_OFF: - case SEC_VOLTAGE_13: - default: - ret |= lme2510_usb_talk(d, - voltage_low, len, rbuf, rlen); - break; - } - - mutex_unlock(&d->i2c_mutex); - - if (st->tuner_config == TUNER_RS2000) - if (st->fe_set_voltage) - st->fe_set_voltage(fe, voltage); - - - return (ret < 0) ? -ENODEV : 0; -} - -static int dm04_rs2000_read_signal_strength(struct dvb_frontend *fe, - u16 *strength) -{ - struct lme2510_state *st = fe_to_priv(fe); - - *strength = (u16)((u32)st->signal_level * 0xffff / 0xff); - - return 0; -} - -static int dm04_rs2000_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct lme2510_state *st = fe_to_priv(fe); - - *snr = (u16)((u32)st->signal_sn * 0xffff / 0x7f); - - return 0; -} - -static int dm04_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - *ber = 0; - - return 0; -} - -static int dm04_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) -{ - *ucblocks = 0; - - return 0; -} - -static int lme_name(struct dvb_usb_adapter *adap) -{ - struct dvb_usb_device *d = adap_to_d(adap); - struct lme2510_state *st = adap_to_priv(adap); - const char *desc = d->name; - char *fe_name[] = {"", " LG TDQY-P001F", " SHARP:BS2F7HZ7395", - " SHARP:BS2F7HZ0194", " RS2000"}; - char *name = adap->fe[0]->ops.info.name; - - strlcpy(name, desc, 128); - strlcat(name, fe_name[st->tuner_config], 128); - - return 0; -} - -static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct dvb_usb_device *d = adap_to_d(adap); - struct lme2510_state *st = d->priv; - int ret = 0; - - st->i2c_talk_onoff = 1; - switch (le16_to_cpu(d->udev->descriptor.idProduct)) { - case 0x1122: - case 0x1120: - st->i2c_gate = 4; - adap->fe[0] = dvb_attach(tda10086_attach, - &tda10086_config, &d->i2c_adap); - if (adap->fe[0]) { - info("TUN Found Frontend TDA10086"); - st->i2c_tuner_gate_w = 4; - st->i2c_tuner_gate_r = 4; - st->i2c_tuner_addr = 0xc0; - st->tuner_config = TUNER_LG; - if (st->dvb_usb_lme2510_firmware != TUNER_LG) { - st->dvb_usb_lme2510_firmware = TUNER_LG; - ret = lme_firmware_switch(d, 1) ? 0 : -ENODEV; - } - break; - } - - st->i2c_gate = 4; - adap->fe[0] = dvb_attach(stv0299_attach, - &sharp_z0194_config, &d->i2c_adap); - if (adap->fe[0]) { - info("FE Found Stv0299"); - st->i2c_tuner_gate_w = 4; - st->i2c_tuner_gate_r = 5; - st->i2c_tuner_addr = 0xc0; - st->tuner_config = TUNER_S0194; - if (st->dvb_usb_lme2510_firmware != TUNER_S0194) { - st->dvb_usb_lme2510_firmware = TUNER_S0194; - ret = lme_firmware_switch(d, 1) ? 0 : -ENODEV; - } - break; - } - - st->i2c_gate = 5; - adap->fe[0] = dvb_attach(stv0288_attach, &lme_config, - &d->i2c_adap); - - if (adap->fe[0]) { - info("FE Found Stv0288"); - st->i2c_tuner_gate_w = 4; - st->i2c_tuner_gate_r = 5; - st->i2c_tuner_addr = 0xc0; - st->tuner_config = TUNER_S7395; - if (st->dvb_usb_lme2510_firmware != TUNER_S7395) { - st->dvb_usb_lme2510_firmware = TUNER_S7395; - ret = lme_firmware_switch(d, 1) ? 0 : -ENODEV; - } - break; - } - case 0x22f0: - st->i2c_gate = 5; - adap->fe[0] = dvb_attach(m88rs2000_attach, - &m88rs2000_config, &d->i2c_adap); - - if (adap->fe[0]) { - info("FE Found M88RS2000"); - st->i2c_tuner_gate_w = 5; - st->i2c_tuner_gate_r = 5; - st->i2c_tuner_addr = 0xc0; - st->tuner_config = TUNER_RS2000; - st->fe_set_voltage = - adap->fe[0]->ops.set_voltage; - - adap->fe[0]->ops.read_signal_strength = - dm04_rs2000_read_signal_strength; - adap->fe[0]->ops.read_snr = - dm04_rs2000_read_snr; - adap->fe[0]->ops.read_ber = - dm04_read_ber; - adap->fe[0]->ops.read_ucblocks = - dm04_read_ucblocks; - } - break; - } - - if (adap->fe[0] == NULL) { - info("DM04/QQBOX Not Powered up or not Supported"); - return -ENODEV; - } - - if (ret) { - if (adap->fe[0]) { - dvb_frontend_detach(adap->fe[0]); - adap->fe[0] = NULL; - } - d->rc_map = NULL; - return -ENODEV; - } - - adap->fe[0]->ops.set_voltage = dm04_lme2510_set_voltage; - ret = lme_name(adap); - return ret; -} - -static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap) -{ - struct dvb_usb_device *d = adap_to_d(adap); - struct lme2510_state *st = adap_to_priv(adap); - char *tun_msg[] = {"", "TDA8263", "IX2505V", "DVB_PLL_OPERA", "RS2000"}; - int ret = 0; - - switch (st->tuner_config) { - case TUNER_LG: - if (dvb_attach(tda826x_attach, adap->fe[0], 0xc0, - &d->i2c_adap, 1)) - ret = st->tuner_config; - break; - case TUNER_S7395: - if (dvb_attach(ix2505v_attach , adap->fe[0], &lme_tuner, - &d->i2c_adap)) - ret = st->tuner_config; - break; - case TUNER_S0194: - if (dvb_attach(dvb_pll_attach , adap->fe[0], 0xc0, - &d->i2c_adap, DVB_PLL_OPERA1)) - ret = st->tuner_config; - break; - case TUNER_RS2000: - ret = st->tuner_config; - break; - default: - break; - } - - if (ret) - info("TUN Found %s tuner", tun_msg[ret]); - else { - info("TUN No tuner found --- resetting device"); - lme_coldreset(d); - return -ENODEV; - } - - /* Start the Interrupt*/ - ret = lme2510_int_read(adap); - if (ret < 0) { - info("INT Unable to start Interrupt Service"); - return -ENODEV; - } - - return ret; -} - -static int lme2510_powerup(struct dvb_usb_device *d, int onoff) -{ - struct lme2510_state *st = d->priv; - static u8 lnb_on[] = LNB_ON; - static u8 lnb_off[] = LNB_OFF; - static u8 rbuf[1]; - int ret = 0, len = 3, rlen = 1; - - mutex_lock(&d->i2c_mutex); - - if (onoff) - ret = lme2510_usb_talk(d, lnb_on, len, rbuf, rlen); - else - ret = lme2510_usb_talk(d, lnb_off, len, rbuf, rlen); - - st->i2c_talk_onoff = 1; - - mutex_unlock(&d->i2c_mutex); - - return ret; -} - -static int lme2510_get_adapter_count(struct dvb_usb_device *d) -{ - return 1; -} - -static int lme2510_identify_state(struct dvb_usb_device *d, const char **name) -{ - struct lme2510_state *st = d->priv; - - usb_reset_configuration(d->udev); - - usb_set_interface(d->udev, - d->intf->cur_altsetting->desc.bInterfaceNumber, 1); - - st->dvb_usb_lme2510_firmware = dvb_usb_lme2510_firmware; - - if (lme2510_return_status(d) == 0x44) { - *name = lme_firmware_switch(d, 0); - return COLD; - } - - return 0; -} - -static int lme2510_get_stream_config(struct dvb_frontend *fe, u8 *ts_type, - struct usb_data_stream_properties *stream) -{ - struct dvb_usb_adapter *adap = fe_to_adap(fe); - struct dvb_usb_device *d = adap_to_d(adap); - - if (adap == NULL) - return 0; - /* Turn PID filter on the fly by module option */ - if (pid_filter == 2) { - adap->pid_filtering = 1; - adap->max_feed_count = 15; - } - - if (!(le16_to_cpu(d->udev->descriptor.idProduct) - == 0x1122)) - stream->endpoint = 0x8; - - return 0; -} - -static int lme2510_get_rc_config(struct dvb_usb_device *d, - struct dvb_usb_rc *rc) -{ - rc->allowed_protos = RC_TYPE_NEC; - return 0; -} - -static void *lme2510_exit_int(struct dvb_usb_device *d) -{ - struct lme2510_state *st = d->priv; - struct dvb_usb_adapter *adap = &d->adapter[0]; - void *buffer = NULL; - - if (adap != NULL) { - lme2510_kill_urb(&adap->stream); - } - - if (st->usb_buffer != NULL) { - st->i2c_talk_onoff = 1; - st->signal_lock = 0; - st->signal_level = 0; - st->signal_sn = 0; - buffer = st->usb_buffer; - } - - if (st->lme_urb != NULL) { - usb_kill_urb(st->lme_urb); - usb_free_coherent(d->udev, 128, st->buffer, - st->lme_urb->transfer_dma); - info("Interrupt Service Stopped"); - } - - return buffer; -} - -static void lme2510_exit(struct dvb_usb_device *d) -{ - void *usb_buffer; - - if (d != NULL) { - usb_buffer = lme2510_exit_int(d); - if (usb_buffer != NULL) - kfree(usb_buffer); - } -} - -static struct dvb_usb_device_properties lme2510_props = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .bInterfaceNumber = 0, - .adapter_nr = adapter_nr, - .size_of_priv = sizeof(struct lme2510_state), - - .download_firmware = lme2510_download_firmware, - - .power_ctrl = lme2510_powerup, - .identify_state = lme2510_identify_state, - .i2c_algo = &lme2510_i2c_algo, - - .frontend_attach = dm04_lme2510_frontend_attach, - .tuner_attach = dm04_lme2510_tuner, - .get_stream_config = lme2510_get_stream_config, - .get_adapter_count = lme2510_get_adapter_count, - .streaming_ctrl = lme2510_streaming_ctrl, - - .get_rc_config = lme2510_get_rc_config, - - .exit = lme2510_exit, - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER| - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 15, - .pid_filter = lme2510_pid_filter, - .pid_filter_ctrl = lme2510_pid_filter_ctrl, - .stream = - DVB_USB_STREAM_BULK(0x86, 10, 4096), - }, - { - } - }, -}; - -static const struct usb_device_id lme2510_id_table[] = { - { DVB_USB_DEVICE(0x3344, 0x1122, &lme2510_props, - "DM04_LME2510_DVB-S", RC_MAP_LME2510) }, - { DVB_USB_DEVICE(0x3344, 0x1120, &lme2510_props, - "DM04_LME2510C_DVB-S", RC_MAP_LME2510) }, - { DVB_USB_DEVICE(0x3344, 0x22f0, &lme2510_props, - "DM04_LME2510C_DVB-S RS2000", RC_MAP_LME2510) }, - {} /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, lme2510_id_table); - -static struct usb_driver lme2510_driver = { - .name = KBUILD_MODNAME, - .probe = dvb_usbv2_probe, - .disconnect = dvb_usbv2_disconnect, - .id_table = lme2510_id_table, - .no_dynamic_id = 1, - .soft_unbind = 1, -}; - -module_usb_driver(lme2510_driver); - -MODULE_AUTHOR("Malcolm Priestley "); -MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0"); -MODULE_VERSION("2.06"); -MODULE_LICENSE("GPL"); -MODULE_FIRMWARE(LME2510_C_S7395); -MODULE_FIRMWARE(LME2510_C_LG); -MODULE_FIRMWARE(LME2510_C_S0194); -MODULE_FIRMWARE(LME2510_C_RS2000); -MODULE_FIRMWARE(LME2510_LG); -MODULE_FIRMWARE(LME2510_S0194); - diff --git a/drivers/media/dvb/dvb-usb/lmedm04.h b/drivers/media/dvb/dvb-usb/lmedm04.h deleted file mode 100644 index e9c207205c2f..000000000000 --- a/drivers/media/dvb/dvb-usb/lmedm04.h +++ /dev/null @@ -1,175 +0,0 @@ -/* DVB USB compliant linux driver for - * - * DM04/QQBOX DVB-S USB BOX LME2510C + SHARP:BS2F7HZ7395 - * LME2510C + LG TDQY-P001F - * LME2510 + LG TDQY-P001F - * - * MVB7395 (LME2510C+SHARP:BS2F7HZ7395) - * SHARP:BS2F7HZ7395 = (STV0288+Sharp IX2505V) - * - * MVB001F (LME2510+LGTDQT-P001F) - * LG TDQY - P001F =(TDA8263 + TDA10086H) - * - * MVB0001F (LME2510C+LGTDQT-P001F) - * - * 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, version 2. - * * - * see Documentation/dvb/README.dvb-usb for more information - */ -#ifndef _DVB_USB_LME2510_H_ -#define _DVB_USB_LME2510_H_ - -/* Streamer & PID - * - * Note: These commands do not actually stop the streaming - * but form some kind of packet filtering/stream count - * or tuning related functions. - * 06 XX - * offset 1 = 00 Enable Streaming - * - * - * PID - * 03 XX XX ----> reg number ---> setting....20 XX - * offset 1 = length - * offset 2 = start of data - * end byte -1 = 20 - * end byte = clear pid always a0, other wise 9c, 9a ?? - * -*/ -#define LME_ST_ON_W {0x06, 0x00} -#define LME_CLEAR_PID {0x03, 0x02, 0x20, 0xa0} -#define LME_ZERO_PID {0x03, 0x06, 0x00, 0x00, 0x01, 0x00, 0x20, 0x9c} -#define LME_ALL_PIDS {0x03, 0x06, 0x00, 0xff, 0x01, 0x1f, 0x20, 0x81} - -/* LNB Voltage - * 07 XX XX - * offset 1 = 01 - * offset 2 = 00=Voltage low 01=Voltage high - * - * LNB Power - * 03 01 XX - * offset 2 = 00=ON 01=OFF - */ - -#define LME_VOLTAGE_L {0x07, 0x01, 0x00} -#define LME_VOLTAGE_H {0x07, 0x01, 0x01} -#define LNB_ON {0x3a, 0x01, 0x00} -#define LNB_OFF {0x3a, 0x01, 0x01} - -/* Initial stv0288 settings for 7395 Frontend */ -static u8 s7395_inittab[] = { - 0x01, 0x15, - 0x02, 0x20, - 0x03, 0xa0, - 0x04, 0xa0, - 0x05, 0x12, - 0x06, 0x00, - 0x09, 0x00, - 0x0a, 0x04, - 0x0b, 0x00, - 0x0c, 0x00, - 0x0d, 0x00, - 0x0e, 0xc1, - 0x0f, 0x54, - 0x11, 0x7a, - 0x12, 0x03, - 0x13, 0x48, - 0x14, 0x84, - 0x15, 0xc5, - 0x16, 0xb8, - 0x17, 0x9c, - 0x18, 0x00, - 0x19, 0xa6, - 0x1a, 0x88, - 0x1b, 0x8f, - 0x1c, 0xf0, - 0x20, 0x0b, - 0x21, 0x54, - 0x22, 0xff, - 0x23, 0x01, - 0x28, 0x46, - 0x29, 0x66, - 0x2a, 0x90, - 0x2b, 0xfa, - 0x2c, 0xd9, - 0x30, 0x0, - 0x31, 0x1e, - 0x32, 0x14, - 0x33, 0x0f, - 0x34, 0x09, - 0x35, 0x0c, - 0x36, 0x05, - 0x37, 0x2f, - 0x38, 0x16, - 0x39, 0xbd, - 0x3a, 0x0, - 0x3b, 0x13, - 0x3c, 0x11, - 0x3d, 0x30, - 0x40, 0x63, - 0x41, 0x04, - 0x42, 0x20, - 0x43, 0x00, - 0x44, 0x00, - 0x45, 0x00, - 0x46, 0x00, - 0x47, 0x00, - 0x4a, 0x00, - 0x50, 0x10, - 0x51, 0x36, - 0x52, 0x21, - 0x53, 0x94, - 0x54, 0xb2, - 0x55, 0x29, - 0x56, 0x64, - 0x57, 0x2b, - 0x58, 0x54, - 0x59, 0x86, - 0x5a, 0x00, - 0x5b, 0x9b, - 0x5c, 0x08, - 0x5d, 0x7f, - 0x5e, 0xff, - 0x5f, 0x8d, - 0x70, 0x0, - 0x71, 0x0, - 0x72, 0x0, - 0x74, 0x0, - 0x75, 0x0, - 0x76, 0x0, - 0x81, 0x0, - 0x82, 0x3f, - 0x83, 0x3f, - 0x84, 0x0, - 0x85, 0x0, - 0x88, 0x0, - 0x89, 0x0, - 0x8a, 0x0, - 0x8b, 0x0, - 0x8c, 0x0, - 0x90, 0x0, - 0x91, 0x0, - 0x92, 0x0, - 0x93, 0x0, - 0x94, 0x1c, - 0x97, 0x0, - 0xa0, 0x48, - 0xa1, 0x0, - 0xb0, 0xb8, - 0xb1, 0x3a, - 0xb2, 0x10, - 0xb3, 0x82, - 0xb4, 0x80, - 0xb5, 0x82, - 0xb6, 0x82, - 0xb7, 0x82, - 0xb8, 0x20, - 0xb9, 0x0, - 0xf0, 0x0, - 0xf1, 0x0, - 0xf2, 0xc0, - 0xff, 0xff, -}; -#endif