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