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