GNU Linux-libre 6.7.9-gnu
[releases.git] / drivers / media / usb / dvb-usb / dtt200u.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* 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 information
10  */
11 #include "dtt200u.h"
12
13 /* debug */
14 int dvb_usb_dtt200u_debug;
15 module_param_named(debug,dvb_usb_dtt200u_debug, int, 0644);
16 MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2 (or-able))." DVB_USB_DEBUG_STATUS);
17
18 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
19
20 struct dtt200u_state {
21         unsigned char data[80];
22 };
23
24 static 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
40 static 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
60 ret:
61         mutex_unlock(&d->data_mutex);
62
63         return ret;
64 }
65
66 static 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
86 static 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                 else
116                         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
126 ret:
127         mutex_unlock(&d->data_mutex);
128         return ret;
129 }
130
131 static 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
137 static struct dvb_usb_device_properties dtt200u_properties;
138 static struct dvb_usb_device_properties wt220u_fc_properties;
139 static struct dvb_usb_device_properties wt220u_properties;
140 static struct dvb_usb_device_properties wt220u_zl0353_properties;
141 static struct dvb_usb_device_properties wt220u_miglia_properties;
142
143 static 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
161 enum {
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
174 static 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
188 MODULE_DEVICE_TABLE(usb, dtt200u_usb_table);
189
190 static struct dvb_usb_device_properties dtt200u_properties = {
191         .usb_ctrl = CYPRESS_FX2,
192         .firmware = "/*(DEBLOBBED)*/",
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
242 static struct dvb_usb_device_properties wt220u_properties = {
243         .usb_ctrl = CYPRESS_FX2,
244         .firmware = "/*(DEBLOBBED)*/",
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
294 static struct dvb_usb_device_properties wt220u_fc_properties = {
295         .usb_ctrl = CYPRESS_FX2,
296         .firmware = "/*(DEBLOBBED)*/",
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
346 static struct dvb_usb_device_properties wt220u_zl0353_properties = {
347         .usb_ctrl = CYPRESS_FX2,
348         .firmware = "/*(DEBLOBBED)*/",
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
398 static struct dvb_usb_device_properties wt220u_miglia_properties = {
399         .usb_ctrl = CYPRESS_FX2,
400         .firmware = "/*(DEBLOBBED)*/",
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 fw
412                      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 */
420 static 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
427 module_usb_driver(dtt200u_usb_driver);
428
429 MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
430 MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon/Club3D/Miglia DVB-T USB2.0 devices");
431 MODULE_VERSION("1.0");
432 MODULE_LICENSE("GPL");