1 /* DVB USB library compliant Linux driver for the WideView/ Yakumo/ Hama/ 2 * Typhoon/ Yuan/ Miglia DVB-T USB2.0 receiver. 3 * 4 * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@posteo.de) 5 * 6 * Thanks to Steve Chang from WideView for providing support for the WT-220U. 7 * 8 * This program is free software; you can redistribute it and/or modify it 9 * under the terms of the GNU General Public License as published by the Free 10 * Software Foundation, version 2. 11 * 12 * see Documentation/dvb/README.dvb-usb for more information 13 */ 14 #include "dtt200u.h" 15 16 /* debug */ 17 int dvb_usb_dtt200u_debug; 18 module_param_named(debug,dvb_usb_dtt200u_debug, int, 0644); 19 MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2 (or-able))." DVB_USB_DEBUG_STATUS); 20 21 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); 22 23 struct dtt200u_state { 24 unsigned char data[80]; 25 struct mutex data_mutex; 26 }; 27 28 static int dtt200u_power_ctrl(struct dvb_usb_device *d, int onoff) 29 { 30 struct dtt200u_state *st = d->priv; 31 int ret = 0; 32 33 mutex_lock(&st->data_mutex); 34 35 st->data[0] = SET_INIT; 36 37 if (onoff) 38 ret = dvb_usb_generic_write(d, st->data, 2); 39 40 mutex_unlock(&st->data_mutex); 41 return ret; 42 } 43 44 static int dtt200u_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) 45 { 46 struct dtt200u_state *st = adap->dev->priv; 47 int ret; 48 49 mutex_lock(&st->data_mutex); 50 st->data[0] = SET_STREAMING; 51 st->data[1] = onoff; 52 53 ret = dvb_usb_generic_write(adap->dev, st->data, 2); 54 if (ret < 0) 55 goto ret; 56 57 if (onoff) 58 goto ret; 59 60 st->data[0] = RESET_PID_FILTER; 61 ret = dvb_usb_generic_write(adap->dev, st->data, 1); 62 63 ret: 64 mutex_unlock(&st->data_mutex); 65 66 return ret; 67 } 68 69 static int dtt200u_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff) 70 { 71 struct dtt200u_state *st = adap->dev->priv; 72 int ret; 73 74 pid = onoff ? pid : 0; 75 76 mutex_lock(&st->data_mutex); 77 st->data[0] = SET_PID_FILTER; 78 st->data[1] = index; 79 st->data[2] = pid & 0xff; 80 st->data[3] = (pid >> 8) & 0x1f; 81 82 ret = dvb_usb_generic_write(adap->dev, st->data, 4); 83 mutex_unlock(&st->data_mutex); 84 85 return ret; 86 } 87 88 static int dtt200u_rc_query(struct dvb_usb_device *d) 89 { 90 struct dtt200u_state *st = d->priv; 91 u32 scancode; 92 int ret; 93 94 mutex_lock(&st->data_mutex); 95 st->data[0] = GET_RC_CODE; 96 97 ret = dvb_usb_generic_rw(d, st->data, 1, st->data, 5, 0); 98 if (ret < 0) 99 goto ret; 100 101 if (st->data[0] == 1) { 102 enum rc_type proto = RC_TYPE_NEC; 103 104 scancode = st->data[1]; 105 if ((u8) ~st->data[1] != st->data[2]) { 106 /* Extended NEC */ 107 scancode = scancode << 8; 108 scancode |= st->data[2]; 109 proto = RC_TYPE_NECX; 110 } 111 scancode = scancode << 8; 112 scancode |= st->data[3]; 113 114 /* Check command checksum is ok */ 115 if ((u8) ~st->data[3] == st->data[4]) 116 rc_keydown(d->rc_dev, proto, scancode, 0); 117 else 118 rc_keyup(d->rc_dev); 119 } else if (st->data[0] == 2) { 120 rc_repeat(d->rc_dev); 121 } else { 122 rc_keyup(d->rc_dev); 123 } 124 125 if (st->data[0] != 0) 126 deb_info("st->data: %*ph\n", 5, st->data); 127 128 ret: 129 mutex_unlock(&st->data_mutex); 130 return ret; 131 } 132 133 static int dtt200u_frontend_attach(struct dvb_usb_adapter *adap) 134 { 135 adap->fe_adap[0].fe = dtt200u_fe_attach(adap->dev); 136 return 0; 137 } 138 139 static struct dvb_usb_device_properties dtt200u_properties; 140 static struct dvb_usb_device_properties wt220u_fc_properties; 141 static struct dvb_usb_device_properties wt220u_properties; 142 static struct dvb_usb_device_properties wt220u_zl0353_properties; 143 static struct dvb_usb_device_properties wt220u_miglia_properties; 144 145 static int dtt200u_usb_probe(struct usb_interface *intf, 146 const struct usb_device_id *id) 147 { 148 struct dvb_usb_device *d; 149 struct dtt200u_state *st; 150 151 if (0 == dvb_usb_device_init(intf, &dtt200u_properties, 152 THIS_MODULE, &d, adapter_nr) || 153 0 == dvb_usb_device_init(intf, &wt220u_properties, 154 THIS_MODULE, &d, adapter_nr) || 155 0 == dvb_usb_device_init(intf, &wt220u_fc_properties, 156 THIS_MODULE, &d, adapter_nr) || 157 0 == dvb_usb_device_init(intf, &wt220u_zl0353_properties, 158 THIS_MODULE, &d, adapter_nr) || 159 0 == dvb_usb_device_init(intf, &wt220u_miglia_properties, 160 THIS_MODULE, &d, adapter_nr)) { 161 st = d->priv; 162 mutex_init(&st->data_mutex); 163 164 return 0; 165 } 166 167 return -ENODEV; 168 } 169 170 static struct usb_device_id dtt200u_usb_table [] = { 171 { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_COLD) }, 172 { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_WARM) }, 173 { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_COLD) }, 174 { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_WARM) }, 175 { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_COLD) }, 176 { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_WARM) }, 177 { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_COLD) }, 178 { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_WARM) }, 179 { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZAP250_COLD) }, 180 { USB_DEVICE(USB_VID_MIGLIA, USB_PID_WT220U_ZAP250_COLD) }, 181 { 0 }, 182 }; 183 MODULE_DEVICE_TABLE(usb, dtt200u_usb_table); 184 185 static struct dvb_usb_device_properties dtt200u_properties = { 186 .usb_ctrl = CYPRESS_FX2, 187 .firmware = "dvb-usb-dtt200u-01.fw", 188 189 .size_of_priv = sizeof(struct dtt200u_state), 190 191 .num_adapters = 1, 192 .adapter = { 193 { 194 .num_frontends = 1, 195 .fe = {{ 196 .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING, 197 .pid_filter_count = 15, 198 199 .streaming_ctrl = dtt200u_streaming_ctrl, 200 .pid_filter = dtt200u_pid_filter, 201 .frontend_attach = dtt200u_frontend_attach, 202 /* parameter for the MPEG2-data transfer */ 203 .stream = { 204 .type = USB_BULK, 205 .count = 7, 206 .endpoint = 0x02, 207 .u = { 208 .bulk = { 209 .buffersize = 4096, 210 } 211 } 212 }, 213 }}, 214 } 215 }, 216 .power_ctrl = dtt200u_power_ctrl, 217 218 .rc.core = { 219 .rc_interval = 300, 220 .rc_codes = RC_MAP_DTT200U, 221 .rc_query = dtt200u_rc_query, 222 .allowed_protos = RC_BIT_NEC, 223 }, 224 225 .generic_bulk_ctrl_endpoint = 0x01, 226 227 .num_device_descs = 1, 228 .devices = { 229 { .name = "WideView/Yuan/Yakumo/Hama/Typhoon DVB-T USB2.0 (WT-200U)", 230 .cold_ids = { &dtt200u_usb_table[0], NULL }, 231 .warm_ids = { &dtt200u_usb_table[1], NULL }, 232 }, 233 { NULL }, 234 } 235 }; 236 237 static struct dvb_usb_device_properties wt220u_properties = { 238 .usb_ctrl = CYPRESS_FX2, 239 .firmware = "dvb-usb-wt220u-02.fw", 240 241 .size_of_priv = sizeof(struct dtt200u_state), 242 243 .num_adapters = 1, 244 .adapter = { 245 { 246 .num_frontends = 1, 247 .fe = {{ 248 .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING, 249 .pid_filter_count = 15, 250 251 .streaming_ctrl = dtt200u_streaming_ctrl, 252 .pid_filter = dtt200u_pid_filter, 253 .frontend_attach = dtt200u_frontend_attach, 254 /* parameter for the MPEG2-data transfer */ 255 .stream = { 256 .type = USB_BULK, 257 .count = 7, 258 .endpoint = 0x02, 259 .u = { 260 .bulk = { 261 .buffersize = 4096, 262 } 263 } 264 }, 265 }}, 266 } 267 }, 268 .power_ctrl = dtt200u_power_ctrl, 269 270 .rc.core = { 271 .rc_interval = 300, 272 .rc_codes = RC_MAP_DTT200U, 273 .rc_query = dtt200u_rc_query, 274 .allowed_protos = RC_BIT_NEC, 275 }, 276 277 .generic_bulk_ctrl_endpoint = 0x01, 278 279 .num_device_descs = 1, 280 .devices = { 281 { .name = "WideView WT-220U PenType Receiver (Typhoon/Freecom)", 282 .cold_ids = { &dtt200u_usb_table[2], &dtt200u_usb_table[8], NULL }, 283 .warm_ids = { &dtt200u_usb_table[3], NULL }, 284 }, 285 { NULL }, 286 } 287 }; 288 289 static struct dvb_usb_device_properties wt220u_fc_properties = { 290 .usb_ctrl = CYPRESS_FX2, 291 .firmware = "dvb-usb-wt220u-fc03.fw", 292 293 .size_of_priv = sizeof(struct dtt200u_state), 294 295 .num_adapters = 1, 296 .adapter = { 297 { 298 .num_frontends = 1, 299 .fe = {{ 300 .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING, 301 .pid_filter_count = 15, 302 303 .streaming_ctrl = dtt200u_streaming_ctrl, 304 .pid_filter = dtt200u_pid_filter, 305 .frontend_attach = dtt200u_frontend_attach, 306 /* parameter for the MPEG2-data transfer */ 307 .stream = { 308 .type = USB_BULK, 309 .count = 7, 310 .endpoint = 0x06, 311 .u = { 312 .bulk = { 313 .buffersize = 4096, 314 } 315 } 316 }, 317 }}, 318 } 319 }, 320 .power_ctrl = dtt200u_power_ctrl, 321 322 .rc.core = { 323 .rc_interval = 300, 324 .rc_codes = RC_MAP_DTT200U, 325 .rc_query = dtt200u_rc_query, 326 .allowed_protos = RC_BIT_NEC, 327 }, 328 329 .generic_bulk_ctrl_endpoint = 0x01, 330 331 .num_device_descs = 1, 332 .devices = { 333 { .name = "WideView WT-220U PenType Receiver (Typhoon/Freecom)", 334 .cold_ids = { &dtt200u_usb_table[6], NULL }, 335 .warm_ids = { &dtt200u_usb_table[7], NULL }, 336 }, 337 { NULL }, 338 } 339 }; 340 341 static struct dvb_usb_device_properties wt220u_zl0353_properties = { 342 .usb_ctrl = CYPRESS_FX2, 343 .firmware = "dvb-usb-wt220u-zl0353-01.fw", 344 345 .size_of_priv = sizeof(struct dtt200u_state), 346 347 .num_adapters = 1, 348 .adapter = { 349 { 350 .num_frontends = 1, 351 .fe = {{ 352 .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING, 353 .pid_filter_count = 15, 354 355 .streaming_ctrl = dtt200u_streaming_ctrl, 356 .pid_filter = dtt200u_pid_filter, 357 .frontend_attach = dtt200u_frontend_attach, 358 /* parameter for the MPEG2-data transfer */ 359 .stream = { 360 .type = USB_BULK, 361 .count = 7, 362 .endpoint = 0x02, 363 .u = { 364 .bulk = { 365 .buffersize = 4096, 366 } 367 } 368 }, 369 }}, 370 } 371 }, 372 .power_ctrl = dtt200u_power_ctrl, 373 374 .rc.core = { 375 .rc_interval = 300, 376 .rc_codes = RC_MAP_DTT200U, 377 .rc_query = dtt200u_rc_query, 378 .allowed_protos = RC_BIT_NEC, 379 }, 380 381 .generic_bulk_ctrl_endpoint = 0x01, 382 383 .num_device_descs = 1, 384 .devices = { 385 { .name = "WideView WT-220U PenType Receiver (based on ZL353)", 386 .cold_ids = { &dtt200u_usb_table[4], NULL }, 387 .warm_ids = { &dtt200u_usb_table[5], NULL }, 388 }, 389 { NULL }, 390 } 391 }; 392 393 static struct dvb_usb_device_properties wt220u_miglia_properties = { 394 .usb_ctrl = CYPRESS_FX2, 395 .firmware = "dvb-usb-wt220u-miglia-01.fw", 396 397 .size_of_priv = sizeof(struct dtt200u_state), 398 399 .num_adapters = 1, 400 .generic_bulk_ctrl_endpoint = 0x01, 401 402 .num_device_descs = 1, 403 .devices = { 404 { .name = "WideView WT-220U PenType Receiver (Miglia)", 405 .cold_ids = { &dtt200u_usb_table[9], NULL }, 406 /* This device turns into WT220U_ZL0353_WARM when fw 407 has been uploaded */ 408 .warm_ids = { NULL }, 409 }, 410 { NULL }, 411 } 412 }; 413 414 /* usb specific object needed to register this driver with the usb subsystem */ 415 static struct usb_driver dtt200u_usb_driver = { 416 .name = "dvb_usb_dtt200u", 417 .probe = dtt200u_usb_probe, 418 .disconnect = dvb_usb_device_exit, 419 .id_table = dtt200u_usb_table, 420 }; 421 422 module_usb_driver(dtt200u_usb_driver); 423 424 MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>"); 425 MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon/Club3D/Miglia DVB-T USB2.0 devices"); 426 MODULE_VERSION("1.0"); 427 MODULE_LICENSE("GPL"); 428