Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /* DVB USB compliant Linux driver for the TwinhanDTV StarBox USB2.0 DVB-S
0003  * receiver.
0004  *
0005  * Copyright (C) 2005 Ralph Metzler <rjkm@metzlerbros.de>
0006  *                    Metzler Brothers Systementwicklung GbR
0007  *
0008  * Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@posteo.de>
0009  *
0010  * Thanks to Twinhan who kindly provided hardware and information.
0011  *
0012  * see Documentation/driver-api/media/drivers/dvb-usb.rst for more information
0013  */
0014 #include "vp702x.h"
0015 #include <linux/mutex.h>
0016 
0017 /* debug */
0018 int dvb_usb_vp702x_debug;
0019 module_param_named(debug,dvb_usb_vp702x_debug, int, 0644);
0020 MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
0021 
0022 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
0023 
0024 struct vp702x_adapter_state {
0025     int pid_filter_count;
0026     int pid_filter_can_bypass;
0027     u8  pid_filter_state;
0028 };
0029 
0030 static int vp702x_usb_in_op_unlocked(struct dvb_usb_device *d, u8 req,
0031                      u16 value, u16 index, u8 *b, int blen)
0032 {
0033     int ret;
0034 
0035     ret = usb_control_msg(d->udev,
0036         usb_rcvctrlpipe(d->udev, 0),
0037         req,
0038         USB_TYPE_VENDOR | USB_DIR_IN,
0039         value, index, b, blen,
0040         2000);
0041 
0042     if (ret < 0) {
0043         warn("usb in operation failed. (%d)", ret);
0044         ret = -EIO;
0045     } else
0046         ret = 0;
0047 
0048 
0049     deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
0050     debug_dump(b,blen,deb_xfer);
0051 
0052     return ret;
0053 }
0054 
0055 int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value,
0056              u16 index, u8 *b, int blen)
0057 {
0058     int ret;
0059 
0060     mutex_lock(&d->usb_mutex);
0061     ret = vp702x_usb_in_op_unlocked(d, req, value, index, b, blen);
0062     mutex_unlock(&d->usb_mutex);
0063 
0064     return ret;
0065 }
0066 
0067 static int vp702x_usb_out_op_unlocked(struct dvb_usb_device *d, u8 req,
0068                       u16 value, u16 index, u8 *b, int blen)
0069 {
0070     int ret;
0071     deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
0072     debug_dump(b,blen,deb_xfer);
0073 
0074     if ((ret = usb_control_msg(d->udev,
0075             usb_sndctrlpipe(d->udev,0),
0076             req,
0077             USB_TYPE_VENDOR | USB_DIR_OUT,
0078             value,index,b,blen,
0079             2000)) != blen) {
0080         warn("usb out operation failed. (%d)",ret);
0081         return -EIO;
0082     } else
0083         return 0;
0084 }
0085 
0086 static int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
0087                  u16 index, u8 *b, int blen)
0088 {
0089     int ret;
0090 
0091     mutex_lock(&d->usb_mutex);
0092     ret = vp702x_usb_out_op_unlocked(d, req, value, index, b, blen);
0093     mutex_unlock(&d->usb_mutex);
0094 
0095     return ret;
0096 }
0097 
0098 int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec)
0099 {
0100     int ret;
0101 
0102     if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
0103         return ret;
0104 
0105     ret = vp702x_usb_out_op_unlocked(d, REQUEST_OUT, 0, 0, o, olen);
0106     msleep(msec);
0107     ret = vp702x_usb_in_op_unlocked(d, REQUEST_IN, 0, 0, i, ilen);
0108 
0109     mutex_unlock(&d->usb_mutex);
0110     return ret;
0111 }
0112 
0113 static int vp702x_usb_inout_cmd(struct dvb_usb_device *d, u8 cmd, u8 *o,
0114                 int olen, u8 *i, int ilen, int msec)
0115 {
0116     struct vp702x_device_state *st = d->priv;
0117     int ret = 0;
0118     u8 *buf;
0119     int buflen = max(olen + 2, ilen + 1);
0120 
0121     ret = mutex_lock_interruptible(&st->buf_mutex);
0122     if (ret < 0)
0123         return ret;
0124 
0125     if (buflen > st->buf_len) {
0126         buf = kmalloc(buflen, GFP_KERNEL);
0127         if (!buf) {
0128             mutex_unlock(&st->buf_mutex);
0129             return -ENOMEM;
0130         }
0131         info("successfully reallocated a bigger buffer");
0132         kfree(st->buf);
0133         st->buf = buf;
0134         st->buf_len = buflen;
0135     } else {
0136         buf = st->buf;
0137     }
0138 
0139     buf[0] = 0x00;
0140     buf[1] = cmd;
0141     memcpy(&buf[2], o, olen);
0142 
0143     ret = vp702x_usb_inout_op(d, buf, olen+2, buf, ilen+1, msec);
0144 
0145     if (ret == 0)
0146         memcpy(i, &buf[1], ilen);
0147     mutex_unlock(&st->buf_mutex);
0148 
0149     return ret;
0150 }
0151 
0152 static int vp702x_set_pld_mode(struct dvb_usb_adapter *adap, u8 bypass)
0153 {
0154     int ret;
0155     struct vp702x_device_state *st = adap->dev->priv;
0156     u8 *buf;
0157 
0158     mutex_lock(&st->buf_mutex);
0159 
0160     buf = st->buf;
0161     memset(buf, 0, 16);
0162 
0163     ret = vp702x_usb_in_op(adap->dev, 0xe0, (bypass << 8) | 0x0e,
0164             0, buf, 16);
0165     mutex_unlock(&st->buf_mutex);
0166     return ret;
0167 }
0168 
0169 static int vp702x_set_pld_state(struct dvb_usb_adapter *adap, u8 state)
0170 {
0171     int ret;
0172     struct vp702x_device_state *st = adap->dev->priv;
0173     u8 *buf;
0174 
0175     mutex_lock(&st->buf_mutex);
0176 
0177     buf = st->buf;
0178     memset(buf, 0, 16);
0179     ret = vp702x_usb_in_op(adap->dev, 0xe0, (state << 8) | 0x0f,
0180             0, buf, 16);
0181 
0182     mutex_unlock(&st->buf_mutex);
0183 
0184     return ret;
0185 }
0186 
0187 static int vp702x_set_pid(struct dvb_usb_adapter *adap, u16 pid, u8 id, int onoff)
0188 {
0189     struct vp702x_adapter_state *st = adap->priv;
0190     struct vp702x_device_state *dst = adap->dev->priv;
0191     u8 *buf;
0192 
0193     if (onoff)
0194         st->pid_filter_state |=  (1 << id);
0195     else {
0196         st->pid_filter_state &= ~(1 << id);
0197         pid = 0xffff;
0198     }
0199 
0200     id = 0x10 + id*2;
0201 
0202     vp702x_set_pld_state(adap, st->pid_filter_state);
0203 
0204     mutex_lock(&dst->buf_mutex);
0205 
0206     buf = dst->buf;
0207     memset(buf, 0, 16);
0208     vp702x_usb_in_op(adap->dev, 0xe0, (((pid >> 8) & 0xff) << 8) | (id), 0, buf, 16);
0209     vp702x_usb_in_op(adap->dev, 0xe0, (((pid     ) & 0xff) << 8) | (id+1), 0, buf, 16);
0210 
0211     mutex_unlock(&dst->buf_mutex);
0212 
0213     return 0;
0214 }
0215 
0216 
0217 static int vp702x_init_pid_filter(struct dvb_usb_adapter *adap)
0218 {
0219     struct vp702x_adapter_state *st = adap->priv;
0220     struct vp702x_device_state *dst = adap->dev->priv;
0221     int i;
0222     u8 *b;
0223 
0224     st->pid_filter_count = 8;
0225     st->pid_filter_can_bypass = 1;
0226     st->pid_filter_state = 0x00;
0227 
0228     vp702x_set_pld_mode(adap, 1); /* bypass */
0229 
0230     for (i = 0; i < st->pid_filter_count; i++)
0231         vp702x_set_pid(adap, 0xffff, i, 1);
0232 
0233     mutex_lock(&dst->buf_mutex);
0234     b = dst->buf;
0235     memset(b, 0, 10);
0236     vp702x_usb_in_op(adap->dev, 0xb5, 3, 0, b, 10);
0237     vp702x_usb_in_op(adap->dev, 0xb5, 0, 0, b, 10);
0238     vp702x_usb_in_op(adap->dev, 0xb5, 1, 0, b, 10);
0239     mutex_unlock(&dst->buf_mutex);
0240     /*vp702x_set_pld_mode(d, 0); // filter */
0241 
0242     return 0;
0243 }
0244 
0245 static int vp702x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
0246 {
0247     return 0;
0248 }
0249 
0250 /* keys for the enclosed remote control */
0251 static struct rc_map_table rc_map_vp702x_table[] = {
0252     { 0x0001, KEY_1 },
0253     { 0x0002, KEY_2 },
0254 };
0255 
0256 /* remote control stuff (does not work with my box) */
0257 static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
0258 {
0259 /* remove the following return to enabled remote querying */
0260 #if 0
0261     u8 *key;
0262     int i;
0263 
0264     key = kmalloc(10, GFP_KERNEL);
0265     if (!key)
0266         return -ENOMEM;
0267 
0268     vp702x_usb_in_op(d,READ_REMOTE_REQ,0,0,key,10);
0269 
0270     deb_rc("remote query key: %x %d\n",key[1],key[1]);
0271 
0272     if (key[1] == 0x44) {
0273         *state = REMOTE_NO_KEY_PRESSED;
0274         kfree(key);
0275         return 0;
0276     }
0277 
0278     for (i = 0; i < ARRAY_SIZE(rc_map_vp702x_table); i++)
0279         if (rc5_custom(&rc_map_vp702x_table[i]) == key[1]) {
0280             *state = REMOTE_KEY_PRESSED;
0281             *event = rc_map_vp702x_table[i].keycode;
0282             break;
0283         }
0284     kfree(key);
0285 #endif
0286 
0287     return 0;
0288 }
0289 
0290 
0291 static int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
0292 {
0293     u8 i, *buf;
0294     int ret;
0295     struct vp702x_device_state *st = d->priv;
0296 
0297     mutex_lock(&st->buf_mutex);
0298     buf = st->buf;
0299     for (i = 6; i < 12; i++) {
0300         ret = vp702x_usb_in_op(d, READ_EEPROM_REQ, i, 1,
0301                        &buf[i - 6], 1);
0302         if (ret < 0)
0303             goto err;
0304     }
0305 
0306     memcpy(mac, buf, 6);
0307 err:
0308     mutex_unlock(&st->buf_mutex);
0309     return ret;
0310 }
0311 
0312 static int vp702x_frontend_attach(struct dvb_usb_adapter *adap)
0313 {
0314     u8 buf[10] = { 0 };
0315 
0316     vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 0, 7, NULL, 0);
0317 
0318     if (vp702x_usb_inout_cmd(adap->dev, GET_SYSTEM_STRING, NULL, 0,
0319                    buf, 10, 10))
0320         return -EIO;
0321 
0322     buf[9] = '\0';
0323     info("system string: %s",&buf[1]);
0324 
0325     vp702x_init_pid_filter(adap);
0326 
0327     adap->fe_adap[0].fe = vp702x_fe_attach(adap->dev);
0328     vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 1, 7, NULL, 0);
0329 
0330     return 0;
0331 }
0332 
0333 static struct dvb_usb_device_properties vp702x_properties;
0334 
0335 static int vp702x_usb_probe(struct usb_interface *intf,
0336         const struct usb_device_id *id)
0337 {
0338     struct dvb_usb_device *d;
0339     struct vp702x_device_state *st;
0340     int ret;
0341 
0342     ret = dvb_usb_device_init(intf, &vp702x_properties,
0343                    THIS_MODULE, &d, adapter_nr);
0344     if (ret)
0345         goto out;
0346 
0347     st = d->priv;
0348     st->buf_len = 16;
0349     st->buf = kmalloc(st->buf_len, GFP_KERNEL);
0350     if (!st->buf) {
0351         ret = -ENOMEM;
0352         dvb_usb_device_exit(intf);
0353         goto out;
0354     }
0355     mutex_init(&st->buf_mutex);
0356 
0357 out:
0358     return ret;
0359 
0360 }
0361 
0362 static void vp702x_usb_disconnect(struct usb_interface *intf)
0363 {
0364     struct dvb_usb_device *d = usb_get_intfdata(intf);
0365     struct vp702x_device_state *st = d->priv;
0366     mutex_lock(&st->buf_mutex);
0367     kfree(st->buf);
0368     mutex_unlock(&st->buf_mutex);
0369     dvb_usb_device_exit(intf);
0370 }
0371 
0372 enum {
0373     VISIONPLUS_VP7021_COLD,
0374     VISIONPLUS_VP7020_COLD,
0375     VISIONPLUS_VP7020_WARM,
0376 };
0377 
0378 static struct usb_device_id vp702x_usb_table[] = {
0379     DVB_USB_DEV(VISIONPLUS, VISIONPLUS_VP7021_COLD),
0380 //  DVB_USB_DEV(VISIONPLUS, VISIONPLUS_VP7020_COLD),
0381 //  DVB_USB_DEV(VISIONPLUS, VISIONPLUS_VP7020_WARM),
0382     { }
0383 };
0384 
0385 MODULE_DEVICE_TABLE(usb, vp702x_usb_table);
0386 
0387 static struct dvb_usb_device_properties vp702x_properties = {
0388     .usb_ctrl = CYPRESS_FX2,
0389     .firmware            = "dvb-usb-vp702x-02.fw",
0390     .no_reconnect        = 1,
0391 
0392     .size_of_priv     = sizeof(struct vp702x_device_state),
0393 
0394     .num_adapters = 1,
0395     .adapter = {
0396         {
0397         .num_frontends = 1,
0398         .fe = {{
0399             .caps             = DVB_USB_ADAP_RECEIVES_204_BYTE_TS,
0400 
0401             .streaming_ctrl   = vp702x_streaming_ctrl,
0402             .frontend_attach  = vp702x_frontend_attach,
0403 
0404             /* parameter for the MPEG2-data transfer */
0405             .stream = {
0406                 .type = USB_BULK,
0407                 .count = 10,
0408                 .endpoint = 0x02,
0409                 .u = {
0410                     .bulk = {
0411                         .buffersize = 4096,
0412                     }
0413                 }
0414             },
0415         }},
0416             .size_of_priv     = sizeof(struct vp702x_adapter_state),
0417         }
0418     },
0419     .read_mac_address = vp702x_read_mac_addr,
0420 
0421     .rc.legacy = {
0422         .rc_map_table       = rc_map_vp702x_table,
0423         .rc_map_size  = ARRAY_SIZE(rc_map_vp702x_table),
0424         .rc_interval      = 400,
0425         .rc_query         = vp702x_rc_query,
0426     },
0427 
0428     .num_device_descs = 1,
0429     .devices = {
0430         { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7021)",
0431           .cold_ids = { &vp702x_usb_table[VISIONPLUS_VP7021_COLD], NULL },
0432           .warm_ids = { NULL },
0433         },
0434 /*      { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7020)",
0435           .cold_ids = { &vp702x_usb_table[VISIONPLUS_VP7020_COLD], NULL },
0436           .warm_ids = { &vp702x_usb_table[VISIONPLUS_VP7020_WARM], NULL },
0437         },
0438 */      { NULL },
0439     }
0440 };
0441 
0442 /* usb specific object needed to register this driver with the usb subsystem */
0443 static struct usb_driver vp702x_usb_driver = {
0444     .name       = "dvb_usb_vp702x",
0445     .probe      = vp702x_usb_probe,
0446     .disconnect = vp702x_usb_disconnect,
0447     .id_table   = vp702x_usb_table,
0448 };
0449 
0450 module_usb_driver(vp702x_usb_driver);
0451 
0452 MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
0453 MODULE_DESCRIPTION("Driver for Twinhan StarBox DVB-S USB2.0 and clones");
0454 MODULE_VERSION("1.0");
0455 MODULE_LICENSE("GPL");