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