linux/drivers/media/usb/dvb-usb/vp7045.c
<<
>>
Prefs
   1/* DVB USB compliant Linux driver for the
   2 *  - TwinhanDTV Alpha/MagicBoxII USB2.0 DVB-T receiver
   3 *  - DigitalNow TinyUSB2 DVB-t receiver
   4 *
   5 * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@posteo.de)
   6 *
   7 * Thanks to Twinhan who kindly provided hardware and information.
   8 *
   9 *      This program is free software; you can redistribute it and/or modify it
  10 *      under the terms of the GNU General Public License as published by the Free
  11 *      Software Foundation, version 2.
  12 *
  13 * see Documentation/dvb/README.dvb-usb for more information
  14 */
  15#include "vp7045.h"
  16
  17/* debug */
  18static int dvb_usb_vp7045_debug;
  19module_param_named(debug,dvb_usb_vp7045_debug, int, 0644);
  20MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
  21
  22DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
  23
  24#define deb_info(args...) dprintk(dvb_usb_vp7045_debug,0x01,args)
  25#define deb_xfer(args...) dprintk(dvb_usb_vp7045_debug,0x02,args)
  26#define deb_rc(args...)   dprintk(dvb_usb_vp7045_debug,0x04,args)
  27
  28int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, int inlen, int msec)
  29{
  30        int ret = 0;
  31        u8 *buf = d->priv;
  32
  33        buf[0] = cmd;
  34
  35        if (outlen > 19)
  36                outlen = 19;
  37
  38        if (inlen > 11)
  39                inlen = 11;
  40
  41        ret = mutex_lock_interruptible(&d->usb_mutex);
  42        if (ret)
  43                return ret;
  44
  45        if (out != NULL && outlen > 0)
  46                memcpy(&buf[1], out, outlen);
  47
  48        deb_xfer("out buffer: ");
  49        debug_dump(buf, outlen+1, deb_xfer);
  50
  51
  52        if (usb_control_msg(d->udev,
  53                        usb_sndctrlpipe(d->udev,0),
  54                        TH_COMMAND_OUT, USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0,
  55                        buf, 20, 2000) != 20) {
  56                err("USB control message 'out' went wrong.");
  57                ret = -EIO;
  58                goto unlock;
  59        }
  60
  61        msleep(msec);
  62
  63        if (usb_control_msg(d->udev,
  64                        usb_rcvctrlpipe(d->udev,0),
  65                        TH_COMMAND_IN, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
  66                        buf, 12, 2000) != 12) {
  67                err("USB control message 'in' went wrong.");
  68                ret = -EIO;
  69                goto unlock;
  70        }
  71
  72        deb_xfer("in buffer: ");
  73        debug_dump(buf, 12, deb_xfer);
  74
  75        if (in != NULL && inlen > 0)
  76                memcpy(in, &buf[1], inlen);
  77
  78unlock:
  79        mutex_unlock(&d->usb_mutex);
  80
  81        return ret;
  82}
  83
  84u8 vp7045_read_reg(struct dvb_usb_device *d, u8 reg)
  85{
  86        u8 obuf[2] = { 0 },v;
  87        obuf[1] = reg;
  88
  89        vp7045_usb_op(d,TUNER_REG_READ,obuf,2,&v,1,30);
  90
  91        return v;
  92}
  93
  94static int vp7045_power_ctrl(struct dvb_usb_device *d, int onoff)
  95{
  96        u8 v = onoff;
  97        return vp7045_usb_op(d,SET_TUNER_POWER,&v,1,NULL,0,150);
  98}
  99
 100static int vp7045_rc_query(struct dvb_usb_device *d)
 101{
 102        u8 key;
 103        vp7045_usb_op(d,RC_VAL_READ,NULL,0,&key,1,20);
 104
 105        deb_rc("remote query key: %x %d\n",key,key);
 106
 107        if (key != 0x44) {
 108                /*
 109                 * The 8 bit address isn't available, but since the remote uses
 110                 * address 0 we'll use that. nec repeats are ignored too, even
 111                 * though the remote sends them.
 112                 */
 113                rc_keydown(d->rc_dev, RC_PROTO_NEC, RC_SCANCODE_NEC(0, key), 0);
 114        }
 115
 116        return 0;
 117}
 118
 119static int vp7045_read_eeprom(struct dvb_usb_device *d,u8 *buf, int len, int offset)
 120{
 121        int i = 0;
 122        u8 v,br[2];
 123        for (i=0; i < len; i++) {
 124                v = offset + i;
 125                vp7045_usb_op(d,GET_EE_VALUE,&v,1,br,2,5);
 126                buf[i] = br[1];
 127        }
 128        deb_info("VP7045 EEPROM read (offs: %d, len: %d) : ",offset, i);
 129        debug_dump(buf,i,deb_info);
 130        return 0;
 131}
 132
 133static int vp7045_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
 134{
 135        return vp7045_read_eeprom(d,mac, 6, MAC_0_ADDR);
 136}
 137
 138static int vp7045_frontend_attach(struct dvb_usb_adapter *adap)
 139{
 140        u8 buf[255] = { 0 };
 141
 142        vp7045_usb_op(adap->dev,VENDOR_STRING_READ,NULL,0,buf,20,0);
 143        buf[10] = '\0';
 144        deb_info("firmware says: %s ",buf);
 145
 146        vp7045_usb_op(adap->dev,PRODUCT_STRING_READ,NULL,0,buf,20,0);
 147        buf[10] = '\0';
 148        deb_info("%s ",buf);
 149
 150        vp7045_usb_op(adap->dev,FW_VERSION_READ,NULL,0,buf,20,0);
 151        buf[10] = '\0';
 152        deb_info("v%s\n",buf);
 153
 154/*      Dump the EEPROM */
 155/*      vp7045_read_eeprom(d,buf, 255, FX2_ID_ADDR); */
 156
 157        adap->fe_adap[0].fe = vp7045_fe_attach(adap->dev);
 158
 159        return 0;
 160}
 161
 162static struct dvb_usb_device_properties vp7045_properties;
 163
 164static int vp7045_usb_probe(struct usb_interface *intf,
 165                const struct usb_device_id *id)
 166{
 167        return dvb_usb_device_init(intf, &vp7045_properties,
 168                                   THIS_MODULE, NULL, adapter_nr);
 169}
 170
 171static struct usb_device_id vp7045_usb_table [] = {
 172            { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7045_COLD) },
 173            { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7045_WARM) },
 174            { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_DNTV_TINYUSB2_COLD) },
 175            { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_DNTV_TINYUSB2_WARM) },
 176            { 0 },
 177};
 178MODULE_DEVICE_TABLE(usb, vp7045_usb_table);
 179
 180static struct dvb_usb_device_properties vp7045_properties = {
 181        .usb_ctrl = CYPRESS_FX2,
 182        .firmware = "dvb-usb-vp7045-01.fw",
 183        .size_of_priv = 20,
 184
 185        .num_adapters = 1,
 186        .adapter = {
 187                {
 188                .num_frontends = 1,
 189                .fe = {{
 190                        .frontend_attach  = vp7045_frontend_attach,
 191                        /* parameter for the MPEG2-data transfer */
 192                        .stream = {
 193                                .type = USB_BULK,
 194                                .count = 7,
 195                                .endpoint = 0x02,
 196                                .u = {
 197                                        .bulk = {
 198                                                .buffersize = 4096,
 199                                        }
 200                                }
 201                        },
 202                }},
 203                }
 204        },
 205        .power_ctrl       = vp7045_power_ctrl,
 206        .read_mac_address = vp7045_read_mac_addr,
 207
 208        .rc.core = {
 209                .rc_interval    = 400,
 210                .rc_codes       = RC_MAP_TWINHAN_VP1027_DVBS,
 211                .module_name    = KBUILD_MODNAME,
 212                .rc_query       = vp7045_rc_query,
 213                .allowed_protos = RC_PROTO_BIT_NEC,
 214                .scancode_mask  = 0xff,
 215        },
 216
 217        .num_device_descs = 2,
 218        .devices = {
 219                { .name = "Twinhan USB2.0 DVB-T receiver (TwinhanDTV Alpha/MagicBox II)",
 220                  .cold_ids = { &vp7045_usb_table[0], NULL },
 221                  .warm_ids = { &vp7045_usb_table[1], NULL },
 222                },
 223                { .name = "DigitalNow TinyUSB 2 DVB-t Receiver",
 224                  .cold_ids = { &vp7045_usb_table[2], NULL },
 225                  .warm_ids = { &vp7045_usb_table[3], NULL },
 226                },
 227                { NULL },
 228        }
 229};
 230
 231/* usb specific object needed to register this driver with the usb subsystem */
 232static struct usb_driver vp7045_usb_driver = {
 233        .name           = "dvb_usb_vp7045",
 234        .probe          = vp7045_usb_probe,
 235        .disconnect     = dvb_usb_device_exit,
 236        .id_table       = vp7045_usb_table,
 237};
 238
 239module_usb_driver(vp7045_usb_driver);
 240
 241MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
 242MODULE_DESCRIPTION("Driver for Twinhan MagicBox/Alpha and DNTV tinyUSB2 DVB-T USB2.0");
 243MODULE_VERSION("1.0");
 244MODULE_LICENSE("GPL");
 245