1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver |
4 | * |
5 | * Copyright (C) 2007 Antti Palosaari <crope@iki.fi> |
6 | * |
7 | * Thanks to Afatech who kindly provided information. |
8 | */ |
9 | |
10 | #include "af9015.h" |
11 | |
12 | static int dvb_usb_af9015_remote; |
13 | module_param_named(remote, dvb_usb_af9015_remote, int, 0644); |
14 | MODULE_PARM_DESC(remote, "select remote" ); |
15 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); |
16 | |
17 | static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) |
18 | { |
19 | #define REQ_HDR_LEN 8 /* send header size */ |
20 | #define ACK_HDR_LEN 2 /* rece header size */ |
21 | struct af9015_state *state = d_to_priv(d); |
22 | struct usb_interface *intf = d->intf; |
23 | int ret, wlen, rlen; |
24 | u8 write = 1; |
25 | |
26 | mutex_lock(&d->usb_mutex); |
27 | |
28 | state->buf[0] = req->cmd; |
29 | state->buf[1] = state->seq++; |
30 | state->buf[2] = req->i2c_addr << 1; |
31 | state->buf[3] = req->addr >> 8; |
32 | state->buf[4] = req->addr & 0xff; |
33 | state->buf[5] = req->mbox; |
34 | state->buf[6] = req->addr_len; |
35 | state->buf[7] = req->data_len; |
36 | |
37 | switch (req->cmd) { |
38 | case GET_CONFIG: |
39 | case READ_MEMORY: |
40 | case RECONNECT_USB: |
41 | write = 0; |
42 | break; |
43 | case READ_I2C: |
44 | write = 0; |
45 | state->buf[2] |= 0x01; /* set I2C direction */ |
46 | fallthrough; |
47 | case WRITE_I2C: |
48 | state->buf[0] = READ_WRITE_I2C; |
49 | break; |
50 | case WRITE_MEMORY: |
51 | if (((req->addr & 0xff00) == 0xff00) || |
52 | ((req->addr & 0xff00) == 0xae00)) |
53 | state->buf[0] = WRITE_VIRTUAL_MEMORY; |
54 | break; |
55 | case WRITE_VIRTUAL_MEMORY: |
56 | case COPY_FIRMWARE: |
57 | case DOWNLOAD_FIRMWARE: |
58 | case BOOT: |
59 | break; |
60 | default: |
61 | dev_err(&intf->dev, "unknown cmd %d\n" , req->cmd); |
62 | ret = -EIO; |
63 | goto error; |
64 | } |
65 | |
66 | /* Buffer overflow check */ |
67 | if ((write && (req->data_len > BUF_LEN - REQ_HDR_LEN)) || |
68 | (!write && (req->data_len > BUF_LEN - ACK_HDR_LEN))) { |
69 | dev_err(&intf->dev, "too much data, cmd %u, len %u\n" , |
70 | req->cmd, req->data_len); |
71 | ret = -EINVAL; |
72 | goto error; |
73 | } |
74 | |
75 | /* |
76 | * Write receives seq + status = 2 bytes |
77 | * Read receives seq + status + data = 2 + N bytes |
78 | */ |
79 | wlen = REQ_HDR_LEN; |
80 | rlen = ACK_HDR_LEN; |
81 | if (write) { |
82 | wlen += req->data_len; |
83 | memcpy(&state->buf[REQ_HDR_LEN], req->data, req->data_len); |
84 | } else { |
85 | rlen += req->data_len; |
86 | } |
87 | |
88 | /* no ack for these packets */ |
89 | if (req->cmd == DOWNLOAD_FIRMWARE || req->cmd == RECONNECT_USB) |
90 | rlen = 0; |
91 | |
92 | ret = dvb_usbv2_generic_rw_locked(d, state->buf, wlen, |
93 | state->buf, rlen); |
94 | if (ret) |
95 | goto error; |
96 | |
97 | /* check status */ |
98 | if (rlen && state->buf[1]) { |
99 | dev_err(&intf->dev, "cmd failed %u\n" , state->buf[1]); |
100 | ret = -EIO; |
101 | goto error; |
102 | } |
103 | |
104 | /* read request, copy returned data to return buf */ |
105 | if (!write) |
106 | memcpy(req->data, &state->buf[ACK_HDR_LEN], req->data_len); |
107 | error: |
108 | mutex_unlock(lock: &d->usb_mutex); |
109 | |
110 | return ret; |
111 | } |
112 | |
113 | static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, |
114 | u8 val) |
115 | { |
116 | struct af9015_state *state = d_to_priv(d); |
117 | struct req_t req = {WRITE_I2C, addr, reg, 1, 1, 1, &val}; |
118 | |
119 | if (addr == state->af9013_i2c_addr[0] || |
120 | addr == state->af9013_i2c_addr[1]) |
121 | req.addr_len = 3; |
122 | |
123 | return af9015_ctrl_msg(d, req: &req); |
124 | } |
125 | |
126 | static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, |
127 | u8 *val) |
128 | { |
129 | struct af9015_state *state = d_to_priv(d); |
130 | struct req_t req = {READ_I2C, addr, reg, 0, 1, 1, val}; |
131 | |
132 | if (addr == state->af9013_i2c_addr[0] || |
133 | addr == state->af9013_i2c_addr[1]) |
134 | req.addr_len = 3; |
135 | |
136 | return af9015_ctrl_msg(d, req: &req); |
137 | } |
138 | |
139 | static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], |
140 | int num) |
141 | { |
142 | struct dvb_usb_device *d = i2c_get_adapdata(adap); |
143 | struct af9015_state *state = d_to_priv(d); |
144 | struct usb_interface *intf = d->intf; |
145 | int ret; |
146 | u16 addr; |
147 | u8 mbox, addr_len; |
148 | struct req_t req; |
149 | |
150 | /* |
151 | * I2C multiplexing: |
152 | * There could be two tuners, both using same I2C address. Demodulator |
153 | * I2C-gate is only possibility to select correct tuner. |
154 | * |
155 | * ........................................... |
156 | * . AF9015 integrates AF9013 demodulator . |
157 | * . ____________ ____________ . ____________ |
158 | * .| USB IF | | demod |. | tuner | |
159 | * .|------------| |------------|. |------------| |
160 | * .| AF9015 | | AF9013 |. | MXL5003 | |
161 | * .| |--+--I2C-----|-----/ -----|.----I2C-----| | |
162 | * .| | | | addr 0x1c |. | addr 0x63 | |
163 | * .|____________| | |____________|. |____________| |
164 | * .................|......................... |
165 | * | ____________ ____________ |
166 | * | | demod | | tuner | |
167 | * | |------------| |------------| |
168 | * | | AF9013 | | MXL5003 | |
169 | * +--I2C-----|-----/ -----|-----I2C-----| | |
170 | * | addr 0x1d | | addr 0x63 | |
171 | * |____________| |____________| |
172 | */ |
173 | |
174 | if (msg[0].len == 0 || msg[0].flags & I2C_M_RD) { |
175 | addr = 0x0000; |
176 | mbox = 0; |
177 | addr_len = 0; |
178 | } else if (msg[0].len == 1) { |
179 | addr = msg[0].buf[0]; |
180 | mbox = 0; |
181 | addr_len = 1; |
182 | } else if (msg[0].len == 2) { |
183 | addr = msg[0].buf[0] << 8 | msg[0].buf[1] << 0; |
184 | mbox = 0; |
185 | addr_len = 2; |
186 | } else { |
187 | addr = msg[0].buf[0] << 8 | msg[0].buf[1] << 0; |
188 | mbox = msg[0].buf[2]; |
189 | addr_len = 3; |
190 | } |
191 | |
192 | if (num == 1 && !(msg[0].flags & I2C_M_RD)) { |
193 | /* i2c write */ |
194 | if (msg[0].len > 21) { |
195 | ret = -EOPNOTSUPP; |
196 | goto err; |
197 | } |
198 | if (msg[0].addr == state->af9013_i2c_addr[0]) |
199 | req.cmd = WRITE_MEMORY; |
200 | else |
201 | req.cmd = WRITE_I2C; |
202 | req.i2c_addr = msg[0].addr; |
203 | req.addr = addr; |
204 | req.mbox = mbox; |
205 | req.addr_len = addr_len; |
206 | req.data_len = msg[0].len - addr_len; |
207 | req.data = &msg[0].buf[addr_len]; |
208 | ret = af9015_ctrl_msg(d, req: &req); |
209 | } else if (num == 2 && !(msg[0].flags & I2C_M_RD) && |
210 | (msg[1].flags & I2C_M_RD)) { |
211 | /* i2c write + read */ |
212 | if (msg[0].len > 3 || msg[1].len > 61) { |
213 | ret = -EOPNOTSUPP; |
214 | goto err; |
215 | } |
216 | if (msg[0].addr == state->af9013_i2c_addr[0]) |
217 | req.cmd = READ_MEMORY; |
218 | else |
219 | req.cmd = READ_I2C; |
220 | req.i2c_addr = msg[0].addr; |
221 | req.addr = addr; |
222 | req.mbox = mbox; |
223 | req.addr_len = addr_len; |
224 | req.data_len = msg[1].len; |
225 | req.data = &msg[1].buf[0]; |
226 | ret = af9015_ctrl_msg(d, req: &req); |
227 | } else if (num == 1 && (msg[0].flags & I2C_M_RD)) { |
228 | /* i2c read */ |
229 | if (msg[0].len > 61) { |
230 | ret = -EOPNOTSUPP; |
231 | goto err; |
232 | } |
233 | if (msg[0].addr == state->af9013_i2c_addr[0]) { |
234 | ret = -EINVAL; |
235 | goto err; |
236 | } |
237 | req.cmd = READ_I2C; |
238 | req.i2c_addr = msg[0].addr; |
239 | req.addr = addr; |
240 | req.mbox = mbox; |
241 | req.addr_len = addr_len; |
242 | req.data_len = msg[0].len; |
243 | req.data = &msg[0].buf[0]; |
244 | ret = af9015_ctrl_msg(d, req: &req); |
245 | } else { |
246 | ret = -EOPNOTSUPP; |
247 | dev_dbg(&intf->dev, "unknown msg, num %u\n" , num); |
248 | } |
249 | if (ret) |
250 | goto err; |
251 | |
252 | return num; |
253 | err: |
254 | dev_dbg(&intf->dev, "failed %d\n" , ret); |
255 | return ret; |
256 | } |
257 | |
258 | static u32 af9015_i2c_func(struct i2c_adapter *adapter) |
259 | { |
260 | return I2C_FUNC_I2C; |
261 | } |
262 | |
263 | static struct i2c_algorithm af9015_i2c_algo = { |
264 | .master_xfer = af9015_i2c_xfer, |
265 | .functionality = af9015_i2c_func, |
266 | }; |
267 | |
268 | static int af9015_identify_state(struct dvb_usb_device *d, const char **name) |
269 | { |
270 | struct usb_interface *intf = d->intf; |
271 | int ret; |
272 | u8 reply; |
273 | struct req_t req = {GET_CONFIG, 0, 0, 0, 0, 1, &reply}; |
274 | |
275 | ret = af9015_ctrl_msg(d, req: &req); |
276 | if (ret) |
277 | return ret; |
278 | |
279 | dev_dbg(&intf->dev, "reply %02x\n" , reply); |
280 | |
281 | if (reply == 0x02) |
282 | ret = WARM; |
283 | else |
284 | ret = COLD; |
285 | |
286 | return ret; |
287 | } |
288 | |
289 | static int af9015_download_firmware(struct dvb_usb_device *d, |
290 | const struct firmware *firmware) |
291 | { |
292 | struct af9015_state *state = d_to_priv(d); |
293 | struct usb_interface *intf = d->intf; |
294 | int ret, i, rem; |
295 | struct req_t req = {DOWNLOAD_FIRMWARE, 0, 0, 0, 0, 0, NULL}; |
296 | u16 checksum; |
297 | |
298 | dev_dbg(&intf->dev, "\n" ); |
299 | |
300 | /* Calc checksum, we need it when copy firmware to slave demod */ |
301 | for (i = 0, checksum = 0; i < firmware->size; i++) |
302 | checksum += firmware->data[i]; |
303 | |
304 | state->firmware_size = firmware->size; |
305 | state->firmware_checksum = checksum; |
306 | |
307 | #define LEN_MAX (BUF_LEN - REQ_HDR_LEN) /* Max payload size */ |
308 | for (rem = firmware->size; rem > 0; rem -= LEN_MAX) { |
309 | req.data_len = min(LEN_MAX, rem); |
310 | req.data = (u8 *)&firmware->data[firmware->size - rem]; |
311 | req.addr = 0x5100 + firmware->size - rem; |
312 | ret = af9015_ctrl_msg(d, req: &req); |
313 | if (ret) { |
314 | dev_err(&intf->dev, "firmware download failed %d\n" , |
315 | ret); |
316 | goto err; |
317 | } |
318 | } |
319 | |
320 | req.cmd = BOOT; |
321 | req.data_len = 0; |
322 | ret = af9015_ctrl_msg(d, req: &req); |
323 | if (ret) { |
324 | dev_err(&intf->dev, "firmware boot failed %d\n" , ret); |
325 | goto err; |
326 | } |
327 | |
328 | return 0; |
329 | err: |
330 | dev_dbg(&intf->dev, "failed %d\n" , ret); |
331 | return ret; |
332 | } |
333 | |
334 | #define AF9015_EEPROM_SIZE 256 |
335 | /* 2^31 + 2^29 - 2^25 + 2^22 - 2^19 - 2^16 + 1 */ |
336 | #define GOLDEN_RATIO_PRIME_32 0x9e370001UL |
337 | |
338 | /* hash (and dump) eeprom */ |
339 | static int af9015_eeprom_hash(struct dvb_usb_device *d) |
340 | { |
341 | struct af9015_state *state = d_to_priv(d); |
342 | struct usb_interface *intf = d->intf; |
343 | int ret, i; |
344 | u8 buf[AF9015_EEPROM_SIZE]; |
345 | struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, NULL}; |
346 | |
347 | /* read eeprom */ |
348 | for (i = 0; i < AF9015_EEPROM_SIZE; i++) { |
349 | req.addr = i; |
350 | req.data = &buf[i]; |
351 | ret = af9015_ctrl_msg(d, req: &req); |
352 | if (ret < 0) |
353 | goto err; |
354 | } |
355 | |
356 | /* calculate checksum */ |
357 | for (i = 0; i < AF9015_EEPROM_SIZE / sizeof(u32); i++) { |
358 | state->eeprom_sum *= GOLDEN_RATIO_PRIME_32; |
359 | state->eeprom_sum += le32_to_cpu(((__le32 *)buf)[i]); |
360 | } |
361 | |
362 | for (i = 0; i < AF9015_EEPROM_SIZE; i += 16) |
363 | dev_dbg(&intf->dev, "%*ph\n" , 16, buf + i); |
364 | |
365 | dev_dbg(&intf->dev, "eeprom sum %.8x\n" , state->eeprom_sum); |
366 | return 0; |
367 | err: |
368 | dev_dbg(&intf->dev, "failed %d\n" , ret); |
369 | return ret; |
370 | } |
371 | |
372 | static int af9015_read_config(struct dvb_usb_device *d) |
373 | { |
374 | struct af9015_state *state = d_to_priv(d); |
375 | struct usb_interface *intf = d->intf; |
376 | int ret; |
377 | u8 val, i, offset = 0; |
378 | struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val}; |
379 | |
380 | dev_dbg(&intf->dev, "\n" ); |
381 | |
382 | /* IR remote controller */ |
383 | req.addr = AF9015_EEPROM_IR_MODE; |
384 | /* first message will timeout often due to possible hw bug */ |
385 | for (i = 0; i < 4; i++) { |
386 | ret = af9015_ctrl_msg(d, req: &req); |
387 | if (!ret) |
388 | break; |
389 | } |
390 | if (ret) |
391 | goto error; |
392 | |
393 | ret = af9015_eeprom_hash(d); |
394 | if (ret) |
395 | goto error; |
396 | |
397 | state->ir_mode = val; |
398 | dev_dbg(&intf->dev, "ir mode %02x\n" , val); |
399 | |
400 | /* TS mode - one or two receivers */ |
401 | req.addr = AF9015_EEPROM_TS_MODE; |
402 | ret = af9015_ctrl_msg(d, req: &req); |
403 | if (ret) |
404 | goto error; |
405 | |
406 | state->dual_mode = val; |
407 | dev_dbg(&intf->dev, "ts mode %02x\n" , state->dual_mode); |
408 | |
409 | state->af9013_i2c_addr[0] = AF9015_I2C_DEMOD; |
410 | |
411 | if (state->dual_mode) { |
412 | /* read 2nd demodulator I2C address */ |
413 | req.addr = AF9015_EEPROM_DEMOD2_I2C; |
414 | ret = af9015_ctrl_msg(d, req: &req); |
415 | if (ret) |
416 | goto error; |
417 | |
418 | state->af9013_i2c_addr[1] = val >> 1; |
419 | } |
420 | |
421 | for (i = 0; i < state->dual_mode + 1; i++) { |
422 | if (i == 1) |
423 | offset = AF9015_EEPROM_OFFSET; |
424 | /* xtal */ |
425 | req.addr = AF9015_EEPROM_XTAL_TYPE1 + offset; |
426 | ret = af9015_ctrl_msg(d, req: &req); |
427 | if (ret) |
428 | goto error; |
429 | switch (val) { |
430 | case 0: |
431 | state->af9013_pdata[i].clk = 28800000; |
432 | break; |
433 | case 1: |
434 | state->af9013_pdata[i].clk = 20480000; |
435 | break; |
436 | case 2: |
437 | state->af9013_pdata[i].clk = 28000000; |
438 | break; |
439 | case 3: |
440 | state->af9013_pdata[i].clk = 25000000; |
441 | break; |
442 | } |
443 | dev_dbg(&intf->dev, "[%d] xtal %02x, clk %u\n" , |
444 | i, val, state->af9013_pdata[i].clk); |
445 | |
446 | /* IF frequency */ |
447 | req.addr = AF9015_EEPROM_IF1H + offset; |
448 | ret = af9015_ctrl_msg(d, req: &req); |
449 | if (ret) |
450 | goto error; |
451 | |
452 | state->af9013_pdata[i].if_frequency = val << 8; |
453 | |
454 | req.addr = AF9015_EEPROM_IF1L + offset; |
455 | ret = af9015_ctrl_msg(d, req: &req); |
456 | if (ret) |
457 | goto error; |
458 | |
459 | state->af9013_pdata[i].if_frequency += val; |
460 | state->af9013_pdata[i].if_frequency *= 1000; |
461 | dev_dbg(&intf->dev, "[%d] if frequency %u\n" , |
462 | i, state->af9013_pdata[i].if_frequency); |
463 | |
464 | /* MT2060 IF1 */ |
465 | req.addr = AF9015_EEPROM_MT2060_IF1H + offset; |
466 | ret = af9015_ctrl_msg(d, req: &req); |
467 | if (ret) |
468 | goto error; |
469 | state->mt2060_if1[i] = val << 8; |
470 | req.addr = AF9015_EEPROM_MT2060_IF1L + offset; |
471 | ret = af9015_ctrl_msg(d, req: &req); |
472 | if (ret) |
473 | goto error; |
474 | state->mt2060_if1[i] += val; |
475 | dev_dbg(&intf->dev, "[%d] MT2060 IF1 %u\n" , |
476 | i, state->mt2060_if1[i]); |
477 | |
478 | /* tuner */ |
479 | req.addr = AF9015_EEPROM_TUNER_ID1 + offset; |
480 | ret = af9015_ctrl_msg(d, req: &req); |
481 | if (ret) |
482 | goto error; |
483 | switch (val) { |
484 | case AF9013_TUNER_ENV77H11D5: |
485 | case AF9013_TUNER_MT2060: |
486 | case AF9013_TUNER_QT1010: |
487 | case AF9013_TUNER_UNKNOWN: |
488 | case AF9013_TUNER_MT2060_2: |
489 | case AF9013_TUNER_TDA18271: |
490 | case AF9013_TUNER_QT1010A: |
491 | case AF9013_TUNER_TDA18218: |
492 | state->af9013_pdata[i].spec_inv = 1; |
493 | break; |
494 | case AF9013_TUNER_MXL5003D: |
495 | case AF9013_TUNER_MXL5005D: |
496 | case AF9013_TUNER_MXL5005R: |
497 | case AF9013_TUNER_MXL5007T: |
498 | state->af9013_pdata[i].spec_inv = 0; |
499 | break; |
500 | case AF9013_TUNER_MC44S803: |
501 | state->af9013_pdata[i].gpio[1] = AF9013_GPIO_LO; |
502 | state->af9013_pdata[i].spec_inv = 1; |
503 | break; |
504 | default: |
505 | dev_err(&intf->dev, |
506 | "tuner id %02x not supported, please report!\n" , |
507 | val); |
508 | return -ENODEV; |
509 | } |
510 | |
511 | state->af9013_pdata[i].tuner = val; |
512 | dev_dbg(&intf->dev, "[%d] tuner id %02x\n" , i, val); |
513 | } |
514 | |
515 | error: |
516 | if (ret) |
517 | dev_err(&intf->dev, "eeprom read failed %d\n" , ret); |
518 | |
519 | /* |
520 | * AverMedia AVerTV Volar Black HD (A850) device have bad EEPROM |
521 | * content :-( Override some wrong values here. Ditto for the |
522 | * AVerTV Red HD+ (A850T) device. |
523 | */ |
524 | if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_AVERMEDIA && |
525 | ((le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_AVERMEDIA_A850) || |
526 | (le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_AVERMEDIA_A850T))) { |
527 | dev_dbg(&intf->dev, "AverMedia A850: overriding config\n" ); |
528 | /* disable dual mode */ |
529 | state->dual_mode = 0; |
530 | |
531 | /* set correct IF */ |
532 | state->af9013_pdata[0].if_frequency = 4570000; |
533 | } |
534 | |
535 | return ret; |
536 | } |
537 | |
538 | static int af9015_get_stream_config(struct dvb_frontend *fe, u8 *ts_type, |
539 | struct usb_data_stream_properties *stream) |
540 | { |
541 | struct dvb_usb_device *d = fe_to_d(fe); |
542 | struct usb_interface *intf = d->intf; |
543 | |
544 | dev_dbg(&intf->dev, "adap %u\n" , fe_to_adap(fe)->id); |
545 | |
546 | if (d->udev->speed == USB_SPEED_FULL) |
547 | stream->u.bulk.buffersize = 5 * 188; |
548 | |
549 | return 0; |
550 | } |
551 | |
552 | static int af9015_streaming_ctrl(struct dvb_frontend *fe, int onoff) |
553 | { |
554 | struct dvb_usb_device *d = fe_to_d(fe); |
555 | struct af9015_state *state = d_to_priv(d); |
556 | struct usb_interface *intf = d->intf; |
557 | int ret; |
558 | unsigned int utmp1, utmp2, reg1, reg2; |
559 | u8 buf[2]; |
560 | const unsigned int adap_id = fe_to_adap(fe)->id; |
561 | |
562 | dev_dbg(&intf->dev, "adap id %d, onoff %d\n" , adap_id, onoff); |
563 | |
564 | if (!state->usb_ts_if_configured[adap_id]) { |
565 | dev_dbg(&intf->dev, "set usb and ts interface\n" ); |
566 | |
567 | /* USB IF stream settings */ |
568 | utmp1 = (d->udev->speed == USB_SPEED_FULL ? 5 : 87) * 188 / 4; |
569 | utmp2 = (d->udev->speed == USB_SPEED_FULL ? 64 : 512) / 4; |
570 | |
571 | buf[0] = (utmp1 >> 0) & 0xff; |
572 | buf[1] = (utmp1 >> 8) & 0xff; |
573 | if (adap_id == 0) { |
574 | /* 1st USB IF (EP4) stream settings */ |
575 | reg1 = 0xdd88; |
576 | reg2 = 0xdd0c; |
577 | } else { |
578 | /* 2nd USB IF (EP5) stream settings */ |
579 | reg1 = 0xdd8a; |
580 | reg2 = 0xdd0d; |
581 | } |
582 | ret = regmap_bulk_write(map: state->regmap, reg: reg1, val: buf, val_count: 2); |
583 | if (ret) |
584 | goto err; |
585 | ret = regmap_write(map: state->regmap, reg: reg2, val: utmp2); |
586 | if (ret) |
587 | goto err; |
588 | |
589 | /* TS IF settings */ |
590 | if (state->dual_mode) { |
591 | utmp1 = 0x01; |
592 | utmp2 = 0x10; |
593 | } else { |
594 | utmp1 = 0x00; |
595 | utmp2 = 0x00; |
596 | } |
597 | ret = regmap_update_bits(map: state->regmap, reg: 0xd50b, mask: 0x01, val: utmp1); |
598 | if (ret) |
599 | goto err; |
600 | ret = regmap_update_bits(map: state->regmap, reg: 0xd520, mask: 0x10, val: utmp2); |
601 | if (ret) |
602 | goto err; |
603 | |
604 | state->usb_ts_if_configured[adap_id] = true; |
605 | } |
606 | |
607 | if (adap_id == 0 && onoff) { |
608 | /* Adapter 0 stream on. EP4: clear NAK, enable, clear reset */ |
609 | ret = regmap_update_bits(map: state->regmap, reg: 0xdd13, mask: 0x20, val: 0x00); |
610 | if (ret) |
611 | goto err; |
612 | ret = regmap_update_bits(map: state->regmap, reg: 0xdd11, mask: 0x20, val: 0x20); |
613 | if (ret) |
614 | goto err; |
615 | ret = regmap_update_bits(map: state->regmap, reg: 0xd507, mask: 0x04, val: 0x00); |
616 | if (ret) |
617 | goto err; |
618 | } else if (adap_id == 1 && onoff) { |
619 | /* Adapter 1 stream on. EP5: clear NAK, enable, clear reset */ |
620 | ret = regmap_update_bits(map: state->regmap, reg: 0xdd13, mask: 0x40, val: 0x00); |
621 | if (ret) |
622 | goto err; |
623 | ret = regmap_update_bits(map: state->regmap, reg: 0xdd11, mask: 0x40, val: 0x40); |
624 | if (ret) |
625 | goto err; |
626 | ret = regmap_update_bits(map: state->regmap, reg: 0xd50b, mask: 0x02, val: 0x00); |
627 | if (ret) |
628 | goto err; |
629 | } else if (adap_id == 0 && !onoff) { |
630 | /* Adapter 0 stream off. EP4: set reset, disable, set NAK */ |
631 | ret = regmap_update_bits(map: state->regmap, reg: 0xd507, mask: 0x04, val: 0x04); |
632 | if (ret) |
633 | goto err; |
634 | ret = regmap_update_bits(map: state->regmap, reg: 0xdd11, mask: 0x20, val: 0x00); |
635 | if (ret) |
636 | goto err; |
637 | ret = regmap_update_bits(map: state->regmap, reg: 0xdd13, mask: 0x20, val: 0x20); |
638 | if (ret) |
639 | goto err; |
640 | } else if (adap_id == 1 && !onoff) { |
641 | /* Adapter 1 stream off. EP5: set reset, disable, set NAK */ |
642 | ret = regmap_update_bits(map: state->regmap, reg: 0xd50b, mask: 0x02, val: 0x02); |
643 | if (ret) |
644 | goto err; |
645 | ret = regmap_update_bits(map: state->regmap, reg: 0xdd11, mask: 0x40, val: 0x00); |
646 | if (ret) |
647 | goto err; |
648 | ret = regmap_update_bits(map: state->regmap, reg: 0xdd13, mask: 0x40, val: 0x40); |
649 | if (ret) |
650 | goto err; |
651 | } |
652 | |
653 | return 0; |
654 | err: |
655 | dev_dbg(&intf->dev, "failed %d\n" , ret); |
656 | return ret; |
657 | } |
658 | |
659 | static int af9015_get_adapter_count(struct dvb_usb_device *d) |
660 | { |
661 | struct af9015_state *state = d_to_priv(d); |
662 | |
663 | return state->dual_mode + 1; |
664 | } |
665 | |
666 | /* override demod callbacks for resource locking */ |
667 | static int af9015_af9013_set_frontend(struct dvb_frontend *fe) |
668 | { |
669 | int ret; |
670 | struct af9015_state *state = fe_to_priv(fe); |
671 | |
672 | if (mutex_lock_interruptible(&state->fe_mutex)) |
673 | return -EAGAIN; |
674 | |
675 | ret = state->set_frontend[fe_to_adap(fe)->id](fe); |
676 | |
677 | mutex_unlock(lock: &state->fe_mutex); |
678 | |
679 | return ret; |
680 | } |
681 | |
682 | /* override demod callbacks for resource locking */ |
683 | static int af9015_af9013_read_status(struct dvb_frontend *fe, |
684 | enum fe_status *status) |
685 | { |
686 | int ret; |
687 | struct af9015_state *state = fe_to_priv(fe); |
688 | |
689 | if (mutex_lock_interruptible(&state->fe_mutex)) |
690 | return -EAGAIN; |
691 | |
692 | ret = state->read_status[fe_to_adap(fe)->id](fe, status); |
693 | |
694 | mutex_unlock(lock: &state->fe_mutex); |
695 | |
696 | return ret; |
697 | } |
698 | |
699 | /* override demod callbacks for resource locking */ |
700 | static int af9015_af9013_init(struct dvb_frontend *fe) |
701 | { |
702 | int ret; |
703 | struct af9015_state *state = fe_to_priv(fe); |
704 | |
705 | if (mutex_lock_interruptible(&state->fe_mutex)) |
706 | return -EAGAIN; |
707 | |
708 | ret = state->init[fe_to_adap(fe)->id](fe); |
709 | |
710 | mutex_unlock(lock: &state->fe_mutex); |
711 | |
712 | return ret; |
713 | } |
714 | |
715 | /* override demod callbacks for resource locking */ |
716 | static int af9015_af9013_sleep(struct dvb_frontend *fe) |
717 | { |
718 | int ret; |
719 | struct af9015_state *state = fe_to_priv(fe); |
720 | |
721 | if (mutex_lock_interruptible(&state->fe_mutex)) |
722 | return -EAGAIN; |
723 | |
724 | ret = state->sleep[fe_to_adap(fe)->id](fe); |
725 | |
726 | mutex_unlock(lock: &state->fe_mutex); |
727 | |
728 | return ret; |
729 | } |
730 | |
731 | /* override tuner callbacks for resource locking */ |
732 | static int af9015_tuner_init(struct dvb_frontend *fe) |
733 | { |
734 | int ret; |
735 | struct af9015_state *state = fe_to_priv(fe); |
736 | |
737 | if (mutex_lock_interruptible(&state->fe_mutex)) |
738 | return -EAGAIN; |
739 | |
740 | ret = state->tuner_init[fe_to_adap(fe)->id](fe); |
741 | |
742 | mutex_unlock(lock: &state->fe_mutex); |
743 | |
744 | return ret; |
745 | } |
746 | |
747 | /* override tuner callbacks for resource locking */ |
748 | static int af9015_tuner_sleep(struct dvb_frontend *fe) |
749 | { |
750 | int ret; |
751 | struct af9015_state *state = fe_to_priv(fe); |
752 | |
753 | if (mutex_lock_interruptible(&state->fe_mutex)) |
754 | return -EAGAIN; |
755 | |
756 | ret = state->tuner_sleep[fe_to_adap(fe)->id](fe); |
757 | |
758 | mutex_unlock(lock: &state->fe_mutex); |
759 | |
760 | return ret; |
761 | } |
762 | |
763 | static int af9015_copy_firmware(struct dvb_usb_device *d) |
764 | { |
765 | struct af9015_state *state = d_to_priv(d); |
766 | struct usb_interface *intf = d->intf; |
767 | int ret; |
768 | unsigned long timeout; |
769 | u8 val, firmware_info[4]; |
770 | struct req_t req = {COPY_FIRMWARE, 0, 0x5100, 0, 0, 4, firmware_info}; |
771 | |
772 | dev_dbg(&intf->dev, "\n" ); |
773 | |
774 | firmware_info[0] = (state->firmware_size >> 8) & 0xff; |
775 | firmware_info[1] = (state->firmware_size >> 0) & 0xff; |
776 | firmware_info[2] = (state->firmware_checksum >> 8) & 0xff; |
777 | firmware_info[3] = (state->firmware_checksum >> 0) & 0xff; |
778 | |
779 | /* Check whether firmware is already running */ |
780 | ret = af9015_read_reg_i2c(d, addr: state->af9013_i2c_addr[1], reg: 0x98be, val: &val); |
781 | if (ret) |
782 | goto err; |
783 | |
784 | dev_dbg(&intf->dev, "firmware status %02x\n" , val); |
785 | |
786 | if (val == 0x0c) |
787 | return 0; |
788 | |
789 | /* Set i2c clock to 625kHz to speed up firmware copy */ |
790 | ret = regmap_write(map: state->regmap, reg: 0xd416, val: 0x04); |
791 | if (ret) |
792 | goto err; |
793 | |
794 | /* Copy firmware from master demod to slave demod */ |
795 | ret = af9015_ctrl_msg(d, req: &req); |
796 | if (ret) { |
797 | dev_err(&intf->dev, "firmware copy cmd failed %d\n" , ret); |
798 | goto err; |
799 | } |
800 | |
801 | /* Set i2c clock to 125kHz */ |
802 | ret = regmap_write(map: state->regmap, reg: 0xd416, val: 0x14); |
803 | if (ret) |
804 | goto err; |
805 | |
806 | /* Boot firmware */ |
807 | ret = af9015_write_reg_i2c(d, addr: state->af9013_i2c_addr[1], reg: 0xe205, val: 0x01); |
808 | if (ret) |
809 | goto err; |
810 | |
811 | /* Poll firmware ready */ |
812 | for (val = 0x00, timeout = jiffies + msecs_to_jiffies(m: 1000); |
813 | !time_after(jiffies, timeout) && val != 0x0c && val != 0x04;) { |
814 | msleep(msecs: 20); |
815 | |
816 | /* Check firmware status. 0c=OK, 04=fail */ |
817 | ret = af9015_read_reg_i2c(d, addr: state->af9013_i2c_addr[1], |
818 | reg: 0x98be, val: &val); |
819 | if (ret) |
820 | goto err; |
821 | |
822 | dev_dbg(&intf->dev, "firmware status %02x\n" , val); |
823 | } |
824 | |
825 | dev_dbg(&intf->dev, "firmware boot took %u ms\n" , |
826 | jiffies_to_msecs(jiffies) - (jiffies_to_msecs(timeout) - 1000)); |
827 | |
828 | if (val == 0x04) { |
829 | ret = -ENODEV; |
830 | dev_err(&intf->dev, "firmware did not run\n" ); |
831 | goto err; |
832 | } else if (val != 0x0c) { |
833 | ret = -ETIMEDOUT; |
834 | dev_err(&intf->dev, "firmware boot timeout\n" ); |
835 | goto err; |
836 | } |
837 | |
838 | return 0; |
839 | err: |
840 | dev_dbg(&intf->dev, "failed %d\n" , ret); |
841 | return ret; |
842 | } |
843 | |
844 | static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) |
845 | { |
846 | struct af9015_state *state = adap_to_priv(adap); |
847 | struct dvb_usb_device *d = adap_to_d(adap); |
848 | struct usb_interface *intf = d->intf; |
849 | struct i2c_client *client; |
850 | int ret; |
851 | |
852 | dev_dbg(&intf->dev, "adap id %u\n" , adap->id); |
853 | |
854 | if (adap->id == 0) { |
855 | state->af9013_pdata[0].ts_mode = AF9013_TS_MODE_USB; |
856 | memcpy(state->af9013_pdata[0].api_version, "\x0\x1\x9\x0" , 4); |
857 | state->af9013_pdata[0].gpio[0] = AF9013_GPIO_HI; |
858 | state->af9013_pdata[0].gpio[3] = AF9013_GPIO_TUNER_ON; |
859 | } else if (adap->id == 1) { |
860 | state->af9013_pdata[1].ts_mode = AF9013_TS_MODE_SERIAL; |
861 | state->af9013_pdata[1].ts_output_pin = 7; |
862 | memcpy(state->af9013_pdata[1].api_version, "\x0\x1\x9\x0" , 4); |
863 | state->af9013_pdata[1].gpio[0] = AF9013_GPIO_TUNER_ON; |
864 | state->af9013_pdata[1].gpio[1] = AF9013_GPIO_LO; |
865 | |
866 | /* copy firmware to 2nd demodulator */ |
867 | if (state->dual_mode) { |
868 | /* Wait 2nd demodulator ready */ |
869 | msleep(msecs: 100); |
870 | |
871 | ret = af9015_copy_firmware(adap_to_d(adap)); |
872 | if (ret) { |
873 | dev_err(&intf->dev, |
874 | "firmware copy to 2nd frontend failed, will disable it\n" ); |
875 | state->dual_mode = 0; |
876 | goto err; |
877 | } |
878 | } else { |
879 | ret = -ENODEV; |
880 | goto err; |
881 | } |
882 | } |
883 | |
884 | /* Add I2C demod */ |
885 | client = dvb_module_probe(module_name: "af9013" , NULL, adap: &d->i2c_adap, |
886 | addr: state->af9013_i2c_addr[adap->id], |
887 | platform_data: &state->af9013_pdata[adap->id]); |
888 | if (!client) { |
889 | ret = -ENODEV; |
890 | goto err; |
891 | } |
892 | adap->fe[0] = state->af9013_pdata[adap->id].get_dvb_frontend(client); |
893 | state->demod_i2c_client[adap->id] = client; |
894 | |
895 | /* |
896 | * AF9015 firmware does not like if it gets interrupted by I2C adapter |
897 | * request on some critical phases. During normal operation I2C adapter |
898 | * is used only 2nd demodulator and tuner on dual tuner devices. |
899 | * Override demodulator callbacks and use mutex for limit access to |
900 | * those "critical" paths to keep AF9015 happy. |
901 | */ |
902 | if (adap->fe[0]) { |
903 | state->set_frontend[adap->id] = adap->fe[0]->ops.set_frontend; |
904 | adap->fe[0]->ops.set_frontend = af9015_af9013_set_frontend; |
905 | state->read_status[adap->id] = adap->fe[0]->ops.read_status; |
906 | adap->fe[0]->ops.read_status = af9015_af9013_read_status; |
907 | state->init[adap->id] = adap->fe[0]->ops.init; |
908 | adap->fe[0]->ops.init = af9015_af9013_init; |
909 | state->sleep[adap->id] = adap->fe[0]->ops.sleep; |
910 | adap->fe[0]->ops.sleep = af9015_af9013_sleep; |
911 | } |
912 | |
913 | return 0; |
914 | err: |
915 | dev_dbg(&intf->dev, "failed %d\n" , ret); |
916 | return ret; |
917 | } |
918 | |
919 | static int af9015_frontend_detach(struct dvb_usb_adapter *adap) |
920 | { |
921 | struct af9015_state *state = adap_to_priv(adap); |
922 | struct dvb_usb_device *d = adap_to_d(adap); |
923 | struct usb_interface *intf = d->intf; |
924 | struct i2c_client *client; |
925 | |
926 | dev_dbg(&intf->dev, "adap id %u\n" , adap->id); |
927 | |
928 | /* Remove I2C demod */ |
929 | client = state->demod_i2c_client[adap->id]; |
930 | dvb_module_release(client); |
931 | |
932 | return 0; |
933 | } |
934 | |
935 | static struct mt2060_config af9015_mt2060_config = { |
936 | .i2c_address = 0x60, |
937 | .clock_out = 0, |
938 | }; |
939 | |
940 | static struct qt1010_config af9015_qt1010_config = { |
941 | .i2c_address = 0x62, |
942 | }; |
943 | |
944 | static struct tda18271_config af9015_tda18271_config = { |
945 | .gate = TDA18271_GATE_DIGITAL, |
946 | .small_i2c = TDA18271_16_BYTE_CHUNK_INIT, |
947 | }; |
948 | |
949 | static struct mxl5005s_config af9015_mxl5003_config = { |
950 | .i2c_address = 0x63, |
951 | .if_freq = IF_FREQ_4570000HZ, |
952 | .xtal_freq = CRYSTAL_FREQ_16000000HZ, |
953 | .agc_mode = MXL_SINGLE_AGC, |
954 | .tracking_filter = MXL_TF_DEFAULT, |
955 | .rssi_enable = MXL_RSSI_ENABLE, |
956 | .cap_select = MXL_CAP_SEL_ENABLE, |
957 | .div_out = MXL_DIV_OUT_4, |
958 | .clock_out = MXL_CLOCK_OUT_DISABLE, |
959 | .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, |
960 | .top = MXL5005S_TOP_25P2, |
961 | .mod_mode = MXL_DIGITAL_MODE, |
962 | .if_mode = MXL_ZERO_IF, |
963 | .AgcMasterByte = 0x00, |
964 | }; |
965 | |
966 | static struct mxl5005s_config af9015_mxl5005_config = { |
967 | .i2c_address = 0x63, |
968 | .if_freq = IF_FREQ_4570000HZ, |
969 | .xtal_freq = CRYSTAL_FREQ_16000000HZ, |
970 | .agc_mode = MXL_SINGLE_AGC, |
971 | .tracking_filter = MXL_TF_OFF, |
972 | .rssi_enable = MXL_RSSI_ENABLE, |
973 | .cap_select = MXL_CAP_SEL_ENABLE, |
974 | .div_out = MXL_DIV_OUT_4, |
975 | .clock_out = MXL_CLOCK_OUT_DISABLE, |
976 | .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, |
977 | .top = MXL5005S_TOP_25P2, |
978 | .mod_mode = MXL_DIGITAL_MODE, |
979 | .if_mode = MXL_ZERO_IF, |
980 | .AgcMasterByte = 0x00, |
981 | }; |
982 | |
983 | static struct mc44s803_config af9015_mc44s803_config = { |
984 | .i2c_address = 0x60, |
985 | .dig_out = 1, |
986 | }; |
987 | |
988 | static struct tda18218_config af9015_tda18218_config = { |
989 | .i2c_address = 0x60, |
990 | .i2c_wr_max = 21, /* max wr bytes AF9015 I2C adap can handle at once */ |
991 | }; |
992 | |
993 | static struct mxl5007t_config af9015_mxl5007t_config = { |
994 | .xtal_freq_hz = MxL_XTAL_24_MHZ, |
995 | .if_freq_hz = MxL_IF_4_57_MHZ, |
996 | }; |
997 | |
998 | static int af9015_tuner_attach(struct dvb_usb_adapter *adap) |
999 | { |
1000 | struct dvb_usb_device *d = adap_to_d(adap); |
1001 | struct af9015_state *state = d_to_priv(d); |
1002 | struct usb_interface *intf = d->intf; |
1003 | struct i2c_client *client; |
1004 | struct i2c_adapter *adapter; |
1005 | int ret; |
1006 | |
1007 | dev_dbg(&intf->dev, "adap id %u\n" , adap->id); |
1008 | |
1009 | client = state->demod_i2c_client[adap->id]; |
1010 | adapter = state->af9013_pdata[adap->id].get_i2c_adapter(client); |
1011 | |
1012 | switch (state->af9013_pdata[adap->id].tuner) { |
1013 | case AF9013_TUNER_MT2060: |
1014 | case AF9013_TUNER_MT2060_2: |
1015 | ret = dvb_attach(mt2060_attach, adap->fe[0], adapter, |
1016 | &af9015_mt2060_config, |
1017 | state->mt2060_if1[adap->id]) == NULL ? -ENODEV : 0; |
1018 | break; |
1019 | case AF9013_TUNER_QT1010: |
1020 | case AF9013_TUNER_QT1010A: |
1021 | ret = dvb_attach(qt1010_attach, adap->fe[0], adapter, |
1022 | &af9015_qt1010_config) == NULL ? -ENODEV : 0; |
1023 | break; |
1024 | case AF9013_TUNER_TDA18271: |
1025 | ret = dvb_attach(tda18271_attach, adap->fe[0], 0x60, adapter, |
1026 | &af9015_tda18271_config) == NULL ? -ENODEV : 0; |
1027 | break; |
1028 | case AF9013_TUNER_TDA18218: |
1029 | ret = dvb_attach(tda18218_attach, adap->fe[0], adapter, |
1030 | &af9015_tda18218_config) == NULL ? -ENODEV : 0; |
1031 | break; |
1032 | case AF9013_TUNER_MXL5003D: |
1033 | ret = dvb_attach(mxl5005s_attach, adap->fe[0], adapter, |
1034 | &af9015_mxl5003_config) == NULL ? -ENODEV : 0; |
1035 | break; |
1036 | case AF9013_TUNER_MXL5005D: |
1037 | case AF9013_TUNER_MXL5005R: |
1038 | ret = dvb_attach(mxl5005s_attach, adap->fe[0], adapter, |
1039 | &af9015_mxl5005_config) == NULL ? -ENODEV : 0; |
1040 | break; |
1041 | case AF9013_TUNER_ENV77H11D5: |
1042 | ret = dvb_attach(dvb_pll_attach, adap->fe[0], 0x60, adapter, |
1043 | DVB_PLL_TDA665X) == NULL ? -ENODEV : 0; |
1044 | break; |
1045 | case AF9013_TUNER_MC44S803: |
1046 | ret = dvb_attach(mc44s803_attach, adap->fe[0], adapter, |
1047 | &af9015_mc44s803_config) == NULL ? -ENODEV : 0; |
1048 | break; |
1049 | case AF9013_TUNER_MXL5007T: |
1050 | ret = dvb_attach(mxl5007t_attach, adap->fe[0], adapter, |
1051 | 0x60, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0; |
1052 | break; |
1053 | case AF9013_TUNER_UNKNOWN: |
1054 | default: |
1055 | dev_err(&intf->dev, "unknown tuner, tuner id %02x\n" , |
1056 | state->af9013_pdata[adap->id].tuner); |
1057 | ret = -ENODEV; |
1058 | } |
1059 | |
1060 | if (adap->fe[0]->ops.tuner_ops.init) { |
1061 | state->tuner_init[adap->id] = |
1062 | adap->fe[0]->ops.tuner_ops.init; |
1063 | adap->fe[0]->ops.tuner_ops.init = af9015_tuner_init; |
1064 | } |
1065 | |
1066 | if (adap->fe[0]->ops.tuner_ops.sleep) { |
1067 | state->tuner_sleep[adap->id] = |
1068 | adap->fe[0]->ops.tuner_ops.sleep; |
1069 | adap->fe[0]->ops.tuner_ops.sleep = af9015_tuner_sleep; |
1070 | } |
1071 | |
1072 | return ret; |
1073 | } |
1074 | |
1075 | static int af9015_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) |
1076 | { |
1077 | struct af9015_state *state = adap_to_priv(adap); |
1078 | struct af9013_platform_data *pdata = &state->af9013_pdata[adap->id]; |
1079 | int ret; |
1080 | |
1081 | mutex_lock(&state->fe_mutex); |
1082 | ret = pdata->pid_filter_ctrl(adap->fe[0], onoff); |
1083 | mutex_unlock(lock: &state->fe_mutex); |
1084 | |
1085 | return ret; |
1086 | } |
1087 | |
1088 | static int af9015_pid_filter(struct dvb_usb_adapter *adap, int index, |
1089 | u16 pid, int onoff) |
1090 | { |
1091 | struct af9015_state *state = adap_to_priv(adap); |
1092 | struct af9013_platform_data *pdata = &state->af9013_pdata[adap->id]; |
1093 | int ret; |
1094 | |
1095 | mutex_lock(&state->fe_mutex); |
1096 | ret = pdata->pid_filter(adap->fe[0], index, pid, onoff); |
1097 | mutex_unlock(lock: &state->fe_mutex); |
1098 | |
1099 | return ret; |
1100 | } |
1101 | |
1102 | static int af9015_init(struct dvb_usb_device *d) |
1103 | { |
1104 | struct af9015_state *state = d_to_priv(d); |
1105 | struct usb_interface *intf = d->intf; |
1106 | int ret; |
1107 | |
1108 | dev_dbg(&intf->dev, "\n" ); |
1109 | |
1110 | mutex_init(&state->fe_mutex); |
1111 | |
1112 | /* init RC canary */ |
1113 | ret = regmap_write(map: state->regmap, reg: 0x98e9, val: 0xff); |
1114 | if (ret) |
1115 | goto error; |
1116 | |
1117 | error: |
1118 | return ret; |
1119 | } |
1120 | |
1121 | #if IS_ENABLED(CONFIG_RC_CORE) |
1122 | struct af9015_rc_setup { |
1123 | unsigned int id; |
1124 | char *rc_codes; |
1125 | }; |
1126 | |
1127 | static char *af9015_rc_setup_match(unsigned int id, |
1128 | const struct af9015_rc_setup *table) |
1129 | { |
1130 | for (; table->rc_codes; table++) |
1131 | if (table->id == id) |
1132 | return table->rc_codes; |
1133 | return NULL; |
1134 | } |
1135 | |
1136 | static const struct af9015_rc_setup af9015_rc_setup_modparam[] = { |
1137 | { AF9015_REMOTE_A_LINK_DTU_M, RC_MAP_ALINK_DTU_M }, |
1138 | { AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, RC_MAP_MSI_DIGIVOX_II }, |
1139 | { AF9015_REMOTE_MYGICTV_U718, RC_MAP_TOTAL_MEDIA_IN_HAND }, |
1140 | { AF9015_REMOTE_DIGITTRADE_DVB_T, RC_MAP_DIGITTRADE }, |
1141 | { AF9015_REMOTE_AVERMEDIA_KS, RC_MAP_AVERMEDIA_RM_KS }, |
1142 | { } |
1143 | }; |
1144 | |
1145 | static const struct af9015_rc_setup af9015_rc_setup_hashes[] = { |
1146 | { 0xb8feb708, RC_MAP_MSI_DIGIVOX_II }, |
1147 | { 0xa3703d00, RC_MAP_ALINK_DTU_M }, |
1148 | { 0x9b7dc64e, RC_MAP_TOTAL_MEDIA_IN_HAND }, /* MYGICTV U718 */ |
1149 | { 0x5d49e3db, RC_MAP_DIGITTRADE }, /* LC-Power LC-USB-DVBT */ |
1150 | { } |
1151 | }; |
1152 | |
1153 | static int af9015_rc_query(struct dvb_usb_device *d) |
1154 | { |
1155 | struct af9015_state *state = d_to_priv(d); |
1156 | struct usb_interface *intf = d->intf; |
1157 | int ret; |
1158 | u8 buf[17]; |
1159 | |
1160 | /* read registers needed to detect remote controller code */ |
1161 | ret = regmap_bulk_read(map: state->regmap, reg: 0x98d9, val: buf, val_count: sizeof(buf)); |
1162 | if (ret) |
1163 | goto error; |
1164 | |
1165 | /* If any of these are non-zero, assume invalid data */ |
1166 | if (buf[1] || buf[2] || buf[3]) { |
1167 | dev_dbg(&intf->dev, "invalid data\n" ); |
1168 | return 0; |
1169 | } |
1170 | |
1171 | /* Check for repeat of previous code */ |
1172 | if ((state->rc_repeat != buf[6] || buf[0]) && |
1173 | !memcmp(p: &buf[12], q: state->rc_last, size: 4)) { |
1174 | dev_dbg(&intf->dev, "key repeated\n" ); |
1175 | rc_repeat(dev: d->rc_dev); |
1176 | state->rc_repeat = buf[6]; |
1177 | return 0; |
1178 | } |
1179 | |
1180 | /* Only process key if canary killed */ |
1181 | if (buf[16] != 0xff && buf[0] != 0x01) { |
1182 | enum rc_proto proto; |
1183 | |
1184 | dev_dbg(&intf->dev, "key pressed %*ph\n" , 4, buf + 12); |
1185 | |
1186 | /* Reset the canary */ |
1187 | ret = regmap_write(map: state->regmap, reg: 0x98e9, val: 0xff); |
1188 | if (ret) |
1189 | goto error; |
1190 | |
1191 | /* Remember this key */ |
1192 | memcpy(state->rc_last, &buf[12], 4); |
1193 | if (buf[14] == (u8)~buf[15]) { |
1194 | if (buf[12] == (u8)~buf[13]) { |
1195 | /* NEC */ |
1196 | state->rc_keycode = RC_SCANCODE_NEC(buf[12], |
1197 | buf[14]); |
1198 | proto = RC_PROTO_NEC; |
1199 | } else { |
1200 | /* NEC extended*/ |
1201 | state->rc_keycode = RC_SCANCODE_NECX(buf[12] << 8 | |
1202 | buf[13], |
1203 | buf[14]); |
1204 | proto = RC_PROTO_NECX; |
1205 | } |
1206 | } else { |
1207 | /* 32 bit NEC */ |
1208 | state->rc_keycode = RC_SCANCODE_NEC32(buf[12] << 24 | |
1209 | buf[13] << 16 | |
1210 | buf[14] << 8 | |
1211 | buf[15]); |
1212 | proto = RC_PROTO_NEC32; |
1213 | } |
1214 | rc_keydown(dev: d->rc_dev, protocol: proto, scancode: state->rc_keycode, toggle: 0); |
1215 | } else { |
1216 | dev_dbg(&intf->dev, "no key press\n" ); |
1217 | /* Invalidate last keypress */ |
1218 | /* Not really needed, but helps with debug */ |
1219 | state->rc_last[2] = state->rc_last[3]; |
1220 | } |
1221 | |
1222 | state->rc_repeat = buf[6]; |
1223 | state->rc_failed = false; |
1224 | |
1225 | error: |
1226 | if (ret) { |
1227 | dev_warn(&intf->dev, "rc query failed %d\n" , ret); |
1228 | |
1229 | /* allow random errors as dvb-usb will stop polling on error */ |
1230 | if (!state->rc_failed) |
1231 | ret = 0; |
1232 | |
1233 | state->rc_failed = true; |
1234 | } |
1235 | |
1236 | return ret; |
1237 | } |
1238 | |
1239 | static int af9015_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) |
1240 | { |
1241 | struct af9015_state *state = d_to_priv(d); |
1242 | u16 vid = le16_to_cpu(d->udev->descriptor.idVendor); |
1243 | |
1244 | if (state->ir_mode == AF9015_IR_MODE_DISABLED) |
1245 | return 0; |
1246 | |
1247 | /* try to load remote based module param */ |
1248 | if (!rc->map_name) |
1249 | rc->map_name = af9015_rc_setup_match(id: dvb_usb_af9015_remote, |
1250 | table: af9015_rc_setup_modparam); |
1251 | |
1252 | /* try to load remote based eeprom hash */ |
1253 | if (!rc->map_name) |
1254 | rc->map_name = af9015_rc_setup_match(id: state->eeprom_sum, |
1255 | table: af9015_rc_setup_hashes); |
1256 | |
1257 | /* try to load remote based USB iManufacturer string */ |
1258 | if (!rc->map_name && vid == USB_VID_AFATECH) { |
1259 | /* |
1260 | * Check USB manufacturer and product strings and try |
1261 | * to determine correct remote in case of chip vendor |
1262 | * reference IDs are used. |
1263 | * DO NOT ADD ANYTHING NEW HERE. Use hashes instead. |
1264 | */ |
1265 | char manufacturer[10]; |
1266 | |
1267 | memset(manufacturer, 0, sizeof(manufacturer)); |
1268 | usb_string(dev: d->udev, index: d->udev->descriptor.iManufacturer, |
1269 | buf: manufacturer, size: sizeof(manufacturer)); |
1270 | if (!strcmp("MSI" , manufacturer)) { |
1271 | /* |
1272 | * iManufacturer 1 MSI |
1273 | * iProduct 2 MSI K-VOX |
1274 | */ |
1275 | rc->map_name = af9015_rc_setup_match(id: AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, |
1276 | table: af9015_rc_setup_modparam); |
1277 | } |
1278 | } |
1279 | |
1280 | /* load empty to enable rc */ |
1281 | if (!rc->map_name) |
1282 | rc->map_name = RC_MAP_EMPTY; |
1283 | |
1284 | rc->allowed_protos = RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX | |
1285 | RC_PROTO_BIT_NEC32; |
1286 | rc->query = af9015_rc_query; |
1287 | rc->interval = 500; |
1288 | |
1289 | return 0; |
1290 | } |
1291 | #else |
1292 | #define af9015_get_rc_config NULL |
1293 | #endif |
1294 | |
1295 | static int af9015_regmap_write(void *context, const void *data, size_t count) |
1296 | { |
1297 | struct dvb_usb_device *d = context; |
1298 | struct usb_interface *intf = d->intf; |
1299 | int ret; |
1300 | u16 reg = ((u8 *)data)[0] << 8 | ((u8 *)data)[1] << 0; |
1301 | u8 *val = &((u8 *)data)[2]; |
1302 | const unsigned int len = count - 2; |
1303 | struct req_t req = {WRITE_MEMORY, 0, reg, 0, 0, len, val}; |
1304 | |
1305 | ret = af9015_ctrl_msg(d, req: &req); |
1306 | if (ret) |
1307 | goto err; |
1308 | |
1309 | return 0; |
1310 | err: |
1311 | dev_dbg(&intf->dev, "failed %d\n" , ret); |
1312 | return ret; |
1313 | } |
1314 | |
1315 | static int af9015_regmap_read(void *context, const void *reg_buf, |
1316 | size_t reg_size, void *val_buf, size_t val_size) |
1317 | { |
1318 | struct dvb_usb_device *d = context; |
1319 | struct usb_interface *intf = d->intf; |
1320 | int ret; |
1321 | u16 reg = ((u8 *)reg_buf)[0] << 8 | ((u8 *)reg_buf)[1] << 0; |
1322 | u8 *val = &((u8 *)val_buf)[0]; |
1323 | const unsigned int len = val_size; |
1324 | struct req_t req = {READ_MEMORY, 0, reg, 0, 0, len, val}; |
1325 | |
1326 | ret = af9015_ctrl_msg(d, req: &req); |
1327 | if (ret) |
1328 | goto err; |
1329 | |
1330 | return 0; |
1331 | err: |
1332 | dev_dbg(&intf->dev, "failed %d\n" , ret); |
1333 | return ret; |
1334 | } |
1335 | |
1336 | static int af9015_probe(struct dvb_usb_device *d) |
1337 | { |
1338 | struct af9015_state *state = d_to_priv(d); |
1339 | struct usb_interface *intf = d->intf; |
1340 | struct usb_device *udev = interface_to_usbdev(intf); |
1341 | int ret; |
1342 | char manufacturer[sizeof("ITE Technologies, Inc." )]; |
1343 | static const struct regmap_config regmap_config = { |
1344 | .reg_bits = 16, |
1345 | .val_bits = 8, |
1346 | }; |
1347 | static const struct regmap_bus regmap_bus = { |
1348 | .read = af9015_regmap_read, |
1349 | .write = af9015_regmap_write, |
1350 | }; |
1351 | |
1352 | dev_dbg(&intf->dev, "\n" ); |
1353 | |
1354 | memset(manufacturer, 0, sizeof(manufacturer)); |
1355 | usb_string(dev: udev, index: udev->descriptor.iManufacturer, |
1356 | buf: manufacturer, size: sizeof(manufacturer)); |
1357 | /* |
1358 | * There is two devices having same ID but different chipset. One uses |
1359 | * AF9015 and the other IT9135 chipset. Only difference seen on lsusb |
1360 | * is iManufacturer string. |
1361 | * |
1362 | * idVendor 0x0ccd TerraTec Electronic GmbH |
1363 | * idProduct 0x0099 |
1364 | * bcdDevice 2.00 |
1365 | * iManufacturer 1 Afatech |
1366 | * iProduct 2 DVB-T 2 |
1367 | * |
1368 | * idVendor 0x0ccd TerraTec Electronic GmbH |
1369 | * idProduct 0x0099 |
1370 | * bcdDevice 2.00 |
1371 | * iManufacturer 1 ITE Technologies, Inc. |
1372 | * iProduct 2 DVB-T TV Stick |
1373 | */ |
1374 | if ((le16_to_cpu(udev->descriptor.idVendor) == USB_VID_TERRATEC) && |
1375 | (le16_to_cpu(udev->descriptor.idProduct) == 0x0099)) { |
1376 | if (!strcmp("ITE Technologies, Inc." , manufacturer)) { |
1377 | ret = -ENODEV; |
1378 | dev_dbg(&intf->dev, "rejecting device\n" ); |
1379 | goto err; |
1380 | } |
1381 | } |
1382 | |
1383 | state->regmap = regmap_init(&intf->dev, ®map_bus, d, ®map_config); |
1384 | if (IS_ERR(ptr: state->regmap)) { |
1385 | ret = PTR_ERR(ptr: state->regmap); |
1386 | goto err; |
1387 | } |
1388 | |
1389 | return 0; |
1390 | err: |
1391 | dev_dbg(&intf->dev, "failed %d\n" , ret); |
1392 | return ret; |
1393 | } |
1394 | |
1395 | static void af9015_disconnect(struct dvb_usb_device *d) |
1396 | { |
1397 | struct af9015_state *state = d_to_priv(d); |
1398 | struct usb_interface *intf = d->intf; |
1399 | |
1400 | dev_dbg(&intf->dev, "\n" ); |
1401 | |
1402 | regmap_exit(map: state->regmap); |
1403 | } |
1404 | |
1405 | /* |
1406 | * Interface 0 is used by DVB-T receiver and |
1407 | * interface 1 is for remote controller (HID) |
1408 | */ |
1409 | static const struct dvb_usb_device_properties af9015_props = { |
1410 | .driver_name = KBUILD_MODNAME, |
1411 | .owner = THIS_MODULE, |
1412 | .adapter_nr = adapter_nr, |
1413 | .size_of_priv = sizeof(struct af9015_state), |
1414 | |
1415 | .generic_bulk_ctrl_endpoint = 0x02, |
1416 | .generic_bulk_ctrl_endpoint_response = 0x81, |
1417 | |
1418 | .probe = af9015_probe, |
1419 | .disconnect = af9015_disconnect, |
1420 | .identify_state = af9015_identify_state, |
1421 | .firmware = AF9015_FIRMWARE, |
1422 | .download_firmware = af9015_download_firmware, |
1423 | |
1424 | .i2c_algo = &af9015_i2c_algo, |
1425 | .read_config = af9015_read_config, |
1426 | .frontend_attach = af9015_af9013_frontend_attach, |
1427 | .frontend_detach = af9015_frontend_detach, |
1428 | .tuner_attach = af9015_tuner_attach, |
1429 | .init = af9015_init, |
1430 | .get_rc_config = af9015_get_rc_config, |
1431 | .get_stream_config = af9015_get_stream_config, |
1432 | .streaming_ctrl = af9015_streaming_ctrl, |
1433 | |
1434 | .get_adapter_count = af9015_get_adapter_count, |
1435 | .adapter = { |
1436 | { |
1437 | .caps = DVB_USB_ADAP_HAS_PID_FILTER | |
1438 | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, |
1439 | .pid_filter_count = 32, |
1440 | .pid_filter = af9015_pid_filter, |
1441 | .pid_filter_ctrl = af9015_pid_filter_ctrl, |
1442 | |
1443 | .stream = DVB_USB_STREAM_BULK(0x84, 6, 87 * 188), |
1444 | }, { |
1445 | .caps = DVB_USB_ADAP_HAS_PID_FILTER | |
1446 | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, |
1447 | .pid_filter_count = 32, |
1448 | .pid_filter = af9015_pid_filter, |
1449 | .pid_filter_ctrl = af9015_pid_filter_ctrl, |
1450 | |
1451 | .stream = DVB_USB_STREAM_BULK(0x85, 6, 87 * 188), |
1452 | }, |
1453 | }, |
1454 | }; |
1455 | |
1456 | static const struct usb_device_id af9015_id_table[] = { |
1457 | { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9015, |
1458 | &af9015_props, "Afatech AF9015 reference design" , NULL) }, |
1459 | { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9016, |
1460 | &af9015_props, "Afatech AF9015 reference design" , NULL) }, |
1461 | { DVB_USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_GOLD, |
1462 | &af9015_props, "Leadtek WinFast DTV Dongle Gold" , RC_MAP_LEADTEK_Y04G0051) }, |
1463 | { DVB_USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV71E, |
1464 | &af9015_props, "Pinnacle PCTV 71e" , NULL) }, |
1465 | { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U, |
1466 | &af9015_props, "KWorld PlusTV Dual DVB-T Stick (DVB-T 399U)" , NULL) }, |
1467 | { DVB_USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TINYTWIN, |
1468 | &af9015_props, "DigitalNow TinyTwin" , RC_MAP_AZUREWAVE_AD_TU700) }, |
1469 | { DVB_USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_AZUREWAVE_AD_TU700, |
1470 | &af9015_props, "TwinHan AzureWave AD-TU700(704J)" , RC_MAP_AZUREWAVE_AD_TU700) }, |
1471 | { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2, |
1472 | &af9015_props, "TerraTec Cinergy T USB XE" , NULL) }, |
1473 | { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_2T, |
1474 | &af9015_props, "KWorld PlusTV Dual DVB-T PCI (DVB-T PC160-2T)" , NULL) }, |
1475 | { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X, |
1476 | &af9015_props, "AVerMedia AVerTV DVB-T Volar X" , RC_MAP_AVERMEDIA_M135A) }, |
1477 | { DVB_USB_DEVICE(USB_VID_XTENSIONS, USB_PID_XTENSIONS_XD_380, |
1478 | &af9015_props, "Xtensions XD-380" , NULL) }, |
1479 | { DVB_USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGIVOX_DUO, |
1480 | &af9015_props, "MSI DIGIVOX Duo" , RC_MAP_MSI_DIGIVOX_III) }, |
1481 | { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2, |
1482 | &af9015_props, "Fujitsu-Siemens Slim Mobile USB DVB-T" , NULL) }, |
1483 | { DVB_USB_DEVICE(USB_VID_TELESTAR, USB_PID_TELESTAR_STARSTICK_2, |
1484 | &af9015_props, "Telestar Starstick 2" , NULL) }, |
1485 | { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309, |
1486 | &af9015_props, "AVerMedia A309" , NULL) }, |
1487 | { DVB_USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III, |
1488 | &af9015_props, "MSI Digi VOX mini III" , RC_MAP_MSI_DIGIVOX_III) }, |
1489 | { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U, |
1490 | &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)" , NULL) }, |
1491 | { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_2, |
1492 | &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)" , NULL) }, |
1493 | { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_3, |
1494 | &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)" , NULL) }, |
1495 | { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_TREKSTOR_DVBT, |
1496 | &af9015_props, "TrekStor DVB-T USB Stick" , RC_MAP_TREKSTOR) }, |
1497 | { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850, |
1498 | &af9015_props, "AverMedia AVerTV Volar Black HD (A850)" , NULL) }, |
1499 | { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A805, |
1500 | &af9015_props, "AverMedia AVerTV Volar GPS 805 (A805)" , NULL) }, |
1501 | { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CONCEPTRONIC_CTVDIGRCU, |
1502 | &af9015_props, "Conceptronic USB2.0 DVB-T CTVDIGRCU V3.0" , NULL) }, |
1503 | { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_MC810, |
1504 | &af9015_props, "KWorld Digital MC-810" , NULL) }, |
1505 | { DVB_USB_DEVICE(USB_VID_KYE, USB_PID_GENIUS_TVGO_DVB_T03, |
1506 | &af9015_props, "Genius TVGo DVB-T03" , NULL) }, |
1507 | { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U_2, |
1508 | &af9015_props, "KWorld PlusTV Dual DVB-T Stick (DVB-T 399U)" , NULL) }, |
1509 | { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_T, |
1510 | &af9015_props, "KWorld PlusTV DVB-T PCI Pro Card (DVB-T PC160-T)" , NULL) }, |
1511 | { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20, |
1512 | &af9015_props, "Sveon STV20 Tuner USB DVB-T HDTV" , NULL) }, |
1513 | { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_TINYTWIN_2, |
1514 | &af9015_props, "DigitalNow TinyTwin v2" , RC_MAP_DIGITALNOW_TINYTWIN) }, |
1515 | { DVB_USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS, |
1516 | &af9015_props, "Leadtek WinFast DTV2000DS" , RC_MAP_LEADTEK_Y04G0051) }, |
1517 | { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB383_T, |
1518 | &af9015_props, "KWorld USB DVB-T Stick Mobile (UB383-T)" , NULL) }, |
1519 | { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_4, |
1520 | &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)" , NULL) }, |
1521 | { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A815M, |
1522 | &af9015_props, "AverMedia AVerTV Volar M (A815Mac)" , NULL) }, |
1523 | { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_RC, |
1524 | &af9015_props, "TerraTec Cinergy T Stick RC" , RC_MAP_TERRATEC_SLIM_2) }, |
1525 | /* XXX: that same ID [0ccd:0099] is used by af9035 driver too */ |
1526 | { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC, |
1527 | &af9015_props, "TerraTec Cinergy T Stick Dual RC" , RC_MAP_TERRATEC_SLIM) }, |
1528 | { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T, |
1529 | &af9015_props, "AverMedia AVerTV Red HD+ (A850T)" , NULL) }, |
1530 | { DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_TINYTWIN_3, |
1531 | &af9015_props, "DigitalNow TinyTwin v3" , RC_MAP_DIGITALNOW_TINYTWIN) }, |
1532 | { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22, |
1533 | &af9015_props, "Sveon STV22 Dual USB DVB-T Tuner HDTV" , RC_MAP_MSI_DIGIVOX_III) }, |
1534 | { } |
1535 | }; |
1536 | MODULE_DEVICE_TABLE(usb, af9015_id_table); |
1537 | |
1538 | /* usb specific object needed to register this driver with the usb subsystem */ |
1539 | static struct usb_driver af9015_usb_driver = { |
1540 | .name = KBUILD_MODNAME, |
1541 | .id_table = af9015_id_table, |
1542 | .probe = dvb_usbv2_probe, |
1543 | .disconnect = dvb_usbv2_disconnect, |
1544 | .suspend = dvb_usbv2_suspend, |
1545 | .resume = dvb_usbv2_resume, |
1546 | .reset_resume = dvb_usbv2_reset_resume, |
1547 | .no_dynamic_id = 1, |
1548 | .soft_unbind = 1, |
1549 | }; |
1550 | |
1551 | module_usb_driver(af9015_usb_driver); |
1552 | |
1553 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>" ); |
1554 | MODULE_DESCRIPTION("Afatech AF9015 driver" ); |
1555 | MODULE_LICENSE("GPL" ); |
1556 | MODULE_FIRMWARE(AF9015_FIRMWARE); |
1557 | |