linux/drivers/media/dvb/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@desy.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#define deb_info(args...) dprintk(dvb_usb_vp7045_debug,0x01,args)
  22#define deb_xfer(args...) dprintk(dvb_usb_vp7045_debug,0x02,args)
  23#define deb_rc(args...)   dprintk(dvb_usb_vp7045_debug,0x04,args)
  24
  25int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, int inlen, int msec)
  26{
  27        int ret = 0;
  28        u8 inbuf[12] = { 0 }, outbuf[20] = { 0 };
  29
  30        outbuf[0] = cmd;
  31
  32        if (outlen > 19)
  33                outlen = 19;
  34
  35        if (inlen > 11)
  36                inlen = 11;
  37
  38        if (out != NULL && outlen > 0)
  39                memcpy(&outbuf[1], out, outlen);
  40
  41        deb_xfer("out buffer: ");
  42        debug_dump(outbuf,outlen+1,deb_xfer);
  43
  44        if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
  45                return ret;
  46
  47        if (usb_control_msg(d->udev,
  48                        usb_sndctrlpipe(d->udev,0),
  49                        TH_COMMAND_OUT, USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0,
  50                        outbuf, 20, 2000) != 20) {
  51                err("USB control message 'out' went wrong.");
  52                ret = -EIO;
  53                goto unlock;
  54        }
  55
  56        msleep(msec);
  57
  58        if (usb_control_msg(d->udev,
  59                        usb_rcvctrlpipe(d->udev,0),
  60                        TH_COMMAND_IN, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
  61                        inbuf, 12, 2000) != 12) {
  62                err("USB control message 'in' went wrong.");
  63                ret = -EIO;
  64                goto unlock;
  65        }
  66
  67        deb_xfer("in buffer: ");
  68        debug_dump(inbuf,12,deb_xfer);
  69
  70        if (in != NULL && inlen > 0)
  71                memcpy(in,&inbuf[1],inlen);
  72
  73unlock:
  74        mutex_unlock(&d->usb_mutex);
  75
  76        return ret;
  77}
  78
  79u8 vp7045_read_reg(struct dvb_usb_device *d, u8 reg)
  80{
  81        u8 obuf[2] = { 0 },v;
  82        obuf[1] = reg;
  83
  84        vp7045_usb_op(d,TUNER_REG_READ,obuf,2,&v,1,30);
  85
  86        return v;
  87}
  88
  89static int vp7045_power_ctrl(struct dvb_usb_device *d, int onoff)
  90{
  91        u8 v = onoff;
  92        return vp7045_usb_op(d,SET_TUNER_POWER,&v,1,NULL,0,150);
  93}
  94
  95/* remote control stuff */
  96
  97/* The keymapping struct. Somehow this should be loaded to the driver, but
  98 * currently it is hardcoded. */
  99static struct dvb_usb_rc_key vp7045_rc_keys[] = {
 100        { 0x00, 0x16, KEY_POWER },
 101        { 0x00, 0x10, KEY_MUTE },
 102        { 0x00, 0x03, KEY_1 },
 103        { 0x00, 0x01, KEY_2 },
 104        { 0x00, 0x06, KEY_3 },
 105        { 0x00, 0x09, KEY_4 },
 106        { 0x00, 0x1d, KEY_5 },
 107        { 0x00, 0x1f, KEY_6 },
 108        { 0x00, 0x0d, KEY_7 },
 109        { 0x00, 0x19, KEY_8 },
 110        { 0x00, 0x1b, KEY_9 },
 111        { 0x00, 0x15, KEY_0 },
 112        { 0x00, 0x05, KEY_CHANNELUP },
 113        { 0x00, 0x02, KEY_CHANNELDOWN },
 114        { 0x00, 0x1e, KEY_VOLUMEUP },
 115        { 0x00, 0x0a, KEY_VOLUMEDOWN },
 116        { 0x00, 0x11, KEY_RECORD },
 117        { 0x00, 0x17, KEY_FAVORITES }, /* Heart symbol - Channel list. */
 118        { 0x00, 0x14, KEY_PLAY },
 119        { 0x00, 0x1a, KEY_STOP },
 120        { 0x00, 0x40, KEY_REWIND },
 121        { 0x00, 0x12, KEY_FASTFORWARD },
 122        { 0x00, 0x0e, KEY_PREVIOUS }, /* Recall - Previous channel. */
 123        { 0x00, 0x4c, KEY_PAUSE },
 124        { 0x00, 0x4d, KEY_SCREEN }, /* Full screen mode. */
 125        { 0x00, 0x54, KEY_AUDIO }, /* MTS - Switch to secondary audio. */
 126        { 0x00, 0x0c, KEY_CANCEL }, /* Cancel */
 127        { 0x00, 0x1c, KEY_EPG }, /* EPG */
 128        { 0x00, 0x00, KEY_TAB }, /* Tab */
 129        { 0x00, 0x48, KEY_INFO }, /* Preview */
 130        { 0x00, 0x04, KEY_LIST }, /* RecordList */
 131        { 0x00, 0x0f, KEY_TEXT }, /* Teletext */
 132        { 0x00, 0x41, KEY_PREVIOUSSONG },
 133        { 0x00, 0x42, KEY_NEXTSONG },
 134        { 0x00, 0x4b, KEY_UP },
 135        { 0x00, 0x51, KEY_DOWN },
 136        { 0x00, 0x4e, KEY_LEFT },
 137        { 0x00, 0x52, KEY_RIGHT },
 138        { 0x00, 0x4f, KEY_ENTER },
 139        { 0x00, 0x13, KEY_CANCEL },
 140        { 0x00, 0x4a, KEY_CLEAR },
 141        { 0x00, 0x54, KEY_PRINT }, /* Capture */
 142        { 0x00, 0x43, KEY_SUBTITLE }, /* Subtitle/CC */
 143        { 0x00, 0x08, KEY_VIDEO }, /* A/V */
 144        { 0x00, 0x07, KEY_SLEEP }, /* Hibernate */
 145        { 0x00, 0x45, KEY_ZOOM }, /* Zoom+ */
 146        { 0x00, 0x18, KEY_RED},
 147        { 0x00, 0x53, KEY_GREEN},
 148        { 0x00, 0x5e, KEY_YELLOW},
 149        { 0x00, 0x5f, KEY_BLUE}
 150};
 151
 152static int vp7045_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 153{
 154        u8 key;
 155        int i;
 156        vp7045_usb_op(d,RC_VAL_READ,NULL,0,&key,1,20);
 157
 158        deb_rc("remote query key: %x %d\n",key,key);
 159
 160        if (key == 0x44) {
 161                *state = REMOTE_NO_KEY_PRESSED;
 162                return 0;
 163        }
 164
 165        for (i = 0; i < ARRAY_SIZE(vp7045_rc_keys); i++)
 166                if (vp7045_rc_keys[i].data == key) {
 167                        *state = REMOTE_KEY_PRESSED;
 168                        *event = vp7045_rc_keys[i].event;
 169                        break;
 170                }
 171        return 0;
 172}
 173
 174static int vp7045_read_eeprom(struct dvb_usb_device *d,u8 *buf, int len, int offset)
 175{
 176        int i = 0;
 177        u8 v,br[2];
 178        for (i=0; i < len; i++) {
 179                v = offset + i;
 180                vp7045_usb_op(d,GET_EE_VALUE,&v,1,br,2,5);
 181                buf[i] = br[1];
 182        }
 183        deb_info("VP7045 EEPROM read (offs: %d, len: %d) : ",offset, i);
 184        debug_dump(buf,i,deb_info);
 185        return 0;
 186}
 187
 188static int vp7045_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
 189{
 190        return vp7045_read_eeprom(d,mac, 6, MAC_0_ADDR);
 191}
 192
 193static int vp7045_frontend_attach(struct dvb_usb_adapter *adap)
 194{
 195        u8 buf[255] = { 0 };
 196
 197        vp7045_usb_op(adap->dev,VENDOR_STRING_READ,NULL,0,buf,20,0);
 198        buf[10] = '\0';
 199        deb_info("firmware says: %s ",buf);
 200
 201        vp7045_usb_op(adap->dev,PRODUCT_STRING_READ,NULL,0,buf,20,0);
 202        buf[10] = '\0';
 203        deb_info("%s ",buf);
 204
 205        vp7045_usb_op(adap->dev,FW_VERSION_READ,NULL,0,buf,20,0);
 206        buf[10] = '\0';
 207        deb_info("v%s\n",buf);
 208
 209/*      Dump the EEPROM */
 210/*      vp7045_read_eeprom(d,buf, 255, FX2_ID_ADDR); */
 211
 212        adap->fe = vp7045_fe_attach(adap->dev);
 213
 214        return 0;
 215}
 216
 217static struct dvb_usb_device_properties vp7045_properties;
 218
 219static int vp7045_usb_probe(struct usb_interface *intf,
 220                const struct usb_device_id *id)
 221{
 222        return dvb_usb_device_init(intf,&vp7045_properties,THIS_MODULE,NULL);
 223}
 224
 225static struct usb_device_id vp7045_usb_table [] = {
 226            { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7045_COLD) },
 227            { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7045_WARM) },
 228            { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_DNTV_TINYUSB2_COLD) },
 229            { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_DNTV_TINYUSB2_WARM) },
 230            { 0 },
 231};
 232MODULE_DEVICE_TABLE(usb, vp7045_usb_table);
 233
 234static struct dvb_usb_device_properties vp7045_properties = {
 235        .usb_ctrl = CYPRESS_FX2,
 236        .firmware = "dvb-usb-vp7045-01.fw",
 237
 238        .num_adapters = 1,
 239        .adapter = {
 240                {
 241                        .frontend_attach  = vp7045_frontend_attach,
 242                        /* parameter for the MPEG2-data transfer */
 243                        .stream = {
 244                                .type = USB_BULK,
 245                                .count = 7,
 246                                .endpoint = 0x02,
 247                                .u = {
 248                                        .bulk = {
 249                                                .buffersize = 4096,
 250                                        }
 251                                }
 252                        },
 253                }
 254        },
 255        .power_ctrl       = vp7045_power_ctrl,
 256        .read_mac_address = vp7045_read_mac_addr,
 257
 258        .rc_interval      = 400,
 259        .rc_key_map       = vp7045_rc_keys,
 260        .rc_key_map_size  = ARRAY_SIZE(vp7045_rc_keys),
 261        .rc_query         = vp7045_rc_query,
 262
 263        .num_device_descs = 2,
 264        .devices = {
 265                { .name = "Twinhan USB2.0 DVB-T receiver (TwinhanDTV Alpha/MagicBox II)",
 266                  .cold_ids = { &vp7045_usb_table[0], NULL },
 267                  .warm_ids = { &vp7045_usb_table[1], NULL },
 268                },
 269                { .name = "DigitalNow TinyUSB 2 DVB-t Receiver",
 270                  .cold_ids = { &vp7045_usb_table[2], NULL },
 271                  .warm_ids = { &vp7045_usb_table[3], NULL },
 272                },
 273                { NULL },
 274        }
 275};
 276
 277/* usb specific object needed to register this driver with the usb subsystem */
 278static struct usb_driver vp7045_usb_driver = {
 279        .name           = "dvb_usb_vp7045",
 280        .probe          = vp7045_usb_probe,
 281        .disconnect = dvb_usb_device_exit,
 282        .id_table       = vp7045_usb_table,
 283};
 284
 285/* module stuff */
 286static int __init vp7045_usb_module_init(void)
 287{
 288        int result;
 289        if ((result = usb_register(&vp7045_usb_driver))) {
 290                err("usb_register failed. (%d)",result);
 291                return result;
 292        }
 293
 294        return 0;
 295}
 296
 297static void __exit vp7045_usb_module_exit(void)
 298{
 299        /* deregister this driver from the USB subsystem */
 300        usb_deregister(&vp7045_usb_driver);
 301}
 302
 303module_init(vp7045_usb_module_init);
 304module_exit(vp7045_usb_module_exit);
 305
 306MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
 307MODULE_DESCRIPTION("Driver for Twinhan MagicBox/Alpha and DNTV tinyUSB2 DVB-T USB2.0");
 308MODULE_VERSION("1.0");
 309MODULE_LICENSE("GPL");
 310
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.