Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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