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