2019-05-27 08:55:06 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2008-05-28 03:57:39 -03:00
/*
* DVB USB Linux driver for Alcor Micro AU6610 DVB - T USB2 .0 .
2006-11-05 16:05:38 -03:00
*
2007-01-21 15:56:10 -03:00
* Copyright ( C ) 2006 Antti Palosaari < crope @ iki . fi >
2006-11-05 16:05:38 -03:00
*/
# include "au6610.h"
# include "zl10353.h"
# include "qt1010.h"
2008-04-09 19:13:13 -03:00
DVB_DEFINE_MOD_OPT_ADAPTER_NR ( adapter_nr ) ;
2006-11-05 16:05:38 -03:00
static int au6610_usb_msg ( struct dvb_usb_device * d , u8 operation , u8 addr ,
u8 * wbuf , u16 wlen , u8 * rbuf , u16 rlen )
{
int ret ;
u16 index ;
2011-03-20 18:50:50 -03:00
u8 * usb_buf ;
/*
* allocate enough for all known requests ,
* read returns 5 and write 6 bytes
*/
usb_buf = kmalloc ( 6 , GFP_KERNEL ) ;
if ( ! usb_buf )
return - ENOMEM ;
2006-11-05 16:05:38 -03:00
switch ( wlen ) {
case 1 :
index = wbuf [ 0 ] < < 8 ;
break ;
case 2 :
index = wbuf [ 0 ] < < 8 ;
index + = wbuf [ 1 ] ;
break ;
default :
2012-09-12 20:23:54 -03:00
dev_err ( & d - > udev - > dev , " %s: wlen=%d, aborting \n " ,
KBUILD_MODNAME , wlen ) ;
2011-03-20 18:50:50 -03:00
ret = - EINVAL ;
goto error ;
2006-11-05 16:05:38 -03:00
}
ret = usb_control_msg ( d - > udev , usb_rcvctrlpipe ( d - > udev , 0 ) , operation ,
2008-05-28 00:53:27 -03:00
USB_TYPE_VENDOR | USB_DIR_IN , addr < < 1 , index ,
2011-03-20 18:50:50 -03:00
usb_buf , 6 , AU6610_USB_TIMEOUT ) ;
2012-08-22 19:42:00 -03:00
dvb_usb_dbg_usb_control_msg ( d - > udev , operation ,
( USB_TYPE_VENDOR | USB_DIR_IN ) , addr < < 1 , index ,
usb_buf , 6 ) ;
2006-11-05 16:05:38 -03:00
if ( ret < 0 )
2011-03-20 18:50:50 -03:00
goto error ;
2006-11-05 16:05:38 -03:00
switch ( operation ) {
case AU6610_REQ_I2C_READ :
case AU6610_REQ_USB_READ :
/* requested value is always 5th byte in buffer */
rbuf [ 0 ] = usb_buf [ 4 ] ;
}
2011-03-20 18:50:50 -03:00
error :
kfree ( usb_buf ) ;
2006-11-05 16:05:38 -03:00
return ret ;
}
2007-01-21 15:57:48 -03:00
static int au6610_i2c_msg ( struct dvb_usb_device * d , u8 addr ,
u8 * wbuf , u16 wlen , u8 * rbuf , u16 rlen )
2006-11-05 16:05:38 -03:00
{
u8 request ;
u8 wo = ( rbuf = = NULL | | rlen = = 0 ) ; /* write-only */
if ( wo ) {
request = AU6610_REQ_I2C_WRITE ;
} else { /* rw */
request = AU6610_REQ_I2C_READ ;
}
return au6610_usb_msg ( d , request , addr , wbuf , wlen , rbuf , rlen ) ;
}
/* I2C */
2007-01-21 15:57:48 -03:00
static int au6610_i2c_xfer ( struct i2c_adapter * adap , struct i2c_msg msg [ ] ,
int num )
2006-11-05 16:05:38 -03:00
{
struct dvb_usb_device * d = i2c_get_adapdata ( adap ) ;
int i ;
if ( num > 2 )
return - EINVAL ;
2007-11-06 10:25:16 -03:00
if ( mutex_lock_interruptible ( & d - > i2c_mutex ) < 0 )
return - EAGAIN ;
2006-11-05 16:05:38 -03:00
for ( i = 0 ; i < num ; i + + ) {
/* write/read request */
if ( i + 1 < num & & ( msg [ i + 1 ] . flags & I2C_M_RD ) ) {
if ( au6610_i2c_msg ( d , msg [ i ] . addr , msg [ i ] . buf ,
2007-01-21 15:57:48 -03:00
msg [ i ] . len , msg [ i + 1 ] . buf ,
msg [ i + 1 ] . len ) < 0 )
2006-11-05 16:05:38 -03:00
break ;
i + + ;
} else if ( au6610_i2c_msg ( d , msg [ i ] . addr , msg [ i ] . buf ,
msg [ i ] . len , NULL , 0 ) < 0 )
break ;
}
mutex_unlock ( & d - > i2c_mutex ) ;
return i ;
}
static u32 au6610_i2c_func ( struct i2c_adapter * adapter )
{
return I2C_FUNC_I2C ;
}
static struct i2c_algorithm au6610_i2c_algo = {
. master_xfer = au6610_i2c_xfer ,
. functionality = au6610_i2c_func ,
} ;
/* Callbacks for DVB USB */
static struct zl10353_config au6610_zl10353_config = {
2007-03-05 18:25:36 -03:00
. demod_address = 0x0f ,
2006-11-05 16:05:38 -03:00
. no_tuner = 1 ,
. parallel_ts = 1 ,
} ;
static int au6610_zl10353_frontend_attach ( struct dvb_usb_adapter * adap )
{
2012-06-12 22:49:54 -03:00
adap - > fe [ 0 ] = dvb_attach ( zl10353_attach , & au6610_zl10353_config ,
2012-06-18 19:44:08 -03:00
& adap_to_d ( adap ) - > i2c_adap ) ;
2012-06-12 22:49:54 -03:00
if ( adap - > fe [ 0 ] = = NULL )
2008-05-28 03:57:39 -03:00
return - ENODEV ;
2006-11-05 16:05:38 -03:00
2008-05-28 00:53:27 -03:00
return 0 ;
2006-11-05 16:05:38 -03:00
}
2007-01-21 15:56:10 -03:00
static struct qt1010_config au6610_qt1010_config = {
2007-03-05 18:25:36 -03:00
. i2c_address = 0x62
2007-01-21 15:56:10 -03:00
} ;
static int au6610_qt1010_tuner_attach ( struct dvb_usb_adapter * adap )
{
2012-06-18 19:44:08 -03:00
return dvb_attach ( qt1010_attach , adap - > fe [ 0 ] ,
& adap_to_d ( adap ) - > i2c_adap ,
& au6610_qt1010_config ) = = NULL ? - ENODEV : 0 ;
2007-01-21 15:56:10 -03:00
}
2012-06-12 22:49:54 -03:00
static int au6610_init ( struct dvb_usb_device * d )
2006-11-05 16:05:38 -03:00
{
2012-06-12 22:49:54 -03:00
/* TODO: this functionality belongs likely to the streaming control */
/* bInterfaceNumber 0, bAlternateSetting 5 */
return usb_set_interface ( d - > udev , 0 , 5 ) ;
2006-11-05 16:05:38 -03:00
}
2012-06-12 22:49:54 -03:00
static struct dvb_usb_device_properties au6610_props = {
. driver_name = KBUILD_MODNAME ,
. owner = THIS_MODULE ,
. adapter_nr = adapter_nr ,
2008-05-28 03:57:39 -03:00
2012-06-12 22:49:54 -03:00
. i2c_algo = & au6610_i2c_algo ,
. frontend_attach = au6610_zl10353_frontend_attach ,
. tuner_attach = au6610_qt1010_tuner_attach ,
. init = au6610_init ,
2008-05-28 03:57:39 -03:00
2006-11-05 16:05:38 -03:00
. num_adapters = 1 ,
. adapter = {
{
2012-06-18 19:44:08 -03:00
. stream = DVB_USB_STREAM_ISOC ( 0x82 , 5 , 40 , 942 , 1 ) ,
2012-06-12 22:49:54 -03:00
} ,
2006-11-05 16:05:38 -03:00
} ,
2012-06-12 22:49:54 -03:00
} ;
2008-05-28 03:57:39 -03:00
2012-06-12 22:49:54 -03:00
static const struct usb_device_id au6610_id_table [ ] = {
{ DVB_USB_DEVICE ( USB_VID_ALCOR_MICRO , USB_PID_SIGMATEK_DVB_110 ,
& au6610_props , " Sigmatek DVB-110 " , NULL ) } ,
{ }
2006-11-05 16:05:38 -03:00
} ;
2012-06-12 22:49:54 -03:00
MODULE_DEVICE_TABLE ( usb , au6610_id_table ) ;
2006-11-05 16:05:38 -03:00
static struct usb_driver au6610_driver = {
2012-06-12 22:49:54 -03:00
. name = KBUILD_MODNAME ,
. id_table = au6610_id_table ,
. probe = dvb_usbv2_probe ,
. disconnect = dvb_usbv2_disconnect ,
. suspend = dvb_usbv2_suspend ,
. resume = dvb_usbv2_resume ,
2012-08-22 18:52:05 -03:00
. reset_resume = dvb_usbv2_reset_resume ,
2012-06-12 22:49:54 -03:00
. no_dynamic_id = 1 ,
. soft_unbind = 1 ,
2006-11-05 16:05:38 -03:00
} ;
2011-11-18 09:46:12 -08:00
module_usb_driver ( au6610_driver ) ;
2006-11-05 16:05:38 -03:00
MODULE_AUTHOR ( " Antti Palosaari <crope@iki.fi> " ) ;
2008-05-28 03:57:39 -03:00
MODULE_DESCRIPTION ( " Driver for Alcor Micro AU6610 DVB-T USB2.0 " ) ;
2006-11-05 16:05:38 -03:00
MODULE_VERSION ( " 0.1 " ) ;
MODULE_LICENSE ( " GPL " ) ;