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