root/drivers/media/usb/dvb-usb/vp702x.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. vp702x_usb_in_op_unlocked
  2. vp702x_usb_in_op
  3. vp702x_usb_out_op_unlocked
  4. vp702x_usb_out_op
  5. vp702x_usb_inout_op
  6. vp702x_usb_inout_cmd
  7. vp702x_set_pld_mode
  8. vp702x_set_pld_state
  9. vp702x_set_pid
  10. vp702x_init_pid_filter
  11. vp702x_streaming_ctrl
  12. vp702x_rc_query
  13. vp702x_read_mac_addr
  14. vp702x_frontend_attach
  15. vp702x_usb_probe
  16. vp702x_usb_disconnect

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

/* [<][>][^][v][top][bottom][index][help] */