linux/drivers/media/usb/dvb-usb/vp702x.c
<<
>>
Prefs
   1/* DVB USB compliant Linux driver for the TwinhanDTV StarBox USB2.0 DVB-S
   2 * receiver.
   3 *
   4 * Copyright (C) 2005 Ralph Metzler <rjkm@metzlerbros.de>
   5 *                    Metzler Brothers Systementwicklung GbR
   6 *
   7 * Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@posteo.de>
   8 *
   9 * Thanks to Twinhan who kindly provided hardware and information.
  10 *
  11 *      This program is free software; you can redistribute it and/or modify it
  12 *      under the terms of the GNU General Public License as published by the Free
  13 *      Software Foundation, version 2.
  14 *
  15 * see Documentation/dvb/README.dvb-usb for more information
  16 */
  17#include "vp702x.h"
  18#include <linux/mutex.h>
  19
  20/* debug */
  21int dvb_usb_vp702x_debug;
  22module_param_named(debug,dvb_usb_vp702x_debug, int, 0644);
  23MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
  24
  25DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
  26
  27struct vp702x_adapter_state {
  28        int pid_filter_count;
  29        int pid_filter_can_bypass;
  30        u8  pid_filter_state;
  31};
  32
  33static int vp702x_usb_in_op_unlocked(struct dvb_usb_device *d, u8 req,
  34                                     u16 value, u16 index, u8 *b, int blen)
  35{
  36        int ret;
  37
  38        ret = usb_control_msg(d->udev,
  39                usb_rcvctrlpipe(d->udev, 0),
  40                req,
  41                USB_TYPE_VENDOR | USB_DIR_IN,
  42                value, index, b, blen,
  43                2000);
  44
  45        if (ret < 0) {
  46                warn("usb in operation failed. (%d)", ret);
  47                ret = -EIO;
  48        } else
  49                ret = 0;
  50
  51
  52        deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
  53        debug_dump(b,blen,deb_xfer);
  54
  55        return ret;
  56}
  57
  58int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value,
  59                     u16 index, u8 *b, int blen)
  60{
  61        int ret;
  62
  63        mutex_lock(&d->usb_mutex);
  64        ret = vp702x_usb_in_op_unlocked(d, req, value, index, b, blen);
  65        mutex_unlock(&d->usb_mutex);
  66
  67        return ret;
  68}
  69
  70static int vp702x_usb_out_op_unlocked(struct dvb_usb_device *d, u8 req,
  71                                      u16 value, u16 index, u8 *b, int blen)
  72{
  73        int ret;
  74        deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
  75        debug_dump(b,blen,deb_xfer);
  76
  77        if ((ret = usb_control_msg(d->udev,
  78                        usb_sndctrlpipe(d->udev,0),
  79                        req,
  80                        USB_TYPE_VENDOR | USB_DIR_OUT,
  81                        value,index,b,blen,
  82                        2000)) != blen) {
  83                warn("usb out operation failed. (%d)",ret);
  84                return -EIO;
  85        } else
  86                return 0;
  87}
  88
  89static int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
  90                             u16 index, u8 *b, int blen)
  91{
  92        int ret;
  93
  94        mutex_lock(&d->usb_mutex);
  95        ret = vp702x_usb_out_op_unlocked(d, req, value, index, b, blen);
  96        mutex_unlock(&d->usb_mutex);
  97
  98        return ret;
  99}
 100
 101int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec)
 102{
 103        int ret;
 104
 105        if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
 106                return ret;
 107
 108        ret = vp702x_usb_out_op_unlocked(d, REQUEST_OUT, 0, 0, o, olen);
 109        msleep(msec);
 110        ret = vp702x_usb_in_op_unlocked(d, REQUEST_IN, 0, 0, i, ilen);
 111
 112        mutex_unlock(&d->usb_mutex);
 113        return ret;
 114}
 115
 116static int vp702x_usb_inout_cmd(struct dvb_usb_device *d, u8 cmd, u8 *o,
 117                                int olen, u8 *i, int ilen, int msec)
 118{
 119        struct vp702x_device_state *st = d->priv;
 120        int ret = 0;
 121        u8 *buf;
 122        int buflen = max(olen + 2, ilen + 1);
 123
 124        ret = mutex_lock_interruptible(&st->buf_mutex);
 125        if (ret < 0)
 126                return ret;
 127
 128        if (buflen > st->buf_len) {
 129                buf = kmalloc(buflen, GFP_KERNEL);
 130                if (!buf) {
 131                        mutex_unlock(&st->buf_mutex);
 132                        return -ENOMEM;
 133                }
 134                info("successfully reallocated a bigger buffer");
 135                kfree(st->buf);
 136                st->buf = buf;
 137                st->buf_len = buflen;
 138        } else {
 139                buf = st->buf;
 140        }
 141
 142        buf[0] = 0x00;
 143        buf[1] = cmd;
 144        memcpy(&buf[2], o, olen);
 145
 146        ret = vp702x_usb_inout_op(d, buf, olen+2, buf, ilen+1, msec);
 147
 148        if (ret == 0)
 149                memcpy(i, &buf[1], ilen);
 150        mutex_unlock(&st->buf_mutex);
 151
 152        return ret;
 153}
 154
 155static int vp702x_set_pld_mode(struct dvb_usb_adapter *adap, u8 bypass)
 156{
 157        int ret;
 158        struct vp702x_device_state *st = adap->dev->priv;
 159        u8 *buf;
 160
 161        mutex_lock(&st->buf_mutex);
 162
 163        buf = st->buf;
 164        memset(buf, 0, 16);
 165
 166        ret = vp702x_usb_in_op(adap->dev, 0xe0, (bypass << 8) | 0x0e,
 167                        0, buf, 16);
 168        mutex_unlock(&st->buf_mutex);
 169        return ret;
 170}
 171
 172static int vp702x_set_pld_state(struct dvb_usb_adapter *adap, u8 state)
 173{
 174        int ret;
 175        struct vp702x_device_state *st = adap->dev->priv;
 176        u8 *buf;
 177
 178        mutex_lock(&st->buf_mutex);
 179
 180        buf = st->buf;
 181        memset(buf, 0, 16);
 182        ret = vp702x_usb_in_op(adap->dev, 0xe0, (state << 8) | 0x0f,
 183                        0, buf, 16);
 184
 185        mutex_unlock(&st->buf_mutex);
 186
 187        return ret;
 188}
 189
 190static int vp702x_set_pid(struct dvb_usb_adapter *adap, u16 pid, u8 id, int onoff)
 191{
 192        struct vp702x_adapter_state *st = adap->priv;
 193        struct vp702x_device_state *dst = adap->dev->priv;
 194        u8 *buf;
 195
 196        if (onoff)
 197                st->pid_filter_state |=  (1 << id);
 198        else {
 199                st->pid_filter_state &= ~(1 << id);
 200                pid = 0xffff;
 201        }
 202
 203        id = 0x10 + id*2;
 204
 205        vp702x_set_pld_state(adap, st->pid_filter_state);
 206
 207        mutex_lock(&dst->buf_mutex);
 208
 209        buf = dst->buf;
 210        memset(buf, 0, 16);
 211        vp702x_usb_in_op(adap->dev, 0xe0, (((pid >> 8) & 0xff) << 8) | (id), 0, buf, 16);
 212        vp702x_usb_in_op(adap->dev, 0xe0, (((pid     ) & 0xff) << 8) | (id+1), 0, buf, 16);
 213
 214        mutex_unlock(&dst->buf_mutex);
 215
 216        return 0;
 217}
 218
 219
 220static int vp702x_init_pid_filter(struct dvb_usb_adapter *adap)
 221{
 222        struct vp702x_adapter_state *st = adap->priv;
 223        struct vp702x_device_state *dst = adap->dev->priv;
 224        int i;
 225        u8 *b;
 226
 227        st->pid_filter_count = 8;
 228        st->pid_filter_can_bypass = 1;
 229        st->pid_filter_state = 0x00;
 230
 231        vp702x_set_pld_mode(adap, 1); /* bypass */
 232
 233        for (i = 0; i < st->pid_filter_count; i++)
 234                vp702x_set_pid(adap, 0xffff, i, 1);
 235
 236        mutex_lock(&dst->buf_mutex);
 237        b = dst->buf;
 238        memset(b, 0, 10);
 239        vp702x_usb_in_op(adap->dev, 0xb5, 3, 0, b, 10);
 240        vp702x_usb_in_op(adap->dev, 0xb5, 0, 0, b, 10);
 241        vp702x_usb_in_op(adap->dev, 0xb5, 1, 0, b, 10);
 242        mutex_unlock(&dst->buf_mutex);
 243        /*vp702x_set_pld_mode(d, 0); // filter */
 244
 245        return 0;
 246}
 247
 248static int vp702x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 249{
 250        return 0;
 251}
 252
 253/* keys for the enclosed remote control */
 254static struct rc_map_table rc_map_vp702x_table[] = {
 255        { 0x0001, KEY_1 },
 256        { 0x0002, KEY_2 },
 257};
 258
 259/* remote control stuff (does not work with my box) */
 260static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 261{
 262/* remove the following return to enabled remote querying */
 263#if 0
 264        u8 *key;
 265        int i;
 266
 267        key = kmalloc(10, GFP_KERNEL);
 268        if (!key)
 269                return -ENOMEM;
 270
 271        vp702x_usb_in_op(d,READ_REMOTE_REQ,0,0,key,10);
 272
 273        deb_rc("remote query key: %x %d\n",key[1],key[1]);
 274
 275        if (key[1] == 0x44) {
 276                *state = REMOTE_NO_KEY_PRESSED;
 277                kfree(key);
 278                return 0;
 279        }
 280
 281        for (i = 0; i < ARRAY_SIZE(rc_map_vp702x_table); i++)
 282                if (rc5_custom(&rc_map_vp702x_table[i]) == key[1]) {
 283                        *state = REMOTE_KEY_PRESSED;
 284                        *event = rc_map_vp702x_table[i].keycode;
 285                        break;
 286                }
 287        kfree(key);
 288#endif
 289
 290        return 0;
 291}
 292
 293
 294static int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
 295{
 296        u8 i, *buf;
 297        struct vp702x_device_state *st = d->priv;
 298
 299        mutex_lock(&st->buf_mutex);
 300        buf = st->buf;
 301        for (i = 6; i < 12; i++)
 302                vp702x_usb_in_op(d, READ_EEPROM_REQ, i, 1, &buf[i - 6], 1);
 303
 304        memcpy(mac, buf, 6);
 305        mutex_unlock(&st->buf_mutex);
 306        return 0;
 307}
 308
 309static int vp702x_frontend_attach(struct dvb_usb_adapter *adap)
 310{
 311        u8 buf[10] = { 0 };
 312
 313        vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 0, 7, NULL, 0);
 314
 315        if (vp702x_usb_inout_cmd(adap->dev, GET_SYSTEM_STRING, NULL, 0,
 316                                   buf, 10, 10))
 317                return -EIO;
 318
 319        buf[9] = '\0';
 320        info("system string: %s",&buf[1]);
 321
 322        vp702x_init_pid_filter(adap);
 323
 324        adap->fe_adap[0].fe = vp702x_fe_attach(adap->dev);
 325        vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 1, 7, NULL, 0);
 326
 327        return 0;
 328}
 329
 330static struct dvb_usb_device_properties vp702x_properties;
 331
 332static int vp702x_usb_probe(struct usb_interface *intf,
 333                const struct usb_device_id *id)
 334{
 335        struct dvb_usb_device *d;
 336        struct vp702x_device_state *st;
 337        int ret;
 338
 339        ret = dvb_usb_device_init(intf, &vp702x_properties,
 340                                   THIS_MODULE, &d, adapter_nr);
 341        if (ret)
 342                goto out;
 343
 344        st = d->priv;
 345        st->buf_len = 16;
 346        st->buf = kmalloc(st->buf_len, GFP_KERNEL);
 347        if (!st->buf) {
 348                ret = -ENOMEM;
 349                dvb_usb_device_exit(intf);
 350                goto out;
 351        }
 352        mutex_init(&st->buf_mutex);
 353
 354out:
 355        return ret;
 356
 357}
 358
 359static void vp702x_usb_disconnect(struct usb_interface *intf)
 360{
 361        struct dvb_usb_device *d = usb_get_intfdata(intf);
 362        struct vp702x_device_state *st = d->priv;
 363        mutex_lock(&st->buf_mutex);
 364        kfree(st->buf);
 365        mutex_unlock(&st->buf_mutex);
 366        dvb_usb_device_exit(intf);
 367}
 368
 369static struct usb_device_id vp702x_usb_table [] = {
 370            { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7021_COLD) },
 371//          { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_COLD) },
 372//          { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_WARM) },
 373            { 0 },
 374};
 375MODULE_DEVICE_TABLE(usb, vp702x_usb_table);
 376
 377static struct dvb_usb_device_properties vp702x_properties = {
 378        .usb_ctrl = CYPRESS_FX2,
 379        .firmware            = "dvb-usb-vp702x-02.fw",
 380        .no_reconnect        = 1,
 381
 382        .size_of_priv     = sizeof(struct vp702x_device_state),
 383
 384        .num_adapters = 1,
 385        .adapter = {
 386                {
 387                .num_frontends = 1,
 388                .fe = {{
 389                        .caps             = DVB_USB_ADAP_RECEIVES_204_BYTE_TS,
 390
 391                        .streaming_ctrl   = vp702x_streaming_ctrl,
 392                        .frontend_attach  = vp702x_frontend_attach,
 393
 394                        /* parameter for the MPEG2-data transfer */
 395                        .stream = {
 396                                .type = USB_BULK,
 397                                .count = 10,
 398                                .endpoint = 0x02,
 399                                .u = {
 400                                        .bulk = {
 401                                                .buffersize = 4096,
 402                                        }
 403                                }
 404                        },
 405                }},
 406                        .size_of_priv     = sizeof(struct vp702x_adapter_state),
 407                }
 408        },
 409        .read_mac_address = vp702x_read_mac_addr,
 410
 411        .rc.legacy = {
 412                .rc_map_table       = rc_map_vp702x_table,
 413                .rc_map_size  = ARRAY_SIZE(rc_map_vp702x_table),
 414                .rc_interval      = 400,
 415                .rc_query         = vp702x_rc_query,
 416        },
 417
 418        .num_device_descs = 1,
 419        .devices = {
 420                { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7021)",
 421                  .cold_ids = { &vp702x_usb_table[0], NULL },
 422                  .warm_ids = { NULL },
 423                },
 424/*              { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7020)",
 425                  .cold_ids = { &vp702x_usb_table[2], NULL },
 426                  .warm_ids = { &vp702x_usb_table[3], NULL },
 427                },
 428*/              { NULL },
 429        }
 430};
 431
 432/* usb specific object needed to register this driver with the usb subsystem */
 433static struct usb_driver vp702x_usb_driver = {
 434        .name           = "dvb_usb_vp702x",
 435        .probe          = vp702x_usb_probe,
 436        .disconnect     = vp702x_usb_disconnect,
 437        .id_table       = vp702x_usb_table,
 438};
 439
 440module_usb_driver(vp702x_usb_driver);
 441
 442MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
 443MODULE_DESCRIPTION("Driver for Twinhan StarBox DVB-S USB2.0 and clones");
 444MODULE_VERSION("1.0");
 445MODULE_LICENSE("GPL");
 446