]> err.no Git - linux-2.6/blob - drivers/media/dvb/dvb-usb/au6610.c
V4L/DVB (5236): Initial support for Sigmatek DVB-110 DVB-T
[linux-2.6] / drivers / media / dvb / dvb-usb / au6610.c
1 /* DVB USB compliant linux driver for Sigmatek DVB-110 DVB-T USB2.0 receiver
2  *
3  * Copyright (C) 2006 Antti Palosaari (crope@iki.fi)
4  *
5  *      This program is free software; you can redistribute it and/or modify it
6  *      under the terms of the GNU General Public License as published by the Free
7  *      Software Foundation, version 2.
8  *
9  * see Documentation/dvb/README.dvb-usb for more information
10  */
11
12 #include "au6610.h"
13
14 #include "zl10353.h"
15 #include "qt1010.h"
16
17 /* debug */
18 static int dvb_usb_au6610_debug;
19 module_param_named(debug, dvb_usb_au6610_debug, int, 0644);
20 MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
21
22
23 static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr,
24                           u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
25 {
26         int ret;
27         u16 index;
28         u8 usb_buf[6]; /* enough for all known requests, read returns 5 and write 6 bytes */
29
30         switch (wlen) {
31         case 1:
32                 index = wbuf[0] << 8;
33                 break;
34         case 2:
35                 index = wbuf[0] << 8;
36                 index += wbuf[1];
37                 break;
38         default:
39                 warn("wlen = %x, aborting.", wlen);
40                 return -EINVAL;
41         }
42
43         ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), operation,
44                               USB_TYPE_VENDOR | USB_DIR_IN, addr, index, usb_buf,
45                               sizeof(usb_buf), AU6610_USB_TIMEOUT);
46
47         if (ret < 0)
48                 return ret;
49
50         switch (operation) {
51         case AU6610_REQ_I2C_READ:
52         case AU6610_REQ_USB_READ:
53                 /* requested value is always 5th byte in buffer */
54                 rbuf[0] = usb_buf[4];
55         }
56
57         return ret;
58 }
59
60 static int au6610_i2c_msg(struct dvb_usb_device *d, u8 addr, u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
61 {
62         u8 request;
63         u8 wo = (rbuf == NULL || rlen == 0); /* write-only */
64
65         if (wo) {
66                 request = AU6610_REQ_I2C_WRITE;
67         } else { /* rw */
68                 request = AU6610_REQ_I2C_READ;
69         }
70
71         return au6610_usb_msg(d, request, addr, wbuf, wlen, rbuf, rlen);
72 }
73
74
75 /* I2C */
76 static int au6610_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
77 {
78         struct dvb_usb_device *d = i2c_get_adapdata(adap);
79         int i;
80
81         if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
82                 return -EAGAIN;
83
84         if (num > 2)
85                 return -EINVAL;
86
87         for (i = 0; i < num; i++) {
88                 /* write/read request */
89                 if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
90                         if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf,
91                                            msg[i].len, msg[i+1].buf, msg[i+1].len) < 0)
92                                 break;
93                         i++;
94                 } else if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf,
95                                                msg[i].len, NULL, 0) < 0)
96                                 break;
97         }
98
99         mutex_unlock(&d->i2c_mutex);
100         return i;
101 }
102
103
104 static u32 au6610_i2c_func(struct i2c_adapter *adapter)
105 {
106         return I2C_FUNC_I2C;
107 }
108
109 static struct i2c_algorithm au6610_i2c_algo = {
110         .master_xfer   = au6610_i2c_xfer,
111         .functionality = au6610_i2c_func,
112 };
113
114 /* Callbacks for DVB USB */
115 static int au6610_identify_state(struct usb_device *udev,
116                                  struct dvb_usb_device_properties *props,
117                                  struct dvb_usb_device_description **desc,
118                                  int *cold)
119 {
120         *cold = 0;
121         return 0;
122 }
123
124 static struct zl10353_config au6610_zl10353_config = {
125         .demod_address = 0x1e,
126         .no_tuner = 1,
127         .parallel_ts = 1,
128 };
129
130
131 static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
132 {
133         if ((adap->fe = dvb_attach(zl10353_attach, &au6610_zl10353_config,
134                                    &adap->dev->i2c_adap)) != NULL) {
135                 return 0;
136         }
137
138         return -EIO;
139 }
140
141 /* DVB USB Driver stuff */
142 static struct dvb_usb_device_properties au6610_properties;
143
144 static int au6610_probe(struct usb_interface *intf, const struct usb_device_id *id)
145 {
146         struct dvb_usb_device *d;
147         struct usb_host_interface *alt;
148         int ret;
149
150         if (intf->num_altsetting < AU6610_ALTSETTING_COUNT)
151                 return -ENODEV;
152
153         if ((ret = dvb_usb_device_init(intf, &au6610_properties, THIS_MODULE, &d)) == 0) {
154                 alt = usb_altnum_to_altsetting(intf, AU6610_ALTSETTING);
155
156                 if (alt == NULL) {
157                         deb_rc("no alt found!\n");
158                         return -ENODEV;
159                 }
160                 ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
161                                         alt->desc.bAlternateSetting);
162         }
163
164         return ret;
165 }
166
167
168 static struct usb_device_id au6610_table [] = {
169         { USB_DEVICE(USB_VID_ALCOR_MICRO, USB_PID_SIGMATEK_DVB_110) },
170         { }             /* Terminating entry */
171 };
172 MODULE_DEVICE_TABLE (usb, au6610_table);
173
174 static struct dvb_usb_device_properties au6610_properties = {
175         .caps = DVB_USB_IS_AN_I2C_ADAPTER,
176         .usb_ctrl = DEVICE_SPECIFIC,
177         .size_of_priv     = 0,
178         .identify_state   = au6610_identify_state,
179         .num_adapters = 1,
180         .adapter = {
181                 {
182                         .frontend_attach  = au6610_zl10353_frontend_attach,
183                         .tuner_attach     = qt1010_tuner_attach,
184
185                         .stream = {
186                                 .type = USB_ISOC,
187                                 .count = 5,
188                                 .endpoint = 0x82,
189                                 .u = {
190                                         .isoc = {
191                                                 .framesperurb = 40,
192                                                 .framesize = 942,   /* maximum packet size */
193                                                 .interval = 1.25,   /* 125 us */
194                                         }
195                                 }
196                         },
197                 }
198         },
199         .i2c_algo = &au6610_i2c_algo,
200         .num_device_descs = 1,
201         .devices = {
202                 {
203                         "Sigmatek DVB-110 DVB-T USB2.0",
204                         { &au6610_table[0], NULL },
205                         { NULL },
206                 },
207         }
208 };
209
210 static struct usb_driver au6610_driver = {
211         .name       = "dvb_usb_au6610",
212         .probe      = au6610_probe,
213         .disconnect = dvb_usb_device_exit,
214         .id_table   = au6610_table,
215 };
216
217 /* module stuff */
218 static int __init au6610_module_init(void)
219 {
220         int ret;
221
222         if ((ret = usb_register(&au6610_driver))) {
223                 err("usb_register failed. Error number %d", ret);
224                 return ret;
225         }
226
227         return 0;
228 }
229
230 static void __exit au6610_module_exit(void)
231 {
232         /* deregister this driver from the USB subsystem */
233         usb_deregister(&au6610_driver);
234 }
235
236 module_init (au6610_module_init);
237 module_exit (au6610_module_exit);
238
239 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
240 MODULE_DESCRIPTION("Driver Sigmatek DVB-110 DVB-T USB2.0 / AU6610");
241 MODULE_VERSION("0.1");
242 MODULE_LICENSE("GPL");