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