aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMalcolm Priestley <tvboxspy@gmail.com>2010-09-02 16:29:30 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-10-20 23:04:54 -0400
commitd2f918bba7a482bee18cc0ede7791f7d846dd5d0 (patch)
treef893a3dab16b3f815f576f08568f17b5d4f1edf9 /drivers
parent9d10f3d7e73d3428555da97134fc597710a55f39 (diff)
V4L/DVB: Support or LME2510(C) DM04/QQBOX USB DVB-S BOXES
DM04/QQBOX DVB-S USB BOX with LME2510C+SHARP:BS2F7HZ7395 or LME2510+LGTDQT-P001F tuner. [mchehab@redhat.com: Fix merge conflicts/compilation and CodingStyle issues] Signed-off-by: Malcolm Priestley <tvboxspy@gmail.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/IR/keymaps/Makefile1
-rw-r--r--drivers/media/IR/keymaps/rc-lme2510.c68
-rw-r--r--drivers/media/dvb/dvb-usb/Kconfig11
-rw-r--r--drivers/media/dvb/dvb-usb/Makefile3
-rw-r--r--drivers/media/dvb/dvb-usb/lmedm04.c936
-rw-r--r--drivers/media/dvb/dvb-usb/lmedm04.h187
6 files changed, 1206 insertions, 0 deletions
diff --git a/drivers/media/IR/keymaps/Makefile b/drivers/media/IR/keymaps/Makefile
index c032b9d2e51a..f755b21eef1a 100644
--- a/drivers/media/IR/keymaps/Makefile
+++ b/drivers/media/IR/keymaps/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
39 rc-kworld-315u.o \ 39 rc-kworld-315u.o \
40 rc-kworld-plus-tv-analog.o \ 40 rc-kworld-plus-tv-analog.o \
41 rc-lirc.o \ 41 rc-lirc.o \
42 rc-lme2510.o \
42 rc-manli.o \ 43 rc-manli.o \
43 rc-msi-tvanywhere.o \ 44 rc-msi-tvanywhere.o \
44 rc-msi-tvanywhere-plus.o \ 45 rc-msi-tvanywhere-plus.o \
diff --git a/drivers/media/IR/keymaps/rc-lme2510.c b/drivers/media/IR/keymaps/rc-lme2510.c
new file mode 100644
index 000000000000..40dcf0b4e21a
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-lme2510.c
@@ -0,0 +1,68 @@
1/* LME2510 remote control
2 *
3 *
4 * Copyright (C) 2010 Malcolm Priestley (tvboxspy@gmail.com)
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#include <media/rc-map.h>
13
14
15static struct ir_scancode lme2510_rc[] = {
16 { 0xba45, KEY_0 },
17 { 0xa05f, KEY_1 },
18 { 0xaf50, KEY_2 },
19 { 0xa25d, KEY_3 },
20 { 0xbe41, KEY_4 },
21 { 0xf50a, KEY_5 },
22 { 0xbd42, KEY_6 },
23 { 0xb847, KEY_7 },
24 { 0xb649, KEY_8 },
25 { 0xfa05, KEY_9 },
26 { 0xbc43, KEY_POWER },
27 { 0xb946, KEY_SUBTITLE },
28 { 0xf906, KEY_PAUSE },
29 { 0xfc03, KEY_MEDIA_REPEAT},
30 { 0xfd02, KEY_PAUSE },
31 { 0xa15e, KEY_VOLUMEUP },
32 { 0xa35c, KEY_VOLUMEDOWN },
33 { 0xf609, KEY_CHANNELUP },
34 { 0xe51a, KEY_CHANNELDOWN },
35 { 0xe11e, KEY_PLAY },
36 { 0xe41b, KEY_ZOOM },
37 { 0xa659, KEY_MUTE },
38 { 0xa55a, KEY_TV },
39 { 0xe718, KEY_RECORD },
40 { 0xf807, KEY_EPG },
41 { 0xfe01, KEY_STOP },
42
43};
44
45static struct rc_keymap lme2510_map = {
46 .map = {
47 .scan = lme2510_rc,
48 .size = ARRAY_SIZE(lme2510_rc),
49 .ir_type = IR_TYPE_UNKNOWN,
50 .name = RC_MAP_LME2510,
51 }
52};
53
54static int __init init_rc_lme2510_map(void)
55{
56 return ir_register_map(&lme2510_map);
57}
58
59static void __exit exit_rc_lme2510_map(void)
60{
61 ir_unregister_map(&lme2510_map);
62}
63
64module_init(init_rc_lme2510_map)
65module_exit(exit_rc_lme2510_map)
66
67MODULE_LICENSE("GPL");
68MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com");
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index c57f828e1eb9..4734ec073e01 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -347,3 +347,14 @@ config DVB_USB_AZ6027
347 select DVB_STB6100 if !DVB_FE_CUSTOMISE 347 select DVB_STB6100 if !DVB_FE_CUSTOMISE
348 help 348 help
349 Say Y here to support the AZ6027 device 349 Say Y here to support the AZ6027 device
350
351config DVB_USB_LME2510
352 tristate "LME DM04/QQBOX DVB-S USB2.0 support"
353 depends on DVB_USB
354 select DVB_TDA10086 if !DVB_FE_CUSTOMISE
355 select DVB_TDA826X if !DVB_FE_CUSTOMISE
356 select DVB_STV0288 if !DVB_FE_CUSTOMISE
357 select DVB_IX2505V if !DVB_FE_CUSTOMISE
358 depends on IR_CORE
359 help
360 Say Y here to support the LME DM04/QQBOX DVB-S USB2.0 .
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
index 1a192453b0e7..5b1d12f2d591 100644
--- a/drivers/media/dvb/dvb-usb/Makefile
+++ b/drivers/media/dvb/dvb-usb/Makefile
@@ -88,6 +88,9 @@ obj-$(CONFIG_DVB_USB_EC168) += dvb-usb-ec168.o
88dvb-usb-az6027-objs = az6027.o 88dvb-usb-az6027-objs = az6027.o
89obj-$(CONFIG_DVB_USB_AZ6027) += dvb-usb-az6027.o 89obj-$(CONFIG_DVB_USB_AZ6027) += dvb-usb-az6027.o
90 90
91dvb-usb-lmedm04-objs = lmedm04.o
92obj-$(CONFIG_DVB_USB_LME2510) += dvb-usb-lmedm04.o
93
91EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ 94EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
92# due to tuner-xc3028 95# due to tuner-xc3028
93EXTRA_CFLAGS += -Idrivers/media/common/tuners 96EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/drivers/media/dvb/dvb-usb/lmedm04.c b/drivers/media/dvb/dvb-usb/lmedm04.c
new file mode 100644
index 000000000000..d5374ac075d3
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/lmedm04.c
@@ -0,0 +1,936 @@
1/* DVB USB compliant linux driver for
2 *
3 * DM04/QQBOX DVB-S USB BOX LME2510C + SHARP:BS2F7HZ7395
4 * LME2510 + LGTDQT-P001F
5 *
6 * MVB7395 (LME2510C+SHARP:BS2F7HZ7395)
7 * SHARP:BS2F7HZ7395 = (STV0288+Sharp IX2505V)
8 *
9 * MV001F (LME2510 +LGTDQY-P001F)
10 * LG TDQY - P001F =(TDA8263 + TDA10086H)
11 *
12 * For firmware see Documentation/dvb/lmedm04.txt
13 *
14 * I2C addresses:
15 * 0xd0 - STV0288 - Demodulator
16 * 0xc0 - Sharp IX2505V - Tuner
17 * --or--
18 * 0x1c - TDA10086 - Demodulator
19 * 0xc0 - TDA8263 - Tuner
20 *
21 * ***Please Note***
22 * There are other variants of the DM04
23 * ***NOT SUPPORTED***
24 * MVB0001F (LME2510C+LGTDQT-P001F)
25 * MV0194 (LME2510+SHARP0194)
26 * MVB0194 (LME2510C+SHARP0194)
27 *
28 *
29 * VID = 3344 PID LME2510=1122 LME2510C=1120
30 *
31 * Copyright (C) 2010 Malcolm Priestley (tvboxspy@gmail.com)
32 * LME2510(C)(C) Leaguerme (Shenzhen) MicroElectronics Co., Ltd.
33 *
34 * This program is free software; you can redistribute it and/or modify
35 * it under the terms of the GNU General Public License Version 2, as
36 * published by the Free Software Foundation.
37 *
38 * This program is distributed in the hope that it will be useful,
39 * but WITHOUT ANY WARRANTY; without even the implied warranty of
40 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
41 * GNU General Public License for more details.
42 *
43 * You should have received a copy of the GNU General Public License
44 * along with this program; if not, write to the Free Software
45 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
46 *
47 *
48 * see Documentation/dvb/README.dvb-usb for more information
49 *
50 * Known Issues :
51 * LME2510: Non Intel USB chipsets fail to maintain High Speed on
52 * Boot or Hot Plug.
53 *
54 * DiSEqC functions are not fully supported in this driver. The main
55 * reason is the frontend is cut off during streaming. Allowing frontend
56 * access will stall the driver. Applications that attempt to this, the
57 * commands are ignored.
58 *
59 * PID functions have been removed from this driver version due to
60 * problems with different firmware and application versions.
61 */
62#define DVB_USB_LOG_PREFIX "LME2510(C)"
63#include <linux/usb.h>
64#include <linux/usb/input.h>
65#include <media/ir-core.h>
66
67#include "dvb-usb.h"
68#include "lmedm04.h"
69#include "tda826x.h"
70#include "tda10086.h"
71#include "stv0288.h"
72#include "ix2505v.h"
73
74
75
76/* debug */
77static int dvb_usb_lme2510_debug;
78#define l_dprintk(var, level, args...) do { \
79 if ((var >= level)) \
80 printk(KERN_DEBUG DVB_USB_LOG_PREFIX ": " args); \
81} while (0)
82
83#define deb_info(level, args...) l_dprintk(dvb_usb_lme2510_debug, level, args)
84#define debug_data_snipet(level, name, p) \
85 deb_info(level, name" (%02x%02x%02x%02x%02x%02x%02x%02x)", \
86 *p, *(p+1), *(p+2), *(p+3), *(p+4), \
87 *(p+5), *(p+6), *(p+7));
88
89
90module_param_named(debug, dvb_usb_lme2510_debug, int, 0644);
91MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."
92 DVB_USB_DEBUG_STATUS);
93
94DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
95#define TUNER_LG 0x1
96#define TUNER_S7395 0x2
97
98struct lme2510_state {
99 u8 id;
100 u8 tuner_config;
101 u8 signal_lock;
102 u8 signal_level;
103 u8 signal_sn;
104 u8 time_key;
105 u8 i2c_talk_onoff;
106 u8 i2c_gate;
107 u8 i2c_tuner_gate_w;
108 u8 i2c_tuner_gate_r;
109 u8 i2c_tuner_addr;
110 void *buffer;
111 struct urb *lme_urb;
112 void *usb_buffer;
113
114};
115
116static int lme2510_bulk_write(struct usb_device *dev,
117 u8 *snd, int len, u8 pipe)
118{
119 int ret, actual_l;
120 ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, pipe),
121 snd, len , &actual_l, 500);
122 return ret;
123}
124
125static int lme2510_bulk_read(struct usb_device *dev,
126 u8 *rev, int len, u8 pipe)
127{
128 int ret, actual_l;
129
130 ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, pipe),
131 rev, len , &actual_l, 500);
132 return ret;
133}
134
135static int lme2510_usb_talk(struct dvb_usb_device *d,
136 u8 *wbuf, int wlen, u8 *rbuf, int rlen)
137{
138 struct lme2510_state *st = d->priv;
139 u8 *buff;
140 int ret = 0;
141
142 if (st->usb_buffer == NULL) {
143 st->usb_buffer = kmalloc(512, GFP_KERNEL);
144 if (st->usb_buffer == NULL) {
145 info("MEM Error no memory");
146 return -ENOMEM;
147 }
148 }
149 buff = st->usb_buffer;
150
151 /* the read/write capped at 512 */
152 memcpy(buff, wbuf, (wlen > 512) ? 512 : wlen);
153
154
155 ret = mutex_lock_interruptible(&d->usb_mutex);
156
157 if (ret < 0)
158 return -EAGAIN;
159
160 ret |= usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, 0x01));
161 msleep(5);
162 ret |= lme2510_bulk_write(d->udev, buff, wlen , 0x1);
163
164 msleep(5);
165 ret |= usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, 0x1));
166
167 msleep(5);
168 ret |= lme2510_bulk_read(d->udev, buff, (rlen > 512) ?
169 512 : rlen , 0x1);
170
171 if (rlen > 0)
172 memcpy(rbuf, buff, rlen);
173
174 mutex_unlock(&d->usb_mutex);
175
176 return (ret < 0) ? -ENODEV : 0;
177}
178
179static int lme2510_remote_keypress(struct dvb_usb_adapter *adap, u16 keypress)
180{
181 struct dvb_usb_device *d = adap->dev;
182
183 deb_info(1, "INT Key Keypress =%04x", keypress);
184
185 if (keypress > 0)
186 ir_keydown(d->rc_input_dev, keypress, 0);
187
188 return 0;
189}
190
191static void lme2510_int_response(struct urb *lme_urb)
192{
193 struct dvb_usb_adapter *adap = lme_urb->context;
194 struct lme2510_state *st = adap->dev->priv;
195 static u8 *ibuf, *rbuf;
196 int i = 0, offset;
197
198 switch (lme_urb->status) {
199 case 0:
200 case -ETIMEDOUT:
201 break;
202 case -ECONNRESET:
203 case -ENOENT:
204 case -ESHUTDOWN:
205 return;
206 default:
207 info("Error %x", lme_urb->status);
208 break;
209 }
210
211 rbuf = (u8 *) lme_urb->transfer_buffer;
212
213 offset = ((lme_urb->actual_length/8) > 4)
214 ? 4 : (lme_urb->actual_length/8) ;
215
216
217 for (i = 0; i < offset; ++i) {
218 ibuf = (u8 *)&rbuf[i*8];
219 deb_info(5, "INT O/S C =%02x C/O=%02x Type =%02x%02x",
220 offset, i, ibuf[0], ibuf[1]);
221
222 switch (ibuf[0]) {
223 case 0xaa:
224 debug_data_snipet(1, "INT Remote data snipet in", ibuf);
225 lme2510_remote_keypress(adap,
226 (u16)(ibuf[4]<<8)+ibuf[5]);
227 break;
228 case 0xbb:
229 switch (st->tuner_config) {
230 case TUNER_LG:
231 st->signal_lock = ibuf[2];
232 st->signal_level = ibuf[4];
233 st->signal_sn = ibuf[3];
234 st->time_key = ibuf[7];
235 break;
236 case TUNER_S7395:
237 /* Tweak for earlier firmware*/
238 if (ibuf[1] == 0x03) {
239 st->signal_level = ibuf[3];
240 st->signal_sn = ibuf[2];
241 } else {
242 st->signal_level = ibuf[4];
243 st->signal_sn = ibuf[5];
244 }
245 break;
246 default:
247 break;
248 }
249 debug_data_snipet(5, "INT Remote data snipet in", ibuf);
250 break;
251 case 0xcc:
252 debug_data_snipet(1, "INT Control data snipet", ibuf);
253 break;
254 default:
255 debug_data_snipet(1, "INT Unknown data snipet", ibuf);
256 break;
257 }
258 }
259 usb_submit_urb(lme_urb, GFP_ATOMIC);
260}
261
262static int lme2510_int_read(struct dvb_usb_adapter *adap)
263{
264 struct lme2510_state *lme_int = adap->dev->priv;
265
266 lme_int->lme_urb = usb_alloc_urb(0, GFP_ATOMIC);
267
268 if (lme_int->lme_urb == NULL)
269 return -ENOMEM;
270
271 lme_int->buffer = usb_alloc_coherent(adap->dev->udev, 5000, GFP_ATOMIC,
272 &lme_int->lme_urb->transfer_dma);
273
274 if (lme_int->buffer == NULL)
275 return -ENOMEM;
276
277 usb_fill_int_urb(lme_int->lme_urb,
278 adap->dev->udev,
279 usb_rcvintpipe(adap->dev->udev, 0xa),
280 lme_int->buffer,
281 4096,
282 lme2510_int_response,
283 adap,
284 11);
285
286 lme_int->lme_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
287
288 usb_submit_urb(lme_int->lme_urb, GFP_ATOMIC);
289 info("INT Interupt Service Started");
290
291 return 0;
292}
293
294static int lme2510_return_status(struct usb_device *dev)
295{
296 int ret = 0;
297 u8 data[10] = {0};
298 ret |= usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
299 0x06, 0x80, 0x0302, 0x00, data, 0x0006, 200);
300 info("Firmware Status: %x (%x)", ret , data[2]);
301
302 return (ret < 0) ? -ENODEV : data[2];
303}
304
305static int lme2510_msg(struct dvb_usb_device *d,
306 u8 *wbuf, int wlen, u8 *rbuf, int rlen)
307{
308 int ret = 0;
309 struct lme2510_state *st = d->priv;
310
311 if (st->i2c_talk_onoff == 1) {
312 if ((wbuf[2] == 0x1c) & (wbuf[3] == 0x0e))
313 msleep(80); /*take your time when waiting for tune*/
314
315 if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
316 return -EAGAIN;
317
318 ret = lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
319
320 mutex_unlock(&d->i2c_mutex);
321 switch (st->tuner_config) {
322 case TUNER_S7395:
323 if (wbuf[3] == 0x24)
324 st->signal_lock = rbuf[1];
325 break;
326 default:
327 break;
328 }
329
330 } else {
331 switch (st->tuner_config) {
332 case TUNER_LG:
333 switch (wbuf[3]) {
334 case 0x0e:
335 rbuf[0] = 0x55;
336 rbuf[1] = st->signal_lock;
337 break;
338 case 0x43:
339 rbuf[0] = 0x55;
340 rbuf[1] = st->signal_level;
341 break;
342 case 0x1c:
343 rbuf[0] = 0x55;
344 rbuf[1] = st->signal_sn;
345 break;
346 default:
347 break;
348 }
349 break;
350 case TUNER_S7395:
351 switch (wbuf[3]) {
352 case 0x10:
353 rbuf[0] = 0x55;
354 rbuf[1] = (st->signal_level & 0x80)
355 ? 0 : (st->signal_level * 2);
356 break;
357 case 0x2d:
358 rbuf[0] = 0x55;
359 rbuf[1] = st->signal_sn;
360 break;
361 case 0x24:
362 rbuf[0] = 0x55;
363 rbuf[1] = (st->signal_level & 0x80)
364 ? 0 : st->signal_lock;
365 default:
366 break;
367 }
368 break;
369 default:
370 break;
371
372 }
373
374 deb_info(4, "I2C From Interupt Message out(%02x) in(%02x)",
375 wbuf[3], rbuf[1]);
376
377 }
378
379 return ret;
380}
381
382
383static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
384 int num)
385{
386 struct dvb_usb_device *d = i2c_get_adapdata(adap);
387 struct lme2510_state *st = d->priv;
388 static u8 obuf[64], ibuf[512];
389 int i, read, read_o;
390 u16 len;
391 u8 gate = st->i2c_gate;
392
393 if (gate == 0)
394 gate = 5;
395
396 if (num > 2)
397 warn("more than 2 i2c messages"
398 "at a time is not handled yet. TODO.");
399
400 for (i = 0; i < num; i++) {
401 read_o = 1 & (msg[i].flags & I2C_M_RD);
402 read = i+1 < num && (msg[i+1].flags & I2C_M_RD);
403 read |= read_o;
404 gate = (msg[i].addr == st->i2c_tuner_addr)
405 ? (read) ? st->i2c_tuner_gate_r
406 : st->i2c_tuner_gate_w
407 : st->i2c_gate;
408 obuf[0] = gate | (read << 7);
409
410 if (gate == 5)
411 obuf[1] = (read) ? 2 : msg[i].len + 1;
412 else
413 obuf[1] = msg[i].len + read + 1;
414
415 obuf[2] = msg[i].addr;
416 if (read) {
417 if (read_o)
418 len = 3;
419 else {
420 memcpy(&obuf[3], msg[i].buf, msg[i].len);
421 obuf[msg[i].len+3] = msg[i+1].len;
422 len = msg[i].len+4;
423 }
424 } else {
425 memcpy(&obuf[3], msg[i].buf, msg[i].len);
426 len = msg[i].len+3;
427 }
428
429 if (lme2510_msg(d, obuf, len, ibuf, 512) < 0) {
430 deb_info(1, "i2c transfer failed.");
431 return -EAGAIN;
432 }
433
434 if (read) {
435 if (read_o)
436 memcpy(msg[i].buf, &ibuf[1], msg[i].len);
437 else {
438 memcpy(msg[i+1].buf, &ibuf[1], msg[i+1].len);
439 i++;
440 }
441 }
442 }
443 return i;
444}
445
446static u32 lme2510_i2c_func(struct i2c_adapter *adapter)
447{
448 return I2C_FUNC_I2C;
449}
450
451static struct i2c_algorithm lme2510_i2c_algo = {
452 .master_xfer = lme2510_i2c_xfer,
453 .functionality = lme2510_i2c_func,
454};
455
456/* Callbacks for DVB USB */
457static int lme2510_identify_state(struct usb_device *udev,
458 struct dvb_usb_device_properties *props,
459 struct dvb_usb_device_description **desc,
460 int *cold)
461{
462 if (lme2510_return_status(udev) == 0x44)
463 *cold = 1;
464 else
465 *cold = 0;
466 return 0;
467}
468
469static int lme2510_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
470{
471 struct lme2510_state *st = adap->dev->priv;
472 static u8 reset[] = LME_RESET;
473 static u8 stream_on[] = LME_ST_ON_W;
474 static u8 clear_reg_3[] = LME_CLEAR_PID;
475 static u8 rbuf[1];
476 int ret = 0, len = 2, rlen = sizeof(rbuf);
477
478 deb_info(1, "STM (%02x)", onoff);
479
480 if (onoff == 1) {
481 st->i2c_talk_onoff = 0;
482 msleep(400); /* give enough time for i2c to stop */
483 ret |= lme2510_usb_talk(adap->dev,
484 stream_on, len, rbuf, rlen);
485 } else {
486 deb_info(1, "STM Steam Off");
487 if (st->tuner_config == TUNER_LG)
488 ret |= lme2510_usb_talk(adap->dev, clear_reg_3,
489 sizeof(clear_reg_3), rbuf, rlen);
490 else
491 ret |= lme2510_usb_talk(adap->dev,
492 reset, sizeof(reset), rbuf, rlen);
493
494 msleep(400);
495 st->i2c_talk_onoff = 1;
496 }
497
498 return (ret < 0) ? -ENODEV : 0;
499}
500
501static int lme2510_int_service(struct dvb_usb_adapter *adap)
502{
503 struct dvb_usb_device *d = adap->dev;
504 struct input_dev *input_dev;
505 char *ir_codes = RC_MAP_LME2510;
506 int ret = 0;
507
508 info("STA Configuring Remote");
509
510 usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
511
512 strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys));
513
514 input_dev = input_allocate_device();
515 if (!input_dev)
516 return -ENOMEM;
517
518 input_dev->name = "LME2510 Remote Control";
519 input_dev->phys = d->rc_phys;
520
521 usb_to_input_id(d->udev, &input_dev->id);
522
523 ret |= ir_input_register(input_dev, ir_codes, NULL, "LME 2510");
524
525 if (ret) {
526 input_free_device(input_dev);
527 return ret;
528 }
529
530 d->rc_input_dev = input_dev;
531 /* Start the Interupt */
532 ret = lme2510_int_read(adap);
533
534 if (ret < 0) {
535 ir_input_unregister(input_dev);
536 input_free_device(input_dev);
537 }
538 return (ret < 0) ? -ENODEV : 0;
539}
540
541static u8 check_sum(u8 *p, u8 len)
542{
543 u8 sum = 0;
544 while (len--)
545 sum += *p++;
546 return sum;
547}
548
549static int lme2510_download_firmware(struct usb_device *dev,
550 const struct firmware *fw)
551{
552 int ret = 0;
553 u8 data[512] = {0};
554 u16 j, wlen, len_in, start, end;
555 u8 packet_size, dlen, i;
556 u8 *fw_data;
557
558 packet_size = 0x31;
559 len_in = 1;
560
561
562 info("FRM Starting Firmware Download");
563
564 for (i = 1; i < 3; i++) {
565 start = (i == 1) ? 0 : 512;
566 end = (i == 1) ? 512 : fw->size;
567 for (j = start; j < end; j += (packet_size+1)) {
568 fw_data = (u8 *)(fw->data + j);
569 if ((end - j) > packet_size) {
570 data[0] = i;
571 dlen = packet_size;
572 } else {
573 data[0] = i | 0x80;
574 dlen = (u8)(end - j)-1;
575 }
576 data[1] = dlen;
577 memcpy(&data[2], fw_data, dlen+1);
578 wlen = (u8) dlen + 4;
579 data[wlen-1] = check_sum(fw_data, dlen+1);
580 deb_info(1, "Data S=%02x:E=%02x CS= %02x", data[3],
581 data[dlen+2], data[dlen+3]);
582 ret |= lme2510_bulk_write(dev, data, wlen, 1);
583 ret |= lme2510_bulk_read(dev, data, len_in , 1);
584 ret |= (data[0] == 0x88) ? 0 : -1;
585 }
586 }
587 usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
588 0x06, 0x80, 0x0200, 0x00, data, 0x0109, 1000);
589
590
591 data[0] = 0x8a;
592 len_in = 1;
593 msleep(2000);
594 ret |= lme2510_bulk_write(dev, data , len_in, 1); /*Resetting*/
595 ret |= lme2510_bulk_read(dev, data, len_in, 1);
596 msleep(400);
597
598 if (ret < 0)
599 info("FRM Firmware Download Failed (%04x)" , ret);
600 else
601 info("FRM Firmware Download Completed - Resetting Device");
602
603
604 return (ret < 0) ? -ENODEV : 0;
605}
606
607
608static int lme2510_kill_urb(struct usb_data_stream *stream)
609{
610 int i;
611 for (i = 0; i < stream->urbs_submitted; i++) {
612 deb_info(3, "killing URB no. %d.", i);
613
614 /* stop the URB */
615 usb_kill_urb(stream->urb_list[i]);
616 }
617 stream->urbs_submitted = 0;
618 return 0;
619}
620
621static struct tda10086_config tda10086_config = {
622 .demod_address = 0x1c,
623 .invert = 0,
624 .diseqc_tone = 1,
625 .xtal_freq = TDA10086_XTAL_16M,
626};
627
628static struct stv0288_config lme_config = {
629 .demod_address = 0xd0,
630 .min_delay_ms = 15,
631 .inittab = s7395_inittab,
632};
633
634static struct ix2505v_config lme_tuner = {
635 .tuner_address = 0xc0,
636 .min_delay_ms = 100,
637 .tuner_gain = 0x0,
638 .tuner_chargepump = 0x3,
639};
640
641
642static int dm04_lme2510_set_voltage(struct dvb_frontend *fe,
643 fe_sec_voltage_t voltage)
644{
645 struct dvb_usb_adapter *adap = fe->dvb->priv;
646 struct lme2510_state *st = adap->dev->priv;
647 static u8 voltage_low[] = LME_VOLTAGE_L;
648 static u8 voltage_high[] = LME_VOLTAGE_H;
649 static u8 reset[] = LME_RESET;
650 static u8 clear_reg_3[] = LME_CLEAR_PID;
651 static u8 rbuf[1];
652 int ret = 0, len = 3, rlen = 1;
653
654 msleep(100);
655
656 if (st->tuner_config == TUNER_LG)
657 ret |= lme2510_usb_talk(adap->dev, clear_reg_3,
658 sizeof(clear_reg_3), rbuf, rlen);
659 else
660 ret |= lme2510_usb_talk(adap->dev,
661 reset, sizeof(reset), rbuf, rlen);
662
663 /*always check & stop streaming*/
664 lme2510_kill_urb(&adap->stream);
665 adap->feedcount = 0;
666
667 switch (voltage) {
668
669 case SEC_VOLTAGE_18:
670 ret |= lme2510_usb_talk(adap->dev,
671 voltage_high, len, rbuf, rlen);
672 break;
673
674 case SEC_VOLTAGE_OFF:
675 case SEC_VOLTAGE_13:
676 default:
677 ret |= lme2510_usb_talk(adap->dev,
678 voltage_low, len, rbuf, rlen);
679 break;
680
681
682 };
683 st->i2c_talk_onoff = 1;
684 return (ret < 0) ? -ENODEV : 0;
685}
686
687static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
688{
689 int ret = 0;
690 struct lme2510_state *st = adap->dev->priv;
691
692 /* Interupt Start */
693 ret = lme2510_int_service(adap);
694 if (ret < 0) {
695 info("INT Unable to start Interupt Service");
696 return -ENODEV;
697 }
698
699 st->i2c_talk_onoff = 1;
700 st->i2c_gate = 4;
701
702 adap->fe = dvb_attach(tda10086_attach, &tda10086_config,
703 &adap->dev->i2c_adap);
704
705 if (adap->fe) {
706 info("TUN Found Frontend TDA10086");
707 memcpy(&adap->fe->ops.info.name,
708 &"DM04_LG_TDQY-P001F DVB-S", 24);
709 adap->fe->ops.set_voltage = dm04_lme2510_set_voltage;
710 st->i2c_tuner_gate_w = 4;
711 st->i2c_tuner_gate_r = 4;
712 st->i2c_tuner_addr = 0xc0;
713 if (dvb_attach(tda826x_attach, adap->fe, 0xc0,
714 &adap->dev->i2c_adap, 1)) {
715 info("TUN TDA8263 Found");
716 st->tuner_config = TUNER_LG;
717 return 0;
718 }
719 kfree(adap->fe);
720 adap->fe = NULL;
721 }
722 st->i2c_gate = 5;
723 adap->fe = dvb_attach(stv0288_attach, &lme_config,
724 &adap->dev->i2c_adap);
725
726 if (adap->fe) {
727 info("FE Found Stv0288");
728 memcpy(&adap->fe->ops.info.name,
729 &"DM04_SHARP:BS2F7HZ7395", 22);
730 adap->fe->ops.set_voltage = dm04_lme2510_set_voltage;
731 st->i2c_tuner_gate_w = 4;
732 st->i2c_tuner_gate_r = 5;
733 st->i2c_tuner_addr = 0xc0;
734 if (dvb_attach(ix2505v_attach , adap->fe, &lme_tuner,
735 &adap->dev->i2c_adap)) {
736 st->tuner_config = TUNER_S7395;
737 info("TUN Sharp IX2505V silicon tuner");
738 return 0;
739 }
740 kfree(adap->fe);
741 adap->fe = NULL;
742 }
743
744 info("DM04 Not Supported");
745 return -ENODEV;
746}
747
748static int lme2510_powerup(struct dvb_usb_device *d, int onoff)
749{
750 struct lme2510_state *st = d->priv;
751 st->i2c_talk_onoff = 1;
752 return 0;
753}
754
755/* DVB USB Driver stuff */
756static struct dvb_usb_device_properties lme2510_properties;
757static struct dvb_usb_device_properties lme2510c_properties;
758
759static int lme2510_probe(struct usb_interface *intf,
760 const struct usb_device_id *id)
761{
762 struct usb_device *udev = interface_to_usbdev(intf);
763 int ret = 0;
764
765 usb_reset_configuration(udev);
766
767 usb_set_interface(udev, intf->cur_altsetting->desc.bInterfaceNumber, 1);
768
769 if (udev->speed != USB_SPEED_HIGH) {
770 ret = usb_reset_device(udev);
771 info("DEV Failed to connect in HIGH SPEED mode");
772 return -ENODEV;
773 }
774
775 if (0 == dvb_usb_device_init(intf, &lme2510_properties,
776 THIS_MODULE, NULL, adapter_nr)) {
777 info("DEV registering device driver");
778 return 0;
779 }
780 if (0 == dvb_usb_device_init(intf, &lme2510c_properties,
781 THIS_MODULE, NULL, adapter_nr)) {
782 info("DEV registering device driver");
783 return 0;
784 }
785
786 info("DEV lme2510 Error");
787 return -ENODEV;
788
789}
790
791static struct usb_device_id lme2510_table[] = {
792 { USB_DEVICE(0x3344, 0x1122) }, /* LME2510 */
793 { USB_DEVICE(0x3344, 0x1120) }, /* LME2510C */
794 {} /* Terminating entry */
795};
796
797MODULE_DEVICE_TABLE(usb, lme2510_table);
798
799static struct dvb_usb_device_properties lme2510_properties = {
800 .caps = DVB_USB_IS_AN_I2C_ADAPTER,
801 .usb_ctrl = DEVICE_SPECIFIC,
802 .download_firmware = lme2510_download_firmware,
803 .firmware = "dvb-usb-lme2510-lg.fw",
804
805 .size_of_priv = sizeof(struct lme2510_state),
806 .num_adapters = 1,
807 .adapter = {
808 {
809 .streaming_ctrl = lme2510_streaming_ctrl,
810 .frontend_attach = dm04_lme2510_frontend_attach,
811 /* parameter for the MPEG2-data transfer */
812 .stream = {
813 .type = USB_BULK,
814 .count = 10,
815 .endpoint = 0x06,
816 .u = {
817 .bulk = {
818 .buffersize = 4096,
819
820 }
821 }
822 }
823 }
824 },
825 .power_ctrl = lme2510_powerup,
826 .identify_state = lme2510_identify_state,
827 .i2c_algo = &lme2510_i2c_algo,
828 .generic_bulk_ctrl_endpoint = 0,
829 .num_device_descs = 1,
830 .devices = {
831 { "DM04 LME2510 DVB-S USB 2.0",
832 { &lme2510_table[0], NULL },
833 },
834
835 }
836};
837
838static struct dvb_usb_device_properties lme2510c_properties = {
839 .caps = DVB_USB_IS_AN_I2C_ADAPTER,
840 .usb_ctrl = DEVICE_SPECIFIC,
841 .download_firmware = lme2510_download_firmware,
842 .firmware = "dvb-usb-lme2510c-s7395.fw",
843 .size_of_priv = sizeof(struct lme2510_state),
844 .num_adapters = 1,
845 .adapter = {
846 {
847 .streaming_ctrl = lme2510_streaming_ctrl,
848 .frontend_attach = dm04_lme2510_frontend_attach,
849 /* parameter for the MPEG2-data transfer */
850 .stream = {
851 .type = USB_BULK,
852 .count = 8,
853 .endpoint = 0x8,
854 .u = {
855 .bulk = {
856 .buffersize = 4096,
857
858 }
859 }
860 }
861 }
862 },
863 .power_ctrl = lme2510_powerup,
864 .identify_state = lme2510_identify_state,
865 .i2c_algo = &lme2510_i2c_algo,
866 .generic_bulk_ctrl_endpoint = 0,
867 .num_device_descs = 1,
868 .devices = {
869 { "DM04 LME2510C USB2.0",
870 { &lme2510_table[1], NULL },
871 },
872 }
873};
874
875void lme2510_exit_int(struct dvb_usb_device *d)
876{
877 struct lme2510_state *st = d->priv;
878 if (st->lme_urb != NULL) {
879 st->i2c_talk_onoff = 0;
880 st->signal_lock = 0;
881 st->signal_level = 0;
882 st->signal_sn = 0;
883 kfree(st->usb_buffer);
884 usb_kill_urb(st->lme_urb);
885 usb_free_coherent(d->udev, 5000, st->buffer,
886 st->lme_urb->transfer_dma);
887 info("Interupt Service Stopped");
888 ir_input_unregister(d->rc_input_dev);
889 info("Remote Stopped");
890 }
891 return;
892}
893
894void lme2510_exit(struct usb_interface *intf)
895{
896 struct dvb_usb_device *d = usb_get_intfdata(intf);
897 if (d != NULL) {
898 d->adapter[0].feedcount = 0;
899 lme2510_exit_int(d);
900 dvb_usb_device_exit(intf);
901 }
902
903}
904
905static struct usb_driver lme2510_driver = {
906 .name = "LME2510C_DVBS",
907 .probe = lme2510_probe,
908 .disconnect = lme2510_exit,
909 .id_table = lme2510_table,
910};
911
912/* module stuff */
913static int __init lme2510_module_init(void)
914{
915 int result = usb_register(&lme2510_driver);
916 if (result) {
917 err("usb_register failed. Error number %d", result);
918 return result;
919 }
920
921 return 0;
922}
923
924static void __exit lme2510_module_exit(void)
925{
926 /* deregister this driver from the USB subsystem */
927 usb_deregister(&lme2510_driver);
928}
929
930module_init(lme2510_module_init);
931module_exit(lme2510_module_exit);
932
933MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
934MODULE_DESCRIPTION("LM2510(C) DVB-S USB2.0");
935MODULE_VERSION("1.4");
936MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/lmedm04.h b/drivers/media/dvb/dvb-usb/lmedm04.h
new file mode 100644
index 000000000000..5a66c7ec4511
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/lmedm04.h
@@ -0,0 +1,187 @@
1/* DVB USB compliant linux driver for
2 *
3 * DM04/QQBOX DVB-S USB BOX LME2510C + SHARP:BS2F7HZ7395
4 * LME2510C + LGTDQT-P001F
5 *
6 * MVB7395 (LME2510C+SHARP:BS2F7HZ7395)
7 * SHARP:BS2F7HZ7395 = (STV0288+Sharp IX2505V)
8 *
9 * MVB0001F (LME2510C+LGTDQT-P001F)
10 * LG TDQY - P001F =(TDA8263 + TDA10086H)
11 *
12 *
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the Free
15 * Software Foundation, version 2.
16 * *
17 * see Documentation/dvb/README.dvb-usb for more information
18 */
19#ifndef _DVB_USB_LME2510_H_
20#define _DVB_USB_LME2510_H_
21
22/* Streamer & PID
23 *
24 * Note: These commands do not actually stop the streaming
25 * but form some kind of packet filtering/stream count
26 * or tuning related functions.
27 * 06 XX
28 * offset 1 = 00 Enable Streaming
29 *
30 *
31 * PID
32 * 03 XX XX ----> reg number ---> setting....20 XX
33 * offset 1 = length
34 * offset 2 = start of data
35 * end byte -1 = 20
36 * end byte = clear pid always a0, other wise 9c, 9a ??
37 *
38 * RESET (also clears PID filter)
39 * 3a 01 00
40*/
41#define LME_ST_ON_W {0x06, 0x00}
42#define LME_RESET {0x3a, 0x01, 0x00}
43#define LME_CLEAR_PID {0x03, 0x02, 0x20, 0xa0}
44
45
46/* LME Power Control
47 * 07 XX XX
48 * offset 1 = 01 Power? my device cannot be powered down
49 * offset 2 = 00=Voltage low 01=Voltage high
50 */
51
52#define LME_VOLTAGE_L {0x07, 0x01, 0x00}
53#define LME_VOLTAGE_H {0x07, 0x01, 0x01}
54
55
56/* Initial stv0288 settings for 7395 Frontend */
57static u8 s7395_inittab[] = {
58 0x00, 0x11,
59 0x01, 0x15,
60 0x02, 0x20,
61 0x03, 0x8e,
62 0x04, 0x8e,
63 0x05, 0x12,
64 0x06, 0xff,
65 0x07, 0x20,
66 0x08, 0x00,
67 0x09, 0x00,
68 0x0a, 0x04,
69 0x0b, 0x00,
70 0x0c, 0x00,
71 0x0d, 0x00,
72 0x0e, 0xc1,
73 0x0f, 0x54,
74 0x10, 0x40,
75 0x11, 0x7a,
76 0x12, 0x03,
77 0x13, 0x48,
78 0x14, 0x84,
79 0x15, 0xc5,
80 0x16, 0xb8,
81 0x17, 0x9c,
82 0x18, 0x00,
83 0x19, 0xa6,
84 0x1a, 0x88,
85 0x1b, 0x8f,
86 0x1c, 0xf0,
87 0x1e, 0x80,
88 0x20, 0x0b,
89 0x21, 0x54,
90 0x22, 0xff,
91 0x23, 0x01,
92 0x24, 0x9a,
93 0x25, 0x7f,
94 0x26, 0x00,
95 0x27, 0x00,
96 0x28, 0x46,
97 0x29, 0x66,
98 0x2a, 0x90,
99 0x2b, 0xfa,
100 0x2c, 0xd9,
101 0x2d, 0x02,
102 0x2e, 0xb1,
103 0x2f, 0x00,
104 0x30, 0x0,
105 0x31, 0x1e,
106 0x32, 0x14,
107 0x33, 0x0f,
108 0x34, 0x09,
109 0x35, 0x0c,
110 0x36, 0x05,
111 0x37, 0x2f,
112 0x38, 0x16,
113 0x39, 0xbd,
114 0x3a, 0x0,
115 0x3b, 0x13,
116 0x3c, 0x11,
117 0x3d, 0x30,
118 0x3e, 0x00,
119 0x3f, 0x00,
120 0x40, 0x63,
121 0x41, 0x04,
122 0x42, 0x60,
123 0x43, 0x00,
124 0x44, 0x00,
125 0x45, 0x00,
126 0x46, 0x00,
127 0x47, 0x00,
128 0x4a, 0x00,
129 0x4b, 0xd1,
130 0x4c, 0x33,
131 0x50, 0x12,
132 0x51, 0x36,
133 0x52, 0x21,
134 0x53, 0x94,
135 0x54, 0xb2,
136 0x55, 0x29,
137 0x56, 0x64,
138 0x57, 0x2b,
139 0x58, 0x54,
140 0x59, 0x86,
141 0x5a, 0x00,
142 0x5b, 0x9b,
143 0x5c, 0x08,
144 0x5d, 0x7f,
145 0x5e, 0xff,
146 0x5f, 0x8d,
147 0x70, 0x0,
148 0x71, 0x0,
149 0x72, 0x0,
150 0x74, 0x0,
151 0x75, 0x0,
152 0x76, 0x0,
153 0x81, 0x0,
154 0x82, 0x3f,
155 0x83, 0x3f,
156 0x84, 0x0,
157 0x85, 0x0,
158 0x88, 0x0,
159 0x89, 0x0,
160 0x8a, 0x0,
161 0x8b, 0x0,
162 0x8c, 0x0,
163 0x90, 0x0,
164 0x91, 0x0,
165 0x92, 0x0,
166 0x93, 0x0,
167 0x94, 0x1c,
168 0x97, 0x0,
169 0xa0, 0x48,
170 0xa1, 0x0,
171 0xb0, 0xb8,
172 0xb1, 0x3a,
173 0xb2, 0x10,
174 0xb3, 0x82,
175 0xb4, 0x80,
176 0xb5, 0x82,
177 0xb6, 0x82,
178 0xb7, 0x82,
179 0xb8, 0x20,
180 0xb9, 0x0,
181 0xf0, 0x0,
182 0xf1, 0x0,
183 0xf2, 0xc0,
184 0xff, 0xff,
185};
186
187#endif