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@desy.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        u8 *key;
 263        int i;
 264
 265/* remove the following return to enabled remote querying */
 266        return 0;
 267
 268        key = kmalloc(10, GFP_KERNEL);
 269        if (!key)
 270                return -ENOMEM;
 271
 272        vp702x_usb_in_op(d,READ_REMOTE_REQ,0,0,key,10);
 273
 274        deb_rc("remote query key: %x %d\n",key[1],key[1]);
 275
 276        if (key[1] == 0x44) {
 277                *state = REMOTE_NO_KEY_PRESSED;
 278                kfree(key);
 279                return 0;
 280        }
 281
 282        for (i = 0; i < ARRAY_SIZE(rc_map_vp702x_table); i++)
 283                if (rc5_custom(&rc_map_vp702x_table[i]) == key[1]) {
 284                        *state = REMOTE_KEY_PRESSED;
 285                        *event = rc_map_vp702x_table[i].keycode;
 286                        break;
 287                }
 288        kfree(key);
 289        return 0;
 290}
 291
 292
 293static int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
 294{
 295        u8 i, *buf;
 296        struct vp702x_device_state *st = d->priv;
 297
 298        mutex_lock(&st->buf_mutex);
 299        buf = st->buf;
 300        for (i = 6; i < 12; i++)
 301                vp702x_usb_in_op(d, READ_EEPROM_REQ, i, 1, &buf[i - 6], 1);
 302
 303        memcpy(mac, buf, 6);
 304        mutex_unlock(&st->buf_mutex);
 305        return 0;
 306}
 307
 308static int vp702x_frontend_attach(struct dvb_usb_adapter *adap)
 309{
 310        u8 buf[10] = { 0 };
 311
 312        vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 0, 7, NULL, 0);
 313
 314        if (vp702x_usb_inout_cmd(adap->dev, GET_SYSTEM_STRING, NULL, 0,
 315                                   buf, 10, 10))
 316                return -EIO;
 317
 318        buf[9] = '\0';
 319        info("system string: %s",&buf[1]);
 320
 321        vp702x_init_pid_filter(adap);
 322
 323        adap->fe_adap[0].fe = vp702x_fe_attach(adap->dev);
 324        vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 1, 7, NULL, 0);
 325
 326        return 0;
 327}
 328
 329static struct dvb_usb_device_properties vp702x_properties;
 330
 331static int vp702x_usb_probe(struct usb_interface *intf,
 332                const struct usb_device_id *id)
 333{
 334        struct dvb_usb_device *d;
 335        struct vp702x_device_state *st;
 336        int ret;
 337
 338        ret = dvb_usb_device_init(intf, &vp702x_properties,
 339                                   THIS_MODULE, &d, adapter_nr);
 340        if (ret)
 341                goto out;
 342
 343        st = d->priv;
 344        st->buf_len = 16;
 345        st->buf = kmalloc(st->buf_len, GFP_KERNEL);
 346        if (!st->buf) {
 347                ret = -ENOMEM;
 348                dvb_usb_device_exit(intf);
 349                goto out;
 350        }
 351        mutex_init(&st->buf_mutex);
 352
 353out:
 354        return ret;
 355
 356}
 357
 358static void vp702x_usb_disconnect(struct usb_interface *intf)
 359{
 360        struct dvb_usb_device *d = usb_get_intfdata(intf);
 361        struct vp702x_device_state *st = d->priv;
 362        mutex_lock(&st->buf_mutex);
 363        kfree(st->buf);
 364        mutex_unlock(&st->buf_mutex);
 365        dvb_usb_device_exit(intf);
 366}
 367
 368static struct usb_device_id vp702x_usb_table [] = {
 369            { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7021_COLD) },
 370//          { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_COLD) },
 371//          { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_WARM) },
 372            { 0 },
 373};
 374MODULE_DEVICE_TABLE(usb, vp702x_usb_table);
 375
 376static struct dvb_usb_device_properties vp702x_properties = {
 377        .usb_ctrl = CYPRESS_FX2,
 378        .firmware            = "dvb-usb-vp702x-02.fw",
 379        .no_reconnect        = 1,
 380
 381        .size_of_priv     = sizeof(struct vp702x_device_state),
 382
 383        .num_adapters = 1,
 384        .adapter = {
 385                {
 386                .num_frontends = 1,
 387                .fe = {{
 388                        .caps             = DVB_USB_ADAP_RECEIVES_204_BYTE_TS,
 389
 390                        .streaming_ctrl   = vp702x_streaming_ctrl,
 391                        .frontend_attach  = vp702x_frontend_attach,
 392
 393                        /* parameter for the MPEG2-data transfer */
 394                        .stream = {
 395                                .type = USB_BULK,
 396                                .count = 10,
 397                                .endpoint = 0x02,
 398                                .u = {
 399                                        .bulk = {
 400                                                .buffersize = 4096,
 401                                        }
 402                                }
 403                        },
 404                }},
 405                        .size_of_priv     = sizeof(struct vp702x_adapter_state),
 406                }
 407        },
 408        .read_mac_address = vp702x_read_mac_addr,
 409
 410        .rc.legacy = {
 411                .rc_map_table       = rc_map_vp702x_table,
 412                .rc_map_size  = ARRAY_SIZE(rc_map_vp702x_table),
 413                .rc_interval      = 400,
 414                .rc_query         = vp702x_rc_query,
 415        },
 416
 417        .num_device_descs = 1,
 418        .devices = {
 419                { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7021)",
 420                  .cold_ids = { &vp702x_usb_table[0], NULL },
 421                  .warm_ids = { NULL },
 422                },
 423/*              { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7020)",
 424                  .cold_ids = { &vp702x_usb_table[2], NULL },
 425                  .warm_ids = { &vp702x_usb_table[3], NULL },
 426                },
 427*/              { NULL },
 428        }
 429};
 430
 431/* usb specific object needed to register this driver with the usb subsystem */
 432static struct usb_driver vp702x_usb_driver = {
 433        .name           = "dvb_usb_vp702x",
 434        .probe          = vp702x_usb_probe,
 435        .disconnect     = vp702x_usb_disconnect,
 436        .id_table       = vp702x_usb_table,
 437};
 438
 439module_usb_driver(vp702x_usb_driver);
 440
 441MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
 442MODULE_DESCRIPTION("Driver for Twinhan StarBox DVB-S USB2.0 and clones");
 443MODULE_VERSION("1.0");
 444MODULE_LICENSE("GPL");
 445