linux/drivers/media/usb/dvb-usb/technisat-usb2.c
<<
>>
Prefs
   1/*
   2 * Linux driver for Technisat DVB-S/S2 USB 2.0 device
   3 *
   4 * Copyright (C) 2010 Patrick Boettcher,
   5 *                    Kernel Labs Inc. PO Box 745, St James, NY 11780
   6 *
   7 * Development was sponsored by Technisat Digital UK Limited, whose
   8 * registered office is Witan Gate House 500 - 600 Witan Gate West,
   9 * Milton Keynes, MK9 1SH
  10 *
  11 * This program is free software; you can redistribute it and/or
  12 * modify it under the terms of the GNU General Public License as
  13 * published by the Free Software Foundation; either version 2 of the
  14 * License, or (at your option) any later version.
  15 *
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program; if not, write to the Free Software
  19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20 *
  21 * THIS PROGRAM IS PROVIDED "AS IS" AND BOTH THE COPYRIGHT HOLDER AND
  22 * TECHNISAT DIGITAL UK LTD DISCLAIM ALL WARRANTIES WITH REGARD TO
  23 * THIS PROGRAM INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY OR
  24 * FITNESS FOR A PARTICULAR PURPOSE.  NEITHER THE COPYRIGHT HOLDER
  25 * NOR TECHNISAT DIGITAL UK LIMITED SHALL BE LIABLE FOR ANY SPECIAL,
  26 * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
  27 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  28 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
  29 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS PROGRAM. See the
  30 * GNU General Public License for more details.
  31 */
  32
  33#define DVB_USB_LOG_PREFIX "technisat-usb2"
  34#include "dvb-usb.h"
  35
  36#include "stv6110x.h"
  37#include "stv090x.h"
  38
  39/* module parameters */
  40DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
  41
  42static int debug;
  43module_param(debug, int, 0644);
  44MODULE_PARM_DESC(debug,
  45                "set debugging level (bit-mask: 1=info,2=eeprom,4=i2c,8=rc)." \
  46                DVB_USB_DEBUG_STATUS);
  47
  48/* disables all LED control command and
  49 * also does not start the signal polling thread */
  50static int disable_led_control;
  51module_param(disable_led_control, int, 0444);
  52MODULE_PARM_DESC(disable_led_control,
  53                "disable LED control of the device "
  54                "(default: 0 - LED control is active).");
  55
  56/* device private data */
  57struct technisat_usb2_state {
  58        struct dvb_usb_device *dev;
  59        struct delayed_work green_led_work;
  60        u8 power_state;
  61
  62        u16 last_scan_code;
  63};
  64
  65/* debug print helpers */
  66#define deb_info(args...)    dprintk(debug, 0x01, args)
  67#define deb_eeprom(args...)  dprintk(debug, 0x02, args)
  68#define deb_i2c(args...)     dprintk(debug, 0x04, args)
  69#define deb_rc(args...)      dprintk(debug, 0x08, args)
  70
  71/* vendor requests */
  72#define SET_IFCLK_TO_EXTERNAL_TSCLK_VENDOR_REQUEST 0xB3
  73#define SET_FRONT_END_RESET_VENDOR_REQUEST         0xB4
  74#define GET_VERSION_INFO_VENDOR_REQUEST            0xB5
  75#define SET_GREEN_LED_VENDOR_REQUEST               0xB6
  76#define SET_RED_LED_VENDOR_REQUEST                 0xB7
  77#define GET_IR_DATA_VENDOR_REQUEST                 0xB8
  78#define SET_LED_TIMER_DIVIDER_VENDOR_REQUEST       0xB9
  79#define SET_USB_REENUMERATION                      0xBA
  80
  81/* i2c-access methods */
  82#define I2C_SPEED_100KHZ_BIT 0x40
  83
  84#define I2C_STATUS_NAK 7
  85#define I2C_STATUS_OK 8
  86
  87static int technisat_usb2_i2c_access(struct usb_device *udev,
  88                u8 device_addr, u8 *tx, u8 txlen, u8 *rx, u8 rxlen)
  89{
  90        u8 b[64];
  91        int ret, actual_length;
  92
  93        deb_i2c("i2c-access: %02x, tx: ", device_addr);
  94        debug_dump(tx, txlen, deb_i2c);
  95        deb_i2c(" ");
  96
  97        if (txlen > 62) {
  98                err("i2c TX buffer can't exceed 62 bytes (dev 0x%02x)",
  99                                device_addr);
 100                txlen = 62;
 101        }
 102        if (rxlen > 62) {
 103                err("i2c RX buffer can't exceed 62 bytes (dev 0x%02x)",
 104                                device_addr);
 105                txlen = 62;
 106        }
 107
 108        b[0] = I2C_SPEED_100KHZ_BIT;
 109        b[1] = device_addr << 1;
 110
 111        if (rx != NULL) {
 112                b[0] |= rxlen;
 113                b[1] |= 1;
 114        }
 115
 116        memcpy(&b[2], tx, txlen);
 117        ret = usb_bulk_msg(udev,
 118                        usb_sndbulkpipe(udev, 0x01),
 119                        b, 2 + txlen,
 120                        NULL, 1000);
 121
 122        if (ret < 0) {
 123                err("i2c-error: out failed %02x = %d", device_addr, ret);
 124                return -ENODEV;
 125        }
 126
 127        ret = usb_bulk_msg(udev,
 128                        usb_rcvbulkpipe(udev, 0x01),
 129                        b, 64, &actual_length, 1000);
 130        if (ret < 0) {
 131                err("i2c-error: in failed %02x = %d", device_addr, ret);
 132                return -ENODEV;
 133        }
 134
 135        if (b[0] != I2C_STATUS_OK) {
 136                err("i2c-error: %02x = %d", device_addr, b[0]);
 137                /* handle tuner-i2c-nak */
 138                if (!(b[0] == I2C_STATUS_NAK &&
 139                                device_addr == 0x60
 140                                /* && device_is_technisat_usb2 */))
 141                        return -ENODEV;
 142        }
 143
 144        deb_i2c("status: %d, ", b[0]);
 145
 146        if (rx != NULL) {
 147                memcpy(rx, &b[2], rxlen);
 148
 149                deb_i2c("rx (%d): ", rxlen);
 150                debug_dump(rx, rxlen, deb_i2c);
 151        }
 152
 153        deb_i2c("\n");
 154
 155        return 0;
 156}
 157
 158static int technisat_usb2_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
 159                                int num)
 160{
 161        int ret = 0, i;
 162        struct dvb_usb_device *d = i2c_get_adapdata(adap);
 163
 164        /* Ensure nobody else hits the i2c bus while we're sending our
 165           sequence of messages, (such as the remote control thread) */
 166        if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
 167                return -EAGAIN;
 168
 169        for (i = 0; i < num; i++) {
 170                if (i+1 < num && msg[i+1].flags & I2C_M_RD) {
 171                        ret = technisat_usb2_i2c_access(d->udev, msg[i+1].addr,
 172                                                msg[i].buf, msg[i].len,
 173                                                msg[i+1].buf, msg[i+1].len);
 174                        if (ret != 0)
 175                                break;
 176                        i++;
 177                } else {
 178                        ret = technisat_usb2_i2c_access(d->udev, msg[i].addr,
 179                                                msg[i].buf, msg[i].len,
 180                                                NULL, 0);
 181                        if (ret != 0)
 182                                break;
 183                }
 184        }
 185
 186        if (ret == 0)
 187                ret = i;
 188
 189        mutex_unlock(&d->i2c_mutex);
 190
 191        return ret;
 192}
 193
 194static u32 technisat_usb2_i2c_func(struct i2c_adapter *adapter)
 195{
 196        return I2C_FUNC_I2C;
 197}
 198
 199static struct i2c_algorithm technisat_usb2_i2c_algo = {
 200        .master_xfer   = technisat_usb2_i2c_xfer,
 201        .functionality = technisat_usb2_i2c_func,
 202};
 203
 204#if 0
 205static void technisat_usb2_frontend_reset(struct usb_device *udev)
 206{
 207        usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
 208                        SET_FRONT_END_RESET_VENDOR_REQUEST,
 209                        USB_TYPE_VENDOR | USB_DIR_OUT,
 210                        10, 0,
 211                        NULL, 0, 500);
 212}
 213#endif
 214
 215/* LED control */
 216enum technisat_usb2_led_state {
 217        LED_OFF,
 218        LED_BLINK,
 219        LED_ON,
 220        LED_UNDEFINED
 221};
 222
 223static int technisat_usb2_set_led(struct dvb_usb_device *d, int red, enum technisat_usb2_led_state state)
 224{
 225        int ret;
 226
 227        u8 led[8] = {
 228                red ? SET_RED_LED_VENDOR_REQUEST : SET_GREEN_LED_VENDOR_REQUEST,
 229                0
 230        };
 231
 232        if (disable_led_control && state != LED_OFF)
 233                return 0;
 234
 235        switch (state) {
 236        case LED_ON:
 237                led[1] = 0x82;
 238                break;
 239        case LED_BLINK:
 240                led[1] = 0x82;
 241                if (red) {
 242                        led[2] = 0x02;
 243                        led[3] = 10;
 244                        led[4] = 10;
 245                } else {
 246                        led[2] = 0xff;
 247                        led[3] = 50;
 248                        led[4] = 50;
 249                }
 250                led[5] = 1;
 251                break;
 252
 253        default:
 254        case LED_OFF:
 255                led[1] = 0x80;
 256                break;
 257        }
 258
 259        if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
 260                return -EAGAIN;
 261
 262        ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
 263                red ? SET_RED_LED_VENDOR_REQUEST : SET_GREEN_LED_VENDOR_REQUEST,
 264                USB_TYPE_VENDOR | USB_DIR_OUT,
 265                0, 0,
 266                led, sizeof(led), 500);
 267
 268        mutex_unlock(&d->i2c_mutex);
 269        return ret;
 270}
 271
 272static int technisat_usb2_set_led_timer(struct dvb_usb_device *d, u8 red, u8 green)
 273{
 274        int ret;
 275        u8 b = 0;
 276
 277        if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
 278                return -EAGAIN;
 279
 280        ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
 281                SET_LED_TIMER_DIVIDER_VENDOR_REQUEST,
 282                USB_TYPE_VENDOR | USB_DIR_OUT,
 283                (red << 8) | green, 0,
 284                &b, 1, 500);
 285
 286        mutex_unlock(&d->i2c_mutex);
 287
 288        return ret;
 289}
 290
 291static void technisat_usb2_green_led_control(struct work_struct *work)
 292{
 293        struct technisat_usb2_state *state =
 294                container_of(work, struct technisat_usb2_state, green_led_work.work);
 295        struct dvb_frontend *fe = state->dev->adapter[0].fe_adap[0].fe;
 296
 297        if (state->power_state == 0)
 298                goto schedule;
 299
 300        if (fe != NULL) {
 301                enum fe_status status;
 302
 303                if (fe->ops.read_status(fe, &status) != 0)
 304                        goto schedule;
 305
 306                if (status & FE_HAS_LOCK) {
 307                        u32 ber;
 308
 309                        if (fe->ops.read_ber(fe, &ber) != 0)
 310                                goto schedule;
 311
 312                        if (ber > 1000)
 313                                technisat_usb2_set_led(state->dev, 0, LED_BLINK);
 314                        else
 315                                technisat_usb2_set_led(state->dev, 0, LED_ON);
 316                } else
 317                        technisat_usb2_set_led(state->dev, 0, LED_OFF);
 318        }
 319
 320schedule:
 321        schedule_delayed_work(&state->green_led_work,
 322                        msecs_to_jiffies(500));
 323}
 324
 325/* method to find out whether the firmware has to be downloaded or not */
 326static int technisat_usb2_identify_state(struct usb_device *udev,
 327                struct dvb_usb_device_properties *props,
 328                struct dvb_usb_device_description **desc, int *cold)
 329{
 330        int ret;
 331        u8 version[3];
 332
 333        /* first select the interface */
 334        if (usb_set_interface(udev, 0, 1) != 0)
 335                err("could not set alternate setting to 0");
 336        else
 337                info("set alternate setting");
 338
 339        *cold = 0; /* by default do not download a firmware - just in case something is wrong */
 340
 341        ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
 342                GET_VERSION_INFO_VENDOR_REQUEST,
 343                USB_TYPE_VENDOR | USB_DIR_IN,
 344                0, 0,
 345                version, sizeof(version), 500);
 346
 347        if (ret < 0)
 348                *cold = 1;
 349        else {
 350                info("firmware version: %d.%d", version[1], version[2]);
 351                *cold = 0;
 352        }
 353
 354        return 0;
 355}
 356
 357/* power control */
 358static int technisat_usb2_power_ctrl(struct dvb_usb_device *d, int level)
 359{
 360        struct technisat_usb2_state *state = d->priv;
 361
 362        state->power_state = level;
 363
 364        if (disable_led_control)
 365                return 0;
 366
 367        /* green led is turned off in any case - will be turned on when tuning */
 368        technisat_usb2_set_led(d, 0, LED_OFF);
 369        /* red led is turned on all the time */
 370        technisat_usb2_set_led(d, 1, LED_ON);
 371        return 0;
 372}
 373
 374/* mac address reading - from the eeprom */
 375#if 0
 376static void technisat_usb2_eeprom_dump(struct dvb_usb_device *d)
 377{
 378        u8 reg;
 379        u8 b[16];
 380        int i, j;
 381
 382        /* full EEPROM dump */
 383        for (j = 0; j < 256 * 4; j += 16) {
 384                reg = j;
 385                if (technisat_usb2_i2c_access(d->udev, 0x50 + j / 256, &reg, 1, b, 16) != 0)
 386                        break;
 387
 388                deb_eeprom("EEPROM: %01x%02x: ", j / 256, reg);
 389                for (i = 0; i < 16; i++)
 390                        deb_eeprom("%02x ", b[i]);
 391                deb_eeprom("\n");
 392        }
 393}
 394#endif
 395
 396static u8 technisat_usb2_calc_lrc(const u8 *b, u16 length)
 397{
 398        u8 lrc = 0;
 399        while (--length)
 400                lrc ^= *b++;
 401        return lrc;
 402}
 403
 404static int technisat_usb2_eeprom_lrc_read(struct dvb_usb_device *d,
 405        u16 offset, u8 *b, u16 length, u8 tries)
 406{
 407        u8 bo = offset & 0xff;
 408        struct i2c_msg msg[] = {
 409                {
 410                        .addr = 0x50 | ((offset >> 8) & 0x3),
 411                        .buf = &bo,
 412                        .len = 1
 413                }, {
 414                        .addr = 0x50 | ((offset >> 8) & 0x3),
 415                        .flags  = I2C_M_RD,
 416                        .buf = b,
 417                        .len = length
 418                }
 419        };
 420
 421        while (tries--) {
 422                int status;
 423
 424                if (i2c_transfer(&d->i2c_adap, msg, 2) != 2)
 425                        break;
 426
 427                status =
 428                        technisat_usb2_calc_lrc(b, length - 1) == b[length - 1];
 429
 430                if (status)
 431                        return 0;
 432        }
 433
 434        return -EREMOTEIO;
 435}
 436
 437#define EEPROM_MAC_START 0x3f8
 438#define EEPROM_MAC_TOTAL 8
 439static int technisat_usb2_read_mac_address(struct dvb_usb_device *d,
 440                u8 mac[])
 441{
 442        u8 buf[EEPROM_MAC_TOTAL];
 443
 444        if (technisat_usb2_eeprom_lrc_read(d, EEPROM_MAC_START,
 445                                buf, EEPROM_MAC_TOTAL, 4) != 0)
 446                return -ENODEV;
 447
 448        memcpy(mac, buf, 6);
 449        return 0;
 450}
 451
 452/* frontend attach */
 453static int technisat_usb2_set_voltage(struct dvb_frontend *fe,
 454                fe_sec_voltage_t voltage)
 455{
 456        int i;
 457        u8 gpio[3] = { 0 }; /* 0 = 2, 1 = 3, 2 = 4 */
 458
 459        gpio[2] = 1; /* high - voltage ? */
 460
 461        switch (voltage) {
 462        case SEC_VOLTAGE_13:
 463                gpio[0] = 1;
 464                break;
 465        case SEC_VOLTAGE_18:
 466                gpio[0] = 1;
 467                gpio[1] = 1;
 468                break;
 469        default:
 470        case SEC_VOLTAGE_OFF:
 471                break;
 472        }
 473
 474        for (i = 0; i < 3; i++)
 475                if (stv090x_set_gpio(fe, i+2, 0, gpio[i], 0) != 0)
 476                        return -EREMOTEIO;
 477        return 0;
 478}
 479
 480static struct stv090x_config technisat_usb2_stv090x_config = {
 481        .device         = STV0903,
 482        .demod_mode     = STV090x_SINGLE,
 483        .clk_mode       = STV090x_CLK_EXT,
 484
 485        .xtal           = 8000000,
 486        .address        = 0x68,
 487
 488        .ts1_mode       = STV090x_TSMODE_DVBCI,
 489        .ts1_clk        = 13400000,
 490        .ts1_tei        = 1,
 491
 492        .repeater_level = STV090x_RPTLEVEL_64,
 493
 494        .tuner_bbgain   = 6,
 495};
 496
 497static struct stv6110x_config technisat_usb2_stv6110x_config = {
 498        .addr           = 0x60,
 499        .refclk         = 16000000,
 500        .clk_div        = 2,
 501};
 502
 503static int technisat_usb2_frontend_attach(struct dvb_usb_adapter *a)
 504{
 505        struct usb_device *udev = a->dev->udev;
 506        int ret;
 507
 508        a->fe_adap[0].fe = dvb_attach(stv090x_attach, &technisat_usb2_stv090x_config,
 509                        &a->dev->i2c_adap, STV090x_DEMODULATOR_0);
 510
 511        if (a->fe_adap[0].fe) {
 512                struct stv6110x_devctl *ctl;
 513
 514                ctl = dvb_attach(stv6110x_attach,
 515                                a->fe_adap[0].fe,
 516                                &technisat_usb2_stv6110x_config,
 517                                &a->dev->i2c_adap);
 518
 519                if (ctl) {
 520                        technisat_usb2_stv090x_config.tuner_init          = ctl->tuner_init;
 521                        technisat_usb2_stv090x_config.tuner_sleep         = ctl->tuner_sleep;
 522                        technisat_usb2_stv090x_config.tuner_set_mode      = ctl->tuner_set_mode;
 523                        technisat_usb2_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency;
 524                        technisat_usb2_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency;
 525                        technisat_usb2_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth;
 526                        technisat_usb2_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth;
 527                        technisat_usb2_stv090x_config.tuner_set_bbgain    = ctl->tuner_set_bbgain;
 528                        technisat_usb2_stv090x_config.tuner_get_bbgain    = ctl->tuner_get_bbgain;
 529                        technisat_usb2_stv090x_config.tuner_set_refclk    = ctl->tuner_set_refclk;
 530                        technisat_usb2_stv090x_config.tuner_get_status    = ctl->tuner_get_status;
 531
 532                        /* call the init function once to initialize
 533                           tuner's clock output divider and demod's
 534                           master clock */
 535                        if (a->fe_adap[0].fe->ops.init)
 536                                a->fe_adap[0].fe->ops.init(a->fe_adap[0].fe);
 537
 538                        if (mutex_lock_interruptible(&a->dev->i2c_mutex) < 0)
 539                                return -EAGAIN;
 540
 541                        ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
 542                                        SET_IFCLK_TO_EXTERNAL_TSCLK_VENDOR_REQUEST,
 543                                        USB_TYPE_VENDOR | USB_DIR_OUT,
 544                                        0, 0,
 545                                        NULL, 0, 500);
 546                        mutex_unlock(&a->dev->i2c_mutex);
 547
 548                        if (ret != 0)
 549                                err("could not set IF_CLK to external");
 550
 551                        a->fe_adap[0].fe->ops.set_voltage = technisat_usb2_set_voltage;
 552
 553                        /* if everything was successful assign a nice name to the frontend */
 554                        strlcpy(a->fe_adap[0].fe->ops.info.name, a->dev->desc->name,
 555                                        sizeof(a->fe_adap[0].fe->ops.info.name));
 556                } else {
 557                        dvb_frontend_detach(a->fe_adap[0].fe);
 558                        a->fe_adap[0].fe = NULL;
 559                }
 560        }
 561
 562        technisat_usb2_set_led_timer(a->dev, 1, 1);
 563
 564        return a->fe_adap[0].fe == NULL ? -ENODEV : 0;
 565}
 566
 567/* Remote control */
 568
 569/* the device is giving providing raw IR-signals to the host mapping
 570 * it only to one remote control is just the default implementation
 571 */
 572#define NOMINAL_IR_BIT_TRANSITION_TIME_US 889
 573#define NOMINAL_IR_BIT_TIME_US (2 * NOMINAL_IR_BIT_TRANSITION_TIME_US)
 574
 575#define FIRMWARE_CLOCK_TICK 83333
 576#define FIRMWARE_CLOCK_DIVISOR 256
 577
 578#define IR_PERCENT_TOLERANCE 15
 579
 580#define NOMINAL_IR_BIT_TRANSITION_TICKS ((NOMINAL_IR_BIT_TRANSITION_TIME_US * 1000 * 1000) / FIRMWARE_CLOCK_TICK)
 581#define NOMINAL_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICKS / FIRMWARE_CLOCK_DIVISOR)
 582
 583#define NOMINAL_IR_BIT_TIME_TICKS ((NOMINAL_IR_BIT_TIME_US * 1000 * 1000) / FIRMWARE_CLOCK_TICK)
 584#define NOMINAL_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICKS / FIRMWARE_CLOCK_DIVISOR)
 585
 586#define MINIMUM_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICK_COUNT - ((NOMINAL_IR_BIT_TRANSITION_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100))
 587#define MAXIMUM_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICK_COUNT + ((NOMINAL_IR_BIT_TRANSITION_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100))
 588
 589#define MINIMUM_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICK_COUNT - ((NOMINAL_IR_BIT_TIME_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100))
 590#define MAXIMUM_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICK_COUNT + ((NOMINAL_IR_BIT_TIME_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100))
 591
 592static int technisat_usb2_get_ir(struct dvb_usb_device *d)
 593{
 594        u8 buf[62], *b;
 595        int ret;
 596        struct ir_raw_event ev;
 597
 598        buf[0] = GET_IR_DATA_VENDOR_REQUEST;
 599        buf[1] = 0x08;
 600        buf[2] = 0x8f;
 601        buf[3] = MINIMUM_IR_BIT_TRANSITION_TICK_COUNT;
 602        buf[4] = MAXIMUM_IR_BIT_TIME_TICK_COUNT;
 603
 604        if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
 605                return -EAGAIN;
 606        ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
 607                        GET_IR_DATA_VENDOR_REQUEST,
 608                        USB_TYPE_VENDOR | USB_DIR_OUT,
 609                        0, 0,
 610                        buf, 5, 500);
 611        if (ret < 0)
 612                goto unlock;
 613
 614        buf[1] = 0;
 615        buf[2] = 0;
 616        ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
 617                        GET_IR_DATA_VENDOR_REQUEST,
 618                        USB_TYPE_VENDOR | USB_DIR_IN,
 619                        0x8080, 0,
 620                        buf, sizeof(buf), 500);
 621
 622unlock:
 623        mutex_unlock(&d->i2c_mutex);
 624
 625        if (ret < 0)
 626                return ret;
 627
 628        if (ret == 1)
 629                return 0; /* no key pressed */
 630
 631        /* decoding */
 632        b = buf+1;
 633
 634#if 0
 635        deb_rc("RC: %d ", ret);
 636        debug_dump(b, ret, deb_rc);
 637#endif
 638
 639        ev.pulse = 0;
 640        while (1) {
 641                ev.pulse = !ev.pulse;
 642                ev.duration = (*b * FIRMWARE_CLOCK_DIVISOR * FIRMWARE_CLOCK_TICK) / 1000;
 643                ir_raw_event_store(d->rc_dev, &ev);
 644
 645                b++;
 646                if (*b == 0xff) {
 647                        ev.pulse = 0;
 648                        ev.duration = 888888*2;
 649                        ir_raw_event_store(d->rc_dev, &ev);
 650                        break;
 651                }
 652        }
 653
 654        ir_raw_event_handle(d->rc_dev);
 655
 656        return 1;
 657}
 658
 659static int technisat_usb2_rc_query(struct dvb_usb_device *d)
 660{
 661        int ret = technisat_usb2_get_ir(d);
 662
 663        if (ret < 0)
 664                return ret;
 665
 666        if (ret == 0)
 667                return 0;
 668
 669        if (!disable_led_control)
 670                technisat_usb2_set_led(d, 1, LED_BLINK);
 671
 672        return 0;
 673}
 674
 675/* DVB-USB and USB stuff follows */
 676static struct usb_device_id technisat_usb2_id_table[] = {
 677        { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_DVB_S2) },
 678        { 0 }           /* Terminating entry */
 679};
 680MODULE_DEVICE_TABLE(usb, technisat_usb2_id_table);
 681
 682/* device description */
 683static struct dvb_usb_device_properties technisat_usb2_devices = {
 684        .caps              = DVB_USB_IS_AN_I2C_ADAPTER,
 685
 686        .usb_ctrl          = CYPRESS_FX2,
 687
 688        .identify_state    = technisat_usb2_identify_state,
 689        .firmware          = "dvb-usb-SkyStar_USB_HD_FW_v17_63.HEX.fw",
 690
 691        .size_of_priv      = sizeof(struct technisat_usb2_state),
 692
 693        .i2c_algo          = &technisat_usb2_i2c_algo,
 694
 695        .power_ctrl        = technisat_usb2_power_ctrl,
 696        .read_mac_address  = technisat_usb2_read_mac_address,
 697
 698        .num_adapters = 1,
 699        .adapter = {
 700                {
 701                .num_frontends = 1,
 702                .fe = {{
 703                        .frontend_attach  = technisat_usb2_frontend_attach,
 704
 705                        .stream = {
 706                                .type = USB_ISOC,
 707                                .count = 8,
 708                                .endpoint = 0x2,
 709                                .u = {
 710                                        .isoc = {
 711                                                .framesperurb = 32,
 712                                                .framesize = 2048,
 713                                                .interval = 3,
 714                                        }
 715                                }
 716                        },
 717                }},
 718                        .size_of_priv = 0,
 719                },
 720        },
 721
 722        .num_device_descs = 1,
 723        .devices = {
 724                {   "Technisat SkyStar USB HD (DVB-S/S2)",
 725                        { &technisat_usb2_id_table[0], NULL },
 726                        { NULL },
 727                },
 728        },
 729
 730        .rc.core = {
 731                .rc_interval = 100,
 732                .rc_codes    = RC_MAP_TECHNISAT_USB2,
 733                .module_name = "technisat-usb2",
 734                .rc_query    = technisat_usb2_rc_query,
 735                .allowed_protos = RC_BIT_ALL,
 736                .driver_type    = RC_DRIVER_IR_RAW,
 737        }
 738};
 739
 740static int technisat_usb2_probe(struct usb_interface *intf,
 741                const struct usb_device_id *id)
 742{
 743        struct dvb_usb_device *dev;
 744
 745        if (dvb_usb_device_init(intf, &technisat_usb2_devices, THIS_MODULE,
 746                                &dev, adapter_nr) != 0)
 747                return -ENODEV;
 748
 749        if (dev) {
 750                struct technisat_usb2_state *state = dev->priv;
 751                state->dev = dev;
 752
 753                if (!disable_led_control) {
 754                        INIT_DELAYED_WORK(&state->green_led_work,
 755                                        technisat_usb2_green_led_control);
 756                        schedule_delayed_work(&state->green_led_work,
 757                                        msecs_to_jiffies(500));
 758                }
 759        }
 760
 761        return 0;
 762}
 763
 764static void technisat_usb2_disconnect(struct usb_interface *intf)
 765{
 766        struct dvb_usb_device *dev = usb_get_intfdata(intf);
 767
 768        /* work and stuff was only created when the device is is hot-state */
 769        if (dev != NULL) {
 770                struct technisat_usb2_state *state = dev->priv;
 771                if (state != NULL)
 772                        cancel_delayed_work_sync(&state->green_led_work);
 773        }
 774
 775        dvb_usb_device_exit(intf);
 776}
 777
 778static struct usb_driver technisat_usb2_driver = {
 779        .name       = "dvb_usb_technisat_usb2",
 780        .probe      = technisat_usb2_probe,
 781        .disconnect = technisat_usb2_disconnect,
 782        .id_table   = technisat_usb2_id_table,
 783};
 784
 785module_usb_driver(technisat_usb2_driver);
 786
 787MODULE_AUTHOR("Patrick Boettcher <pboettcher@kernellabs.com>");
 788MODULE_DESCRIPTION("Driver for Technisat DVB-S/S2 USB 2.0 device");
 789MODULE_VERSION("1.0");
 790MODULE_LICENSE("GPL");
 791