]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/media/dvb/dvb-usb/cxusb.c
8ca07fdab03df891a6a88b6da277257e7369128a
[linux-2.6-omap-h63xx.git] / drivers / media / dvb / dvb-usb / cxusb.c
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  * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de)
18  *
19  *      This program is free software; you can redistribute it and/or modify it
20  *      under the terms of the GNU General Public License as published by the Free
21  *      Software Foundation, version 2.
22  *
23  * see Documentation/dvb/README.dvb-usb for more information
24  */
25 #include "cxusb.h"
26
27 #include "cx22702.h"
28 #include "lgdt330x.h"
29
30 /* debug */
31 int dvb_usb_cxusb_debug;
32 module_param_named(debug,dvb_usb_cxusb_debug, int, 0644);
33 MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
34
35 static int cxusb_ctrl_msg(struct dvb_usb_device *d,
36                 u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
37 {
38         int wo = (rbuf == NULL || rlen == 0); /* write-only */
39         u8 sndbuf[1+wlen];
40         memset(sndbuf,0,1+wlen);
41
42         sndbuf[0] = cmd;
43         memcpy(&sndbuf[1],wbuf,wlen);
44         if (wo)
45                 dvb_usb_generic_write(d,sndbuf,1+wlen);
46         else
47                 dvb_usb_generic_rw(d,sndbuf,1+wlen,rbuf,rlen,0);
48
49         return 0;
50 }
51
52 /* GPIO */
53 static void cxusb_gpio_tuner(struct dvb_usb_device *d, int onoff)
54 {
55         struct cxusb_state *st = d->priv;
56         u8 o[2],i;
57
58         if (st->gpio_write_state[GPIO_TUNER] == onoff)
59                 return;
60
61         o[0] = GPIO_TUNER;
62         o[1] = onoff;
63         cxusb_ctrl_msg(d,CMD_GPIO_WRITE,o,2,&i,1);
64
65         if (i != 0x01)
66                 deb_info("gpio_write failed.\n");
67
68         st->gpio_write_state[GPIO_TUNER] = onoff;
69 }
70
71 /* I2C */
72 static int cxusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
73 {
74         struct dvb_usb_device *d = i2c_get_adapdata(adap);
75         int i;
76
77         if (down_interruptible(&d->i2c_sem) < 0)
78                 return -EAGAIN;
79
80         if (num > 2)
81                 warn("more than 2 i2c messages at a time is not handled yet. TODO.");
82
83         for (i = 0; i < num; i++) {
84
85                 switch (msg[i].addr) {
86                         case 0x63:
87                                 cxusb_gpio_tuner(d,0);
88                                 break;
89                         default:
90                                 cxusb_gpio_tuner(d,1);
91                                 break;
92                 }
93
94                 /* read request */
95                 if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
96                         u8 obuf[3+msg[i].len], ibuf[1+msg[i+1].len];
97                         obuf[0] = msg[i].len;
98                         obuf[1] = msg[i+1].len;
99                         obuf[2] = msg[i].addr;
100                         memcpy(&obuf[3],msg[i].buf,msg[i].len);
101
102                         if (cxusb_ctrl_msg(d, CMD_I2C_READ,
103                                                 obuf, 3+msg[i].len,
104                                                 ibuf, 1+msg[i+1].len) < 0)
105                                 break;
106
107                         if (ibuf[0] != 0x08)
108                                 deb_info("i2c read could have been failed\n");
109
110                         memcpy(msg[i+1].buf,&ibuf[1],msg[i+1].len);
111
112                         i++;
113                 } else { /* write */
114                         u8 obuf[2+msg[i].len], ibuf;
115                         obuf[0] = msg[i].addr;
116                         obuf[1] = msg[i].len;
117                         memcpy(&obuf[2],msg[i].buf,msg[i].len);
118
119                         if (cxusb_ctrl_msg(d,CMD_I2C_WRITE, obuf, 2+msg[i].len, &ibuf,1) < 0)
120                                 break;
121                         if (ibuf != 0x08)
122                                 deb_info("i2c write could have been failed\n");
123                 }
124         }
125
126         up(&d->i2c_sem);
127         return i;
128 }
129
130 static u32 cxusb_i2c_func(struct i2c_adapter *adapter)
131 {
132         return I2C_FUNC_I2C;
133 }
134
135 static struct i2c_algorithm cxusb_i2c_algo = {
136         .master_xfer   = cxusb_i2c_xfer,
137         .functionality = cxusb_i2c_func,
138 };
139
140 static int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff)
141 {
142         u8 b = 0;
143         if (onoff)
144                 return cxusb_ctrl_msg(d, CMD_POWER_ON, &b, 1, NULL, 0);
145         else
146                 return cxusb_ctrl_msg(d, CMD_POWER_OFF, &b, 1, NULL, 0);
147 }
148
149 static int cxusb_streaming_ctrl(struct dvb_usb_device *d, int onoff)
150 {
151         u8 buf[2] = { 0x03, 0x00 };
152         if (onoff)
153                 cxusb_ctrl_msg(d,CMD_STREAMING_ON, buf, 2, NULL, 0);
154         else
155                 cxusb_ctrl_msg(d,CMD_STREAMING_OFF, NULL, 0, NULL, 0);
156
157         return 0;
158 }
159
160 struct cx22702_config cxusb_cx22702_config = {
161         .demod_address = 0x63,
162
163         .output_mode = CX22702_PARALLEL_OUTPUT,
164
165         .pll_init = dvb_usb_pll_init_i2c,
166         .pll_set  = dvb_usb_pll_set_i2c,
167 };
168
169 struct lgdt330x_config cxusb_lgdt330x_config = {
170         .demod_address = 0x0e,
171         .demod_chip    = LGDT3303,
172         .pll_set       = dvb_usb_pll_set_i2c,
173 };
174
175 /* Callbacks for DVB USB */
176 static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_device *d)
177 {
178         u8 bpll[4] = { 0x0b, 0xdc, 0x9c, 0xa0 };
179         d->pll_addr = 0x61;
180         memcpy(d->pll_init, bpll, 4);
181         d->pll_desc = &dvb_pll_fmd1216me;
182         return 0;
183 }
184
185 static int cxusb_lgh064f_tuner_attach(struct dvb_usb_device *d)
186 {
187         u8 bpll[4] = { 0x00, 0x00, 0x18, 0x50 };
188         /* bpll[2] : unset bit 3, set bits 4&5
189            bpll[3] : 0x50 - digital, 0x20 - analog */
190         d->pll_addr = 0x61;
191         memcpy(d->pll_init, bpll, 4);
192         d->pll_desc = &dvb_pll_tdvs_tua6034;
193         return 0;
194 }
195
196 static int cxusb_cx22702_frontend_attach(struct dvb_usb_device *d)
197 {
198         u8 b;
199         if (usb_set_interface(d->udev,0,6) < 0)
200                 err("set interface failed");
201
202         cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, &b, 1);
203
204         if ((d->fe = cx22702_attach(&cxusb_cx22702_config, &d->i2c_adap)) != NULL)
205                 return 0;
206
207         return -EIO;
208 }
209
210 static int cxusb_lgdt330x_frontend_attach(struct dvb_usb_device *d)
211 {
212         if (usb_set_interface(d->udev,0,0) < 0)
213                 err("set interface failed");
214
215         cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0);
216
217         if ((d->fe = lgdt330x_attach(&cxusb_lgdt330x_config, &d->i2c_adap)) != NULL)
218                 return 0;
219
220         return -EIO;
221 }
222
223 /* DVB USB Driver stuff */
224 static struct dvb_usb_properties cxusb_medion_properties;
225 static struct dvb_usb_properties cxusb_bluebird_atsc_properties;
226
227 static int cxusb_probe(struct usb_interface *intf,
228                 const struct usb_device_id *id)
229 {
230         if (dvb_usb_device_init(intf,&cxusb_medion_properties,THIS_MODULE,NULL) == 0 ||
231                 dvb_usb_device_init(intf,&cxusb_bluebird_atsc_properties,THIS_MODULE,NULL) == 0) {
232                 return 0;
233         }
234
235         return -EINVAL;
236 }
237
238 static struct usb_device_id cxusb_table [] = {
239                 { USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) },
240                 { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_COLD) },
241                 { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_WARM) },
242                 {}              /* Terminating entry */
243 };
244 MODULE_DEVICE_TABLE (usb, cxusb_table);
245
246 static struct dvb_usb_properties cxusb_medion_properties = {
247         .caps = DVB_USB_IS_AN_I2C_ADAPTER,
248
249         .usb_ctrl = CYPRESS_FX2,
250
251         .size_of_priv     = sizeof(struct cxusb_state),
252
253         .streaming_ctrl   = cxusb_streaming_ctrl,
254         .power_ctrl       = cxusb_power_ctrl,
255         .frontend_attach  = cxusb_cx22702_frontend_attach,
256         .tuner_attach     = cxusb_fmd1216me_tuner_attach,
257
258         .i2c_algo         = &cxusb_i2c_algo,
259
260         .generic_bulk_ctrl_endpoint = 0x01,
261         /* parameter for the MPEG2-data transfer */
262         .urb = {
263                 .type = DVB_USB_BULK,
264                 .count = 5,
265                 .endpoint = 0x02,
266                 .u = {
267                         .bulk = {
268                                 .buffersize = 8192,
269                         }
270                 }
271         },
272
273         .num_device_descs = 1,
274         .devices = {
275                 {   "Medion MD95700 (MDUSBTV-HYBRID)",
276                         { NULL },
277                         { &cxusb_table[0], NULL },
278                 },
279         }
280 };
281
282 static struct dvb_usb_properties cxusb_bluebird_atsc_properties = {
283         .caps = DVB_USB_IS_AN_I2C_ADAPTER,
284
285         .usb_ctrl         = CYPRESS_FX2,
286         .firmware         = "dvb-usb-bluebird-atsc-01.fw",
287
288         .size_of_priv     = sizeof(struct cxusb_state),
289
290         .streaming_ctrl   = cxusb_streaming_ctrl,
291         .power_ctrl       = cxusb_power_ctrl,
292         .frontend_attach  = cxusb_lgdt330x_frontend_attach,
293         .tuner_attach     = cxusb_lgh064f_tuner_attach,
294
295         .i2c_algo         = &cxusb_i2c_algo,
296
297         .generic_bulk_ctrl_endpoint = 0x01,
298         /* parameter for the MPEG2-data transfer */
299         .urb = {
300                 .type = DVB_USB_BULK,
301                 .count = 5,
302                 .endpoint = 0x02,
303                 .u = {
304                         .bulk = {
305                                 .buffersize = 8192,
306                         }
307                 }
308         },
309
310         .num_device_descs = 1,
311         .devices = {
312                 {   "DViCO FusionHDTV5 USB Gold",
313                         { &cxusb_table[1], NULL },
314                         { &cxusb_table[2], NULL },
315                 },
316         }
317 };
318
319 static struct usb_driver cxusb_driver = {
320         .name           = "dvb_usb_cxusb",
321         .probe          = cxusb_probe,
322         .disconnect = dvb_usb_device_exit,
323         .id_table       = cxusb_table,
324 };
325
326 /* module stuff */
327 static int __init cxusb_module_init(void)
328 {
329         int result;
330         if ((result = usb_register(&cxusb_driver))) {
331                 err("usb_register failed. Error number %d",result);
332                 return result;
333         }
334
335         return 0;
336 }
337
338 static void __exit cxusb_module_exit(void)
339 {
340         /* deregister this driver from the USB subsystem */
341         usb_deregister(&cxusb_driver);
342 }
343
344 module_init (cxusb_module_init);
345 module_exit (cxusb_module_exit);
346
347 MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
348 MODULE_DESCRIPTION("Driver for Conexant USB2.0 hybrid reference design");
349 MODULE_VERSION("1.0-alpha");
350 MODULE_LICENSE("GPL");