diff options
Diffstat (limited to 'drivers/media/dvb/dvb-usb/lmedm04.c')
-rw-r--r-- | drivers/media/dvb/dvb-usb/lmedm04.c | 329 |
1 files changed, 177 insertions, 152 deletions
diff --git a/drivers/media/dvb/dvb-usb/lmedm04.c b/drivers/media/dvb/dvb-usb/lmedm04.c index d939fbbf9fe6..9eea4188303b 100644 --- a/drivers/media/dvb/dvb-usb/lmedm04.c +++ b/drivers/media/dvb/dvb-usb/lmedm04.c @@ -61,7 +61,7 @@ #define DVB_USB_LOG_PREFIX "LME2510(C)" #include <linux/usb.h> #include <linux/usb/input.h> -#include <media/ir-core.h> +#include <media/rc-core.h> #include "dvb-usb.h" #include "lmedm04.h" @@ -112,7 +112,6 @@ struct lme2510_state { u8 i2c_tuner_gate_r; u8 i2c_tuner_addr; u8 stream_on; - u8 one_tune; void *buffer; struct urb *lme_urb; void *usb_buffer; @@ -125,7 +124,7 @@ static int lme2510_bulk_write(struct usb_device *dev, int ret, actual_l; ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, pipe), - snd, len , &actual_l, 500); + snd, len , &actual_l, 100); return ret; } @@ -135,7 +134,7 @@ static int lme2510_bulk_read(struct usb_device *dev, int ret, actual_l; ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, pipe), - rev, len , &actual_l, 500); + rev, len , &actual_l, 200); return ret; } @@ -167,7 +166,7 @@ static int lme2510_usb_talk(struct dvb_usb_device *d, ret |= lme2510_bulk_write(d->udev, buff, wlen , 0x01); - msleep(12); + msleep(10); ret |= usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, 0x01)); @@ -182,15 +181,13 @@ static int lme2510_usb_talk(struct dvb_usb_device *d, return (ret < 0) ? -ENODEV : 0; } -static int lme2510_usb_talk_restart(struct dvb_usb_device *d, - u8 *wbuf, int wlen, u8 *rbuf, int rlen) { +static int lme2510_stream_restart(struct dvb_usb_device *d) +{ static u8 stream_on[] = LME_ST_ON_W; int ret; u8 rbuff[10]; - /*Send Normal Command*/ - ret = lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); /*Restart Stream Command*/ - ret |= lme2510_usb_talk(d, stream_on, sizeof(stream_on), + ret = lme2510_usb_talk(d, stream_on, sizeof(stream_on), rbuff, sizeof(rbuff)); return ret; } @@ -201,7 +198,7 @@ static int lme2510_remote_keypress(struct dvb_usb_adapter *adap, u16 keypress) deb_info(1, "INT Key Keypress =%04x", keypress); if (keypress > 0) - ir_keydown(d->rc_input_dev, keypress, 0); + rc_keydown(d->rc_dev, keypress, 0); return 0; } @@ -254,11 +251,16 @@ static void lme2510_int_response(struct urb *lme_urb) case TUNER_S7395: /* 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; default: @@ -341,11 +343,10 @@ static int lme2510_msg(struct dvb_usb_device *d, st->signal_lock = rbuf[1]; if ((st->stream_on & 1) && (st->signal_lock & 0x10)) { - lme2510_usb_talk_restart(d, - wbuf, wlen, rbuf, rlen); + lme2510_stream_restart(d); st->i2c_talk_onoff = 0; } - msleep(80); + msleep(80); } } break; @@ -355,15 +356,12 @@ static int lme2510_msg(struct dvb_usb_device *d, st->signal_lock = rbuf[1]; if ((st->stream_on & 1) && (st->signal_lock & 0x8)) { - lme2510_usb_talk_restart(d, - wbuf, wlen, rbuf, rlen); + lme2510_stream_restart(d); st->i2c_talk_onoff = 0; } } if ((wbuf[3] != 0x6) & (wbuf[3] != 0x5)) msleep(5); - - } break; default: @@ -385,18 +383,16 @@ static int lme2510_msg(struct dvb_usb_device *d, rbuf[0] = 0x55; rbuf[1] = st->signal_sn; break; - /*DiSEqC functions as per TDA10086*/ - case 0x36: - case 0x48: - case 0x49: - case 0x4a: - case 0x4b: - case 0x4c: - case 0x4d: - if (wbuf[2] == 0x1c) - lme2510_usb_talk_restart(d, - wbuf, wlen, rbuf, rlen); + 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; @@ -413,39 +409,22 @@ static int lme2510_msg(struct dvb_usb_device *d, break; case 0x24: rbuf[0] = 0x55; - rbuf[1] = (st->signal_level & 0x80) - ? 0 : st->signal_lock; - break; - case 0x6: - if (wbuf[2] == 0xd0) - lme2510_usb_talk(d, - wbuf, wlen, rbuf, rlen); - break; - case 0x1: - if (st->one_tune > 0) - break; - st->one_tune++; - st->i2c_talk_onoff = 1; - /*DiSEqC functions as per STV0288*/ - case 0x5: - case 0x7: - case 0x8: - case 0x9: - case 0xa: - case 0xb: - if (wbuf[2] == 0xd0) - lme2510_usb_talk_restart(d, - wbuf, wlen, rbuf, rlen); + rbuf[1] = st->signal_lock; break; - default: + 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; default: break; - } deb_info(4, "I2C From Interupt Message out(%02x) in(%02x)", @@ -548,35 +527,26 @@ static int lme2510_identify_state(struct usb_device *udev, static int lme2510_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) { struct lme2510_state *st = adap->dev->priv; - static u8 stream_on[] = LME_ST_ON_W; static u8 clear_reg_3[] = LME_CLEAR_PID; static u8 rbuf[1]; - static u8 timeout; - int ret = 0, len = 2, rlen = sizeof(rbuf); + int ret = 0, rlen = sizeof(rbuf); deb_info(1, "STM (%02x)", onoff); - if (onoff == 1) { - st->i2c_talk_onoff = 0; - timeout = 0; - /* wait for i2C to be free */ - while (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0) { - timeout++; - if (timeout > 5) - return -ENODEV; - } - msleep(100); - ret |= lme2510_usb_talk(adap->dev, - stream_on, len, rbuf, rlen); + /* Streaming is started by FE_HAS_LOCK */ + if (onoff == 1) st->stream_on = 1; - st->one_tune = 0; - mutex_unlock(&adap->dev->i2c_mutex); - } else { + else { deb_info(1, "STM Steam Off"); + /* mutex is here only to avoid collision with I2C */ + ret = mutex_lock_interruptible(&adap->dev->i2c_mutex); + ret |= lme2510_usb_talk(adap->dev, clear_reg_3, sizeof(clear_reg_3), rbuf, rlen); st->stream_on = 0; st->i2c_talk_onoff = 1; + + mutex_unlock(&adap->dev->i2c_mutex); } return (ret < 0) ? -ENODEV : 0; @@ -585,41 +555,40 @@ static int lme2510_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) static int lme2510_int_service(struct dvb_usb_adapter *adap) { struct dvb_usb_device *d = adap->dev; - struct input_dev *input_dev; - char *ir_codes = RC_MAP_LME2510; - int ret = 0; + struct rc_dev *rc; + int ret; info("STA Configuring Remote"); - usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys)); - - strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys)); - - input_dev = input_allocate_device(); - if (!input_dev) + rc = rc_allocate_device(); + if (!rc) return -ENOMEM; - input_dev->name = "LME2510 Remote Control"; - input_dev->phys = d->rc_phys; - - usb_to_input_id(d->udev, &input_dev->id); + usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys)); + strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys)); - ret |= ir_input_register(input_dev, ir_codes, NULL, "LME 2510"); + rc->input_name = "LME2510 Remote Control"; + rc->input_phys = d->rc_phys; + rc->map_name = RC_MAP_LME2510; + rc->driver_name = "LME 2510"; + usb_to_input_id(d->udev, &rc->input_id); + ret = rc_register_device(rc); if (ret) { - input_free_device(input_dev); + rc_free_device(rc); return ret; } + d->rc_dev = rc; - d->rc_input_dev = input_dev; /* Start the Interupt */ ret = lme2510_int_read(adap); - if (ret < 0) { - ir_input_unregister(input_dev); - input_free_device(input_dev); + rc_unregister_device(rc); + info("INT Unable to start Interupt Service"); + return -ENODEV; } - return (ret < 0) ? -ENODEV : 0; + + return 0; } static u8 check_sum(u8 *p, u8 len) @@ -668,6 +637,7 @@ static int lme2510_download_firmware(struct usb_device *dev, ret |= (data[0] == 0x88) ? 0 : -1; } } + usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 0x06, 0x80, 0x0200, 0x00, data, 0x0109, 1000); @@ -701,10 +671,11 @@ static void lme_coldreset(struct usb_device *dev) info("FRM Firmware Cold Reset"); ret |= lme2510_bulk_write(dev, data , len_in, 1); /*Cold Resetting*/ ret |= lme2510_bulk_read(dev, data, len_in, 1); + return; } -static void lme_firmware_switch(struct usb_device *udev, int cold) +static int lme_firmware_switch(struct usb_device *udev, int cold) { const struct firmware *fw = NULL; char lme2510c_s7395[] = "dvb-usb-lme2510c-s7395.fw"; @@ -712,8 +683,10 @@ static void lme_firmware_switch(struct usb_device *udev, int cold) char *firm_msg[] = {"Loading", "Switching to"}; int ret; + cold = (cold > 0) ? (cold & 1) : 0; + if (udev->descriptor.idProduct == 0x1122) - return; + return 0; switch (dvb_usb_lme2510_firmware) { case 0: @@ -740,22 +713,28 @@ static void lme_firmware_switch(struct usb_device *udev, int cold) cold = 0; break; } + release_firmware(fw); - if (cold) + + if (cold) { lme_coldreset(udev); - return; + return -ENODEV; + } + + return ret; } 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; } @@ -783,18 +762,13 @@ static int dm04_lme2510_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) { struct dvb_usb_adapter *adap = fe->dvb->priv; - struct lme2510_state *st = adap->dev->priv; static u8 voltage_low[] = LME_VOLTAGE_L; static u8 voltage_high[] = LME_VOLTAGE_H; - static u8 lnb_on[] = LNB_ON; - static u8 lnb_off[] = LNB_OFF; static u8 rbuf[1]; int ret = 0, len = 3, rlen = 1; - if (st->stream_on == 1) - return 0; - - ret |= lme2510_usb_talk(adap->dev, lnb_on, len, rbuf, rlen); + if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0) + return -EAGAIN; switch (voltage) { case SEC_VOLTAGE_18: @@ -803,94 +777,143 @@ static int dm04_lme2510_set_voltage(struct dvb_frontend *fe, break; case SEC_VOLTAGE_OFF: - ret |= lme2510_usb_talk(adap->dev, - lnb_off, len, rbuf, rlen); case SEC_VOLTAGE_13: default: ret |= lme2510_usb_talk(adap->dev, voltage_low, len, rbuf, rlen); break; + } + mutex_unlock(&adap->dev->i2c_mutex); - }; - st->i2c_talk_onoff = 1; return (ret < 0) ? -ENODEV : 0; } +static int lme_name(struct dvb_usb_adapter *adap) +{ + struct lme2510_state *st = adap->dev->priv; + const char *desc = adap->dev->desc->name; + char *fe_name[] = {"", " LG TDQY-P001F", " SHARP:BS2F7HZ7395"}; + char *name = adap->fe->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) { - int ret = 0; struct lme2510_state *st = adap->dev->priv; - /* Interupt Start */ - ret = lme2510_int_service(adap); - if (ret < 0) { - info("INT Unable to start Interupt Service"); - return -ENODEV; - } + int ret = 0; st->i2c_talk_onoff = 1; - st->i2c_gate = 4; + st->i2c_gate = 4; adap->fe = dvb_attach(tda10086_attach, &tda10086_config, &adap->dev->i2c_adap); if (adap->fe) { info("TUN Found Frontend TDA10086"); - memcpy(&adap->fe->ops.info.name, - &"DM04_LG_TDQY-P001F DVB-S", 24); - adap->fe->ops.set_voltage = dm04_lme2510_set_voltage; st->i2c_tuner_gate_w = 4; st->i2c_tuner_gate_r = 4; st->i2c_tuner_addr = 0xc0; - if (dvb_attach(tda826x_attach, adap->fe, 0xc0, - &adap->dev->i2c_adap, 1)) { - info("TUN TDA8263 Found"); - st->tuner_config = TUNER_LG; - if (dvb_usb_lme2510_firmware != 1) { - dvb_usb_lme2510_firmware = 1; - lme_firmware_switch(adap->dev->udev, 1); - } - return 0; - } - kfree(adap->fe); - adap->fe = NULL; + st->tuner_config = TUNER_LG; + if (dvb_usb_lme2510_firmware != 1) { + dvb_usb_lme2510_firmware = 1; + ret = lme_firmware_switch(adap->dev->udev, 1); + } else /*stops LG/Sharp multi tuner problems*/ + dvb_usb_lme2510_firmware = 0; + goto end; } + st->i2c_gate = 5; adap->fe = dvb_attach(stv0288_attach, &lme_config, &adap->dev->i2c_adap); if (adap->fe) { info("FE Found Stv0288"); - memcpy(&adap->fe->ops.info.name, - &"DM04_SHARP:BS2F7HZ7395", 22); - adap->fe->ops.set_voltage = dm04_lme2510_set_voltage; st->i2c_tuner_gate_w = 4; st->i2c_tuner_gate_r = 5; st->i2c_tuner_addr = 0xc0; - if (dvb_attach(ix2505v_attach , adap->fe, &lme_tuner, - &adap->dev->i2c_adap)) { - st->tuner_config = TUNER_S7395; - info("TUN Sharp IX2505V silicon tuner"); - if (dvb_usb_lme2510_firmware != 0) { - dvb_usb_lme2510_firmware = 0; - lme_firmware_switch(adap->dev->udev, 1); - } - return 0; + st->tuner_config = TUNER_S7395; + if (dvb_usb_lme2510_firmware != 0) { + dvb_usb_lme2510_firmware = 0; + ret = lme_firmware_switch(adap->dev->udev, 1); } + } else { + info("DM04 Not Supported"); + return -ENODEV; + } + +end: if (ret) { kfree(adap->fe); adap->fe = NULL; + return -ENODEV; } - info("DM04 Not Supported"); - return -ENODEV; + adap->fe->ops.set_voltage = dm04_lme2510_set_voltage; + ret = lme_name(adap); + + return ret; +} + +static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap) +{ + struct lme2510_state *st = adap->dev->priv; + char *tun_msg[] = {"", "TDA8263", "IX2505V"}; + int ret = 0; + + switch (st->tuner_config) { + case TUNER_LG: + if (dvb_attach(tda826x_attach, adap->fe, 0xc0, + &adap->dev->i2c_adap, 1)) + ret = st->tuner_config; + break; + case TUNER_S7395: + if (dvb_attach(ix2505v_attach , adap->fe, &lme_tuner, + &adap->dev->i2c_adap)) + ret = st->tuner_config; + break; + default: + break; + } + + if (ret) + info("TUN Found %s tuner", tun_msg[ret]); + else { + info("TUN No tuner found --- reseting device"); + lme_coldreset(adap->dev->udev); + return -ENODEV; + } + + /* Start the Interupt & Remote*/ + ret = lme2510_int_service(adap); + + 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, len = 3, rlen = 1; + + ret = mutex_lock_interruptible(&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; - return 0; + + mutex_unlock(&d->i2c_mutex); + + return ret; } /* DVB USB Driver stuff */ @@ -951,6 +974,7 @@ static struct dvb_usb_device_properties lme2510_properties = { { .streaming_ctrl = lme2510_streaming_ctrl, .frontend_attach = dm04_lme2510_frontend_attach, + .tuner_attach = dm04_lme2510_tuner, /* parameter for the MPEG2-data transfer */ .stream = { .type = USB_BULK, @@ -971,7 +995,7 @@ static struct dvb_usb_device_properties lme2510_properties = { .generic_bulk_ctrl_endpoint = 0, .num_device_descs = 1, .devices = { - { "DM04 LME2510 DVB-S USB 2.0", + { "DM04_LME2510_DVB-S", { &lme2510_table[0], NULL }, }, @@ -989,6 +1013,7 @@ static struct dvb_usb_device_properties lme2510c_properties = { { .streaming_ctrl = lme2510_streaming_ctrl, .frontend_attach = dm04_lme2510_frontend_attach, + .tuner_attach = dm04_lme2510_tuner, /* parameter for the MPEG2-data transfer */ .stream = { .type = USB_BULK, @@ -1009,7 +1034,7 @@ static struct dvb_usb_device_properties lme2510c_properties = { .generic_bulk_ctrl_endpoint = 0, .num_device_descs = 1, .devices = { - { "DM04 LME2510C USB2.0", + { "DM04_LME2510C_DVB-S", { &lme2510_table[1], NULL }, }, } @@ -1036,7 +1061,7 @@ void *lme2510_exit_int(struct dvb_usb_device *d) usb_free_coherent(d->udev, 5000, st->buffer, st->lme_urb->transfer_dma); info("Interupt Service Stopped"); - ir_input_unregister(d->rc_input_dev); + rc_unregister_device(d->rc_dev); info("Remote Stopped"); } return buffer; @@ -1055,7 +1080,7 @@ void lme2510_exit(struct usb_interface *intf) } static struct usb_driver lme2510_driver = { - .name = "LME2510C_DVBS", + .name = "LME2510C_DVB-S", .probe = lme2510_probe, .disconnect = lme2510_exit, .id_table = lme2510_table, @@ -1083,6 +1108,6 @@ module_init(lme2510_module_init); module_exit(lme2510_module_exit); MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>"); -MODULE_DESCRIPTION("LM2510(C) DVB-S USB2.0"); -MODULE_VERSION("1.60"); +MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0"); +MODULE_VERSION("1.74"); MODULE_LICENSE("GPL"); |