Commit | Line | Data |
---|---|---|
5decdd27 AP |
1 | /* DVB USB compliant linux driver for Sigmatek DVB-110 DVB-T USB2.0 receiver |
2 | * | |
4c7e3ea9 | 3 | * Copyright (C) 2006 Antti Palosaari <crope@iki.fi> |
5decdd27 AP |
4 | * |
5 | * This program is free software; you can redistribute it and/or modify it | |
6 | * under the terms of the GNU General Public License as published by the Free | |
7 | * Software Foundation, version 2. | |
8 | * | |
9 | * see Documentation/dvb/README.dvb-usb for more information | |
10 | */ | |
11 | ||
12 | #include "au6610.h" | |
13 | ||
14 | #include "zl10353.h" | |
15 | #include "qt1010.h" | |
16 | ||
17 | /* debug */ | |
18 | static int dvb_usb_au6610_debug; | |
19 | module_param_named(debug, dvb_usb_au6610_debug, int, 0644); | |
20 | MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); | |
21 | ||
78e92006 JG |
22 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); |
23 | ||
5decdd27 AP |
24 | static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr, |
25 | u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) | |
26 | { | |
27 | int ret; | |
28 | u16 index; | |
38d0629f MK |
29 | u8 usb_buf[6]; /* enough for all known requests, |
30 | read returns 5 and write 6 bytes */ | |
5decdd27 AP |
31 | switch (wlen) { |
32 | case 1: | |
33 | index = wbuf[0] << 8; | |
34 | break; | |
35 | case 2: | |
36 | index = wbuf[0] << 8; | |
37 | index += wbuf[1]; | |
38 | break; | |
39 | default: | |
40 | warn("wlen = %x, aborting.", wlen); | |
41 | return -EINVAL; | |
42 | } | |
43 | ||
44 | ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), operation, | |
26a154c3 | 45 | USB_TYPE_VENDOR|USB_DIR_IN, addr << 1, index, usb_buf, |
5decdd27 AP |
46 | sizeof(usb_buf), AU6610_USB_TIMEOUT); |
47 | ||
48 | if (ret < 0) | |
49 | return ret; | |
50 | ||
51 | switch (operation) { | |
52 | case AU6610_REQ_I2C_READ: | |
53 | case AU6610_REQ_USB_READ: | |
54 | /* requested value is always 5th byte in buffer */ | |
55 | rbuf[0] = usb_buf[4]; | |
56 | } | |
57 | ||
58 | return ret; | |
59 | } | |
60 | ||
38d0629f MK |
61 | static int au6610_i2c_msg(struct dvb_usb_device *d, u8 addr, |
62 | u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) | |
5decdd27 AP |
63 | { |
64 | u8 request; | |
65 | u8 wo = (rbuf == NULL || rlen == 0); /* write-only */ | |
66 | ||
67 | if (wo) { | |
68 | request = AU6610_REQ_I2C_WRITE; | |
69 | } else { /* rw */ | |
70 | request = AU6610_REQ_I2C_READ; | |
71 | } | |
72 | ||
73 | return au6610_usb_msg(d, request, addr, wbuf, wlen, rbuf, rlen); | |
74 | } | |
75 | ||
76 | ||
77 | /* I2C */ | |
38d0629f MK |
78 | static int au6610_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], |
79 | int num) | |
5decdd27 AP |
80 | { |
81 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | |
82 | int i; | |
83 | ||
5decdd27 AP |
84 | if (num > 2) |
85 | return -EINVAL; | |
86 | ||
c80296d7 RK |
87 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) |
88 | return -EAGAIN; | |
89 | ||
5decdd27 AP |
90 | for (i = 0; i < num; i++) { |
91 | /* write/read request */ | |
92 | if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { | |
93 | if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf, | |
38d0629f MK |
94 | msg[i].len, msg[i+1].buf, |
95 | msg[i+1].len) < 0) | |
5decdd27 AP |
96 | break; |
97 | i++; | |
98 | } else if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf, | |
99 | msg[i].len, NULL, 0) < 0) | |
100 | break; | |
101 | } | |
102 | ||
103 | mutex_unlock(&d->i2c_mutex); | |
104 | return i; | |
105 | } | |
106 | ||
107 | ||
108 | static u32 au6610_i2c_func(struct i2c_adapter *adapter) | |
109 | { | |
110 | return I2C_FUNC_I2C; | |
111 | } | |
112 | ||
113 | static struct i2c_algorithm au6610_i2c_algo = { | |
114 | .master_xfer = au6610_i2c_xfer, | |
115 | .functionality = au6610_i2c_func, | |
116 | }; | |
117 | ||
118 | /* Callbacks for DVB USB */ | |
119 | static int au6610_identify_state(struct usb_device *udev, | |
120 | struct dvb_usb_device_properties *props, | |
121 | struct dvb_usb_device_description **desc, | |
122 | int *cold) | |
123 | { | |
124 | *cold = 0; | |
125 | return 0; | |
126 | } | |
127 | ||
128 | static struct zl10353_config au6610_zl10353_config = { | |
26a154c3 | 129 | .demod_address = 0x0f, |
5decdd27 AP |
130 | .no_tuner = 1, |
131 | .parallel_ts = 1, | |
132 | }; | |
133 | ||
5decdd27 AP |
134 | static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap) |
135 | { | |
136 | if ((adap->fe = dvb_attach(zl10353_attach, &au6610_zl10353_config, | |
137 | &adap->dev->i2c_adap)) != NULL) { | |
138 | return 0; | |
139 | } | |
140 | ||
141 | return -EIO; | |
142 | } | |
143 | ||
4c7e3ea9 | 144 | static struct qt1010_config au6610_qt1010_config = { |
26a154c3 | 145 | .i2c_address = 0x62 |
4c7e3ea9 AP |
146 | }; |
147 | ||
148 | static int au6610_qt1010_tuner_attach(struct dvb_usb_adapter *adap) | |
149 | { | |
4c7e3ea9 AP |
150 | return dvb_attach(qt1010_attach, |
151 | adap->fe, &adap->dev->i2c_adap, | |
152 | &au6610_qt1010_config) == NULL ? -ENODEV : 0; | |
153 | } | |
154 | ||
5decdd27 AP |
155 | /* DVB USB Driver stuff */ |
156 | static struct dvb_usb_device_properties au6610_properties; | |
157 | ||
38d0629f MK |
158 | static int au6610_probe(struct usb_interface *intf, |
159 | const struct usb_device_id *id) | |
5decdd27 AP |
160 | { |
161 | struct dvb_usb_device *d; | |
162 | struct usb_host_interface *alt; | |
163 | int ret; | |
164 | ||
165 | if (intf->num_altsetting < AU6610_ALTSETTING_COUNT) | |
166 | return -ENODEV; | |
167 | ||
78e92006 JG |
168 | ret = dvb_usb_device_init(intf, &au6610_properties, THIS_MODULE, &d, |
169 | adapter_nr); | |
170 | if (ret == 0) { | |
5decdd27 AP |
171 | alt = usb_altnum_to_altsetting(intf, AU6610_ALTSETTING); |
172 | ||
173 | if (alt == NULL) { | |
174 | deb_rc("no alt found!\n"); | |
175 | return -ENODEV; | |
176 | } | |
177 | ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber, | |
178 | alt->desc.bAlternateSetting); | |
179 | } | |
180 | ||
181 | return ret; | |
182 | } | |
183 | ||
184 | ||
185 | static struct usb_device_id au6610_table [] = { | |
186 | { USB_DEVICE(USB_VID_ALCOR_MICRO, USB_PID_SIGMATEK_DVB_110) }, | |
187 | { } /* Terminating entry */ | |
188 | }; | |
189 | MODULE_DEVICE_TABLE (usb, au6610_table); | |
190 | ||
191 | static struct dvb_usb_device_properties au6610_properties = { | |
192 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, | |
193 | .usb_ctrl = DEVICE_SPECIFIC, | |
194 | .size_of_priv = 0, | |
195 | .identify_state = au6610_identify_state, | |
196 | .num_adapters = 1, | |
197 | .adapter = { | |
198 | { | |
199 | .frontend_attach = au6610_zl10353_frontend_attach, | |
4c7e3ea9 | 200 | .tuner_attach = au6610_qt1010_tuner_attach, |
5decdd27 AP |
201 | |
202 | .stream = { | |
203 | .type = USB_ISOC, | |
204 | .count = 5, | |
205 | .endpoint = 0x82, | |
206 | .u = { | |
207 | .isoc = { | |
208 | .framesperurb = 40, | |
209 | .framesize = 942, /* maximum packet size */ | |
210 | .interval = 1.25, /* 125 us */ | |
211 | } | |
212 | } | |
213 | }, | |
214 | } | |
215 | }, | |
216 | .i2c_algo = &au6610_i2c_algo, | |
217 | .num_device_descs = 1, | |
218 | .devices = { | |
219 | { | |
220 | "Sigmatek DVB-110 DVB-T USB2.0", | |
221 | { &au6610_table[0], NULL }, | |
222 | { NULL }, | |
223 | }, | |
224 | } | |
225 | }; | |
226 | ||
227 | static struct usb_driver au6610_driver = { | |
228 | .name = "dvb_usb_au6610", | |
229 | .probe = au6610_probe, | |
230 | .disconnect = dvb_usb_device_exit, | |
231 | .id_table = au6610_table, | |
232 | }; | |
233 | ||
234 | /* module stuff */ | |
235 | static int __init au6610_module_init(void) | |
236 | { | |
237 | int ret; | |
238 | ||
239 | if ((ret = usb_register(&au6610_driver))) { | |
240 | err("usb_register failed. Error number %d", ret); | |
241 | return ret; | |
242 | } | |
243 | ||
244 | return 0; | |
245 | } | |
246 | ||
247 | static void __exit au6610_module_exit(void) | |
248 | { | |
249 | /* deregister this driver from the USB subsystem */ | |
250 | usb_deregister(&au6610_driver); | |
251 | } | |
252 | ||
253 | module_init (au6610_module_init); | |
254 | module_exit (au6610_module_exit); | |
255 | ||
256 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | |
257 | MODULE_DESCRIPTION("Driver Sigmatek DVB-110 DVB-T USB2.0 / AU6610"); | |
258 | MODULE_VERSION("0.1"); | |
259 | MODULE_LICENSE("GPL"); |