aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb/dvb-usb/cxusb.c
diff options
context:
space:
mode:
authorPatrick Boettcher <pb@linuxtv.org>2005-07-07 20:58:10 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-07-07 21:23:59 -0400
commit22c6d93a73105fddd58796d7cb10f5f90ee2a338 (patch)
treec5d49186c531e768fd5b137e3a573bcee0011600 /drivers/media/dvb/dvb-usb/cxusb.c
parent49dc82fdac3866e6ce9c978df80cedfb735d740c (diff)
[PATCH] dvb: usb: support Medion hybrid USB2.0 DVB-T/analogue box
Add preliminary support for the Medion Hybrid USB2.0 DVB-T/Analogue box. Analogue part is not working yet (cx25842 --> ivtv?). Signed-off-by: Patrick Boettcher <pb@linuxtv.org> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/media/dvb/dvb-usb/cxusb.c')
-rw-r--r--drivers/media/dvb/dvb-usb/cxusb.c287
1 files changed, 287 insertions, 0 deletions
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
new file mode 100644
index 000000000000..0324807376cf
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -0,0 +1,287 @@
1/* DVB USB compliant linux driver for Conexant USB reference design.
2 *
3 * The Conexant reference design I saw on their website was only for analogue
4 * capturing (using the cx25842). The box I took to write this driver (reverse
5 * engineered) is the one labeled Medion MD95700. In addition to the cx25842
6 * for analogue capturing it also has a cx22702 DVB-T demodulator on the main
7 * board. Besides it has a atiremote (X10) and a USB2.0 hub onboard.
8 *
9 * Maybe it is a little bit premature to call this driver cxusb, but I assume
10 * the USB protocol is identical or at least inherited from the reference
11 * design, so it can be reused for the "analogue-only" device (if it will
12 * appear at all).
13 *
14 * TODO: check if the cx25840-driver (from ivtv) can be used for the analogue
15 * part
16 *
17 * FIXME: We're getting a lock and signal, but the isochronous transfer is empty
18 * for DVB-T.
19 *
20 * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de)
21 *
22 * This program is free software; you can redistribute it and/or modify it
23 * under the terms of the GNU General Public License as published by the Free
24 * Software Foundation, version 2.
25 *
26 * see Documentation/dvb/README.dvb-usb for more information
27 */
28#include "cxusb.h"
29
30#include "cx22702.h"
31
32/* debug */
33int dvb_usb_cxusb_debug;
34module_param_named(debug,dvb_usb_cxusb_debug, int, 0644);
35MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
36
37static int cxusb_ctrl_msg(struct dvb_usb_device *d,
38 u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
39{
40 int wo = (rbuf == NULL || rlen == 0); /* write-only */
41 u8 sndbuf[1+wlen];
42 memset(sndbuf,0,1+wlen);
43
44 sndbuf[0] = cmd;
45 memcpy(&sndbuf[1],wbuf,wlen);
46 if (wo)
47 dvb_usb_generic_write(d,sndbuf,1+wlen);
48 else
49 dvb_usb_generic_rw(d,sndbuf,1+wlen,rbuf,rlen,0);
50
51 return 0;
52}
53
54/* I2C */
55static void cxusb_set_i2c_path(struct dvb_usb_device *d, enum cxusb_i2c_pathes path)
56{
57 struct cxusb_state *st = d->priv;
58 u8 o[2],i;
59
60 if (path == st->cur_i2c_path)
61 return;
62
63 o[0] = IOCTL_SET_I2C_PATH;
64 switch (path) {
65 case PATH_CX22702:
66 o[1] = 0;
67 break;
68 case PATH_TUNER_OTHER:
69 o[1] = 1;
70 break;
71 default:
72 err("unkown i2c path");
73 return;
74 }
75 cxusb_ctrl_msg(d,CMD_IOCTL,o,2,&i,1);
76
77 if (i != 0x01)
78 deb_info("i2c_path setting failed.\n");
79
80 st->cur_i2c_path = path;
81}
82
83static int cxusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
84{
85 struct dvb_usb_device *d = i2c_get_adapdata(adap);
86 int i;
87
88 if (down_interruptible(&d->i2c_sem) < 0)
89 return -EAGAIN;
90
91 if (num > 2)
92 warn("more than 2 i2c messages at a time is not handled yet. TODO.");
93
94 for (i = 0; i < num; i++) {
95
96 switch (msg[i].addr) {
97 case 0x63:
98 cxusb_set_i2c_path(d,PATH_CX22702);
99 break;
100 default:
101 cxusb_set_i2c_path(d,PATH_TUNER_OTHER);
102 break;
103 }
104
105 /* read request */
106 if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
107 u8 obuf[3+msg[i].len], ibuf[1+msg[i+1].len];
108 obuf[0] = msg[i].len;
109 obuf[1] = msg[i+1].len;
110 obuf[2] = msg[i].addr;
111 memcpy(&obuf[3],msg[i].buf,msg[i].len);
112
113 if (cxusb_ctrl_msg(d, CMD_I2C_READ,
114 obuf, 3+msg[i].len,
115 ibuf, 1+msg[i+1].len) < 0)
116 break;
117
118 if (ibuf[0] != 0x08)
119 deb_info("i2c read could have been failed\n");
120
121 memcpy(msg[i+1].buf,&ibuf[1],msg[i+1].len);
122
123 i++;
124 } else { /* write */
125 u8 obuf[2+msg[i].len], ibuf;
126 obuf[0] = msg[i].addr;
127 obuf[1] = msg[i].len;
128 memcpy(&obuf[2],msg[i].buf,msg[i].len);
129
130 if (cxusb_ctrl_msg(d,CMD_I2C_WRITE, obuf, 2+msg[i].len, &ibuf,1) < 0)
131 break;
132 if (ibuf != 0x08)
133 deb_info("i2c write could have been failed\n");
134 }
135 }
136
137 up(&d->i2c_sem);
138 return i;
139}
140
141static u32 cxusb_i2c_func(struct i2c_adapter *adapter)
142{
143 return I2C_FUNC_I2C;
144}
145
146static struct i2c_algorithm cxusb_i2c_algo = {
147 .name = "Conexant USB I2C algorithm",
148 .id = I2C_ALGO_BIT,
149 .master_xfer = cxusb_i2c_xfer,
150 .functionality = cxusb_i2c_func,
151};
152
153static int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff)
154{
155 return 0;
156}
157
158static int cxusb_streaming_ctrl(struct dvb_usb_device *d, int onoff)
159{
160 return 0;
161}
162
163struct cx22702_config cxusb_cx22702_config = {
164 .demod_address = 0x63,
165
166 .pll_init = dvb_usb_pll_init_i2c,
167 .pll_set = dvb_usb_pll_set_i2c,
168};
169
170/* Callbacks for DVB USB */
171static int cxusb_tuner_attach(struct dvb_usb_device *d)
172{
173 u8 bpll[4] = { 0x0b, 0xdc, 0x9c, 0xa0 };
174 d->pll_addr = 0x61;
175 memcpy(d->pll_init,bpll,4);
176 d->pll_desc = &dvb_pll_fmd1216me;
177 return 0;
178}
179
180static int cxusb_frontend_attach(struct dvb_usb_device *d)
181{
182 u8 buf[2] = { 0x03, 0x00 };
183 u8 b = 0;
184
185 cxusb_ctrl_msg(d,0xde,&b,0,NULL,0);
186 cxusb_set_i2c_path(d,PATH_TUNER_OTHER);
187 cxusb_ctrl_msg(d,CMD_POWER_OFF, NULL, 0, &b, 1);
188
189 if (usb_set_interface(d->udev,0,6) < 0)
190 err("set interface failed\n");
191
192 cxusb_ctrl_msg(d,0x36, buf, 2, NULL, 0);
193 cxusb_set_i2c_path(d,PATH_CX22702);
194 cxusb_ctrl_msg(d,CMD_POWER_ON, NULL, 0, &b, 1);
195
196 if ((d->fe = cx22702_attach(&cxusb_cx22702_config, &d->i2c_adap)) != NULL)
197 return 0;
198
199 return -EIO;
200}
201
202/* DVB USB Driver stuff */
203static struct dvb_usb_properties cxusb_properties;
204
205static int cxusb_probe(struct usb_interface *intf,
206 const struct usb_device_id *id)
207{
208 return dvb_usb_device_init(intf,&cxusb_properties,THIS_MODULE);
209}
210
211static struct usb_device_id cxusb_table [] = {
212 { USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) },
213 {} /* Terminating entry */
214};
215MODULE_DEVICE_TABLE (usb, cxusb_table);
216
217static struct dvb_usb_properties cxusb_properties = {
218 .caps = DVB_USB_IS_AN_I2C_ADAPTER,
219
220 .usb_ctrl = CYPRESS_FX2,
221
222 .size_of_priv = sizeof(struct cxusb_state),
223
224 .streaming_ctrl = cxusb_streaming_ctrl,
225 .power_ctrl = cxusb_power_ctrl,
226 .frontend_attach = cxusb_frontend_attach,
227 .tuner_attach = cxusb_tuner_attach,
228
229 .i2c_algo = &cxusb_i2c_algo,
230
231 .generic_bulk_ctrl_endpoint = 0x01,
232 /* parameter for the MPEG2-data transfer */
233 .urb = {
234 .type = DVB_USB_ISOC,
235 .count = 5,
236 .endpoint = 0x02,
237 .u = {
238 .isoc = {
239 .framesperurb = 64,
240 .framesize = 940*3,
241 .interval = 1,
242 }
243 }
244 },
245
246 .num_device_descs = 1,
247 .devices = {
248 { "Medion MD95700 (MDUSBTV-HYBRID)",
249 { NULL },
250 { &cxusb_table[0], NULL },
251 },
252 }
253};
254
255static struct usb_driver cxusb_driver = {
256 .owner = THIS_MODULE,
257 .name = "cxusb",
258 .probe = cxusb_probe,
259 .disconnect = dvb_usb_device_exit,
260 .id_table = cxusb_table,
261};
262
263/* module stuff */
264static int __init cxusb_module_init(void)
265{
266 int result;
267 if ((result = usb_register(&cxusb_driver))) {
268 err("usb_register failed. Error number %d",result);
269 return result;
270 }
271
272 return 0;
273}
274
275static void __exit cxusb_module_exit(void)
276{
277 /* deregister this driver from the USB subsystem */
278 usb_deregister(&cxusb_driver);
279}
280
281module_init (cxusb_module_init);
282module_exit (cxusb_module_exit);
283
284MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
285MODULE_DESCRIPTION("Driver for Conexant USB2.0 hybrid reference design");
286MODULE_VERSION("1.0-alpha");
287MODULE_LICENSE("GPL");