diff options
Diffstat (limited to 'drivers/media/dvb/dvb-usb/dw2102.c')
-rw-r--r-- | drivers/media/dvb/dvb-usb/dw2102.c | 572 |
1 files changed, 482 insertions, 90 deletions
diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index a4d898b44e55..ca53df61caa8 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c | |||
@@ -1,4 +1,5 @@ | |||
1 | /* DVB USB framework compliant Linux driver for the DVBWorld DVB-S 2102 Card | 1 | /* DVB USB framework compliant Linux driver for the |
2 | * DVBWorld DVB-S 2101, 2102, DVB-S2 2104 Card | ||
2 | * | 3 | * |
3 | * Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by) | 4 | * Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by) |
4 | * | 5 | * |
@@ -10,62 +11,74 @@ | |||
10 | */ | 11 | */ |
11 | #include <linux/version.h> | 12 | #include <linux/version.h> |
12 | #include "dw2102.h" | 13 | #include "dw2102.h" |
14 | #include "si21xx.h" | ||
13 | #include "stv0299.h" | 15 | #include "stv0299.h" |
14 | #include "z0194a.h" | 16 | #include "z0194a.h" |
17 | #include "stv0288.h" | ||
18 | #include "stb6000.h" | ||
19 | #include "eds1547.h" | ||
20 | #include "cx24116.h" | ||
15 | 21 | ||
16 | #ifndef USB_PID_DW2102 | 22 | #ifndef USB_PID_DW2102 |
17 | #define USB_PID_DW2102 0x2102 | 23 | #define USB_PID_DW2102 0x2102 |
18 | #endif | 24 | #endif |
19 | 25 | ||
20 | #define DW2102_READ_MSG 0 | 26 | #ifndef USB_PID_DW2104 |
21 | #define DW2102_WRITE_MSG 1 | 27 | #define USB_PID_DW2104 0x2104 |
28 | #endif | ||
29 | |||
30 | #define DW210X_READ_MSG 0 | ||
31 | #define DW210X_WRITE_MSG 1 | ||
22 | 32 | ||
23 | #define REG_1F_SYMBOLRATE_BYTE0 0x1f | 33 | #define REG_1F_SYMBOLRATE_BYTE0 0x1f |
24 | #define REG_20_SYMBOLRATE_BYTE1 0x20 | 34 | #define REG_20_SYMBOLRATE_BYTE1 0x20 |
25 | #define REG_21_SYMBOLRATE_BYTE2 0x21 | 35 | #define REG_21_SYMBOLRATE_BYTE2 0x21 |
26 | 36 | /* on my own*/ | |
27 | #define DW2102_VOLTAGE_CTRL (0x1800) | 37 | #define DW2102_VOLTAGE_CTRL (0x1800) |
28 | #define DW2102_RC_QUERY (0x1a00) | 38 | #define DW2102_RC_QUERY (0x1a00) |
29 | 39 | ||
30 | struct dw2102_state { | 40 | struct dw210x_state { |
31 | u32 last_key_pressed; | 41 | u32 last_key_pressed; |
32 | }; | 42 | }; |
33 | struct dw2102_rc_keys { | 43 | struct dw210x_rc_keys { |
34 | u32 keycode; | 44 | u32 keycode; |
35 | u32 event; | 45 | u32 event; |
36 | }; | 46 | }; |
37 | 47 | ||
48 | /* debug */ | ||
49 | static int dvb_usb_dw2102_debug; | ||
50 | module_param_named(debug, dvb_usb_dw2102_debug, int, 0644); | ||
51 | MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer (or-able))." DVB_USB_DEBUG_STATUS); | ||
52 | |||
38 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | 53 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); |
39 | 54 | ||
40 | static int dw2102_op_rw(struct usb_device *dev, u8 request, u16 value, | 55 | static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value, |
41 | u8 *data, u16 len, int flags) | 56 | u16 index, u8 * data, u16 len, int flags) |
42 | { | 57 | { |
43 | int ret; | 58 | int ret; |
44 | u8 u8buf[len]; | 59 | u8 u8buf[len]; |
45 | 60 | ||
46 | unsigned int pipe = (flags == DW2102_READ_MSG) ? | 61 | unsigned int pipe = (flags == DW210X_READ_MSG) ? |
47 | usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0); | 62 | usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0); |
48 | u8 request_type = (flags == DW2102_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT; | 63 | u8 request_type = (flags == DW210X_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT; |
49 | 64 | ||
50 | if (flags == DW2102_WRITE_MSG) | 65 | if (flags == DW210X_WRITE_MSG) |
51 | memcpy(u8buf, data, len); | 66 | memcpy(u8buf, data, len); |
52 | ret = usb_control_msg(dev, pipe, request, | 67 | ret = usb_control_msg(dev, pipe, request, request_type | USB_TYPE_VENDOR, |
53 | request_type | USB_TYPE_VENDOR, value, 0 , u8buf, len, 2000); | 68 | value, index , u8buf, len, 2000); |
54 | 69 | ||
55 | if (flags == DW2102_READ_MSG) | 70 | if (flags == DW210X_READ_MSG) |
56 | memcpy(data, u8buf, len); | 71 | memcpy(data, u8buf, len); |
57 | return ret; | 72 | return ret; |
58 | } | 73 | } |
59 | 74 | ||
60 | /* I2C */ | 75 | /* I2C */ |
61 | |||
62 | static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], | 76 | static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], |
63 | int num) | 77 | int num) |
64 | { | 78 | { |
65 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | 79 | struct dvb_usb_device *d = i2c_get_adapdata(adap); |
66 | int i = 0, ret = 0; | 80 | int i = 0, ret = 0; |
67 | u8 buf6[] = {0x2c, 0x05, 0xc0, 0, 0, 0, 0}; | 81 | u8 buf6[] = {0x2c, 0x05, 0xc0, 0, 0, 0, 0}; |
68 | u8 request; | ||
69 | u16 value; | 82 | u16 value; |
70 | 83 | ||
71 | if (!d) | 84 | if (!d) |
@@ -76,14 +89,12 @@ struct dvb_usb_device *d = i2c_get_adapdata(adap); | |||
76 | switch (num) { | 89 | switch (num) { |
77 | case 2: | 90 | case 2: |
78 | /* read stv0299 register */ | 91 | /* read stv0299 register */ |
79 | request = 0xb5; | ||
80 | value = msg[0].buf[0];/* register */ | 92 | value = msg[0].buf[0];/* register */ |
81 | for (i = 0; i < msg[1].len; i++) { | 93 | for (i = 0; i < msg[1].len; i++) { |
82 | value = value + i; | 94 | value = value + i; |
83 | ret = dw2102_op_rw(d->udev, 0xb5, | 95 | ret = dw210x_op_rw(d->udev, 0xb5, value, 0, |
84 | value, buf6, 2, DW2102_READ_MSG); | 96 | buf6, 2, DW210X_READ_MSG); |
85 | msg[1].buf[i] = buf6[0]; | 97 | msg[1].buf[i] = buf6[0]; |
86 | |||
87 | } | 98 | } |
88 | break; | 99 | break; |
89 | case 1: | 100 | case 1: |
@@ -93,8 +104,8 @@ struct dvb_usb_device *d = i2c_get_adapdata(adap); | |||
93 | buf6[0] = 0x2a; | 104 | buf6[0] = 0x2a; |
94 | buf6[1] = msg[0].buf[0]; | 105 | buf6[1] = msg[0].buf[0]; |
95 | buf6[2] = msg[0].buf[1]; | 106 | buf6[2] = msg[0].buf[1]; |
96 | ret = dw2102_op_rw(d->udev, 0xb2, | 107 | ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, |
97 | 0, buf6, 3, DW2102_WRITE_MSG); | 108 | buf6, 3, DW210X_WRITE_MSG); |
98 | break; | 109 | break; |
99 | case 0x60: | 110 | case 0x60: |
100 | if (msg[0].flags == 0) { | 111 | if (msg[0].flags == 0) { |
@@ -106,26 +117,26 @@ struct dvb_usb_device *d = i2c_get_adapdata(adap); | |||
106 | buf6[4] = msg[0].buf[1]; | 117 | buf6[4] = msg[0].buf[1]; |
107 | buf6[5] = msg[0].buf[2]; | 118 | buf6[5] = msg[0].buf[2]; |
108 | buf6[6] = msg[0].buf[3]; | 119 | buf6[6] = msg[0].buf[3]; |
109 | ret = dw2102_op_rw(d->udev, 0xb2, | 120 | ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, |
110 | 0, buf6, 7, DW2102_WRITE_MSG); | 121 | buf6, 7, DW210X_WRITE_MSG); |
111 | } else { | 122 | } else { |
112 | /* write to tuner pll */ | 123 | /* read from tuner */ |
113 | ret = dw2102_op_rw(d->udev, 0xb5, | 124 | ret = dw210x_op_rw(d->udev, 0xb5, 0, 0, |
114 | 0, buf6, 1, DW2102_READ_MSG); | 125 | buf6, 1, DW210X_READ_MSG); |
115 | msg[0].buf[0] = buf6[0]; | 126 | msg[0].buf[0] = buf6[0]; |
116 | } | 127 | } |
117 | break; | 128 | break; |
118 | case (DW2102_RC_QUERY): | 129 | case (DW2102_RC_QUERY): |
119 | ret = dw2102_op_rw(d->udev, 0xb8, | 130 | ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, |
120 | 0, buf6, 2, DW2102_READ_MSG); | 131 | buf6, 2, DW210X_READ_MSG); |
121 | msg[0].buf[0] = buf6[0]; | 132 | msg[0].buf[0] = buf6[0]; |
122 | msg[0].buf[1] = buf6[1]; | 133 | msg[0].buf[1] = buf6[1]; |
123 | break; | 134 | break; |
124 | case (DW2102_VOLTAGE_CTRL): | 135 | case (DW2102_VOLTAGE_CTRL): |
125 | buf6[0] = 0x30; | 136 | buf6[0] = 0x30; |
126 | buf6[1] = msg[0].buf[0]; | 137 | buf6[1] = msg[0].buf[0]; |
127 | ret = dw2102_op_rw(d->udev, 0xb2, | 138 | ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, |
128 | 0, buf6, 2, DW2102_WRITE_MSG); | 139 | buf6, 2, DW210X_WRITE_MSG); |
129 | break; | 140 | break; |
130 | } | 141 | } |
131 | 142 | ||
@@ -136,17 +147,265 @@ struct dvb_usb_device *d = i2c_get_adapdata(adap); | |||
136 | return num; | 147 | return num; |
137 | } | 148 | } |
138 | 149 | ||
139 | static u32 dw2102_i2c_func(struct i2c_adapter *adapter) | 150 | static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap, |
151 | struct i2c_msg msg[], int num) | ||
152 | { | ||
153 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | ||
154 | int ret = 0; | ||
155 | u8 buf6[] = {0, 0, 0, 0, 0, 0, 0}; | ||
156 | |||
157 | if (!d) | ||
158 | return -ENODEV; | ||
159 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) | ||
160 | return -EAGAIN; | ||
161 | |||
162 | switch (num) { | ||
163 | case 2: | ||
164 | /* read si2109 register by number */ | ||
165 | buf6[0] = 0xd0; | ||
166 | buf6[1] = msg[0].len; | ||
167 | buf6[2] = msg[0].buf[0]; | ||
168 | ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, | ||
169 | buf6, msg[0].len + 2, DW210X_WRITE_MSG); | ||
170 | /* read si2109 register */ | ||
171 | ret = dw210x_op_rw(d->udev, 0xc3, 0xd0, 0, | ||
172 | buf6, msg[1].len + 2, DW210X_READ_MSG); | ||
173 | memcpy(msg[1].buf, buf6 + 2, msg[1].len); | ||
174 | |||
175 | break; | ||
176 | case 1: | ||
177 | switch (msg[0].addr) { | ||
178 | case 0x68: | ||
179 | /* write to si2109 register */ | ||
180 | buf6[0] = 0xd0; | ||
181 | buf6[1] = msg[0].len; | ||
182 | memcpy(buf6 + 2, msg[0].buf, msg[0].len); | ||
183 | ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, buf6, | ||
184 | msg[0].len + 2, DW210X_WRITE_MSG); | ||
185 | break; | ||
186 | case(DW2102_RC_QUERY): | ||
187 | ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, | ||
188 | buf6, 2, DW210X_READ_MSG); | ||
189 | msg[0].buf[0] = buf6[0]; | ||
190 | msg[0].buf[1] = buf6[1]; | ||
191 | break; | ||
192 | case(DW2102_VOLTAGE_CTRL): | ||
193 | buf6[0] = 0x30; | ||
194 | buf6[1] = msg[0].buf[0]; | ||
195 | ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, | ||
196 | buf6, 2, DW210X_WRITE_MSG); | ||
197 | break; | ||
198 | } | ||
199 | break; | ||
200 | } | ||
201 | |||
202 | mutex_unlock(&d->i2c_mutex); | ||
203 | return num; | ||
204 | } | ||
205 | static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) | ||
206 | { | ||
207 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | ||
208 | int ret = 0; | ||
209 | |||
210 | if (!d) | ||
211 | return -ENODEV; | ||
212 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) | ||
213 | return -EAGAIN; | ||
214 | |||
215 | switch (num) { | ||
216 | case 2: { | ||
217 | /* read */ | ||
218 | /* first write first register number */ | ||
219 | u8 ibuf [msg[1].len + 2], obuf[3]; | ||
220 | obuf[0] = 0xd0; | ||
221 | obuf[1] = msg[0].len; | ||
222 | obuf[2] = msg[0].buf[0]; | ||
223 | ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, | ||
224 | obuf, msg[0].len + 2, DW210X_WRITE_MSG); | ||
225 | /* second read registers */ | ||
226 | ret = dw210x_op_rw(d->udev, 0xc3, 0xd1 , 0, | ||
227 | ibuf, msg[1].len + 2, DW210X_READ_MSG); | ||
228 | memcpy(msg[1].buf, ibuf + 2, msg[1].len); | ||
229 | |||
230 | break; | ||
231 | } | ||
232 | case 1: | ||
233 | switch (msg[0].addr) { | ||
234 | case 0x68: { | ||
235 | /* write to register */ | ||
236 | u8 obuf[msg[0].len + 2]; | ||
237 | obuf[0] = 0xd0; | ||
238 | obuf[1] = msg[0].len; | ||
239 | memcpy(obuf + 2, msg[0].buf, msg[0].len); | ||
240 | ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, | ||
241 | obuf, msg[0].len + 2, DW210X_WRITE_MSG); | ||
242 | break; | ||
243 | } | ||
244 | case 0x61: { | ||
245 | /* write to tuner */ | ||
246 | u8 obuf[msg[0].len + 2]; | ||
247 | obuf[0] = 0xc2; | ||
248 | obuf[1] = msg[0].len; | ||
249 | memcpy(obuf + 2, msg[0].buf, msg[0].len); | ||
250 | ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, | ||
251 | obuf, msg[0].len + 2, DW210X_WRITE_MSG); | ||
252 | break; | ||
253 | } | ||
254 | case(DW2102_RC_QUERY): { | ||
255 | u8 ibuf[2]; | ||
256 | ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, | ||
257 | ibuf, 2, DW210X_READ_MSG); | ||
258 | memcpy(msg[0].buf, ibuf , 2); | ||
259 | break; | ||
260 | } | ||
261 | case(DW2102_VOLTAGE_CTRL): { | ||
262 | u8 obuf[2]; | ||
263 | obuf[0] = 0x30; | ||
264 | obuf[1] = msg[0].buf[0]; | ||
265 | ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, | ||
266 | obuf, 2, DW210X_WRITE_MSG); | ||
267 | break; | ||
268 | } | ||
269 | } | ||
270 | |||
271 | break; | ||
272 | } | ||
273 | |||
274 | mutex_unlock(&d->i2c_mutex); | ||
275 | return num; | ||
276 | } | ||
277 | |||
278 | static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) | ||
279 | { | ||
280 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | ||
281 | int ret = 0; | ||
282 | int len, i; | ||
283 | |||
284 | if (!d) | ||
285 | return -ENODEV; | ||
286 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) | ||
287 | return -EAGAIN; | ||
288 | |||
289 | switch (num) { | ||
290 | case 2: { | ||
291 | /* read */ | ||
292 | /* first write first register number */ | ||
293 | u8 ibuf [msg[1].len + 2], obuf[3]; | ||
294 | obuf[0] = 0xaa; | ||
295 | obuf[1] = msg[0].len; | ||
296 | obuf[2] = msg[0].buf[0]; | ||
297 | ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, | ||
298 | obuf, msg[0].len + 2, DW210X_WRITE_MSG); | ||
299 | /* second read registers */ | ||
300 | ret = dw210x_op_rw(d->udev, 0xc3, 0xab , 0, | ||
301 | ibuf, msg[1].len + 2, DW210X_READ_MSG); | ||
302 | memcpy(msg[1].buf, ibuf + 2, msg[1].len); | ||
303 | |||
304 | break; | ||
305 | } | ||
306 | case 1: | ||
307 | switch (msg[0].addr) { | ||
308 | case 0x55: { | ||
309 | if (msg[0].buf[0] == 0xf7) { | ||
310 | /* firmware */ | ||
311 | /* Write in small blocks */ | ||
312 | u8 obuf[19]; | ||
313 | obuf[0] = 0xaa; | ||
314 | obuf[1] = 0x11; | ||
315 | obuf[2] = 0xf7; | ||
316 | len = msg[0].len - 1; | ||
317 | i = 1; | ||
318 | do { | ||
319 | memcpy(obuf + 3, msg[0].buf + i, (len > 16 ? 16 : len)); | ||
320 | ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, | ||
321 | obuf, (len > 16 ? 16 : len) + 3, DW210X_WRITE_MSG); | ||
322 | i += 16; | ||
323 | len -= 16; | ||
324 | } while (len > 0); | ||
325 | } else { | ||
326 | /* write to register */ | ||
327 | u8 obuf[msg[0].len + 2]; | ||
328 | obuf[0] = 0xaa; | ||
329 | obuf[1] = msg[0].len; | ||
330 | memcpy(obuf + 2, msg[0].buf, msg[0].len); | ||
331 | ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, | ||
332 | obuf, msg[0].len + 2, DW210X_WRITE_MSG); | ||
333 | } | ||
334 | break; | ||
335 | } | ||
336 | case(DW2102_RC_QUERY): { | ||
337 | u8 ibuf[2]; | ||
338 | ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, | ||
339 | ibuf, 2, DW210X_READ_MSG); | ||
340 | memcpy(msg[0].buf, ibuf , 2); | ||
341 | break; | ||
342 | } | ||
343 | case(DW2102_VOLTAGE_CTRL): { | ||
344 | u8 obuf[2]; | ||
345 | obuf[0] = 0x30; | ||
346 | obuf[1] = msg[0].buf[0]; | ||
347 | ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, | ||
348 | obuf, 2, DW210X_WRITE_MSG); | ||
349 | break; | ||
350 | } | ||
351 | } | ||
352 | |||
353 | break; | ||
354 | } | ||
355 | |||
356 | mutex_unlock(&d->i2c_mutex); | ||
357 | return num; | ||
358 | } | ||
359 | |||
360 | static u32 dw210x_i2c_func(struct i2c_adapter *adapter) | ||
140 | { | 361 | { |
141 | return I2C_FUNC_I2C; | 362 | return I2C_FUNC_I2C; |
142 | } | 363 | } |
143 | 364 | ||
144 | static struct i2c_algorithm dw2102_i2c_algo = { | 365 | static struct i2c_algorithm dw2102_i2c_algo = { |
145 | .master_xfer = dw2102_i2c_transfer, | 366 | .master_xfer = dw2102_i2c_transfer, |
146 | .functionality = dw2102_i2c_func, | 367 | .functionality = dw210x_i2c_func, |
368 | }; | ||
369 | |||
370 | static struct i2c_algorithm dw2102_serit_i2c_algo = { | ||
371 | .master_xfer = dw2102_serit_i2c_transfer, | ||
372 | .functionality = dw210x_i2c_func, | ||
373 | }; | ||
374 | |||
375 | static struct i2c_algorithm dw2102_earda_i2c_algo = { | ||
376 | .master_xfer = dw2102_earda_i2c_transfer, | ||
377 | .functionality = dw210x_i2c_func, | ||
378 | }; | ||
379 | |||
380 | static struct i2c_algorithm dw2104_i2c_algo = { | ||
381 | .master_xfer = dw2104_i2c_transfer, | ||
382 | .functionality = dw210x_i2c_func, | ||
147 | }; | 383 | }; |
148 | 384 | ||
149 | static int dw2102_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) | 385 | static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) |
386 | { | ||
387 | int i; | ||
388 | u8 ibuf[] = {0, 0}; | ||
389 | u8 eeprom[256], eepromline[16]; | ||
390 | |||
391 | for (i = 0; i < 256; i++) { | ||
392 | if (dw210x_op_rw(d->udev, 0xb6, 0xa0 , i, ibuf, 2, DW210X_READ_MSG) < 0) { | ||
393 | err("read eeprom failed."); | ||
394 | return -1; | ||
395 | } else { | ||
396 | eepromline[i%16] = ibuf[0]; | ||
397 | eeprom[i] = ibuf[0]; | ||
398 | } | ||
399 | if ((i % 16) == 15) { | ||
400 | deb_xfer("%02x: ", i - 15); | ||
401 | debug_dump(eepromline, 16, deb_xfer); | ||
402 | } | ||
403 | } | ||
404 | memcpy(mac, eeprom + 8, 6); | ||
405 | return 0; | ||
406 | }; | ||
407 | |||
408 | static int dw210x_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) | ||
150 | { | 409 | { |
151 | static u8 command_13v[1] = {0x00}; | 410 | static u8 command_13v[1] = {0x00}; |
152 | static u8 command_18v[1] = {0x01}; | 411 | static u8 command_18v[1] = {0x01}; |
@@ -163,18 +422,66 @@ static int dw2102_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) | |||
163 | return 0; | 422 | return 0; |
164 | } | 423 | } |
165 | 424 | ||
166 | static int dw2102_frontend_attach(struct dvb_usb_adapter *d) | 425 | static struct cx24116_config dw2104_config = { |
426 | .demod_address = 0x55, | ||
427 | .mpg_clk_pos_pol = 0x01, | ||
428 | }; | ||
429 | |||
430 | static struct si21xx_config serit_sp1511lhb_config = { | ||
431 | .demod_address = 0x68, | ||
432 | .min_delay_ms = 100, | ||
433 | |||
434 | }; | ||
435 | |||
436 | static int dw2104_frontend_attach(struct dvb_usb_adapter *d) | ||
167 | { | 437 | { |
168 | d->fe = dvb_attach(stv0299_attach, &sharp_z0194a_config, | 438 | if ((d->fe = dvb_attach(cx24116_attach, &dw2104_config, |
169 | &d->dev->i2c_adap); | 439 | &d->dev->i2c_adap)) != NULL) { |
170 | if (d->fe != NULL) { | 440 | d->fe->ops.set_voltage = dw210x_set_voltage; |
171 | d->fe->ops.set_voltage = dw2102_set_voltage; | 441 | info("Attached cx24116!\n"); |
172 | info("Attached stv0299!\n"); | ||
173 | return 0; | 442 | return 0; |
174 | } | 443 | } |
175 | return -EIO; | 444 | return -EIO; |
176 | } | 445 | } |
177 | 446 | ||
447 | static struct dvb_usb_device_properties dw2102_properties; | ||
448 | |||
449 | static int dw2102_frontend_attach(struct dvb_usb_adapter *d) | ||
450 | { | ||
451 | if (dw2102_properties.i2c_algo == &dw2102_serit_i2c_algo) { | ||
452 | /*dw2102_properties.adapter->tuner_attach = NULL;*/ | ||
453 | d->fe = dvb_attach(si21xx_attach, &serit_sp1511lhb_config, | ||
454 | &d->dev->i2c_adap); | ||
455 | if (d->fe != NULL) { | ||
456 | d->fe->ops.set_voltage = dw210x_set_voltage; | ||
457 | info("Attached si21xx!\n"); | ||
458 | return 0; | ||
459 | } | ||
460 | } | ||
461 | if (dw2102_properties.i2c_algo == &dw2102_earda_i2c_algo) { | ||
462 | /*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/ | ||
463 | d->fe = dvb_attach(stv0288_attach, &earda_config, | ||
464 | &d->dev->i2c_adap); | ||
465 | if (d->fe != NULL) { | ||
466 | d->fe->ops.set_voltage = dw210x_set_voltage; | ||
467 | info("Attached stv0288!\n"); | ||
468 | return 0; | ||
469 | } | ||
470 | } | ||
471 | |||
472 | if (dw2102_properties.i2c_algo == &dw2102_i2c_algo) { | ||
473 | /*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/ | ||
474 | d->fe = dvb_attach(stv0299_attach, &sharp_z0194a_config, | ||
475 | &d->dev->i2c_adap); | ||
476 | if (d->fe != NULL) { | ||
477 | d->fe->ops.set_voltage = dw210x_set_voltage; | ||
478 | info("Attached stv0299!\n"); | ||
479 | return 0; | ||
480 | } | ||
481 | } | ||
482 | return -EIO; | ||
483 | } | ||
484 | |||
178 | static int dw2102_tuner_attach(struct dvb_usb_adapter *adap) | 485 | static int dw2102_tuner_attach(struct dvb_usb_adapter *adap) |
179 | { | 486 | { |
180 | dvb_attach(dvb_pll_attach, adap->fe, 0x60, | 487 | dvb_attach(dvb_pll_attach, adap->fe, 0x60, |
@@ -182,7 +489,15 @@ static int dw2102_tuner_attach(struct dvb_usb_adapter *adap) | |||
182 | return 0; | 489 | return 0; |
183 | } | 490 | } |
184 | 491 | ||
185 | static struct dvb_usb_rc_key dw2102_rc_keys[] = { | 492 | static int dw2102_earda_tuner_attach(struct dvb_usb_adapter *adap) |
493 | { | ||
494 | dvb_attach(stb6000_attach, adap->fe, 0x61, | ||
495 | &adap->dev->i2c_adap); | ||
496 | |||
497 | return 0; | ||
498 | } | ||
499 | |||
500 | static struct dvb_usb_rc_key dw210x_rc_keys[] = { | ||
186 | { 0xf8, 0x0a, KEY_Q }, /*power*/ | 501 | { 0xf8, 0x0a, KEY_Q }, /*power*/ |
187 | { 0xf8, 0x0c, KEY_M }, /*mute*/ | 502 | { 0xf8, 0x0c, KEY_M }, /*mute*/ |
188 | { 0xf8, 0x11, KEY_1 }, | 503 | { 0xf8, 0x11, KEY_1 }, |
@@ -221,7 +536,7 @@ static struct dvb_usb_rc_key dw2102_rc_keys[] = { | |||
221 | 536 | ||
222 | static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state) | 537 | static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state) |
223 | { | 538 | { |
224 | struct dw2102_state *st = d->priv; | 539 | struct dw210x_state *st = d->priv; |
225 | u8 key[2]; | 540 | u8 key[2]; |
226 | struct i2c_msg msg[] = { | 541 | struct i2c_msg msg[] = { |
227 | {.addr = DW2102_RC_QUERY, .flags = I2C_M_RD, .buf = key, | 542 | {.addr = DW2102_RC_QUERY, .flags = I2C_M_RD, .buf = key, |
@@ -231,12 +546,12 @@ static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state) | |||
231 | 546 | ||
232 | *state = REMOTE_NO_KEY_PRESSED; | 547 | *state = REMOTE_NO_KEY_PRESSED; |
233 | if (dw2102_i2c_transfer(&d->i2c_adap, msg, 1) == 1) { | 548 | if (dw2102_i2c_transfer(&d->i2c_adap, msg, 1) == 1) { |
234 | for (i = 0; i < ARRAY_SIZE(dw2102_rc_keys); i++) { | 549 | for (i = 0; i < ARRAY_SIZE(dw210x_rc_keys); i++) { |
235 | if (dw2102_rc_keys[i].data == msg[0].buf[0]) { | 550 | if (dw210x_rc_keys[i].data == msg[0].buf[0]) { |
236 | *state = REMOTE_KEY_PRESSED; | 551 | *state = REMOTE_KEY_PRESSED; |
237 | *event = dw2102_rc_keys[i].event; | 552 | *event = dw210x_rc_keys[i].event; |
238 | st->last_key_pressed = | 553 | st->last_key_pressed = |
239 | dw2102_rc_keys[i].event; | 554 | dw210x_rc_keys[i].event; |
240 | break; | 555 | break; |
241 | } | 556 | } |
242 | st->last_key_pressed = 0; | 557 | st->last_key_pressed = 0; |
@@ -249,6 +564,8 @@ static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state) | |||
249 | static struct usb_device_id dw2102_table[] = { | 564 | static struct usb_device_id dw2102_table[] = { |
250 | {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)}, | 565 | {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)}, |
251 | {USB_DEVICE(USB_VID_CYPRESS, 0x2101)}, | 566 | {USB_DEVICE(USB_VID_CYPRESS, 0x2101)}, |
567 | {USB_DEVICE(USB_VID_CYPRESS, 0x2104)}, | ||
568 | {USB_DEVICE(0x9022, 0xd650)}, | ||
252 | { } | 569 | { } |
253 | }; | 570 | }; |
254 | 571 | ||
@@ -260,7 +577,7 @@ static int dw2102_load_firmware(struct usb_device *dev, | |||
260 | u8 *b, *p; | 577 | u8 *b, *p; |
261 | int ret = 0, i; | 578 | int ret = 0, i; |
262 | u8 reset; | 579 | u8 reset; |
263 | u8 reset16 [] = {0, 0, 0, 0, 0, 0, 0}; | 580 | u8 reset16[] = {0, 0, 0, 0, 0, 0, 0}; |
264 | const struct firmware *fw; | 581 | const struct firmware *fw; |
265 | const char *filename = "dvb-usb-dw2101.fw"; | 582 | const char *filename = "dvb-usb-dw2101.fw"; |
266 | switch (dev->descriptor.idProduct) { | 583 | switch (dev->descriptor.idProduct) { |
@@ -273,25 +590,23 @@ static int dw2102_load_firmware(struct usb_device *dev, | |||
273 | return ret; | 590 | return ret; |
274 | } | 591 | } |
275 | break; | 592 | break; |
276 | case USB_PID_DW2102: | 593 | default: |
277 | fw = frmwr; | 594 | fw = frmwr; |
278 | break; | 595 | break; |
279 | } | 596 | } |
280 | info("start downloading DW2102 firmware"); | 597 | info("start downloading DW210X firmware"); |
281 | p = kmalloc(fw->size, GFP_KERNEL); | 598 | p = kmalloc(fw->size, GFP_KERNEL); |
282 | reset = 1; | 599 | reset = 1; |
283 | /*stop the CPU*/ | 600 | /*stop the CPU*/ |
284 | dw2102_op_rw(dev, 0xa0, 0x7f92, &reset, 1, DW2102_WRITE_MSG); | 601 | dw210x_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1, DW210X_WRITE_MSG); |
285 | dw2102_op_rw(dev, 0xa0, 0xe600, &reset, 1, DW2102_WRITE_MSG); | 602 | dw210x_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1, DW210X_WRITE_MSG); |
286 | 603 | ||
287 | if (p != NULL) { | 604 | if (p != NULL) { |
288 | memcpy(p, fw->data, fw->size); | 605 | memcpy(p, fw->data, fw->size); |
289 | for (i = 0; i < fw->size; i += 0x40) { | 606 | for (i = 0; i < fw->size; i += 0x40) { |
290 | b = (u8 *) p + i; | 607 | b = (u8 *) p + i; |
291 | if (dw2102_op_rw | 608 | if (dw210x_op_rw(dev, 0xa0, i, 0, b , 0x40, |
292 | (dev, 0xa0, i, b , 0x40, | 609 | DW210X_WRITE_MSG) != 0x40) { |
293 | DW2102_WRITE_MSG) != 0x40 | ||
294 | ) { | ||
295 | err("error while transferring firmware"); | 610 | err("error while transferring firmware"); |
296 | ret = -EINVAL; | 611 | ret = -EINVAL; |
297 | break; | 612 | break; |
@@ -299,43 +614,66 @@ static int dw2102_load_firmware(struct usb_device *dev, | |||
299 | } | 614 | } |
300 | /* restart the CPU */ | 615 | /* restart the CPU */ |
301 | reset = 0; | 616 | reset = 0; |
302 | if (ret || dw2102_op_rw | 617 | if (ret || dw210x_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1, |
303 | (dev, 0xa0, 0x7f92, &reset, 1, | 618 | DW210X_WRITE_MSG) != 1) { |
304 | DW2102_WRITE_MSG) != 1) { | ||
305 | err("could not restart the USB controller CPU."); | 619 | err("could not restart the USB controller CPU."); |
306 | ret = -EINVAL; | 620 | ret = -EINVAL; |
307 | } | 621 | } |
308 | if (ret || dw2102_op_rw | 622 | if (ret || dw210x_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1, |
309 | (dev, 0xa0, 0xe600, &reset, 1, | 623 | DW210X_WRITE_MSG) != 1) { |
310 | DW2102_WRITE_MSG) != 1) { | ||
311 | err("could not restart the USB controller CPU."); | 624 | err("could not restart the USB controller CPU."); |
312 | ret = -EINVAL; | 625 | ret = -EINVAL; |
313 | } | 626 | } |
314 | /* init registers */ | 627 | /* init registers */ |
315 | switch (dev->descriptor.idProduct) { | 628 | switch (dev->descriptor.idProduct) { |
316 | case USB_PID_DW2102: | 629 | case USB_PID_DW2104: |
317 | dw2102_op_rw | 630 | case 0xd650: |
318 | (dev, 0xbf, 0x0040, &reset, 0, | 631 | reset = 1; |
319 | DW2102_WRITE_MSG); | 632 | dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1, |
320 | dw2102_op_rw | 633 | DW210X_WRITE_MSG); |
321 | (dev, 0xb9, 0x0000, &reset16[0], 2, | 634 | reset = 0; |
322 | DW2102_READ_MSG); | 635 | dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, |
636 | DW210X_WRITE_MSG); | ||
323 | break; | 637 | break; |
638 | case USB_PID_DW2102: | ||
639 | dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, | ||
640 | DW210X_WRITE_MSG); | ||
641 | dw210x_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2, | ||
642 | DW210X_READ_MSG); | ||
643 | /* check STV0299 frontend */ | ||
644 | dw210x_op_rw(dev, 0xb5, 0, 0, &reset16[0], 2, | ||
645 | DW210X_READ_MSG); | ||
646 | if (reset16[0] == 0xa1) { | ||
647 | dw2102_properties.i2c_algo = &dw2102_i2c_algo; | ||
648 | dw2102_properties.adapter->tuner_attach = &dw2102_tuner_attach; | ||
649 | break; | ||
650 | } else { | ||
651 | /* check STV0288 frontend */ | ||
652 | reset16[0] = 0xd0; | ||
653 | reset16[1] = 1; | ||
654 | reset16[2] = 0; | ||
655 | dw210x_op_rw(dev, 0xc2, 0, 0, &reset16[0], 3, | ||
656 | DW210X_WRITE_MSG); | ||
657 | dw210x_op_rw(dev, 0xc3, 0xd1, 0, &reset16[0], 3, | ||
658 | DW210X_READ_MSG); | ||
659 | if (reset16[2] == 0x11) { | ||
660 | dw2102_properties.i2c_algo = &dw2102_earda_i2c_algo; | ||
661 | dw2102_properties.adapter->tuner_attach = &dw2102_earda_tuner_attach; | ||
662 | break; | ||
663 | } | ||
664 | } | ||
324 | case 0x2101: | 665 | case 0x2101: |
325 | dw2102_op_rw | 666 | dw210x_op_rw(dev, 0xbc, 0x0030, 0, &reset16[0], 2, |
326 | (dev, 0xbc, 0x0030, &reset16[0], 2, | 667 | DW210X_READ_MSG); |
327 | DW2102_READ_MSG); | 668 | dw210x_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7, |
328 | dw2102_op_rw | 669 | DW210X_READ_MSG); |
329 | (dev, 0xba, 0x0000, &reset16[0], 7, | 670 | dw210x_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7, |
330 | DW2102_READ_MSG); | 671 | DW210X_READ_MSG); |
331 | dw2102_op_rw | 672 | dw210x_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2, |
332 | (dev, 0xba, 0x0000, &reset16[0], 7, | 673 | DW210X_READ_MSG); |
333 | DW2102_READ_MSG); | ||
334 | dw2102_op_rw | ||
335 | (dev, 0xb9, 0x0000, &reset16[0], 2, | ||
336 | DW2102_READ_MSG); | ||
337 | break; | 674 | break; |
338 | } | 675 | } |
676 | msleep(100); | ||
339 | kfree(p); | 677 | kfree(p); |
340 | } | 678 | } |
341 | return ret; | 679 | return ret; |
@@ -345,12 +683,12 @@ static struct dvb_usb_device_properties dw2102_properties = { | |||
345 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, | 683 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, |
346 | .usb_ctrl = DEVICE_SPECIFIC, | 684 | .usb_ctrl = DEVICE_SPECIFIC, |
347 | .firmware = "dvb-usb-dw2102.fw", | 685 | .firmware = "dvb-usb-dw2102.fw", |
348 | .size_of_priv = sizeof(struct dw2102_state), | 686 | .size_of_priv = sizeof(struct dw210x_state), |
349 | .no_reconnect = 1, | 687 | .no_reconnect = 1, |
350 | 688 | ||
351 | .i2c_algo = &dw2102_i2c_algo, | 689 | .i2c_algo = &dw2102_serit_i2c_algo, |
352 | .rc_key_map = dw2102_rc_keys, | 690 | .rc_key_map = dw210x_rc_keys, |
353 | .rc_key_map_size = ARRAY_SIZE(dw2102_rc_keys), | 691 | .rc_key_map_size = ARRAY_SIZE(dw210x_rc_keys), |
354 | .rc_interval = 150, | 692 | .rc_interval = 150, |
355 | .rc_query = dw2102_rc_query, | 693 | .rc_query = dw2102_rc_query, |
356 | 694 | ||
@@ -358,11 +696,12 @@ static struct dvb_usb_device_properties dw2102_properties = { | |||
358 | /* parameter for the MPEG2-data transfer */ | 696 | /* parameter for the MPEG2-data transfer */ |
359 | .num_adapters = 1, | 697 | .num_adapters = 1, |
360 | .download_firmware = dw2102_load_firmware, | 698 | .download_firmware = dw2102_load_firmware, |
361 | .adapter = { | 699 | .read_mac_address = dw210x_read_mac_address, |
700 | .adapter = { | ||
362 | { | 701 | { |
363 | .frontend_attach = dw2102_frontend_attach, | 702 | .frontend_attach = dw2102_frontend_attach, |
364 | .streaming_ctrl = NULL, | 703 | .streaming_ctrl = NULL, |
365 | .tuner_attach = dw2102_tuner_attach, | 704 | .tuner_attach = NULL, |
366 | .stream = { | 705 | .stream = { |
367 | .type = USB_BULK, | 706 | .type = USB_BULK, |
368 | .count = 8, | 707 | .count = 8, |
@@ -388,11 +727,64 @@ static struct dvb_usb_device_properties dw2102_properties = { | |||
388 | } | 727 | } |
389 | }; | 728 | }; |
390 | 729 | ||
730 | static struct dvb_usb_device_properties dw2104_properties = { | ||
731 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, | ||
732 | .usb_ctrl = DEVICE_SPECIFIC, | ||
733 | .firmware = "dvb-usb-dw2104.fw", | ||
734 | .size_of_priv = sizeof(struct dw210x_state), | ||
735 | .no_reconnect = 1, | ||
736 | |||
737 | .i2c_algo = &dw2104_i2c_algo, | ||
738 | .rc_key_map = dw210x_rc_keys, | ||
739 | .rc_key_map_size = ARRAY_SIZE(dw210x_rc_keys), | ||
740 | .rc_interval = 150, | ||
741 | .rc_query = dw2102_rc_query, | ||
742 | |||
743 | .generic_bulk_ctrl_endpoint = 0x81, | ||
744 | /* parameter for the MPEG2-data transfer */ | ||
745 | .num_adapters = 1, | ||
746 | .download_firmware = dw2102_load_firmware, | ||
747 | .read_mac_address = dw210x_read_mac_address, | ||
748 | .adapter = { | ||
749 | { | ||
750 | .frontend_attach = dw2104_frontend_attach, | ||
751 | .streaming_ctrl = NULL, | ||
752 | /*.tuner_attach = dw2104_tuner_attach,*/ | ||
753 | .stream = { | ||
754 | .type = USB_BULK, | ||
755 | .count = 8, | ||
756 | .endpoint = 0x82, | ||
757 | .u = { | ||
758 | .bulk = { | ||
759 | .buffersize = 4096, | ||
760 | } | ||
761 | } | ||
762 | }, | ||
763 | } | ||
764 | }, | ||
765 | .num_device_descs = 2, | ||
766 | .devices = { | ||
767 | { "DVBWorld DW2104 USB2.0", | ||
768 | {&dw2102_table[2], NULL}, | ||
769 | {NULL}, | ||
770 | }, | ||
771 | { "TeVii S650 USB2.0", | ||
772 | {&dw2102_table[3], NULL}, | ||
773 | {NULL}, | ||
774 | }, | ||
775 | } | ||
776 | }; | ||
777 | |||
391 | static int dw2102_probe(struct usb_interface *intf, | 778 | static int dw2102_probe(struct usb_interface *intf, |
392 | const struct usb_device_id *id) | 779 | const struct usb_device_id *id) |
393 | { | 780 | { |
394 | return dvb_usb_device_init(intf, &dw2102_properties, | 781 | if (0 == dvb_usb_device_init(intf, &dw2102_properties, |
395 | THIS_MODULE, NULL, adapter_nr); | 782 | THIS_MODULE, NULL, adapter_nr) || |
783 | 0 == dvb_usb_device_init(intf, &dw2104_properties, | ||
784 | THIS_MODULE, NULL, adapter_nr)) { | ||
785 | return 0; | ||
786 | } | ||
787 | return -ENODEV; | ||
396 | } | 788 | } |
397 | 789 | ||
398 | static struct usb_driver dw2102_driver = { | 790 | static struct usb_driver dw2102_driver = { |
@@ -420,6 +812,6 @@ module_init(dw2102_module_init); | |||
420 | module_exit(dw2102_module_exit); | 812 | module_exit(dw2102_module_exit); |
421 | 813 | ||
422 | MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by"); | 814 | MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by"); |
423 | MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101 2102 USB2.0 device"); | 815 | MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104 USB2.0 device"); |
424 | MODULE_VERSION("0.1"); | 816 | MODULE_VERSION("0.1"); |
425 | MODULE_LICENSE("GPL"); | 817 | MODULE_LICENSE("GPL"); |