Path: blob/master/drivers/media/dvb/dvb-usb/au6610.c
15112 views
/*1* DVB USB Linux driver for Alcor Micro AU6610 DVB-T USB2.0.2*3* Copyright (C) 2006 Antti Palosaari <[email protected]>4*5* This program is free software; you can redistribute it and/or modify6* it under the terms of the GNU General Public License as published by7* the Free Software Foundation; either version 2 of the License, or8* (at your option) any later version.9*10* This program is distributed in the hope that it will be useful,11* but WITHOUT ANY WARRANTY; without even the implied warranty of12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13* GNU General Public License for more details.14*15* You should have received a copy of the GNU General Public License16* along with this program; if not, write to the Free Software17* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.18*/1920#include "au6610.h"21#include "zl10353.h"22#include "qt1010.h"2324/* debug */25static int dvb_usb_au6610_debug;26module_param_named(debug, dvb_usb_au6610_debug, int, 0644);27MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);28DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);2930static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr,31u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)32{33int ret;34u16 index;35u8 *usb_buf;3637/*38* allocate enough for all known requests,39* read returns 5 and write 6 bytes40*/41usb_buf = kmalloc(6, GFP_KERNEL);42if (!usb_buf)43return -ENOMEM;4445switch (wlen) {46case 1:47index = wbuf[0] << 8;48break;49case 2:50index = wbuf[0] << 8;51index += wbuf[1];52break;53default:54warn("wlen = %x, aborting.", wlen);55ret = -EINVAL;56goto error;57}5859ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), operation,60USB_TYPE_VENDOR|USB_DIR_IN, addr << 1, index,61usb_buf, 6, AU6610_USB_TIMEOUT);62if (ret < 0)63goto error;6465switch (operation) {66case AU6610_REQ_I2C_READ:67case AU6610_REQ_USB_READ:68/* requested value is always 5th byte in buffer */69rbuf[0] = usb_buf[4];70}71error:72kfree(usb_buf);73return ret;74}7576static int au6610_i2c_msg(struct dvb_usb_device *d, u8 addr,77u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)78{79u8 request;80u8 wo = (rbuf == NULL || rlen == 0); /* write-only */8182if (wo) {83request = AU6610_REQ_I2C_WRITE;84} else { /* rw */85request = AU6610_REQ_I2C_READ;86}8788return au6610_usb_msg(d, request, addr, wbuf, wlen, rbuf, rlen);89}909192/* I2C */93static int au6610_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],94int num)95{96struct dvb_usb_device *d = i2c_get_adapdata(adap);97int i;9899if (num > 2)100return -EINVAL;101102if (mutex_lock_interruptible(&d->i2c_mutex) < 0)103return -EAGAIN;104105for (i = 0; i < num; i++) {106/* write/read request */107if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {108if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf,109msg[i].len, msg[i+1].buf,110msg[i+1].len) < 0)111break;112i++;113} else if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf,114msg[i].len, NULL, 0) < 0)115break;116}117118mutex_unlock(&d->i2c_mutex);119return i;120}121122123static u32 au6610_i2c_func(struct i2c_adapter *adapter)124{125return I2C_FUNC_I2C;126}127128static struct i2c_algorithm au6610_i2c_algo = {129.master_xfer = au6610_i2c_xfer,130.functionality = au6610_i2c_func,131};132133/* Callbacks for DVB USB */134static struct zl10353_config au6610_zl10353_config = {135.demod_address = 0x0f,136.no_tuner = 1,137.parallel_ts = 1,138};139140static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap)141{142adap->fe = dvb_attach(zl10353_attach, &au6610_zl10353_config,143&adap->dev->i2c_adap);144if (adap->fe == NULL)145return -ENODEV;146147return 0;148}149150static struct qt1010_config au6610_qt1010_config = {151.i2c_address = 0x62152};153154static int au6610_qt1010_tuner_attach(struct dvb_usb_adapter *adap)155{156return dvb_attach(qt1010_attach,157adap->fe, &adap->dev->i2c_adap,158&au6610_qt1010_config) == NULL ? -ENODEV : 0;159}160161/* DVB USB Driver stuff */162static struct dvb_usb_device_properties au6610_properties;163164static int au6610_probe(struct usb_interface *intf,165const struct usb_device_id *id)166{167struct dvb_usb_device *d;168struct usb_host_interface *alt;169int ret;170171if (intf->num_altsetting < AU6610_ALTSETTING_COUNT)172return -ENODEV;173174ret = dvb_usb_device_init(intf, &au6610_properties, THIS_MODULE, &d,175adapter_nr);176if (ret == 0) {177alt = usb_altnum_to_altsetting(intf, AU6610_ALTSETTING);178179if (alt == NULL) {180deb_info("%s: no alt found!\n", __func__);181return -ENODEV;182}183ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,184alt->desc.bAlternateSetting);185}186187return ret;188}189190static struct usb_device_id au6610_table [] = {191{ USB_DEVICE(USB_VID_ALCOR_MICRO, USB_PID_SIGMATEK_DVB_110) },192{ } /* Terminating entry */193};194MODULE_DEVICE_TABLE(usb, au6610_table);195196static struct dvb_usb_device_properties au6610_properties = {197.caps = DVB_USB_IS_AN_I2C_ADAPTER,198199.usb_ctrl = DEVICE_SPECIFIC,200201.size_of_priv = 0,202203.num_adapters = 1,204.adapter = {205{206.frontend_attach = au6610_zl10353_frontend_attach,207.tuner_attach = au6610_qt1010_tuner_attach,208209.stream = {210.type = USB_ISOC,211.count = 5,212.endpoint = 0x82,213.u = {214.isoc = {215.framesperurb = 40,216.framesize = 942,217.interval = 1,218}219}220},221}222},223224.i2c_algo = &au6610_i2c_algo,225226.num_device_descs = 1,227.devices = {228{229.name = "Sigmatek DVB-110 DVB-T USB2.0",230.cold_ids = {NULL},231.warm_ids = {&au6610_table[0], NULL},232},233}234};235236static struct usb_driver au6610_driver = {237.name = "dvb_usb_au6610",238.probe = au6610_probe,239.disconnect = dvb_usb_device_exit,240.id_table = au6610_table,241};242243/* module stuff */244static int __init au6610_module_init(void)245{246int ret;247248ret = usb_register(&au6610_driver);249if (ret)250err("usb_register failed. Error number %d", ret);251252return ret;253}254255static void __exit au6610_module_exit(void)256{257/* deregister this driver from the USB subsystem */258usb_deregister(&au6610_driver);259}260261module_init(au6610_module_init);262module_exit(au6610_module_exit);263264MODULE_AUTHOR("Antti Palosaari <[email protected]>");265MODULE_DESCRIPTION("Driver for Alcor Micro AU6610 DVB-T USB2.0");266MODULE_VERSION("0.1");267MODULE_LICENSE("GPL");268269270