]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/media/dvb/dvb-usb/cxusb.c
[SERIAL] Spelling fix in 8250.c
[karo-tx-linux.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
29 /* debug */
30 int dvb_usb_cxusb_debug;
31 module_param_named(debug,dvb_usb_cxusb_debug, int, 0644);
32 MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
33
34 static int cxusb_ctrl_msg(struct dvb_usb_device *d,
35                 u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
36 {
37         int wo = (rbuf == NULL || rlen == 0); /* write-only */
38         u8 sndbuf[1+wlen];
39         memset(sndbuf,0,1+wlen);
40
41         sndbuf[0] = cmd;
42         memcpy(&sndbuf[1],wbuf,wlen);
43         if (wo)
44                 dvb_usb_generic_write(d,sndbuf,1+wlen);
45         else
46                 dvb_usb_generic_rw(d,sndbuf,1+wlen,rbuf,rlen,0);
47
48         return 0;
49 }
50
51 /* I2C */
52 static void cxusb_set_i2c_path(struct dvb_usb_device *d, enum cxusb_i2c_pathes path)
53 {
54         struct cxusb_state *st = d->priv;
55         u8 o[2],i;
56
57         if (path == st->cur_i2c_path)
58                 return;
59
60         o[0] = IOCTL_SET_I2C_PATH;
61         switch (path) {
62                 case PATH_CX22702:
63                         o[1] = 0;
64                         break;
65                 case PATH_TUNER_OTHER:
66                         o[1] = 1;
67                         break;
68                 default:
69                         err("unkown i2c path");
70                         return;
71         }
72         cxusb_ctrl_msg(d,CMD_IOCTL,o,2,&i,1);
73
74         if (i != 0x01)
75                 deb_info("i2c_path setting failed.\n");
76
77         st->cur_i2c_path = path;
78 }
79
80 static int cxusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
81 {
82         struct dvb_usb_device *d = i2c_get_adapdata(adap);
83         int i;
84
85         if (down_interruptible(&d->i2c_sem) < 0)
86                 return -EAGAIN;
87
88         if (num > 2)
89                 warn("more than 2 i2c messages at a time is not handled yet. TODO.");
90
91         for (i = 0; i < num; i++) {
92
93                 switch (msg[i].addr) {
94                         case 0x63:
95                                 cxusb_set_i2c_path(d,PATH_CX22702);
96                                 break;
97                         default:
98                                 cxusb_set_i2c_path(d,PATH_TUNER_OTHER);
99                                 break;
100                 }
101
102                 /* read request */
103                 if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
104                         u8 obuf[3+msg[i].len], ibuf[1+msg[i+1].len];
105                         obuf[0] = msg[i].len;
106                         obuf[1] = msg[i+1].len;
107                         obuf[2] = msg[i].addr;
108                         memcpy(&obuf[3],msg[i].buf,msg[i].len);
109
110                         if (cxusb_ctrl_msg(d, CMD_I2C_READ,
111                                                 obuf, 3+msg[i].len,
112                                                 ibuf, 1+msg[i+1].len) < 0)
113                                 break;
114
115                         if (ibuf[0] != 0x08)
116                                 deb_info("i2c read could have been failed\n");
117
118                         memcpy(msg[i+1].buf,&ibuf[1],msg[i+1].len);
119
120                         i++;
121                 } else { /* write */
122                         u8 obuf[2+msg[i].len], ibuf;
123                         obuf[0] = msg[i].addr;
124                         obuf[1] = msg[i].len;
125                         memcpy(&obuf[2],msg[i].buf,msg[i].len);
126
127                         if (cxusb_ctrl_msg(d,CMD_I2C_WRITE, obuf, 2+msg[i].len, &ibuf,1) < 0)
128                                 break;
129                         if (ibuf != 0x08)
130                                 deb_info("i2c write could have been failed\n");
131                 }
132         }
133
134         up(&d->i2c_sem);
135         return i;
136 }
137
138 static u32 cxusb_i2c_func(struct i2c_adapter *adapter)
139 {
140         return I2C_FUNC_I2C;
141 }
142
143 static struct i2c_algorithm cxusb_i2c_algo = {
144         .master_xfer   = cxusb_i2c_xfer,
145         .functionality = cxusb_i2c_func,
146 };
147
148 static int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff)
149 {
150         return 0;
151 }
152
153 static int cxusb_streaming_ctrl(struct dvb_usb_device *d, int onoff)
154 {
155         u8 buf[2] = { 0x03, 0x00 };
156         if (onoff)
157                 cxusb_ctrl_msg(d,0x36, buf, 2, NULL, 0);
158         else
159                 cxusb_ctrl_msg(d,0x37, NULL, 0, NULL, 0);
160
161         return 0;
162 }
163
164 struct cx22702_config cxusb_cx22702_config = {
165         .demod_address = 0x63,
166
167         .output_mode = CX22702_PARALLEL_OUTPUT,
168
169         .pll_init = dvb_usb_pll_init_i2c,
170         .pll_set  = dvb_usb_pll_set_i2c,
171 };
172
173 /* Callbacks for DVB USB */
174 static int cxusb_tuner_attach(struct dvb_usb_device *d)
175 {
176         u8 bpll[4] = { 0x0b, 0xdc, 0x9c, 0xa0 };
177         d->pll_addr = 0x61;
178         memcpy(d->pll_init,bpll,4);
179         d->pll_desc = &dvb_pll_fmd1216me;
180         return 0;
181 }
182
183 static int cxusb_frontend_attach(struct dvb_usb_device *d)
184 {
185         u8 buf[2] = { 0x03, 0x00 };
186         u8 b = 0;
187
188         if (usb_set_interface(d->udev,0,0) < 0)
189                 err("set interface to alts=0 failed");
190
191         cxusb_ctrl_msg(d,0xde,&b,0,NULL,0);
192         cxusb_set_i2c_path(d,PATH_TUNER_OTHER);
193         cxusb_ctrl_msg(d,CMD_POWER_OFF, NULL, 0, &b, 1);
194
195         if (usb_set_interface(d->udev,0,6) < 0)
196                 err("set interface failed");
197
198         cxusb_ctrl_msg(d,0x36, buf, 2, NULL, 0);
199         cxusb_set_i2c_path(d,PATH_CX22702);
200         cxusb_ctrl_msg(d,CMD_POWER_ON, NULL, 0, &b, 1);
201
202         if ((d->fe = cx22702_attach(&cxusb_cx22702_config, &d->i2c_adap)) != NULL)
203                 return 0;
204
205         return -EIO;
206 }
207
208 /* DVB USB Driver stuff */
209 static struct dvb_usb_properties cxusb_properties;
210
211 static int cxusb_probe(struct usb_interface *intf,
212                 const struct usb_device_id *id)
213 {
214         return dvb_usb_device_init(intf,&cxusb_properties,THIS_MODULE);
215 }
216
217 static struct usb_device_id cxusb_table [] = {
218                 { USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) },
219                 {}              /* Terminating entry */
220 };
221 MODULE_DEVICE_TABLE (usb, cxusb_table);
222
223 static struct dvb_usb_properties cxusb_properties = {
224         .caps = DVB_USB_IS_AN_I2C_ADAPTER,
225
226         .usb_ctrl = CYPRESS_FX2,
227
228         .size_of_priv     = sizeof(struct cxusb_state),
229
230         .streaming_ctrl   = cxusb_streaming_ctrl,
231         .power_ctrl       = cxusb_power_ctrl,
232         .frontend_attach  = cxusb_frontend_attach,
233         .tuner_attach     = cxusb_tuner_attach,
234
235         .i2c_algo         = &cxusb_i2c_algo,
236
237         .generic_bulk_ctrl_endpoint = 0x01,
238         /* parameter for the MPEG2-data transfer */
239         .urb = {
240                 .type = DVB_USB_ISOC,
241                 .count = 5,
242                 .endpoint = 0x02,
243                 .u = {
244                         .isoc = {
245                                 .framesperurb = 32,
246                                 .framesize = 940,
247                                 .interval = 5,
248                         }
249                 }
250         },
251
252         .num_device_descs = 1,
253         .devices = {
254                 {   "Medion MD95700 (MDUSBTV-HYBRID)",
255                         { NULL },
256                         { &cxusb_table[0], NULL },
257                 },
258         }
259 };
260
261 static struct usb_driver cxusb_driver = {
262         .owner          = THIS_MODULE,
263         .name           = "dvb_usb_cxusb",
264         .probe          = cxusb_probe,
265         .disconnect = dvb_usb_device_exit,
266         .id_table       = cxusb_table,
267 };
268
269 /* module stuff */
270 static int __init cxusb_module_init(void)
271 {
272         int result;
273         if ((result = usb_register(&cxusb_driver))) {
274                 err("usb_register failed. Error number %d",result);
275                 return result;
276         }
277
278         return 0;
279 }
280
281 static void __exit cxusb_module_exit(void)
282 {
283         /* deregister this driver from the USB subsystem */
284         usb_deregister(&cxusb_driver);
285 }
286
287 module_init (cxusb_module_init);
288 module_exit (cxusb_module_exit);
289
290 MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
291 MODULE_DESCRIPTION("Driver for Conexant USB2.0 hybrid reference design");
292 MODULE_VERSION("1.0-alpha");
293 MODULE_LICENSE("GPL");