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