2011-07-23 10:59:25 -03:00
/*
* Driver for AzureWave 6007 DVB - C / T USB2 .0 and clones
*
* Copyright ( c ) Henry Wang < Henry . wang @ AzureWave . com >
*
* This driver was made publicly available by Terratec , at :
* http : //linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz
* The original driver ' s license is GPL , as declared with MODULE_LICENSE ( )
*
* Driver modifiyed by Mauro Carvalho Chehab < mchehab @ redhat . com > in order
* to work with upstream drxk driver , and to fix some bugs .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation under version 2 of the License .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
2011-07-21 17:46:41 -03:00
*/
# include "drxk.h"
# include "mt2063.h"
# include "dvb_ca_en50221.h"
2011-07-23 10:55:10 -03:00
# include "dvb-usb.h"
# define DVB_USB_LOG_PREFIX "az6007"
2011-07-21 17:46:41 -03:00
/* debug */
int dvb_usb_az6007_debug ;
2011-07-23 10:40:08 -03:00
module_param_named ( debug , dvb_usb_az6007_debug , int , 0644 ) ;
MODULE_PARM_DESC ( debug , " set debugging level (1=info,xfer=2,rc=4 (or-able)). "
DVB_USB_DEBUG_STATUS ) ;
2011-07-21 17:46:41 -03:00
2011-07-23 10:55:10 -03:00
# define deb_info(args...) dprintk(dvb_usb_az6007_debug, 0x01, args)
# define deb_xfer(args...) dprintk(dvb_usb_az6007_debug, 0x02, args)
# define deb_rc(args...) dprintk(dvb_usb_az6007_debug, 0x04, args)
# define deb_fe(args...) dprintk(dvb_usb_az6007_debug, 0x08, args)
2011-07-21 17:46:41 -03:00
DVB_DEFINE_MOD_OPT_ADAPTER_NR ( adapter_nr ) ;
struct az6007_device_state {
2011-07-23 10:40:08 -03:00
struct dvb_ca_en50221 ca ;
struct mutex ca_mutex ;
u8 power_state ;
2011-07-21 17:46:41 -03:00
2011-07-21 18:31:14 -03:00
/* Due to DRX-K - probably need changes */
2011-07-23 10:40:08 -03:00
int ( * gate_ctrl ) ( struct dvb_frontend * , int ) ;
struct semaphore pll_mutex ;
2011-07-21 18:31:14 -03:00
bool dont_attach_fe1 ;
2011-07-21 17:46:41 -03:00
} ;
2011-07-23 10:40:08 -03:00
static struct drxk_config terratec_h7_drxk = {
2011-07-21 18:31:14 -03:00
. adr = 0x29 ,
. single_master = 1 ,
2011-07-23 09:51:12 -03:00
. no_i2c_bridge = 0 ,
2011-07-24 09:25:39 -03:00
. max_size = 64 ,
// .microcode_name = "dvb-usb-terratec-h5-drxk.fw",
2011-07-21 17:46:41 -03:00
} ;
2011-07-21 18:31:14 -03:00
static int drxk_gate_ctrl ( struct dvb_frontend * fe , int enable )
{
struct dvb_usb_adapter * adap = fe - > sec_priv ;
2011-07-22 10:31:25 -03:00
struct az6007_device_state * st ;
2011-07-23 11:54:40 -03:00
int status = 0 ;
2011-07-21 18:31:14 -03:00
2011-07-23 11:54:40 -03:00
deb_info ( " %s: %s \n " , __func__ , enable ? " enable " : " disable " ) ;
2011-07-22 10:31:25 -03:00
if ( ! adap )
return - EINVAL ;
st = adap - > priv ;
if ( ! st )
2011-07-21 18:31:14 -03:00
return - EINVAL ;
if ( enable ) {
2011-07-23 09:58:38 -03:00
#if 0
2011-07-21 18:31:14 -03:00
down ( & st - > pll_mutex ) ;
2011-07-23 09:58:38 -03:00
# endif
2011-07-21 18:31:14 -03:00
status = st - > gate_ctrl ( fe , 1 ) ;
} else {
2011-07-23 09:58:38 -03:00
#if 0
2011-07-21 18:31:14 -03:00
status = st - > gate_ctrl ( fe , 0 ) ;
2011-07-23 09:58:38 -03:00
# endif
2011-07-21 18:31:14 -03:00
up ( & st - > pll_mutex ) ;
}
return status ;
}
2011-07-23 10:40:08 -03:00
static struct mt2063_config az6007_mt2063_config = {
2011-07-22 10:31:25 -03:00
. tuner_address = 0x60 ,
2011-07-21 17:46:41 -03:00
. refclock = 36125000 ,
} ;
/* check for mutex FIXME */
2011-07-23 10:40:08 -03:00
static int az6007_usb_in_op ( struct dvb_usb_device * d , u8 req , u16 value ,
u16 index , u8 * b , int blen )
2011-07-21 17:46:41 -03:00
{
int ret = - 1 ;
2011-07-23 10:40:08 -03:00
ret = usb_control_msg ( d - > udev ,
usb_rcvctrlpipe ( d - > udev , 0 ) ,
req ,
USB_TYPE_VENDOR | USB_DIR_IN ,
value , index , b , blen , 5000 ) ;
2011-07-21 17:46:41 -03:00
if ( ret < 0 ) {
warn ( " usb in operation failed. (%d) " , ret ) ;
2011-07-22 10:31:25 -03:00
return - EIO ;
}
2011-07-21 17:46:41 -03:00
2011-07-23 10:40:08 -03:00
deb_xfer ( " in: req. %02x, val: %04x, ind: %04x, buffer: " , req , value ,
index ) ;
debug_dump ( b , blen , deb_xfer ) ;
2011-07-21 17:46:41 -03:00
return ret ;
}
static int az6007_usb_out_op ( struct dvb_usb_device * d , u8 req , u16 value ,
u16 index , u8 * b , int blen )
{
int ret ;
2011-07-23 10:40:08 -03:00
deb_xfer ( " out: req. %02x, val: %04x, ind: %04x, buffer: " , req , value ,
index ) ;
debug_dump ( b , blen , deb_xfer ) ;
2011-07-21 17:46:41 -03:00
2011-07-23 10:12:12 -03:00
if ( blen > 64 ) {
2011-07-24 09:25:39 -03:00
err ( " az6007: tried to write %d bytes, but I2C max size is 64 bytes \n " ,
blen ) ;
2011-07-23 10:12:12 -03:00
return - EOPNOTSUPP ;
2011-07-21 17:46:41 -03:00
}
2011-07-23 10:12:12 -03:00
2011-07-23 10:40:08 -03:00
ret = usb_control_msg ( d - > udev ,
usb_sndctrlpipe ( d - > udev , 0 ) ,
req ,
USB_TYPE_VENDOR | USB_DIR_OUT ,
value , index , b , blen , 5000 ) ;
if ( ret ! = blen ) {
2011-07-23 11:54:40 -03:00
err ( " usb out operation failed. (%d) " , ret ) ;
2011-07-23 10:12:12 -03:00
return - EIO ;
2011-07-21 17:46:41 -03:00
}
2011-07-21 18:31:14 -03:00
2011-07-21 17:46:41 -03:00
return 0 ;
}
static int az6007_streaming_ctrl ( struct dvb_usb_adapter * adap , int onoff )
{
return 0 ;
}
/* keys for the enclosed remote control */
2011-07-23 10:40:08 -03:00
static struct rc_map_table rc_map_az6007_table [ ] = {
{ 0x0001 , KEY_1 } ,
{ 0x0002 , KEY_2 } ,
2011-07-21 17:46:41 -03:00
} ;
/* remote control stuff (does not work with my box) */
2011-07-23 10:40:08 -03:00
static int az6007_rc_query ( struct dvb_usb_device * d , u32 * event , int * state )
2011-07-21 17:46:41 -03:00
{
return 0 ;
#if 0
u8 key [ 10 ] ;
int i ;
2011-07-23 10:40:08 -03:00
/* remove the following return to enabled remote querying */
2011-07-21 17:46:41 -03:00
2011-07-23 10:40:08 -03:00
az6007_usb_in_op ( d , READ_REMOTE_REQ , 0 , 0 , key , 10 ) ;
2011-07-21 17:46:41 -03:00
2011-07-23 10:40:08 -03:00
deb_rc ( " remote query key: %x %d \n " , key [ 1 ] , key [ 1 ] ) ;
2011-07-21 17:46:41 -03:00
if ( key [ 1 ] = = 0x44 ) {
* state = REMOTE_NO_KEY_PRESSED ;
return 0 ;
}
for ( i = 0 ; i < ARRAY_SIZE ( az6007_rc_keys ) ; i + + )
if ( az6007_rc_keys [ i ] . custom = = key [ 1 ] ) {
* state = REMOTE_KEY_PRESSED ;
* event = az6007_rc_keys [ i ] . event ;
break ;
}
return 0 ;
# endif
}
/*
int az6007_power_ctrl ( struct dvb_usb_device * d , int onoff )
{
u8 v = onoff ;
return az6007_usb_out_op ( d , 0xBC , v , 3 , NULL , 1 ) ;
}
*/
2011-07-23 10:40:08 -03:00
static int az6007_read_mac_addr ( struct dvb_usb_device * d , u8 mac [ 6 ] )
2011-07-21 17:46:41 -03:00
{
az6007_usb_in_op ( d , 0xb7 , 6 , 0 , & mac [ 0 ] , 6 ) ;
return 0 ;
}
static int az6007_frontend_poweron ( struct dvb_usb_adapter * adap )
{
int ret ;
u8 req ;
u16 value ;
u16 index ;
int blen ;
2011-07-23 11:54:40 -03:00
deb_info ( " az6007_frontend_poweron adap=%p adap->dev=%p \n " ,
adap , adap - > dev ) ;
2011-07-21 17:46:41 -03:00
req = 0xBC ;
2011-07-23 10:12:12 -03:00
value = 1 ; /* power on */
2011-07-21 17:46:41 -03:00
index = 3 ;
2011-07-23 10:40:08 -03:00
blen = 0 ;
2011-07-21 17:46:41 -03:00
2011-07-23 10:40:08 -03:00
ret = az6007_usb_out_op ( adap - > dev , req , value , index , NULL , blen ) ;
if ( ret ! = 0 ) {
2011-07-21 17:46:41 -03:00
err ( " az6007_frontend_poweron failed!!! " ) ;
2011-07-23 10:40:08 -03:00
return - EIO ;
2011-07-21 17:46:41 -03:00
}
msleep_interruptible ( 200 ) ;
req = 0xBC ;
2011-07-23 10:12:12 -03:00
value = 0 ; /* power off */
2011-07-21 17:46:41 -03:00
index = 3 ;
2011-07-23 10:40:08 -03:00
blen = 0 ;
2011-07-21 17:46:41 -03:00
2011-07-23 10:40:08 -03:00
ret = az6007_usb_out_op ( adap - > dev , req , value , index , NULL , blen ) ;
if ( ret ! = 0 ) {
2011-07-21 17:46:41 -03:00
err ( " az6007_frontend_poweron failed!!! " ) ;
2011-07-23 10:40:08 -03:00
return - EIO ;
2011-07-21 17:46:41 -03:00
}
msleep_interruptible ( 200 ) ;
req = 0xBC ;
2011-07-23 10:12:12 -03:00
value = 1 ; /* power on */
2011-07-21 17:46:41 -03:00
index = 3 ;
2011-07-23 10:40:08 -03:00
blen = 0 ;
2011-07-21 17:46:41 -03:00
2011-07-23 10:40:08 -03:00
ret = az6007_usb_out_op ( adap - > dev , req , value , index , NULL , blen ) ;
if ( ret ! = 0 ) {
2011-07-21 17:46:41 -03:00
err ( " az6007_frontend_poweron failed!!! " ) ;
2011-07-23 10:40:08 -03:00
return - EIO ;
2011-07-21 17:46:41 -03:00
}
2011-07-23 11:54:40 -03:00
deb_info ( " az6007_frontend_poweron: OK \n " ) ;
2011-07-22 10:31:25 -03:00
2011-07-21 17:46:41 -03:00
return 0 ;
}
static int az6007_frontend_reset ( struct dvb_usb_adapter * adap )
{
int ret ;
u8 req ;
u16 value ;
u16 index ;
int blen ;
2011-07-23 11:54:40 -03:00
deb_info ( " az6007_frontend_reset adap=%p adap->dev=%p \n " , adap , adap - > dev ) ;
2011-07-21 18:31:14 -03:00
2011-07-23 10:40:08 -03:00
/* reset demodulator */
2011-07-21 17:46:41 -03:00
req = 0xC0 ;
2011-07-23 10:40:08 -03:00
value = 1 ; /* high */
2011-07-21 17:46:41 -03:00
index = 3 ;
2011-07-23 10:40:08 -03:00
blen = 0 ;
ret = az6007_usb_out_op ( adap - > dev , req , value , index , NULL , blen ) ;
if ( ret ! = 0 ) {
2011-07-21 17:46:41 -03:00
err ( " az6007_frontend_reset failed 1 !!! " ) ;
2011-07-23 10:40:08 -03:00
return - EIO ;
2011-07-21 17:46:41 -03:00
}
2011-07-21 18:31:14 -03:00
2011-07-21 17:46:41 -03:00
req = 0xC0 ;
2011-07-23 10:40:08 -03:00
value = 0 ; /* low */
2011-07-21 17:46:41 -03:00
index = 3 ;
2011-07-23 10:40:08 -03:00
blen = 0 ;
2011-07-21 17:46:41 -03:00
msleep_interruptible ( 200 ) ;
2011-07-23 10:40:08 -03:00
ret = az6007_usb_out_op ( adap - > dev , req , value , index , NULL , blen ) ;
if ( ret ! = 0 ) {
2011-07-21 17:46:41 -03:00
err ( " az6007_frontend_reset failed 2 !!! " ) ;
2011-07-23 10:40:08 -03:00
return - EIO ;
2011-07-21 17:46:41 -03:00
}
msleep_interruptible ( 200 ) ;
req = 0xC0 ;
2011-07-23 10:40:08 -03:00
value = 1 ; /* high */
2011-07-21 17:46:41 -03:00
index = 3 ;
2011-07-23 10:40:08 -03:00
blen = 0 ;
2011-07-21 17:46:41 -03:00
2011-07-23 10:40:08 -03:00
ret = az6007_usb_out_op ( adap - > dev , req , value , index , NULL , blen ) ;
if ( ret ! = 0 ) {
2011-07-21 17:46:41 -03:00
err ( " az6007_frontend_reset failed 3 !!! " ) ;
2011-07-23 10:40:08 -03:00
return - EIO ;
2011-07-21 17:46:41 -03:00
}
2011-07-21 18:31:14 -03:00
2011-07-21 17:46:41 -03:00
msleep_interruptible ( 200 ) ;
2011-07-21 18:31:14 -03:00
2011-07-23 11:54:40 -03:00
deb_info ( " reset az6007 frontend \n " ) ;
2011-07-21 18:31:14 -03:00
2011-07-21 17:46:41 -03:00
return 0 ;
}
static int az6007_led_on_off ( struct usb_interface * intf , int onoff )
{
int ret = - 1 ;
u8 req ;
u16 value ;
u16 index ;
int blen ;
2011-07-23 10:40:08 -03:00
/* TS through */
2011-07-21 17:46:41 -03:00
req = 0xBC ;
value = onoff ;
index = 0 ;
2011-07-23 10:40:08 -03:00
blen = 0 ;
2011-07-21 17:46:41 -03:00
ret = usb_control_msg ( interface_to_usbdev ( intf ) ,
2011-07-23 10:40:08 -03:00
usb_rcvctrlpipe ( interface_to_usbdev ( intf ) , 0 ) ,
req ,
USB_TYPE_VENDOR | USB_DIR_OUT ,
value , index , NULL , blen , 2000 ) ;
2011-07-21 17:46:41 -03:00
if ( ret < 0 ) {
warn ( " usb in operation failed. (%d) " , ret ) ;
ret = - EIO ;
} else
ret = 0 ;
2011-07-23 10:40:08 -03:00
deb_xfer ( " in: req. %02x, val: %04x, ind: %04x, buffer: " , req , value ,
index ) ;
2011-07-21 17:46:41 -03:00
return ret ;
}
2011-07-23 10:40:08 -03:00
static int az6007_frontend_tsbypass ( struct dvb_usb_adapter * adap , int onoff )
2011-07-21 17:46:41 -03:00
{
int ret ;
u8 req ;
u16 value ;
u16 index ;
int blen ;
2011-07-23 10:40:08 -03:00
/* TS through */
2011-07-21 17:46:41 -03:00
req = 0xC7 ;
value = onoff ;
index = 0 ;
2011-07-23 10:40:08 -03:00
blen = 0 ;
2011-07-21 17:46:41 -03:00
2011-07-23 10:40:08 -03:00
ret = az6007_usb_out_op ( adap - > dev , req , value , index , NULL , blen ) ;
if ( ret ! = 0 )
return - EIO ;
2011-07-21 17:46:41 -03:00
return 0 ;
}
static int az6007_frontend_attach ( struct dvb_usb_adapter * adap )
{
2011-07-21 18:31:14 -03:00
struct az6007_device_state * st = adap - > priv ;
int result ;
2011-07-22 10:31:25 -03:00
BUG_ON ( ! st ) ;
2011-07-21 17:46:41 -03:00
az6007_frontend_poweron ( adap ) ;
az6007_frontend_reset ( adap ) ;
2011-07-23 11:54:40 -03:00
info ( " az6007: attaching demod drxk " ) ;
2011-07-21 18:31:14 -03:00
adap - > fe = dvb_attach ( drxk_attach , & terratec_h7_drxk ,
& adap - > dev - > i2c_adap , & adap - > fe2 ) ;
if ( ! adap - > fe ) {
result = - EINVAL ;
goto out_free ;
2011-07-21 17:46:41 -03:00
}
2011-07-21 18:31:14 -03:00
2011-07-23 11:54:40 -03:00
deb_info ( " Setting hacks \n " ) ;
2011-07-22 10:31:25 -03:00
2011-07-21 18:31:14 -03:00
/* FIXME: do we need a pll semaphore? */
adap - > fe - > sec_priv = adap ;
sema_init ( & st - > pll_mutex , 1 ) ;
st - > gate_ctrl = adap - > fe - > ops . i2c_gate_ctrl ;
adap - > fe - > ops . i2c_gate_ctrl = drxk_gate_ctrl ;
adap - > fe2 - > id = 1 ;
2011-07-23 11:54:40 -03:00
info ( " az6007: attaching tuner mt2063 " ) ;
2011-07-21 18:31:14 -03:00
/* Attach mt2063 to DVB-C frontend */
if ( adap - > fe - > ops . i2c_gate_ctrl )
adap - > fe - > ops . i2c_gate_ctrl ( adap - > fe , 1 ) ;
if ( ! dvb_attach ( mt2063_attach , adap - > fe , & az6007_mt2063_config ,
& adap - > dev - > i2c_adap ) ) {
result = - EINVAL ;
goto out_free ;
2011-07-21 17:46:41 -03:00
}
2011-07-21 18:31:14 -03:00
if ( adap - > fe - > ops . i2c_gate_ctrl )
adap - > fe - > ops . i2c_gate_ctrl ( adap - > fe , 0 ) ;
/* Hack - needed due to drxk */
adap - > fe2 - > tuner_priv = adap - > fe - > tuner_priv ;
memcpy ( & adap - > fe2 - > ops . tuner_ops ,
2011-07-23 10:40:08 -03:00
& adap - > fe - > ops . tuner_ops , sizeof ( adap - > fe - > ops . tuner_ops ) ) ;
2011-07-24 09:25:39 -03:00
2011-07-21 17:46:41 -03:00
return 0 ;
2011-07-21 18:31:14 -03:00
out_free :
if ( adap - > fe )
dvb_frontend_detach ( adap - > fe ) ;
adap - > fe = NULL ;
adap - > fe2 = NULL ;
return result ;
2011-07-21 17:46:41 -03:00
}
static struct dvb_usb_device_properties az6007_properties ;
2011-07-23 10:40:08 -03:00
static void az6007_usb_disconnect ( struct usb_interface * intf )
2011-07-21 17:46:41 -03:00
{
2011-07-23 10:40:08 -03:00
dvb_usb_device_exit ( intf ) ;
2011-07-21 17:46:41 -03:00
}
/* I2C */
2011-07-23 10:40:08 -03:00
static int az6007_i2c_xfer ( struct i2c_adapter * adap , struct i2c_msg msgs [ ] ,
int num )
2011-07-21 17:46:41 -03:00
{
struct dvb_usb_device * d = i2c_get_adapdata ( adap ) ;
2011-07-22 10:31:25 -03:00
int i , j , len ;
int ret = 0 ;
2011-07-21 17:46:41 -03:00
u16 index ;
u16 value ;
int length ;
2011-07-22 10:31:25 -03:00
u8 req , addr ;
2011-07-21 17:46:41 -03:00
u8 data [ 512 ] ;
2011-07-21 18:31:14 -03:00
2011-07-21 17:46:41 -03:00
if ( mutex_lock_interruptible ( & d - > i2c_mutex ) < 0 )
return - EAGAIN ;
2011-07-22 10:31:25 -03:00
for ( i = 0 ; i < num ; i + + ) {
addr = msgs [ i ] . addr < < 1 ;
if ( ( ( i + 1 ) < num )
& & ( msgs [ i ] . len = = 1 )
& & ( ! msgs [ i ] . flags & I2C_M_RD )
& & ( msgs [ i + 1 ] . flags & I2C_M_RD )
& & ( msgs [ i ] . addr = = msgs [ i + 1 ] . addr ) ) {
/*
* A write + read xfer for the same address , where
* the first xfer has just 1 byte length .
* Need to join both into one operation
*/
2011-07-23 09:51:12 -03:00
if ( dvb_usb_az6007_debug & 2 )
printk ( KERN_DEBUG
" az6007 I2C xfer write+read addr=0x%x len=%d/%d: " ,
addr , msgs [ i ] . len , msgs [ i + 1 ] . len ) ;
2011-07-22 10:31:25 -03:00
req = 0xb9 ;
2011-07-23 09:51:12 -03:00
index = msgs [ i ] . buf [ 0 ] ;
value = addr | ( 1 < < 8 ) ;
2011-07-22 10:31:25 -03:00
length = 6 + msgs [ i + 1 ] . len ;
len = msgs [ i + 1 ] . len ;
2011-07-23 10:40:08 -03:00
ret = az6007_usb_in_op ( d , req , value , index , data ,
length ) ;
2011-07-22 10:31:25 -03:00
if ( ret > = len ) {
for ( j = 0 ; j < len ; j + + ) {
msgs [ i + 1 ] . buf [ j ] = data [ j + 5 ] ;
2011-07-23 09:51:12 -03:00
if ( dvb_usb_az6007_debug & 2 )
printk ( KERN_CONT
" 0x%02x " ,
msgs [ i + 1 ] . buf [ j ] ) ;
2011-07-22 10:31:25 -03:00
}
} else
ret = - EIO ;
i + + ;
} else if ( ! ( msgs [ i ] . flags & I2C_M_RD ) ) {
/* write bytes */
2011-07-23 09:51:12 -03:00
if ( dvb_usb_az6007_debug & 2 )
printk ( KERN_DEBUG
" az6007 I2C xfer write addr=0x%x len=%d: " ,
addr , msgs [ i ] . len ) ;
2011-07-22 10:31:25 -03:00
req = 0xbd ;
index = msgs [ i ] . buf [ 0 ] ;
value = addr | ( 1 < < 8 ) ;
length = msgs [ i ] . len - 1 ;
len = msgs [ i ] . len - 1 ;
2011-07-23 09:51:12 -03:00
if ( dvb_usb_az6007_debug & 2 )
2011-07-23 10:40:08 -03:00
printk ( KERN_CONT " (0x%02x) " , msgs [ i ] . buf [ 0 ] ) ;
for ( j = 0 ; j < len ; j + + ) {
2011-07-22 10:31:25 -03:00
data [ j ] = msgs [ i ] . buf [ j + 1 ] ;
2011-07-23 09:51:12 -03:00
if ( dvb_usb_az6007_debug & 2 )
2011-07-23 10:40:08 -03:00
printk ( KERN_CONT " 0x%02x " , data [ j ] ) ;
2011-07-21 17:46:41 -03:00
}
2011-07-23 10:40:08 -03:00
ret = az6007_usb_out_op ( d , req , value , index , data ,
length ) ;
2011-07-22 10:31:25 -03:00
} else {
/* read bytes */
2011-07-23 09:51:12 -03:00
if ( dvb_usb_az6007_debug & 2 )
printk ( KERN_DEBUG
" az6007 I2C xfer read addr=0x%x len=%d: " ,
addr , msgs [ i ] . len ) ;
2011-07-22 10:31:25 -03:00
req = 0xb9 ;
index = msgs [ i ] . buf [ 0 ] ;
value = addr ;
length = msgs [ i ] . len + 6 ;
len = msgs [ i ] . len ;
2011-07-23 10:40:08 -03:00
ret = az6007_usb_in_op ( d , req , value , index , data ,
length ) ;
for ( j = 0 ; j < len ; j + + ) {
2011-07-22 10:31:25 -03:00
msgs [ i ] . buf [ j ] = data [ j + 5 ] ;
2011-07-23 09:51:12 -03:00
if ( dvb_usb_az6007_debug & 2 )
printk ( KERN_CONT
" 0x%02x " , data [ j + 5 ] ) ;
2011-07-21 17:46:41 -03:00
}
}
2011-07-23 09:51:12 -03:00
if ( dvb_usb_az6007_debug & 2 )
printk ( KERN_CONT " \n " ) ;
2011-07-22 10:31:25 -03:00
if ( ret < 0 )
goto err ;
2011-07-21 17:46:41 -03:00
}
2011-07-22 10:31:25 -03:00
err :
2011-07-21 17:46:41 -03:00
mutex_unlock ( & d - > i2c_mutex ) ;
2011-07-22 10:31:25 -03:00
if ( ret < 0 ) {
2011-07-23 11:54:40 -03:00
info ( " %s ERROR: %i " , __func__ , ret ) ;
2011-07-22 10:31:25 -03:00
return ret ;
}
return num ;
2011-07-21 17:46:41 -03:00
}
static u32 az6007_i2c_func ( struct i2c_adapter * adapter )
{
return I2C_FUNC_I2C ;
}
static struct i2c_algorithm az6007_i2c_algo = {
2011-07-23 10:40:08 -03:00
. master_xfer = az6007_i2c_xfer ,
2011-07-21 17:46:41 -03:00
. functionality = az6007_i2c_func ,
} ;
2011-07-23 10:40:08 -03:00
int az6007_identify_state ( struct usb_device * udev ,
struct dvb_usb_device_properties * props ,
struct dvb_usb_device_description * * desc , int * cold )
2011-07-21 17:46:41 -03:00
{
u8 b [ 16 ] ;
2011-07-23 10:40:08 -03:00
s16 ret = usb_control_msg ( udev , usb_rcvctrlpipe ( udev , 0 ) ,
0xb7 , USB_TYPE_VENDOR | USB_DIR_IN , 6 , 0 , b ,
6 , USB_CTRL_GET_TIMEOUT ) ;
2011-07-21 17:46:41 -03:00
2011-07-23 11:54:40 -03:00
deb_info ( " FW GET_VERSION length: %d \n " , ret ) ;
2011-07-21 17:46:41 -03:00
* cold = ret < = 0 ;
2011-07-23 11:54:40 -03:00
deb_info ( " cold: %d \n " , * cold ) ;
2011-07-21 17:46:41 -03:00
return 0 ;
}
static int az6007_usb_probe ( struct usb_interface * intf ,
2011-07-23 10:40:08 -03:00
const struct usb_device_id * id )
2011-07-21 17:46:41 -03:00
{
2011-07-21 18:31:14 -03:00
az6007_led_on_off ( intf , 0 ) ;
2011-07-21 17:46:41 -03:00
return dvb_usb_device_init ( intf , & az6007_properties ,
2011-07-21 18:31:14 -03:00
THIS_MODULE , NULL , adapter_nr ) ;
2011-07-21 17:46:41 -03:00
}
2011-07-23 10:40:08 -03:00
static struct usb_device_id az6007_usb_table [ ] = {
{ USB_DEVICE ( USB_VID_AZUREWAVE , USB_PID_AZUREWAVE_6007 ) } ,
{ USB_DEVICE ( USB_VID_TERRATEC , USB_PID_TERRATEC_H7 ) } ,
{ 0 } ,
2011-07-21 17:46:41 -03:00
} ;
MODULE_DEVICE_TABLE ( usb , az6007_usb_table ) ;
static struct dvb_usb_device_properties az6007_properties = {
. caps = DVB_USB_IS_AN_I2C_ADAPTER ,
. usb_ctrl = CYPRESS_FX2 ,
. firmware = " dvb-usb-az6007-03.fw " ,
. no_reconnect = 1 ,
. identify_state = az6007_identify_state ,
. num_adapters = 1 ,
. adapter = {
{
. streaming_ctrl = az6007_streaming_ctrl ,
. frontend_attach = az6007_frontend_attach ,
/* parameter for the MPEG2-data transfer */
. stream = {
. type = USB_BULK ,
. count = 10 ,
. endpoint = 0x02 ,
. u = {
. bulk = {
. buffersize = 4096 ,
}
}
} ,
2011-07-22 10:31:25 -03:00
. size_of_priv = sizeof ( struct az6007_device_state ) ,
2011-07-21 17:46:41 -03:00
}
} ,
2011-07-23 10:40:08 -03:00
/* .power_ctrl = az6007_power_ctrl, */
2011-07-21 17:46:41 -03:00
. read_mac_address = az6007_read_mac_addr ,
2011-07-21 18:31:14 -03:00
. rc . legacy = {
. rc_map_table = rc_map_az6007_table ,
. rc_map_size = ARRAY_SIZE ( rc_map_az6007_table ) ,
. rc_interval = 400 ,
. rc_query = az6007_rc_query ,
} ,
2011-07-21 17:46:41 -03:00
. i2c_algo = & az6007_i2c_algo ,
. num_device_descs = 2 ,
. devices = {
{ . name = " AzureWave DTV StarBox DVB-T/C USB2.0 (az6007) " ,
. cold_ids = { & az6007_usb_table [ 0 ] , NULL } ,
. warm_ids = { NULL } ,
} ,
{ . name = " TerraTec DTV StarBox DVB-T/C USB2.0 (az6007) " ,
. cold_ids = { & az6007_usb_table [ 1 ] , NULL } ,
. warm_ids = { NULL } ,
} ,
2011-07-21 18:31:14 -03:00
{ NULL } ,
2011-07-21 17:46:41 -03:00
}
} ;
2011-07-21 18:31:14 -03:00
2011-07-21 17:46:41 -03:00
/* usb specific object needed to register this driver with the usb subsystem */
static struct usb_driver az6007_usb_driver = {
. name = " dvb_usb_az6007 " ,
2011-07-23 10:40:08 -03:00
. probe = az6007_usb_probe ,
2011-07-21 17:46:41 -03:00
. disconnect = dvb_usb_device_exit ,
2011-07-23 10:40:08 -03:00
/* .disconnect = az6007_usb_disconnect, */
. id_table = az6007_usb_table ,
2011-07-21 17:46:41 -03:00
} ;
/* module stuff */
static int __init az6007_usb_module_init ( void )
{
int result ;
2011-07-23 11:54:40 -03:00
deb_info ( " az6007 usb module init \n " ) ;
2011-07-23 10:40:08 -03:00
result = usb_register ( & az6007_usb_driver ) ;
if ( result ) {
err ( " usb_register failed. (%d) " , result ) ;
2011-07-21 17:46:41 -03:00
return result ;
}
return 0 ;
}
static void __exit az6007_usb_module_exit ( void )
{
/* deregister this driver from the USB subsystem */
2011-07-23 11:54:40 -03:00
deb_info ( " az6007 usb module exit \n " ) ;
2011-07-21 17:46:41 -03:00
usb_deregister ( & az6007_usb_driver ) ;
}
module_init ( az6007_usb_module_init ) ;
module_exit ( az6007_usb_module_exit ) ;
MODULE_AUTHOR ( " Henry Wang <Henry.wang@AzureWave.com> " ) ;
MODULE_DESCRIPTION ( " Driver for AzureWave 6007 DVB-C/T USB2.0 and clones " ) ;
2011-07-23 10:12:12 -03:00
MODULE_VERSION ( " 1.1 " ) ;
2011-07-21 17:46:41 -03:00
MODULE_LICENSE ( " GPL " ) ;