blob: 06a0aa1ae2cb053e69239bf6cfda888cb66e639f [file] [log] [blame]
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -03001/* DVB USB framework compliant Linux driver for the
2* DVBWorld DVB-S 2101, 2102, DVB-S2 2104 Card
Igor M Liplianin7fd48282008-07-20 08:05:50 -03003*
4* Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
5*
6* This program is free software; you can redistribute it and/or modify it
7* under the terms of the GNU General Public License as published by the
8* Free Software Foundation, version 2.
9*
10* see Documentation/dvb/README.dvb-usb for more information
11*/
Igor M Liplianin7fd48282008-07-20 08:05:50 -030012#include "dw2102.h"
Igor M. Liplianin21b007b2008-09-17 19:19:19 -030013#include "si21xx.h"
Igor M Liplianin7fd48282008-07-20 08:05:50 -030014#include "stv0299.h"
15#include "z0194a.h"
Igor M. Liplianin8a4949b2008-10-05 09:11:21 -030016#include "stv0288.h"
17#include "stb6000.h"
18#include "eds1547.h"
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -030019#include "cx24116.h"
Igor M Liplianin7fd48282008-07-20 08:05:50 -030020
21#ifndef USB_PID_DW2102
22#define USB_PID_DW2102 0x2102
23#endif
24
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -030025#ifndef USB_PID_DW2104
26#define USB_PID_DW2104 0x2104
27#endif
28
Igor M. Liplianin4cc0edf2008-11-05 22:12:56 -030029#ifndef USB_PID_CINERGY_S
30#define USB_PID_CINERGY_S 0x0064
31#endif
32
Igor M. Liplianin21b007b2008-09-17 19:19:19 -030033#define DW210X_READ_MSG 0
34#define DW210X_WRITE_MSG 1
Igor M Liplianin7fd48282008-07-20 08:05:50 -030035
36#define REG_1F_SYMBOLRATE_BYTE0 0x1f
37#define REG_20_SYMBOLRATE_BYTE1 0x20
38#define REG_21_SYMBOLRATE_BYTE2 0x21
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -030039/* on my own*/
Igor M Liplianin7fd48282008-07-20 08:05:50 -030040#define DW2102_VOLTAGE_CTRL (0x1800)
41#define DW2102_RC_QUERY (0x1a00)
42
Igor M. Liplianinb42e1d72009-06-14 19:41:22 -030043struct dvb_usb_rc_keys_table {
44 struct dvb_usb_rc_key *rc_keys;
45 int rc_keys_size;
Igor M Liplianin7fd48282008-07-20 08:05:50 -030046};
47
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -030048/* debug */
49static int dvb_usb_dw2102_debug;
50module_param_named(debug, dvb_usb_dw2102_debug, int, 0644);
Igor M. Liplianin8a8dad72009-06-13 08:10:24 -030051MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer 4=rc(or-able))."
52 DVB_USB_DEBUG_STATUS);
53
Igor M. Liplianinb42e1d72009-06-14 19:41:22 -030054/* keymaps */
55static int ir_keymap;
56module_param_named(keymap, ir_keymap, int, 0644);
57MODULE_PARM_DESC(keymap, "set keymap 0=default 1=dvbworld 2=tevii 3=tbs ...");
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -030058
Igor M Liplianin7fd48282008-07-20 08:05:50 -030059DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
60
Igor M. Liplianin21b007b2008-09-17 19:19:19 -030061static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value,
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -030062 u16 index, u8 * data, u16 len, int flags)
Igor M Liplianin7fd48282008-07-20 08:05:50 -030063{
64 int ret;
65 u8 u8buf[len];
66
Igor M. Liplianin21b007b2008-09-17 19:19:19 -030067 unsigned int pipe = (flags == DW210X_READ_MSG) ?
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -030068 usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0);
Igor M. Liplianin21b007b2008-09-17 19:19:19 -030069 u8 request_type = (flags == DW210X_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT;
Igor M Liplianin7fd48282008-07-20 08:05:50 -030070
Igor M. Liplianin21b007b2008-09-17 19:19:19 -030071 if (flags == DW210X_WRITE_MSG)
Igor M Liplianin7fd48282008-07-20 08:05:50 -030072 memcpy(u8buf, data, len);
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -030073 ret = usb_control_msg(dev, pipe, request, request_type | USB_TYPE_VENDOR,
74 value, index , u8buf, len, 2000);
Igor M Liplianin7fd48282008-07-20 08:05:50 -030075
Igor M. Liplianin21b007b2008-09-17 19:19:19 -030076 if (flags == DW210X_READ_MSG)
Igor M Liplianin7fd48282008-07-20 08:05:50 -030077 memcpy(data, u8buf, len);
78 return ret;
79}
80
81/* I2C */
Igor M Liplianin7fd48282008-07-20 08:05:50 -030082static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
83 int num)
84{
85struct dvb_usb_device *d = i2c_get_adapdata(adap);
86 int i = 0, ret = 0;
87 u8 buf6[] = {0x2c, 0x05, 0xc0, 0, 0, 0, 0};
Igor M Liplianin7fd48282008-07-20 08:05:50 -030088 u16 value;
89
90 if (!d)
91 return -ENODEV;
92 if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
93 return -EAGAIN;
94
95 switch (num) {
96 case 2:
97 /* read stv0299 register */
Igor M Liplianin7fd48282008-07-20 08:05:50 -030098 value = msg[0].buf[0];/* register */
99 for (i = 0; i < msg[1].len; i++) {
100 value = value + i;
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300101 ret = dw210x_op_rw(d->udev, 0xb5, value, 0,
102 buf6, 2, DW210X_READ_MSG);
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300103 msg[1].buf[i] = buf6[0];
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300104 }
105 break;
106 case 1:
107 switch (msg[0].addr) {
108 case 0x68:
109 /* write to stv0299 register */
110 buf6[0] = 0x2a;
111 buf6[1] = msg[0].buf[0];
112 buf6[2] = msg[0].buf[1];
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300113 ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
114 buf6, 3, DW210X_WRITE_MSG);
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300115 break;
116 case 0x60:
117 if (msg[0].flags == 0) {
118 /* write to tuner pll */
119 buf6[0] = 0x2c;
120 buf6[1] = 5;
121 buf6[2] = 0xc0;
122 buf6[3] = msg[0].buf[0];
123 buf6[4] = msg[0].buf[1];
124 buf6[5] = msg[0].buf[2];
125 buf6[6] = msg[0].buf[3];
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300126 ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
127 buf6, 7, DW210X_WRITE_MSG);
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300128 } else {
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -0300129 /* read from tuner */
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300130 ret = dw210x_op_rw(d->udev, 0xb5, 0, 0,
131 buf6, 1, DW210X_READ_MSG);
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300132 msg[0].buf[0] = buf6[0];
133 }
134 break;
135 case (DW2102_RC_QUERY):
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300136 ret = dw210x_op_rw(d->udev, 0xb8, 0, 0,
137 buf6, 2, DW210X_READ_MSG);
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300138 msg[0].buf[0] = buf6[0];
139 msg[0].buf[1] = buf6[1];
140 break;
141 case (DW2102_VOLTAGE_CTRL):
142 buf6[0] = 0x30;
143 buf6[1] = msg[0].buf[0];
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300144 ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
145 buf6, 2, DW210X_WRITE_MSG);
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300146 break;
147 }
148
149 break;
150 }
151
152 mutex_unlock(&d->i2c_mutex);
153 return num;
154}
155
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300156static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap,
157 struct i2c_msg msg[], int num)
158{
159 struct dvb_usb_device *d = i2c_get_adapdata(adap);
160 int ret = 0;
161 u8 buf6[] = {0, 0, 0, 0, 0, 0, 0};
162
163 if (!d)
164 return -ENODEV;
165 if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
166 return -EAGAIN;
167
168 switch (num) {
169 case 2:
170 /* read si2109 register by number */
171 buf6[0] = 0xd0;
172 buf6[1] = msg[0].len;
173 buf6[2] = msg[0].buf[0];
174 ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
175 buf6, msg[0].len + 2, DW210X_WRITE_MSG);
176 /* read si2109 register */
177 ret = dw210x_op_rw(d->udev, 0xc3, 0xd0, 0,
178 buf6, msg[1].len + 2, DW210X_READ_MSG);
179 memcpy(msg[1].buf, buf6 + 2, msg[1].len);
180
181 break;
182 case 1:
183 switch (msg[0].addr) {
184 case 0x68:
185 /* write to si2109 register */
186 buf6[0] = 0xd0;
187 buf6[1] = msg[0].len;
188 memcpy(buf6 + 2, msg[0].buf, msg[0].len);
189 ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, buf6,
190 msg[0].len + 2, DW210X_WRITE_MSG);
191 break;
192 case(DW2102_RC_QUERY):
193 ret = dw210x_op_rw(d->udev, 0xb8, 0, 0,
194 buf6, 2, DW210X_READ_MSG);
195 msg[0].buf[0] = buf6[0];
196 msg[0].buf[1] = buf6[1];
197 break;
198 case(DW2102_VOLTAGE_CTRL):
199 buf6[0] = 0x30;
200 buf6[1] = msg[0].buf[0];
201 ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
202 buf6, 2, DW210X_WRITE_MSG);
203 break;
204 }
205 break;
206 }
207
208 mutex_unlock(&d->i2c_mutex);
209 return num;
210}
Igor M. Liplianin8a4949b2008-10-05 09:11:21 -0300211static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
212{
213 struct dvb_usb_device *d = i2c_get_adapdata(adap);
214 int ret = 0;
215
216 if (!d)
217 return -ENODEV;
218 if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
219 return -EAGAIN;
220
221 switch (num) {
222 case 2: {
223 /* read */
224 /* first write first register number */
225 u8 ibuf [msg[1].len + 2], obuf[3];
226 obuf[0] = 0xd0;
227 obuf[1] = msg[0].len;
228 obuf[2] = msg[0].buf[0];
229 ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
230 obuf, msg[0].len + 2, DW210X_WRITE_MSG);
231 /* second read registers */
232 ret = dw210x_op_rw(d->udev, 0xc3, 0xd1 , 0,
233 ibuf, msg[1].len + 2, DW210X_READ_MSG);
234 memcpy(msg[1].buf, ibuf + 2, msg[1].len);
235
236 break;
237 }
238 case 1:
239 switch (msg[0].addr) {
240 case 0x68: {
241 /* write to register */
242 u8 obuf[msg[0].len + 2];
243 obuf[0] = 0xd0;
244 obuf[1] = msg[0].len;
245 memcpy(obuf + 2, msg[0].buf, msg[0].len);
246 ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
247 obuf, msg[0].len + 2, DW210X_WRITE_MSG);
248 break;
249 }
250 case 0x61: {
251 /* write to tuner */
252 u8 obuf[msg[0].len + 2];
253 obuf[0] = 0xc2;
254 obuf[1] = msg[0].len;
255 memcpy(obuf + 2, msg[0].buf, msg[0].len);
256 ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
257 obuf, msg[0].len + 2, DW210X_WRITE_MSG);
258 break;
259 }
260 case(DW2102_RC_QUERY): {
261 u8 ibuf[2];
262 ret = dw210x_op_rw(d->udev, 0xb8, 0, 0,
263 ibuf, 2, DW210X_READ_MSG);
264 memcpy(msg[0].buf, ibuf , 2);
265 break;
266 }
267 case(DW2102_VOLTAGE_CTRL): {
268 u8 obuf[2];
269 obuf[0] = 0x30;
270 obuf[1] = msg[0].buf[0];
271 ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
272 obuf, 2, DW210X_WRITE_MSG);
273 break;
274 }
275 }
276
277 break;
278 }
279
280 mutex_unlock(&d->i2c_mutex);
281 return num;
282}
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300283
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -0300284static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
285{
286 struct dvb_usb_device *d = i2c_get_adapdata(adap);
287 int ret = 0;
288 int len, i;
289
290 if (!d)
291 return -ENODEV;
292 if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
293 return -EAGAIN;
294
295 switch (num) {
296 case 2: {
297 /* read */
298 /* first write first register number */
299 u8 ibuf [msg[1].len + 2], obuf[3];
300 obuf[0] = 0xaa;
301 obuf[1] = msg[0].len;
302 obuf[2] = msg[0].buf[0];
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300303 ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
304 obuf, msg[0].len + 2, DW210X_WRITE_MSG);
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -0300305 /* second read registers */
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300306 ret = dw210x_op_rw(d->udev, 0xc3, 0xab , 0,
307 ibuf, msg[1].len + 2, DW210X_READ_MSG);
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -0300308 memcpy(msg[1].buf, ibuf + 2, msg[1].len);
309
310 break;
311 }
312 case 1:
313 switch (msg[0].addr) {
314 case 0x55: {
315 if (msg[0].buf[0] == 0xf7) {
316 /* firmware */
317 /* Write in small blocks */
318 u8 obuf[19];
319 obuf[0] = 0xaa;
320 obuf[1] = 0x11;
321 obuf[2] = 0xf7;
322 len = msg[0].len - 1;
323 i = 1;
324 do {
325 memcpy(obuf + 3, msg[0].buf + i, (len > 16 ? 16 : len));
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300326 ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
327 obuf, (len > 16 ? 16 : len) + 3, DW210X_WRITE_MSG);
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -0300328 i += 16;
329 len -= 16;
330 } while (len > 0);
331 } else {
332 /* write to register */
333 u8 obuf[msg[0].len + 2];
334 obuf[0] = 0xaa;
335 obuf[1] = msg[0].len;
336 memcpy(obuf + 2, msg[0].buf, msg[0].len);
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300337 ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
338 obuf, msg[0].len + 2, DW210X_WRITE_MSG);
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -0300339 }
340 break;
341 }
342 case(DW2102_RC_QUERY): {
343 u8 ibuf[2];
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300344 ret = dw210x_op_rw(d->udev, 0xb8, 0, 0,
345 ibuf, 2, DW210X_READ_MSG);
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -0300346 memcpy(msg[0].buf, ibuf , 2);
347 break;
348 }
349 case(DW2102_VOLTAGE_CTRL): {
350 u8 obuf[2];
351 obuf[0] = 0x30;
352 obuf[1] = msg[0].buf[0];
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300353 ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
354 obuf, 2, DW210X_WRITE_MSG);
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -0300355 break;
356 }
357 }
358
359 break;
360 }
361
362 mutex_unlock(&d->i2c_mutex);
363 return num;
364}
365
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300366static u32 dw210x_i2c_func(struct i2c_adapter *adapter)
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300367{
368 return I2C_FUNC_I2C;
369}
370
371static struct i2c_algorithm dw2102_i2c_algo = {
372 .master_xfer = dw2102_i2c_transfer,
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300373 .functionality = dw210x_i2c_func,
374};
375
376static struct i2c_algorithm dw2102_serit_i2c_algo = {
377 .master_xfer = dw2102_serit_i2c_transfer,
378 .functionality = dw210x_i2c_func,
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300379};
380
Igor M. Liplianin8a4949b2008-10-05 09:11:21 -0300381static struct i2c_algorithm dw2102_earda_i2c_algo = {
382 .master_xfer = dw2102_earda_i2c_transfer,
383 .functionality = dw210x_i2c_func,
384};
385
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -0300386static struct i2c_algorithm dw2104_i2c_algo = {
387 .master_xfer = dw2104_i2c_transfer,
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300388 .functionality = dw210x_i2c_func,
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -0300389};
390
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300391static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -0300392{
393 int i;
394 u8 ibuf[] = {0, 0};
395 u8 eeprom[256], eepromline[16];
396
397 for (i = 0; i < 256; i++) {
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300398 if (dw210x_op_rw(d->udev, 0xb6, 0xa0 , i, ibuf, 2, DW210X_READ_MSG) < 0) {
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -0300399 err("read eeprom failed.");
400 return -1;
401 } else {
402 eepromline[i%16] = ibuf[0];
403 eeprom[i] = ibuf[0];
404 }
405 if ((i % 16) == 15) {
406 deb_xfer("%02x: ", i - 15);
407 debug_dump(eepromline, 16, deb_xfer);
408 }
409 }
410 memcpy(mac, eeprom + 8, 6);
411 return 0;
412};
413
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300414static int dw210x_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300415{
416 static u8 command_13v[1] = {0x00};
417 static u8 command_18v[1] = {0x01};
418 struct i2c_msg msg[] = {
419 {.addr = DW2102_VOLTAGE_CTRL, .flags = 0,
420 .buf = command_13v, .len = 1},
421 };
422
423 struct dvb_usb_adapter *udev_adap =
424 (struct dvb_usb_adapter *)(fe->dvb->priv);
425 if (voltage == SEC_VOLTAGE_18)
426 msg[0].buf = command_18v;
427 i2c_transfer(&udev_adap->dev->i2c_adap, msg, 1);
428 return 0;
429}
430
Igor M. Liplianind4305c62008-10-17 13:45:55 -0300431static struct stv0299_config sharp_z0194a_config = {
432 .demod_address = 0x68,
433 .inittab = sharp_z0194a_inittab,
434 .mclk = 88000000UL,
435 .invert = 1,
436 .skip_reinit = 0,
437 .lock_output = STV0299_LOCKOUTPUT_1,
438 .volt13_op0_op1 = STV0299_VOLT13_OP1,
439 .min_delay_ms = 100,
440 .set_symbol_rate = sharp_z0194a_set_symbol_rate,
441};
442
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -0300443static struct cx24116_config dw2104_config = {
444 .demod_address = 0x55,
Igor M. Liplianincc8c4f32008-09-09 13:57:47 -0300445 .mpg_clk_pos_pol = 0x01,
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -0300446};
447
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300448static struct si21xx_config serit_sp1511lhb_config = {
449 .demod_address = 0x68,
450 .min_delay_ms = 100,
451
452};
453
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -0300454static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
455{
456 if ((d->fe = dvb_attach(cx24116_attach, &dw2104_config,
457 &d->dev->i2c_adap)) != NULL) {
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300458 d->fe->ops.set_voltage = dw210x_set_voltage;
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -0300459 info("Attached cx24116!\n");
460 return 0;
461 }
462 return -EIO;
463}
464
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300465static struct dvb_usb_device_properties dw2102_properties;
Igor M. Liplianinb42e1d72009-06-14 19:41:22 -0300466static struct dvb_usb_device_properties dw2104_properties;
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300467
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300468static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
469{
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300470 if (dw2102_properties.i2c_algo == &dw2102_serit_i2c_algo) {
471 /*dw2102_properties.adapter->tuner_attach = NULL;*/
472 d->fe = dvb_attach(si21xx_attach, &serit_sp1511lhb_config,
473 &d->dev->i2c_adap);
474 if (d->fe != NULL) {
475 d->fe->ops.set_voltage = dw210x_set_voltage;
476 info("Attached si21xx!\n");
477 return 0;
478 }
479 }
Igor M. Liplianin8a4949b2008-10-05 09:11:21 -0300480 if (dw2102_properties.i2c_algo == &dw2102_earda_i2c_algo) {
481 /*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/
482 d->fe = dvb_attach(stv0288_attach, &earda_config,
483 &d->dev->i2c_adap);
484 if (d->fe != NULL) {
485 d->fe->ops.set_voltage = dw210x_set_voltage;
486 info("Attached stv0288!\n");
487 return 0;
488 }
489 }
490
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300491 if (dw2102_properties.i2c_algo == &dw2102_i2c_algo) {
492 /*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/
493 d->fe = dvb_attach(stv0299_attach, &sharp_z0194a_config,
494 &d->dev->i2c_adap);
495 if (d->fe != NULL) {
496 d->fe->ops.set_voltage = dw210x_set_voltage;
497 info("Attached stv0299!\n");
498 return 0;
499 }
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300500 }
501 return -EIO;
502}
503
504static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
505{
506 dvb_attach(dvb_pll_attach, adap->fe, 0x60,
507 &adap->dev->i2c_adap, DVB_PLL_OPERA1);
508 return 0;
509}
510
Igor M. Liplianin8a4949b2008-10-05 09:11:21 -0300511static int dw2102_earda_tuner_attach(struct dvb_usb_adapter *adap)
512{
513 dvb_attach(stb6000_attach, adap->fe, 0x61,
514 &adap->dev->i2c_adap);
515
516 return 0;
517}
518
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300519static struct dvb_usb_rc_key dw210x_rc_keys[] = {
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300520 { 0xf8, 0x0a, KEY_Q }, /*power*/
521 { 0xf8, 0x0c, KEY_M }, /*mute*/
522 { 0xf8, 0x11, KEY_1 },
523 { 0xf8, 0x12, KEY_2 },
524 { 0xf8, 0x13, KEY_3 },
525 { 0xf8, 0x14, KEY_4 },
526 { 0xf8, 0x15, KEY_5 },
527 { 0xf8, 0x16, KEY_6 },
528 { 0xf8, 0x17, KEY_7 },
529 { 0xf8, 0x18, KEY_8 },
530 { 0xf8, 0x19, KEY_9 },
531 { 0xf8, 0x10, KEY_0 },
532 { 0xf8, 0x1c, KEY_PAGEUP }, /*ch+*/
533 { 0xf8, 0x0f, KEY_PAGEDOWN }, /*ch-*/
534 { 0xf8, 0x1a, KEY_O }, /*vol+*/
535 { 0xf8, 0x0e, KEY_Z }, /*vol-*/
536 { 0xf8, 0x04, KEY_R }, /*rec*/
537 { 0xf8, 0x09, KEY_D }, /*fav*/
538 { 0xf8, 0x08, KEY_BACKSPACE }, /*rewind*/
539 { 0xf8, 0x07, KEY_A }, /*fast*/
540 { 0xf8, 0x0b, KEY_P }, /*pause*/
541 { 0xf8, 0x02, KEY_ESC }, /*cancel*/
542 { 0xf8, 0x03, KEY_G }, /*tab*/
543 { 0xf8, 0x00, KEY_UP }, /*up*/
544 { 0xf8, 0x1f, KEY_ENTER }, /*ok*/
545 { 0xf8, 0x01, KEY_DOWN }, /*down*/
546 { 0xf8, 0x05, KEY_C }, /*cap*/
547 { 0xf8, 0x06, KEY_S }, /*stop*/
548 { 0xf8, 0x40, KEY_F }, /*full*/
549 { 0xf8, 0x1e, KEY_W }, /*tvmode*/
550 { 0xf8, 0x1b, KEY_B }, /*recall*/
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300551};
552
Igor M. Liplianinb42e1d72009-06-14 19:41:22 -0300553static struct dvb_usb_rc_key tevii_rc_keys[] = {
554 { 0xf8, 0x0a, KEY_POWER },
555 { 0xf8, 0x0c, KEY_MUTE },
556 { 0xf8, 0x11, KEY_1 },
557 { 0xf8, 0x12, KEY_2 },
558 { 0xf8, 0x13, KEY_3 },
559 { 0xf8, 0x14, KEY_4 },
560 { 0xf8, 0x15, KEY_5 },
561 { 0xf8, 0x16, KEY_6 },
562 { 0xf8, 0x17, KEY_7 },
563 { 0xf8, 0x18, KEY_8 },
564 { 0xf8, 0x19, KEY_9 },
565 { 0xf8, 0x10, KEY_0 },
566 { 0xf8, 0x1c, KEY_MENU },
567 { 0xf8, 0x0f, KEY_VOLUMEDOWN },
568 { 0xf8, 0x1a, KEY_LAST },
569 { 0xf8, 0x0e, KEY_OPEN },
570 { 0xf8, 0x04, KEY_RECORD },
571 { 0xf8, 0x09, KEY_VOLUMEUP },
572 { 0xf8, 0x08, KEY_CHANNELUP },
573 { 0xf8, 0x07, KEY_PVR },
574 { 0xf8, 0x0b, KEY_TIME },
575 { 0xf8, 0x02, KEY_RIGHT },
576 { 0xf8, 0x03, KEY_LEFT },
577 { 0xf8, 0x00, KEY_UP },
578 { 0xf8, 0x1f, KEY_OK },
579 { 0xf8, 0x01, KEY_DOWN },
580 { 0xf8, 0x05, KEY_TUNER },
581 { 0xf8, 0x06, KEY_CHANNELDOWN },
582 { 0xf8, 0x40, KEY_PLAYPAUSE },
583 { 0xf8, 0x1e, KEY_REWIND },
584 { 0xf8, 0x1b, KEY_FAVORITES },
585 { 0xf8, 0x1d, KEY_BACK },
586 { 0xf8, 0x4d, KEY_FASTFORWARD },
587 { 0xf8, 0x44, KEY_EPG },
588 { 0xf8, 0x4c, KEY_INFO },
589 { 0xf8, 0x41, KEY_AB },
590 { 0xf8, 0x43, KEY_AUDIO },
591 { 0xf8, 0x45, KEY_SUBTITLE },
592 { 0xf8, 0x4a, KEY_LIST },
593 { 0xf8, 0x46, KEY_F1 },
594 { 0xf8, 0x47, KEY_F2 },
595 { 0xf8, 0x5e, KEY_F3 },
596 { 0xf8, 0x5c, KEY_F4 },
597 { 0xf8, 0x52, KEY_F5 },
598 { 0xf8, 0x5a, KEY_F6 },
599 { 0xf8, 0x56, KEY_MODE },
600 { 0xf8, 0x58, KEY_SWITCHVIDEOMODE },
601};
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300602
Igor M. Liplianinb42e1d72009-06-14 19:41:22 -0300603static struct dvb_usb_rc_key tbs_rc_keys[] = {
604 { 0xf8, 0x84, KEY_POWER },
605 { 0xf8, 0x94, KEY_MUTE },
606 { 0xf8, 0x87, KEY_1 },
607 { 0xf8, 0x86, KEY_2 },
608 { 0xf8, 0x85, KEY_3 },
609 { 0xf8, 0x8b, KEY_4 },
610 { 0xf8, 0x8a, KEY_5 },
611 { 0xf8, 0x89, KEY_6 },
612 { 0xf8, 0x8f, KEY_7 },
613 { 0xf8, 0x8e, KEY_8 },
614 { 0xf8, 0x8d, KEY_9 },
615 { 0xf8, 0x92, KEY_0 },
616 { 0xf8, 0x96, KEY_CHANNELUP },
617 { 0xf8, 0x91, KEY_CHANNELDOWN },
618 { 0xf8, 0x93, KEY_VOLUMEUP },
619 { 0xf8, 0x8c, KEY_VOLUMEDOWN },
620 { 0xf8, 0x83, KEY_RECORD },
621 { 0xf8, 0x98, KEY_PAUSE },
622 { 0xf8, 0x99, KEY_OK },
623 { 0xf8, 0x9a, KEY_SHUFFLE },
624 { 0xf8, 0x81, KEY_UP },
625 { 0xf8, 0x90, KEY_LEFT },
626 { 0xf8, 0x82, KEY_RIGHT },
627 { 0xf8, 0x88, KEY_DOWN },
628 { 0xf8, 0x95, KEY_FAVORITES },
629 { 0xf8, 0x97, KEY_SUBTITLE },
630 { 0xf8, 0x9d, KEY_ZOOM },
631 { 0xf8, 0x9f, KEY_EXIT },
632 { 0xf8, 0x9e, KEY_MENU },
633 { 0xf8, 0x9c, KEY_EPG },
634 { 0xf8, 0x80, KEY_PREVIOUS },
635 { 0xf8, 0x9b, KEY_MODE }
636};
637
638static struct dvb_usb_rc_keys_table keys_tables[] = {
639 { dw210x_rc_keys, ARRAY_SIZE(dw210x_rc_keys) },
640 { tevii_rc_keys, ARRAY_SIZE(tevii_rc_keys) },
641 { tbs_rc_keys, ARRAY_SIZE(tbs_rc_keys) },
642};
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300643
644static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
645{
Igor M. Liplianinb42e1d72009-06-14 19:41:22 -0300646 struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
647 int keymap_size = d->props.rc_key_map_size;
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300648 u8 key[2];
Igor M. Liplianin8a8dad72009-06-13 08:10:24 -0300649 struct i2c_msg msg = {
650 .addr = DW2102_RC_QUERY,
651 .flags = I2C_M_RD,
652 .buf = key,
653 .len = 2
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300654 };
655 int i;
Igor M. Liplianinb42e1d72009-06-14 19:41:22 -0300656 /* override keymap */
657 if ((ir_keymap > 0) && (ir_keymap <= ARRAY_SIZE(keys_tables))) {
658 keymap = keys_tables[ir_keymap - 1].rc_keys ;
659 keymap_size = keys_tables[ir_keymap - 1].rc_keys_size;
660 }
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300661
662 *state = REMOTE_NO_KEY_PRESSED;
Igor M. Liplianin8a8dad72009-06-13 08:10:24 -0300663 if (dw2102_i2c_transfer(&d->i2c_adap, &msg, 1) == 1) {
Igor M. Liplianinb42e1d72009-06-14 19:41:22 -0300664 for (i = 0; i < keymap_size ; i++) {
665 if (keymap[i].data == msg.buf[0]) {
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300666 *state = REMOTE_KEY_PRESSED;
Igor M. Liplianinb42e1d72009-06-14 19:41:22 -0300667 *event = keymap[i].event;
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300668 break;
669 }
Igor M. Liplianin8a8dad72009-06-13 08:10:24 -0300670
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300671 }
Igor M. Liplianin8a8dad72009-06-13 08:10:24 -0300672
673 if ((*state) == REMOTE_KEY_PRESSED)
674 deb_rc("%s: found rc key: %x, %x, event: %x\n",
675 __func__, key[0], key[1], (*event));
676 else if (key[0] != 0xff)
677 deb_rc("%s: unknown rc key: %x, %x\n",
678 __func__, key[0], key[1]);
679
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300680 }
Igor M. Liplianin8a8dad72009-06-13 08:10:24 -0300681
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300682 return 0;
683}
684
685static struct usb_device_id dw2102_table[] = {
686 {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)},
687 {USB_DEVICE(USB_VID_CYPRESS, 0x2101)},
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -0300688 {USB_DEVICE(USB_VID_CYPRESS, 0x2104)},
689 {USB_DEVICE(0x9022, 0xd650)},
Igor M. Liplianin4cc0edf2008-11-05 22:12:56 -0300690 {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)},
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300691 { }
692};
693
694MODULE_DEVICE_TABLE(usb, dw2102_table);
695
696static int dw2102_load_firmware(struct usb_device *dev,
697 const struct firmware *frmwr)
698{
699 u8 *b, *p;
700 int ret = 0, i;
701 u8 reset;
Igor M. Liplianin8a4949b2008-10-05 09:11:21 -0300702 u8 reset16[] = {0, 0, 0, 0, 0, 0, 0};
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300703 const struct firmware *fw;
704 const char *filename = "dvb-usb-dw2101.fw";
705 switch (dev->descriptor.idProduct) {
706 case 0x2101:
707 ret = request_firmware(&fw, filename, &dev->dev);
708 if (ret != 0) {
709 err("did not find the firmware file. (%s) "
710 "Please see linux/Documentation/dvb/ for more details "
711 "on firmware-problems.", filename);
712 return ret;
713 }
714 break;
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -0300715 default:
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300716 fw = frmwr;
717 break;
718 }
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -0300719 info("start downloading DW210X firmware");
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300720 p = kmalloc(fw->size, GFP_KERNEL);
721 reset = 1;
722 /*stop the CPU*/
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300723 dw210x_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1, DW210X_WRITE_MSG);
724 dw210x_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1, DW210X_WRITE_MSG);
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300725
726 if (p != NULL) {
727 memcpy(p, fw->data, fw->size);
728 for (i = 0; i < fw->size; i += 0x40) {
729 b = (u8 *) p + i;
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300730 if (dw210x_op_rw(dev, 0xa0, i, 0, b , 0x40,
731 DW210X_WRITE_MSG) != 0x40) {
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300732 err("error while transferring firmware");
733 ret = -EINVAL;
734 break;
735 }
736 }
737 /* restart the CPU */
738 reset = 0;
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300739 if (ret || dw210x_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1,
740 DW210X_WRITE_MSG) != 1) {
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300741 err("could not restart the USB controller CPU.");
742 ret = -EINVAL;
743 }
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300744 if (ret || dw210x_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1,
745 DW210X_WRITE_MSG) != 1) {
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300746 err("could not restart the USB controller CPU.");
747 ret = -EINVAL;
748 }
749 /* init registers */
750 switch (dev->descriptor.idProduct) {
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -0300751 case 0xd650:
Igor M. Liplianinb42e1d72009-06-14 19:41:22 -0300752 dw2104_properties.rc_key_map = tevii_rc_keys;
753 dw2104_properties.rc_key_map_size =
754 ARRAY_SIZE(tevii_rc_keys);
755 case USB_PID_DW2104:
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -0300756 reset = 1;
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300757 dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1,
758 DW210X_WRITE_MSG);
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -0300759 reset = 0;
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300760 dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0,
761 DW210X_WRITE_MSG);
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -0300762 break;
Igor M. Liplianin4cc0edf2008-11-05 22:12:56 -0300763 case USB_PID_CINERGY_S:
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300764 case USB_PID_DW2102:
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300765 dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0,
766 DW210X_WRITE_MSG);
767 dw210x_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2,
768 DW210X_READ_MSG);
769 /* check STV0299 frontend */
770 dw210x_op_rw(dev, 0xb5, 0, 0, &reset16[0], 2,
771 DW210X_READ_MSG);
Igor M. Liplianinea023df2008-12-04 12:49:23 -0300772 if ((reset16[0] == 0xa1) || (reset16[0] == 0x80)) {
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300773 dw2102_properties.i2c_algo = &dw2102_i2c_algo;
Igor M. Liplianin8a4949b2008-10-05 09:11:21 -0300774 dw2102_properties.adapter->tuner_attach = &dw2102_tuner_attach;
775 break;
776 } else {
777 /* check STV0288 frontend */
778 reset16[0] = 0xd0;
779 reset16[1] = 1;
780 reset16[2] = 0;
781 dw210x_op_rw(dev, 0xc2, 0, 0, &reset16[0], 3,
782 DW210X_WRITE_MSG);
783 dw210x_op_rw(dev, 0xc3, 0xd1, 0, &reset16[0], 3,
784 DW210X_READ_MSG);
785 if (reset16[2] == 0x11) {
786 dw2102_properties.i2c_algo = &dw2102_earda_i2c_algo;
787 dw2102_properties.adapter->tuner_attach = &dw2102_earda_tuner_attach;
788 break;
789 }
790 }
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300791 case 0x2101:
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300792 dw210x_op_rw(dev, 0xbc, 0x0030, 0, &reset16[0], 2,
793 DW210X_READ_MSG);
794 dw210x_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7,
795 DW210X_READ_MSG);
796 dw210x_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7,
797 DW210X_READ_MSG);
798 dw210x_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2,
799 DW210X_READ_MSG);
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300800 break;
801 }
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -0300802 msleep(100);
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300803 kfree(p);
804 }
805 return ret;
806}
807
808static struct dvb_usb_device_properties dw2102_properties = {
809 .caps = DVB_USB_IS_AN_I2C_ADAPTER,
810 .usb_ctrl = DEVICE_SPECIFIC,
811 .firmware = "dvb-usb-dw2102.fw",
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300812 .no_reconnect = 1,
813
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300814 .i2c_algo = &dw2102_serit_i2c_algo,
815 .rc_key_map = dw210x_rc_keys,
816 .rc_key_map_size = ARRAY_SIZE(dw210x_rc_keys),
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300817 .rc_interval = 150,
818 .rc_query = dw2102_rc_query,
819
820 .generic_bulk_ctrl_endpoint = 0x81,
821 /* parameter for the MPEG2-data transfer */
822 .num_adapters = 1,
823 .download_firmware = dw2102_load_firmware,
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300824 .read_mac_address = dw210x_read_mac_address,
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -0300825 .adapter = {
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300826 {
827 .frontend_attach = dw2102_frontend_attach,
828 .streaming_ctrl = NULL,
Igor M. Liplianin8a4949b2008-10-05 09:11:21 -0300829 .tuner_attach = NULL,
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300830 .stream = {
831 .type = USB_BULK,
832 .count = 8,
833 .endpoint = 0x82,
834 .u = {
835 .bulk = {
836 .buffersize = 4096,
837 }
838 }
839 },
840 }
841 },
Igor M. Liplianin4cc0edf2008-11-05 22:12:56 -0300842 .num_device_descs = 3,
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300843 .devices = {
844 {"DVBWorld DVB-S 2102 USB2.0",
845 {&dw2102_table[0], NULL},
846 {NULL},
847 },
848 {"DVBWorld DVB-S 2101 USB2.0",
849 {&dw2102_table[1], NULL},
850 {NULL},
851 },
Igor M. Liplianin4cc0edf2008-11-05 22:12:56 -0300852 {"TerraTec Cinergy S USB",
853 {&dw2102_table[4], NULL},
854 {NULL},
855 },
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300856 }
857};
858
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -0300859static struct dvb_usb_device_properties dw2104_properties = {
860 .caps = DVB_USB_IS_AN_I2C_ADAPTER,
861 .usb_ctrl = DEVICE_SPECIFIC,
862 .firmware = "dvb-usb-dw2104.fw",
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -0300863 .no_reconnect = 1,
864
865 .i2c_algo = &dw2104_i2c_algo,
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300866 .rc_key_map = dw210x_rc_keys,
867 .rc_key_map_size = ARRAY_SIZE(dw210x_rc_keys),
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -0300868 .rc_interval = 150,
869 .rc_query = dw2102_rc_query,
870
871 .generic_bulk_ctrl_endpoint = 0x81,
872 /* parameter for the MPEG2-data transfer */
873 .num_adapters = 1,
874 .download_firmware = dw2102_load_firmware,
Igor M. Liplianin21b007b2008-09-17 19:19:19 -0300875 .read_mac_address = dw210x_read_mac_address,
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -0300876 .adapter = {
877 {
878 .frontend_attach = dw2104_frontend_attach,
879 .streaming_ctrl = NULL,
880 /*.tuner_attach = dw2104_tuner_attach,*/
881 .stream = {
882 .type = USB_BULK,
883 .count = 8,
884 .endpoint = 0x82,
885 .u = {
886 .bulk = {
887 .buffersize = 4096,
888 }
889 }
890 },
891 }
892 },
893 .num_device_descs = 2,
894 .devices = {
895 { "DVBWorld DW2104 USB2.0",
896 {&dw2102_table[2], NULL},
897 {NULL},
898 },
899 { "TeVii S650 USB2.0",
900 {&dw2102_table[3], NULL},
901 {NULL},
902 },
903 }
904};
905
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300906static int dw2102_probe(struct usb_interface *intf,
907 const struct usb_device_id *id)
908{
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -0300909 if (0 == dvb_usb_device_init(intf, &dw2102_properties,
910 THIS_MODULE, NULL, adapter_nr) ||
911 0 == dvb_usb_device_init(intf, &dw2104_properties,
912 THIS_MODULE, NULL, adapter_nr)) {
913 return 0;
914 }
915 return -ENODEV;
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300916}
917
918static struct usb_driver dw2102_driver = {
919 .name = "dw2102",
920 .probe = dw2102_probe,
921 .disconnect = dvb_usb_device_exit,
922 .id_table = dw2102_table,
923};
924
925static int __init dw2102_module_init(void)
926{
927 int ret = usb_register(&dw2102_driver);
928 if (ret)
929 err("usb_register failed. Error number %d", ret);
930
931 return ret;
932}
933
934static void __exit dw2102_module_exit(void)
935{
936 usb_deregister(&dw2102_driver);
937}
938
939module_init(dw2102_module_init);
940module_exit(dw2102_module_exit);
941
942MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by");
Igor M. Liplianinfe03d5e2008-09-08 17:16:40 -0300943MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104 USB2.0 device");
Igor M Liplianin7fd48282008-07-20 08:05:50 -0300944MODULE_VERSION("0.1");
945MODULE_LICENSE("GPL");