Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Linux driver for Technisat DVB-S/S2 USB 2.0 device
0003  *
0004  * Copyright (C) 2010 Patrick Boettcher,
0005  *                    Kernel Labs Inc. PO Box 745, St James, NY 11780
0006  *
0007  * Development was sponsored by Technisat Digital UK Limited, whose
0008  * registered office is Witan Gate House 500 - 600 Witan Gate West,
0009  * Milton Keynes, MK9 1SH
0010  *
0011  * This program is free software; you can redistribute it and/or
0012  * modify it under the terms of the GNU General Public License as
0013  * published by the Free Software Foundation; either version 2 of the
0014  * License, or (at your option) any later version.
0015  *
0016  *
0017  * THIS PROGRAM IS PROVIDED "AS IS" AND BOTH THE COPYRIGHT HOLDER AND
0018  * TECHNISAT DIGITAL UK LTD DISCLAIM ALL WARRANTIES WITH REGARD TO
0019  * THIS PROGRAM INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY OR
0020  * FITNESS FOR A PARTICULAR PURPOSE.  NEITHER THE COPYRIGHT HOLDER
0021  * NOR TECHNISAT DIGITAL UK LIMITED SHALL BE LIABLE FOR ANY SPECIAL,
0022  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
0023  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
0024  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
0025  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS PROGRAM. See the
0026  * GNU General Public License for more details.
0027  */
0028 
0029 #define DVB_USB_LOG_PREFIX "technisat-usb2"
0030 #include "dvb-usb.h"
0031 
0032 #include "stv6110x.h"
0033 #include "stv090x.h"
0034 
0035 /* module parameters */
0036 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
0037 
0038 static int debug;
0039 module_param(debug, int, 0644);
0040 MODULE_PARM_DESC(debug,
0041         "set debugging level (bit-mask: 1=info,2=eeprom,4=i2c,8=rc)." \
0042         DVB_USB_DEBUG_STATUS);
0043 
0044 /* disables all LED control command and
0045  * also does not start the signal polling thread */
0046 static int disable_led_control;
0047 module_param(disable_led_control, int, 0444);
0048 MODULE_PARM_DESC(disable_led_control,
0049         "disable LED control of the device (default: 0 - LED control is active).");
0050 
0051 /* device private data */
0052 struct technisat_usb2_state {
0053     struct dvb_usb_device *dev;
0054     struct delayed_work green_led_work;
0055     u8 power_state;
0056 
0057     u16 last_scan_code;
0058 
0059     u8 buf[64];
0060 };
0061 
0062 /* debug print helpers */
0063 #define deb_info(args...)    dprintk(debug, 0x01, args)
0064 #define deb_eeprom(args...)  dprintk(debug, 0x02, args)
0065 #define deb_i2c(args...)     dprintk(debug, 0x04, args)
0066 #define deb_rc(args...)      dprintk(debug, 0x08, args)
0067 
0068 /* vendor requests */
0069 #define SET_IFCLK_TO_EXTERNAL_TSCLK_VENDOR_REQUEST 0xB3
0070 #define SET_FRONT_END_RESET_VENDOR_REQUEST         0xB4
0071 #define GET_VERSION_INFO_VENDOR_REQUEST            0xB5
0072 #define SET_GREEN_LED_VENDOR_REQUEST               0xB6
0073 #define SET_RED_LED_VENDOR_REQUEST                 0xB7
0074 #define GET_IR_DATA_VENDOR_REQUEST                 0xB8
0075 #define SET_LED_TIMER_DIVIDER_VENDOR_REQUEST       0xB9
0076 #define SET_USB_REENUMERATION                      0xBA
0077 
0078 /* i2c-access methods */
0079 #define I2C_SPEED_100KHZ_BIT 0x40
0080 
0081 #define I2C_STATUS_NAK 7
0082 #define I2C_STATUS_OK 8
0083 
0084 static int technisat_usb2_i2c_access(struct usb_device *udev,
0085         u8 device_addr, u8 *tx, u8 txlen, u8 *rx, u8 rxlen)
0086 {
0087     u8 *b;
0088     int ret, actual_length;
0089 
0090     b = kmalloc(64, GFP_KERNEL);
0091     if (!b)
0092         return -ENOMEM;
0093 
0094     deb_i2c("i2c-access: %02x, tx: ", device_addr);
0095     debug_dump(tx, txlen, deb_i2c);
0096     deb_i2c(" ");
0097 
0098     if (txlen > 62) {
0099         err("i2c TX buffer can't exceed 62 bytes (dev 0x%02x)",
0100                 device_addr);
0101         txlen = 62;
0102     }
0103     if (rxlen > 62) {
0104         err("i2c RX buffer can't exceed 62 bytes (dev 0x%02x)",
0105                 device_addr);
0106         rxlen = 62;
0107     }
0108 
0109     b[0] = I2C_SPEED_100KHZ_BIT;
0110     b[1] = device_addr << 1;
0111 
0112     if (rx != NULL) {
0113         b[0] |= rxlen;
0114         b[1] |= 1;
0115     }
0116 
0117     memcpy(&b[2], tx, txlen);
0118     ret = usb_bulk_msg(udev,
0119             usb_sndbulkpipe(udev, 0x01),
0120             b, 2 + txlen,
0121             NULL, 1000);
0122 
0123     if (ret < 0) {
0124         err("i2c-error: out failed %02x = %d", device_addr, ret);
0125         goto err;
0126     }
0127 
0128     ret = usb_bulk_msg(udev,
0129             usb_rcvbulkpipe(udev, 0x01),
0130             b, 64, &actual_length, 1000);
0131     if (ret < 0) {
0132         err("i2c-error: in failed %02x = %d", device_addr, ret);
0133         goto err;
0134     }
0135 
0136     if (b[0] != I2C_STATUS_OK) {
0137         err("i2c-error: %02x = %d", device_addr, b[0]);
0138         /* handle tuner-i2c-nak */
0139         if (!(b[0] == I2C_STATUS_NAK &&
0140                 device_addr == 0x60
0141                 /* && device_is_technisat_usb2 */))
0142             goto err;
0143     }
0144 
0145     deb_i2c("status: %d, ", b[0]);
0146 
0147     if (rx != NULL) {
0148         memcpy(rx, &b[2], rxlen);
0149 
0150         deb_i2c("rx (%d): ", rxlen);
0151         debug_dump(rx, rxlen, deb_i2c);
0152     }
0153 
0154     deb_i2c("\n");
0155 
0156 err:
0157     kfree(b);
0158     return ret;
0159 }
0160 
0161 static int technisat_usb2_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
0162                 int num)
0163 {
0164     int ret = 0, i;
0165     struct dvb_usb_device *d = i2c_get_adapdata(adap);
0166 
0167     /* Ensure nobody else hits the i2c bus while we're sending our
0168        sequence of messages, (such as the remote control thread) */
0169     if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
0170         return -EAGAIN;
0171 
0172     for (i = 0; i < num; i++) {
0173         if (i+1 < num && msg[i+1].flags & I2C_M_RD) {
0174             ret = technisat_usb2_i2c_access(d->udev, msg[i+1].addr,
0175                         msg[i].buf, msg[i].len,
0176                         msg[i+1].buf, msg[i+1].len);
0177             if (ret != 0)
0178                 break;
0179             i++;
0180         } else {
0181             ret = technisat_usb2_i2c_access(d->udev, msg[i].addr,
0182                         msg[i].buf, msg[i].len,
0183                         NULL, 0);
0184             if (ret != 0)
0185                 break;
0186         }
0187     }
0188 
0189     if (ret == 0)
0190         ret = i;
0191 
0192     mutex_unlock(&d->i2c_mutex);
0193 
0194     return ret;
0195 }
0196 
0197 static u32 technisat_usb2_i2c_func(struct i2c_adapter *adapter)
0198 {
0199     return I2C_FUNC_I2C;
0200 }
0201 
0202 static struct i2c_algorithm technisat_usb2_i2c_algo = {
0203     .master_xfer   = technisat_usb2_i2c_xfer,
0204     .functionality = technisat_usb2_i2c_func,
0205 };
0206 
0207 #if 0
0208 static void technisat_usb2_frontend_reset(struct usb_device *udev)
0209 {
0210     usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
0211             SET_FRONT_END_RESET_VENDOR_REQUEST,
0212             USB_TYPE_VENDOR | USB_DIR_OUT,
0213             10, 0,
0214             NULL, 0, 500);
0215 }
0216 #endif
0217 
0218 /* LED control */
0219 enum technisat_usb2_led_state {
0220     TECH_LED_OFF,
0221     TECH_LED_BLINK,
0222     TECH_LED_ON,
0223     TECH_LED_UNDEFINED
0224 };
0225 
0226 static int technisat_usb2_set_led(struct dvb_usb_device *d, int red,
0227                   enum technisat_usb2_led_state st)
0228 {
0229     struct technisat_usb2_state *state = d->priv;
0230     u8 *led = state->buf;
0231     int ret;
0232 
0233     led[0] = red ? SET_RED_LED_VENDOR_REQUEST : SET_GREEN_LED_VENDOR_REQUEST;
0234 
0235     if (disable_led_control && st != TECH_LED_OFF)
0236         return 0;
0237 
0238     switch (st) {
0239     case TECH_LED_ON:
0240         led[1] = 0x82;
0241         break;
0242     case TECH_LED_BLINK:
0243         led[1] = 0x82;
0244         if (red) {
0245             led[2] = 0x02;
0246             led[3] = 10;
0247             led[4] = 10;
0248         } else {
0249             led[2] = 0xff;
0250             led[3] = 50;
0251             led[4] = 50;
0252         }
0253         led[5] = 1;
0254         break;
0255 
0256     default:
0257     case TECH_LED_OFF:
0258         led[1] = 0x80;
0259         break;
0260     }
0261 
0262     if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
0263         return -EAGAIN;
0264 
0265     ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
0266         red ? SET_RED_LED_VENDOR_REQUEST : SET_GREEN_LED_VENDOR_REQUEST,
0267         USB_TYPE_VENDOR | USB_DIR_OUT,
0268         0, 0,
0269         led, 8, 500);
0270 
0271     mutex_unlock(&d->i2c_mutex);
0272     return ret;
0273 }
0274 
0275 static int technisat_usb2_set_led_timer(struct dvb_usb_device *d, u8 red, u8 green)
0276 {
0277     struct technisat_usb2_state *state = d->priv;
0278     u8 *b = state->buf;
0279     int ret;
0280 
0281     b[0] = 0;
0282 
0283     if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
0284         return -EAGAIN;
0285 
0286     ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
0287         SET_LED_TIMER_DIVIDER_VENDOR_REQUEST,
0288         USB_TYPE_VENDOR | USB_DIR_OUT,
0289         (red << 8) | green, 0,
0290         b, 1, 500);
0291 
0292     mutex_unlock(&d->i2c_mutex);
0293 
0294     return ret;
0295 }
0296 
0297 static void technisat_usb2_green_led_control(struct work_struct *work)
0298 {
0299     struct technisat_usb2_state *state =
0300         container_of(work, struct technisat_usb2_state, green_led_work.work);
0301     struct dvb_frontend *fe = state->dev->adapter[0].fe_adap[0].fe;
0302 
0303     if (state->power_state == 0)
0304         goto schedule;
0305 
0306     if (fe != NULL) {
0307         enum fe_status status;
0308 
0309         if (fe->ops.read_status(fe, &status) != 0)
0310             goto schedule;
0311 
0312         if (status & FE_HAS_LOCK) {
0313             u32 ber;
0314 
0315             if (fe->ops.read_ber(fe, &ber) != 0)
0316                 goto schedule;
0317 
0318             if (ber > 1000)
0319                 technisat_usb2_set_led(state->dev, 0, TECH_LED_BLINK);
0320             else
0321                 technisat_usb2_set_led(state->dev, 0, TECH_LED_ON);
0322         } else
0323             technisat_usb2_set_led(state->dev, 0, TECH_LED_OFF);
0324     }
0325 
0326 schedule:
0327     schedule_delayed_work(&state->green_led_work,
0328             msecs_to_jiffies(500));
0329 }
0330 
0331 /* method to find out whether the firmware has to be downloaded or not */
0332 static int technisat_usb2_identify_state(struct usb_device *udev,
0333         const struct dvb_usb_device_properties *props,
0334         const struct dvb_usb_device_description **desc, int *cold)
0335 {
0336     int ret;
0337     u8 *version;
0338 
0339     version = kmalloc(3, GFP_KERNEL);
0340     if (!version)
0341         return -ENOMEM;
0342 
0343     /* first select the interface */
0344     if (usb_set_interface(udev, 0, 1) != 0)
0345         err("could not set alternate setting to 0");
0346     else
0347         info("set alternate setting");
0348 
0349     *cold = 0; /* by default do not download a firmware - just in case something is wrong */
0350 
0351     ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
0352         GET_VERSION_INFO_VENDOR_REQUEST,
0353         USB_TYPE_VENDOR | USB_DIR_IN,
0354         0, 0,
0355         version, 3, 500);
0356 
0357     if (ret < 0)
0358         *cold = 1;
0359     else {
0360         info("firmware version: %d.%d", version[1], version[2]);
0361         *cold = 0;
0362     }
0363 
0364     kfree(version);
0365 
0366     return 0;
0367 }
0368 
0369 /* power control */
0370 static int technisat_usb2_power_ctrl(struct dvb_usb_device *d, int level)
0371 {
0372     struct technisat_usb2_state *state = d->priv;
0373 
0374     state->power_state = level;
0375 
0376     if (disable_led_control)
0377         return 0;
0378 
0379     /* green led is turned off in any case - will be turned on when tuning */
0380     technisat_usb2_set_led(d, 0, TECH_LED_OFF);
0381     /* red led is turned on all the time */
0382     technisat_usb2_set_led(d, 1, TECH_LED_ON);
0383     return 0;
0384 }
0385 
0386 /* mac address reading - from the eeprom */
0387 #if 0
0388 static void technisat_usb2_eeprom_dump(struct dvb_usb_device *d)
0389 {
0390     u8 reg;
0391     u8 b[16];
0392     int i, j;
0393 
0394     /* full EEPROM dump */
0395     for (j = 0; j < 256 * 4; j += 16) {
0396         reg = j;
0397         if (technisat_usb2_i2c_access(d->udev, 0x50 + j / 256, &reg, 1, b, 16) != 0)
0398             break;
0399 
0400         deb_eeprom("EEPROM: %01x%02x: ", j / 256, reg);
0401         for (i = 0; i < 16; i++)
0402             deb_eeprom("%02x ", b[i]);
0403         deb_eeprom("\n");
0404     }
0405 }
0406 #endif
0407 
0408 static u8 technisat_usb2_calc_lrc(const u8 *b, u16 length)
0409 {
0410     u8 lrc = 0;
0411     while (--length)
0412         lrc ^= *b++;
0413     return lrc;
0414 }
0415 
0416 static int technisat_usb2_eeprom_lrc_read(struct dvb_usb_device *d,
0417     u16 offset, u8 *b, u16 length, u8 tries)
0418 {
0419     u8 bo = offset & 0xff;
0420     struct i2c_msg msg[] = {
0421         {
0422             .addr = 0x50 | ((offset >> 8) & 0x3),
0423             .buf = &bo,
0424             .len = 1
0425         }, {
0426             .addr = 0x50 | ((offset >> 8) & 0x3),
0427             .flags  = I2C_M_RD,
0428             .buf = b,
0429             .len = length
0430         }
0431     };
0432 
0433     while (tries--) {
0434         int status;
0435 
0436         if (i2c_transfer(&d->i2c_adap, msg, 2) != 2)
0437             break;
0438 
0439         status =
0440             technisat_usb2_calc_lrc(b, length - 1) == b[length - 1];
0441 
0442         if (status)
0443             return 0;
0444     }
0445 
0446     return -EREMOTEIO;
0447 }
0448 
0449 #define EEPROM_MAC_START 0x3f8
0450 #define EEPROM_MAC_TOTAL 8
0451 static int technisat_usb2_read_mac_address(struct dvb_usb_device *d,
0452         u8 mac[])
0453 {
0454     u8 buf[EEPROM_MAC_TOTAL];
0455 
0456     if (technisat_usb2_eeprom_lrc_read(d, EEPROM_MAC_START,
0457                 buf, EEPROM_MAC_TOTAL, 4) != 0)
0458         return -ENODEV;
0459 
0460     memcpy(mac, buf, 6);
0461     return 0;
0462 }
0463 
0464 static struct stv090x_config technisat_usb2_stv090x_config;
0465 
0466 /* frontend attach */
0467 static int technisat_usb2_set_voltage(struct dvb_frontend *fe,
0468                       enum fe_sec_voltage voltage)
0469 {
0470     int i;
0471     u8 gpio[3] = { 0 }; /* 0 = 2, 1 = 3, 2 = 4 */
0472 
0473     gpio[2] = 1; /* high - voltage ? */
0474 
0475     switch (voltage) {
0476     case SEC_VOLTAGE_13:
0477         gpio[0] = 1;
0478         break;
0479     case SEC_VOLTAGE_18:
0480         gpio[0] = 1;
0481         gpio[1] = 1;
0482         break;
0483     default:
0484     case SEC_VOLTAGE_OFF:
0485         break;
0486     }
0487 
0488     for (i = 0; i < 3; i++)
0489         if (technisat_usb2_stv090x_config.set_gpio(fe, i+2, 0,
0490                                gpio[i], 0) != 0)
0491             return -EREMOTEIO;
0492     return 0;
0493 }
0494 
0495 static struct stv090x_config technisat_usb2_stv090x_config = {
0496     .device         = STV0903,
0497     .demod_mode     = STV090x_SINGLE,
0498     .clk_mode       = STV090x_CLK_EXT,
0499 
0500     .xtal           = 8000000,
0501     .address        = 0x68,
0502 
0503     .ts1_mode       = STV090x_TSMODE_DVBCI,
0504     .ts1_clk        = 13400000,
0505     .ts1_tei        = 1,
0506 
0507     .repeater_level = STV090x_RPTLEVEL_64,
0508 
0509     .tuner_bbgain   = 6,
0510 };
0511 
0512 static struct stv6110x_config technisat_usb2_stv6110x_config = {
0513     .addr           = 0x60,
0514     .refclk         = 16000000,
0515     .clk_div        = 2,
0516 };
0517 
0518 static int technisat_usb2_frontend_attach(struct dvb_usb_adapter *a)
0519 {
0520     struct usb_device *udev = a->dev->udev;
0521     int ret;
0522 
0523     a->fe_adap[0].fe = dvb_attach(stv090x_attach, &technisat_usb2_stv090x_config,
0524             &a->dev->i2c_adap, STV090x_DEMODULATOR_0);
0525 
0526     if (a->fe_adap[0].fe) {
0527         const struct stv6110x_devctl *ctl;
0528 
0529         ctl = dvb_attach(stv6110x_attach,
0530                 a->fe_adap[0].fe,
0531                 &technisat_usb2_stv6110x_config,
0532                 &a->dev->i2c_adap);
0533 
0534         if (ctl) {
0535             technisat_usb2_stv090x_config.tuner_init          = ctl->tuner_init;
0536             technisat_usb2_stv090x_config.tuner_sleep         = ctl->tuner_sleep;
0537             technisat_usb2_stv090x_config.tuner_set_mode      = ctl->tuner_set_mode;
0538             technisat_usb2_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency;
0539             technisat_usb2_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency;
0540             technisat_usb2_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth;
0541             technisat_usb2_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth;
0542             technisat_usb2_stv090x_config.tuner_set_bbgain    = ctl->tuner_set_bbgain;
0543             technisat_usb2_stv090x_config.tuner_get_bbgain    = ctl->tuner_get_bbgain;
0544             technisat_usb2_stv090x_config.tuner_set_refclk    = ctl->tuner_set_refclk;
0545             technisat_usb2_stv090x_config.tuner_get_status    = ctl->tuner_get_status;
0546 
0547             /* call the init function once to initialize
0548                tuner's clock output divider and demod's
0549                master clock */
0550             if (a->fe_adap[0].fe->ops.init)
0551                 a->fe_adap[0].fe->ops.init(a->fe_adap[0].fe);
0552 
0553             if (mutex_lock_interruptible(&a->dev->i2c_mutex) < 0)
0554                 return -EAGAIN;
0555 
0556             ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
0557                     SET_IFCLK_TO_EXTERNAL_TSCLK_VENDOR_REQUEST,
0558                     USB_TYPE_VENDOR | USB_DIR_OUT,
0559                     0, 0,
0560                     NULL, 0, 500);
0561             mutex_unlock(&a->dev->i2c_mutex);
0562 
0563             if (ret != 0)
0564                 err("could not set IF_CLK to external");
0565 
0566             a->fe_adap[0].fe->ops.set_voltage = technisat_usb2_set_voltage;
0567 
0568             /* if everything was successful assign a nice name to the frontend */
0569             strscpy(a->fe_adap[0].fe->ops.info.name,
0570                 a->dev->desc->name,
0571                 sizeof(a->fe_adap[0].fe->ops.info.name));
0572         } else {
0573             dvb_frontend_detach(a->fe_adap[0].fe);
0574             a->fe_adap[0].fe = NULL;
0575         }
0576     }
0577 
0578     technisat_usb2_set_led_timer(a->dev, 1, 1);
0579 
0580     return a->fe_adap[0].fe == NULL ? -ENODEV : 0;
0581 }
0582 
0583 /* Remote control */
0584 
0585 /* the device is giving providing raw IR-signals to the host mapping
0586  * it only to one remote control is just the default implementation
0587  */
0588 #define NOMINAL_IR_BIT_TRANSITION_TIME_US 889
0589 #define NOMINAL_IR_BIT_TIME_US (2 * NOMINAL_IR_BIT_TRANSITION_TIME_US)
0590 
0591 #define FIRMWARE_CLOCK_TICK 83333
0592 #define FIRMWARE_CLOCK_DIVISOR 256
0593 
0594 #define IR_PERCENT_TOLERANCE 15
0595 
0596 #define NOMINAL_IR_BIT_TRANSITION_TICKS ((NOMINAL_IR_BIT_TRANSITION_TIME_US * 1000 * 1000) / FIRMWARE_CLOCK_TICK)
0597 #define NOMINAL_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICKS / FIRMWARE_CLOCK_DIVISOR)
0598 
0599 #define NOMINAL_IR_BIT_TIME_TICKS ((NOMINAL_IR_BIT_TIME_US * 1000 * 1000) / FIRMWARE_CLOCK_TICK)
0600 #define NOMINAL_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICKS / FIRMWARE_CLOCK_DIVISOR)
0601 
0602 #define MINIMUM_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICK_COUNT - ((NOMINAL_IR_BIT_TRANSITION_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100))
0603 #define MAXIMUM_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICK_COUNT + ((NOMINAL_IR_BIT_TRANSITION_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100))
0604 
0605 #define MINIMUM_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICK_COUNT - ((NOMINAL_IR_BIT_TIME_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100))
0606 #define MAXIMUM_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICK_COUNT + ((NOMINAL_IR_BIT_TIME_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100))
0607 
0608 static int technisat_usb2_get_ir(struct dvb_usb_device *d)
0609 {
0610     struct technisat_usb2_state *state = d->priv;
0611     struct ir_raw_event ev;
0612     u8 *buf = state->buf;
0613     int i, ret;
0614 
0615     buf[0] = GET_IR_DATA_VENDOR_REQUEST;
0616     buf[1] = 0x08;
0617     buf[2] = 0x8f;
0618     buf[3] = MINIMUM_IR_BIT_TRANSITION_TICK_COUNT;
0619     buf[4] = MAXIMUM_IR_BIT_TIME_TICK_COUNT;
0620 
0621     if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
0622         return -EAGAIN;
0623     ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
0624             GET_IR_DATA_VENDOR_REQUEST,
0625             USB_TYPE_VENDOR | USB_DIR_OUT,
0626             0, 0,
0627             buf, 5, 500);
0628     if (ret < 0)
0629         goto unlock;
0630 
0631     buf[1] = 0;
0632     buf[2] = 0;
0633     ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
0634             GET_IR_DATA_VENDOR_REQUEST,
0635             USB_TYPE_VENDOR | USB_DIR_IN,
0636             0x8080, 0,
0637             buf, 62, 500);
0638 
0639 unlock:
0640     mutex_unlock(&d->i2c_mutex);
0641 
0642     if (ret < 0)
0643         return ret;
0644 
0645     if (ret == 1)
0646         return 0; /* no key pressed */
0647 
0648     /* decoding */
0649 
0650 #if 0
0651     deb_rc("RC: %d ", ret);
0652     debug_dump(buf + 1, ret, deb_rc);
0653 #endif
0654 
0655     ev.pulse = 0;
0656     for (i = 1; i < ARRAY_SIZE(state->buf); i++) {
0657         if (buf[i] == 0xff) {
0658             ev.pulse = 0;
0659             ev.duration = 889 * 2;
0660             ir_raw_event_store(d->rc_dev, &ev);
0661             break;
0662         }
0663 
0664         ev.pulse = !ev.pulse;
0665         ev.duration = (buf[i] * FIRMWARE_CLOCK_DIVISOR *
0666                    FIRMWARE_CLOCK_TICK) / (1000 * 1000);
0667         ir_raw_event_store(d->rc_dev, &ev);
0668     }
0669 
0670     ir_raw_event_handle(d->rc_dev);
0671 
0672     return 1;
0673 }
0674 
0675 static int technisat_usb2_rc_query(struct dvb_usb_device *d)
0676 {
0677     int ret = technisat_usb2_get_ir(d);
0678 
0679     if (ret < 0)
0680         return ret;
0681 
0682     if (ret == 0)
0683         return 0;
0684 
0685     if (!disable_led_control)
0686         technisat_usb2_set_led(d, 1, TECH_LED_BLINK);
0687 
0688     return 0;
0689 }
0690 
0691 /* DVB-USB and USB stuff follows */
0692 enum {
0693     TECHNISAT_USB2_DVB_S2,
0694 };
0695 
0696 static struct usb_device_id technisat_usb2_id_table[] = {
0697     DVB_USB_DEV(TECHNISAT, TECHNISAT_USB2_DVB_S2),
0698     { }
0699 };
0700 
0701 MODULE_DEVICE_TABLE(usb, technisat_usb2_id_table);
0702 
0703 /* device description */
0704 static struct dvb_usb_device_properties technisat_usb2_devices = {
0705     .caps              = DVB_USB_IS_AN_I2C_ADAPTER,
0706 
0707     .usb_ctrl          = CYPRESS_FX2,
0708 
0709     .identify_state    = technisat_usb2_identify_state,
0710     .firmware          = "dvb-usb-SkyStar_USB_HD_FW_v17_63.HEX.fw",
0711 
0712     .size_of_priv      = sizeof(struct technisat_usb2_state),
0713 
0714     .i2c_algo          = &technisat_usb2_i2c_algo,
0715 
0716     .power_ctrl        = technisat_usb2_power_ctrl,
0717     .read_mac_address  = technisat_usb2_read_mac_address,
0718 
0719     .num_adapters = 1,
0720     .adapter = {
0721         {
0722         .num_frontends = 1,
0723         .fe = {{
0724             .frontend_attach  = technisat_usb2_frontend_attach,
0725 
0726             .stream = {
0727                 .type = USB_ISOC,
0728                 .count = 4,
0729                 .endpoint = 0x2,
0730                 .u = {
0731                     .isoc = {
0732                         .framesperurb = 32,
0733                         .framesize = 2048,
0734                         .interval = 1,
0735                     }
0736                 }
0737             },
0738         }},
0739             .size_of_priv = 0,
0740         },
0741     },
0742 
0743     .num_device_descs = 1,
0744     .devices = {
0745         {   "Technisat SkyStar USB HD (DVB-S/S2)",
0746             { &technisat_usb2_id_table[TECHNISAT_USB2_DVB_S2], NULL },
0747             { NULL },
0748         },
0749     },
0750 
0751     .rc.core = {
0752         .rc_interval = 100,
0753         .rc_codes    = RC_MAP_TECHNISAT_USB2,
0754         .module_name = "technisat-usb2",
0755         .rc_query    = technisat_usb2_rc_query,
0756         .allowed_protos = RC_PROTO_BIT_ALL_IR_DECODER,
0757         .driver_type    = RC_DRIVER_IR_RAW,
0758     }
0759 };
0760 
0761 static int technisat_usb2_probe(struct usb_interface *intf,
0762         const struct usb_device_id *id)
0763 {
0764     struct dvb_usb_device *dev;
0765 
0766     if (dvb_usb_device_init(intf, &technisat_usb2_devices, THIS_MODULE,
0767                 &dev, adapter_nr) != 0)
0768         return -ENODEV;
0769 
0770     if (dev) {
0771         struct technisat_usb2_state *state = dev->priv;
0772         state->dev = dev;
0773 
0774         if (!disable_led_control) {
0775             INIT_DELAYED_WORK(&state->green_led_work,
0776                     technisat_usb2_green_led_control);
0777             schedule_delayed_work(&state->green_led_work,
0778                     msecs_to_jiffies(500));
0779         }
0780     }
0781 
0782     return 0;
0783 }
0784 
0785 static void technisat_usb2_disconnect(struct usb_interface *intf)
0786 {
0787     struct dvb_usb_device *dev = usb_get_intfdata(intf);
0788 
0789     /* work and stuff was only created when the device is is hot-state */
0790     if (dev != NULL) {
0791         struct technisat_usb2_state *state = dev->priv;
0792         if (state != NULL)
0793             cancel_delayed_work_sync(&state->green_led_work);
0794     }
0795 
0796     dvb_usb_device_exit(intf);
0797 }
0798 
0799 static struct usb_driver technisat_usb2_driver = {
0800     .name       = "dvb_usb_technisat_usb2",
0801     .probe      = technisat_usb2_probe,
0802     .disconnect = technisat_usb2_disconnect,
0803     .id_table   = technisat_usb2_id_table,
0804 };
0805 
0806 module_usb_driver(technisat_usb2_driver);
0807 
0808 MODULE_AUTHOR("Patrick Boettcher <pboettcher@kernellabs.com>");
0809 MODULE_DESCRIPTION("Driver for Technisat DVB-S/S2 USB 2.0 device");
0810 MODULE_VERSION("1.0");
0811 MODULE_LICENSE("GPL");