1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* DVB USB framework compliant Linux driver for the AVerMedia AverTV DVB-T |
3 | * USB2.0 (A800) DVB-T receiver. |
4 | * |
5 | * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@posteo.de) |
6 | * |
7 | * Thanks to |
8 | * - AVerMedia who kindly provided information and |
9 | * - Glen Harris who suffered from my mistakes during development. |
10 | * |
11 | * see Documentation/driver-api/media/drivers/dvb-usb.rst for more information |
12 | */ |
13 | #include "dibusb.h" |
14 | |
15 | static int debug; |
16 | module_param(debug, int, 0644); |
17 | MODULE_PARM_DESC(debug, "set debugging level (rc=1 (or-able))." DVB_USB_DEBUG_STATUS); |
18 | |
19 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); |
20 | |
21 | #define deb_rc(args...) dprintk(debug,0x01,args) |
22 | |
23 | static int a800_power_ctrl(struct dvb_usb_device *d, int onoff) |
24 | { |
25 | /* do nothing for the AVerMedia */ |
26 | return 0; |
27 | } |
28 | |
29 | /* assure to put cold to 0 for iManufacturer == 1 */ |
30 | static int a800_identify_state(struct usb_device *udev, |
31 | const struct dvb_usb_device_properties *props, |
32 | const struct dvb_usb_device_description **desc, |
33 | int *cold) |
34 | { |
35 | *cold = udev->descriptor.iManufacturer != 1; |
36 | return 0; |
37 | } |
38 | |
39 | static int a800_rc_query(struct dvb_usb_device *d) |
40 | { |
41 | int ret = 0; |
42 | u8 *key = kmalloc(size: 5, GFP_KERNEL); |
43 | if (!key) |
44 | return -ENOMEM; |
45 | |
46 | if (usb_control_msg(dev: d->udev,usb_rcvctrlpipe(d->udev,0), |
47 | request: 0x04, USB_TYPE_VENDOR | USB_DIR_IN, value: 0, index: 0, data: key, size: 5, |
48 | timeout: 2000) != 5) { |
49 | ret = -ENODEV; |
50 | goto out; |
51 | } |
52 | |
53 | /* Note that extended nec and nec32 are dropped */ |
54 | if (key[0] == 1) |
55 | rc_keydown(dev: d->rc_dev, protocol: RC_PROTO_NEC, |
56 | RC_SCANCODE_NEC(key[1], key[3]), toggle: 0); |
57 | else if (key[0] == 2) |
58 | rc_repeat(dev: d->rc_dev); |
59 | out: |
60 | kfree(objp: key); |
61 | return ret; |
62 | } |
63 | |
64 | /* USB Driver stuff */ |
65 | static struct dvb_usb_device_properties a800_properties; |
66 | |
67 | static int a800_probe(struct usb_interface *intf, |
68 | const struct usb_device_id *id) |
69 | { |
70 | return dvb_usb_device_init(intf, &a800_properties, |
71 | THIS_MODULE, NULL, adapter_nums: adapter_nr); |
72 | } |
73 | |
74 | /* do not change the order of the ID table */ |
75 | enum { |
76 | AVERMEDIA_DVBT_USB2_COLD, |
77 | AVERMEDIA_DVBT_USB2_WARM, |
78 | }; |
79 | |
80 | static struct usb_device_id a800_table[] = { |
81 | DVB_USB_DEV(AVERMEDIA, AVERMEDIA_DVBT_USB2_COLD), |
82 | DVB_USB_DEV(AVERMEDIA, AVERMEDIA_DVBT_USB2_WARM), |
83 | { } |
84 | }; |
85 | |
86 | MODULE_DEVICE_TABLE (usb, a800_table); |
87 | |
88 | static struct dvb_usb_device_properties a800_properties = { |
89 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, |
90 | |
91 | .usb_ctrl = CYPRESS_FX2, |
92 | .firmware = "dvb-usb-avertv-a800-02.fw" , |
93 | |
94 | .num_adapters = 1, |
95 | .adapter = { |
96 | { |
97 | .num_frontends = 1, |
98 | .fe = {{ |
99 | .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, |
100 | .pid_filter_count = 32, |
101 | .streaming_ctrl = dibusb2_0_streaming_ctrl, |
102 | .pid_filter = dibusb_pid_filter, |
103 | .pid_filter_ctrl = dibusb_pid_filter_ctrl, |
104 | |
105 | .frontend_attach = dibusb_dib3000mc_frontend_attach, |
106 | .tuner_attach = dibusb_dib3000mc_tuner_attach, |
107 | |
108 | /* parameter for the MPEG2-data transfer */ |
109 | .stream = { |
110 | .type = USB_BULK, |
111 | .count = 7, |
112 | .endpoint = 0x06, |
113 | .u = { |
114 | .bulk = { |
115 | .buffersize = 4096, |
116 | } |
117 | } |
118 | }, |
119 | }}, |
120 | .size_of_priv = sizeof(struct dibusb_state), |
121 | }, |
122 | }, |
123 | |
124 | .power_ctrl = a800_power_ctrl, |
125 | .identify_state = a800_identify_state, |
126 | |
127 | .rc.core = { |
128 | .rc_interval = DEFAULT_RC_INTERVAL, |
129 | .rc_codes = RC_MAP_AVERMEDIA_M135A, |
130 | .module_name = KBUILD_MODNAME, |
131 | .rc_query = a800_rc_query, |
132 | .allowed_protos = RC_PROTO_BIT_NEC, |
133 | }, |
134 | |
135 | .i2c_algo = &dibusb_i2c_algo, |
136 | |
137 | .generic_bulk_ctrl_endpoint = 0x01, |
138 | .num_device_descs = 1, |
139 | .devices = { |
140 | { "AVerMedia AverTV DVB-T USB 2.0 (A800)" , |
141 | { &a800_table[AVERMEDIA_DVBT_USB2_COLD], NULL }, |
142 | { &a800_table[AVERMEDIA_DVBT_USB2_WARM], NULL }, |
143 | }, |
144 | } |
145 | }; |
146 | |
147 | static struct usb_driver a800_driver = { |
148 | .name = "dvb_usb_a800" , |
149 | .probe = a800_probe, |
150 | .disconnect = dvb_usb_device_exit, |
151 | .id_table = a800_table, |
152 | }; |
153 | |
154 | module_usb_driver(a800_driver); |
155 | |
156 | MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>" ); |
157 | MODULE_DESCRIPTION("AVerMedia AverTV DVB-T USB 2.0 (A800)" ); |
158 | MODULE_VERSION("1.0" ); |
159 | MODULE_LICENSE("GPL" ); |
160 | |