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 ( )
*
2012-01-21 10:35:12 -03:00
* Copyright ( c ) 2010 - 2011 Mauro Carvalho Chehab < mchehab @ redhat . com >
* Driver modified by in order to work with upstream drxk driver , and
* tons of bugs got fixed .
2011-07-23 10:59:25 -03:00
*
* 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
# define DVB_USB_LOG_PREFIX "az6007"
2011-07-25 10:38:20 -03:00
# include "dvb-usb.h"
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 ) ;
2011-07-25 12:45:16 -03:00
/* Known requests (Cypress FX2 firmware + az6007 "private" ones*/
# define FX2_OED 0xb5
# define AZ6007_READ_DATA 0xb7
# define AZ6007_I2C_RD 0xb9
# define AZ6007_POWER 0xbc
# define AZ6007_I2C_WR 0xbd
# define FX2_SCON1 0xc0
# define AZ6007_TS_THROUGH 0xc7
2011-07-29 11:31:13 -03:00
# define AZ6007_READ_IR 0xb4
2011-07-25 12:45:16 -03:00
2011-07-21 17:46:41 -03:00
struct az6007_device_state {
2012-01-21 11:19:16 -03:00
struct mutex mutex ;
2012-03-04 19:22:05 -03:00
struct mutex ca_mutex ;
2012-01-21 11:19:16 -03:00
struct dvb_ca_en50221 ca ;
unsigned warm : 1 ;
2011-07-23 10:40:08 -03:00
int ( * gate_ctrl ) ( struct dvb_frontend * , int ) ;
2012-01-20 18:37:01 -03:00
unsigned char data [ 4096 ] ;
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 ,
2012-01-20 18:36:26 -03:00
. parallel_ts = true ,
. dynamic_clk = true ,
. single_master = true ,
2012-01-21 07:57:06 -03:00
. enable_merr_cfg = true ,
2012-01-20 18:36:26 -03:00
. no_i2c_bridge = false ,
2012-01-16 18:57:51 -03:00
. chunk_size = 64 ,
2012-01-20 19:13:07 -03:00
. mpeg_out_clk_strength = 0x02 ,
2012-01-20 18:37:01 -03:00
. microcode_name = " dvb-usb-terratec-h7-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 ;
2012-01-16 20:37:13 -03:00
st = adap - > dev - > priv ;
2011-07-22 10:31:25 -03:00
if ( ! st )
2011-07-21 18:31:14 -03:00
return - EINVAL ;
2012-01-21 10:35:12 -03:00
if ( enable )
2011-07-21 18:31:14 -03:00
status = st - > gate_ctrl ( fe , 1 ) ;
2012-01-21 10:35:12 -03:00
else
2011-07-21 18:31:14 -03:00
status = st - > gate_ctrl ( fe , 0 ) ;
2012-01-21 10:35:12 -03:00
2011-07-21 18:31:14 -03:00
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 ,
} ;
2012-01-21 11:19:16 -03:00
static int __az6007_read ( struct usb_device * udev , u8 req , u16 value ,
2011-07-23 10:40:08 -03:00
u16 index , u8 * b , int blen )
2011-07-21 17:46:41 -03:00
{
2011-07-29 11:40:40 -03:00
int ret ;
2011-07-21 17:46:41 -03:00
2011-07-25 11:17:41 -03:00
ret = usb_control_msg ( udev ,
usb_rcvctrlpipe ( udev , 0 ) ,
2011-07-23 10:40:08 -03:00
req ,
USB_TYPE_VENDOR | USB_DIR_IN ,
value , index , b , blen , 5000 ) ;
2011-07-21 17:46:41 -03:00
if ( ret < 0 ) {
2011-07-29 11:40:40 -03:00
warn ( " usb read 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 ;
}
2012-01-21 11:19:16 -03:00
static int az6007_read ( struct dvb_usb_device * d , u8 req , u16 value ,
u16 index , u8 * b , int blen )
{
struct az6007_device_state * st = d - > priv ;
int ret ;
if ( mutex_lock_interruptible ( & st - > mutex ) < 0 )
return - EAGAIN ;
ret = __az6007_read ( d - > udev , req , value , index , b , blen ) ;
mutex_unlock ( & st - > mutex ) ;
return ret ;
}
static int __az6007_write ( struct usb_device * udev , u8 req , u16 value ,
2011-07-21 17:46:41 -03:00
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-25 11:17:41 -03:00
ret = usb_control_msg ( udev ,
usb_sndctrlpipe ( udev , 0 ) ,
2011-07-23 10:40:08 -03:00
req ,
USB_TYPE_VENDOR | USB_DIR_OUT ,
value , index , b , blen , 5000 ) ;
if ( ret ! = blen ) {
2011-07-29 11:40:40 -03:00
err ( " usb write 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 ;
}
2012-01-21 11:19:16 -03:00
static int az6007_write ( struct dvb_usb_device * d , u8 req , u16 value ,
u16 index , u8 * b , int blen )
{
struct az6007_device_state * st = d - > priv ;
int ret ;
if ( mutex_lock_interruptible ( & st - > mutex ) < 0 )
return - EAGAIN ;
ret = __az6007_write ( d - > udev , req , value , index , b , blen ) ;
mutex_unlock ( & st - > mutex ) ;
return ret ;
}
2011-07-21 17:46:41 -03:00
static int az6007_streaming_ctrl ( struct dvb_usb_adapter * adap , int onoff )
{
2012-01-21 11:19:16 -03:00
struct dvb_usb_device * d = adap - > dev ;
2012-01-20 18:37:01 -03:00
deb_info ( " %s: %s " , __func__ , onoff ? " enable " : " disable " ) ;
2012-01-21 11:19:16 -03:00
return az6007_write ( d , 0xbc , onoff , 0 , NULL , 0 ) ;
2011-07-21 17:46:41 -03:00
}
/* remote control stuff (does not work with my box) */
2012-01-21 12:20:30 -03:00
static int az6007_rc_query ( struct dvb_usb_device * d )
2011-07-21 17:46:41 -03:00
{
2012-01-21 11:53:18 -03:00
struct az6007_device_state * st = d - > priv ;
2012-01-21 12:14:13 -03:00
unsigned code = 0 ;
2011-07-21 17:46:41 -03:00
2012-01-21 11:53:18 -03:00
az6007_read ( d , AZ6007_READ_IR , 0 , 0 , st - > data , 10 ) ;
2011-07-21 17:46:41 -03:00
2012-01-21 12:20:30 -03:00
if ( st - > data [ 1 ] = = 0x44 )
2011-07-21 17:46:41 -03:00
return 0 ;
2012-01-21 12:14:13 -03:00
if ( ( st - > data [ 1 ] ^ st - > data [ 2 ] ) = = 0xff )
code = st - > data [ 1 ] ;
else
code = st - > data [ 1 ] < < 8 | st - > data [ 2 ] ;
if ( ( st - > data [ 3 ] ^ st - > data [ 4 ] ) = = 0xff )
code = code < < 8 | st - > data [ 3 ] ;
else
2012-01-21 13:52:39 -02:00
code = code < < 16 | st - > data [ 3 ] < < 8 | st - > data [ 4 ] ;
2011-07-29 11:31:13 -03:00
2012-01-21 12:20:30 -03:00
rc_keydown ( d - > rc_dev , code , st - > data [ 5 ] ) ;
2011-07-29 11:31:13 -03:00
2011-07-21 17:46:41 -03:00
return 0 ;
}
2012-03-04 19:22:05 -03:00
static int az6007_ci_read_attribute_mem ( struct dvb_ca_en50221 * ca ,
int slot ,
int address )
{
struct dvb_usb_device * d = ( struct dvb_usb_device * ) ca - > data ;
struct az6007_device_state * state = ( struct az6007_device_state * ) d - > priv ;
int ret ;
u8 req ;
u16 value ;
u16 index ;
int blen ;
u8 * b ;
if ( slot ! = 0 )
return - EINVAL ;
b = kmalloc ( 12 , GFP_KERNEL ) ;
if ( ! b )
return - ENOMEM ;
mutex_lock ( & state - > ca_mutex ) ;
req = 0xC1 ;
value = address ;
index = 0 ;
blen = 1 ;
ret = az6007_read ( d , req , value , index , b , blen ) ;
if ( ret < 0 ) {
warn ( " usb in operation failed. (%d) " , ret ) ;
ret = - EINVAL ;
} else {
ret = b [ 0 ] ;
}
mutex_unlock ( & state - > ca_mutex ) ;
kfree ( b ) ;
return ret ;
}
static int az6007_ci_write_attribute_mem ( struct dvb_ca_en50221 * ca ,
int slot ,
int address ,
u8 value )
{
struct dvb_usb_device * d = ( struct dvb_usb_device * ) ca - > data ;
struct az6007_device_state * state = ( struct az6007_device_state * ) d - > priv ;
int ret ;
u8 req ;
u16 value1 ;
u16 index ;
int blen ;
deb_info ( " %s %d " , __func__ , slot ) ;
if ( slot ! = 0 )
return - EINVAL ;
mutex_lock ( & state - > ca_mutex ) ;
req = 0xC2 ;
value1 = address ;
index = value ;
blen = 0 ;
ret = az6007_write ( d , req , value1 , index , NULL , blen ) ;
if ( ret ! = 0 )
warn ( " usb out operation failed. (%d) " , ret ) ;
mutex_unlock ( & state - > ca_mutex ) ;
return ret ;
}
static int az6007_ci_read_cam_control ( struct dvb_ca_en50221 * ca ,
int slot ,
u8 address )
{
struct dvb_usb_device * d = ( struct dvb_usb_device * ) ca - > data ;
struct az6007_device_state * state = ( struct az6007_device_state * ) d - > priv ;
int ret ;
u8 req ;
u16 value ;
u16 index ;
int blen ;
u8 * b ;
if ( slot ! = 0 )
return - EINVAL ;
b = kmalloc ( 12 , GFP_KERNEL ) ;
if ( ! b )
return - ENOMEM ;
mutex_lock ( & state - > ca_mutex ) ;
req = 0xC3 ;
value = address ;
index = 0 ;
blen = 2 ;
ret = az6007_read ( d , req , value , index , b , blen ) ;
if ( ret < 0 ) {
warn ( " usb in operation failed. (%d) " , ret ) ;
ret = - EINVAL ;
} else {
if ( b [ 0 ] = = 0 )
warn ( " Read CI IO error " ) ;
ret = b [ 1 ] ;
deb_info ( " read cam data = %x from 0x%x " , b [ 1 ] , value ) ;
}
mutex_unlock ( & state - > ca_mutex ) ;
kfree ( b ) ;
return ret ;
}
static int az6007_ci_write_cam_control ( struct dvb_ca_en50221 * ca ,
int slot ,
u8 address ,
u8 value )
{
struct dvb_usb_device * d = ( struct dvb_usb_device * ) ca - > data ;
struct az6007_device_state * state = ( struct az6007_device_state * ) d - > priv ;
int ret ;
u8 req ;
u16 value1 ;
u16 index ;
int blen ;
if ( slot ! = 0 )
return - EINVAL ;
mutex_lock ( & state - > ca_mutex ) ;
req = 0xC4 ;
value1 = address ;
index = value ;
blen = 0 ;
ret = az6007_write ( d , req , value1 , index , NULL , blen ) ;
if ( ret ! = 0 ) {
warn ( " usb out operation failed. (%d) " , ret ) ;
goto failed ;
}
failed :
mutex_unlock ( & state - > ca_mutex ) ;
return ret ;
}
static int CI_CamReady ( struct dvb_ca_en50221 * ca , int slot )
{
struct dvb_usb_device * d = ( struct dvb_usb_device * ) ca - > data ;
int ret ;
u8 req ;
u16 value ;
u16 index ;
int blen ;
u8 * b ;
b = kmalloc ( 12 , GFP_KERNEL ) ;
if ( ! b )
return - ENOMEM ;
req = 0xC8 ;
value = 0 ;
index = 0 ;
blen = 1 ;
ret = az6007_read ( d , req , value , index , b , blen ) ;
if ( ret < 0 ) {
warn ( " usb in operation failed. (%d) " , ret ) ;
ret = - EIO ;
} else {
ret = b [ 0 ] ;
}
kfree ( b ) ;
return ret ;
}
static int az6007_ci_slot_reset ( struct dvb_ca_en50221 * ca , int slot )
{
struct dvb_usb_device * d = ( struct dvb_usb_device * ) ca - > data ;
struct az6007_device_state * state = ( struct az6007_device_state * ) d - > priv ;
int ret , i ;
u8 req ;
u16 value ;
u16 index ;
int blen ;
mutex_lock ( & state - > ca_mutex ) ;
req = 0xC6 ;
value = 1 ;
index = 0 ;
blen = 0 ;
ret = az6007_write ( d , req , value , index , NULL , blen ) ;
if ( ret ! = 0 ) {
warn ( " usb out operation failed. (%d) " , ret ) ;
goto failed ;
}
msleep ( 500 ) ;
req = 0xC6 ;
value = 0 ;
index = 0 ;
blen = 0 ;
ret = az6007_write ( d , req , value , index , NULL , blen ) ;
if ( ret ! = 0 ) {
warn ( " usb out operation failed. (%d) " , ret ) ;
goto failed ;
}
for ( i = 0 ; i < 15 ; i + + ) {
msleep ( 100 ) ;
if ( CI_CamReady ( ca , slot ) ) {
deb_info ( " CAM Ready " ) ;
break ;
}
}
msleep ( 5000 ) ;
failed :
mutex_unlock ( & state - > ca_mutex ) ;
return ret ;
}
static int az6007_ci_slot_shutdown ( struct dvb_ca_en50221 * ca , int slot )
{
return 0 ;
}
static int az6007_ci_slot_ts_enable ( struct dvb_ca_en50221 * ca , int slot )
{
struct dvb_usb_device * d = ( struct dvb_usb_device * ) ca - > data ;
struct az6007_device_state * state = ( struct az6007_device_state * ) d - > priv ;
int ret ;
u8 req ;
u16 value ;
u16 index ;
int blen ;
deb_info ( " %s " , __func__ ) ;
mutex_lock ( & state - > ca_mutex ) ;
req = 0xC7 ;
value = 1 ;
index = 0 ;
blen = 0 ;
ret = az6007_write ( d , req , value , index , NULL , blen ) ;
if ( ret ! = 0 ) {
warn ( " usb out operation failed. (%d) " , ret ) ;
goto failed ;
}
failed :
mutex_unlock ( & state - > ca_mutex ) ;
return ret ;
}
static int az6007_ci_poll_slot_status ( struct dvb_ca_en50221 * ca , int slot , int open )
{
struct dvb_usb_device * d = ( struct dvb_usb_device * ) ca - > data ;
struct az6007_device_state * state = ( struct az6007_device_state * ) d - > priv ;
int ret ;
u8 req ;
u16 value ;
u16 index ;
int blen ;
u8 * b ;
b = kmalloc ( 12 , GFP_KERNEL ) ;
if ( ! b )
return - ENOMEM ;
mutex_lock ( & state - > ca_mutex ) ;
req = 0xC5 ;
value = 0 ;
index = 0 ;
blen = 1 ;
ret = az6007_read ( d , req , value , index , b , blen ) ;
if ( ret < 0 ) {
warn ( " usb in operation failed. (%d) " , ret ) ;
ret = - EIO ;
} else
ret = 0 ;
if ( ! ret & & b [ 0 ] = = 1 ) {
ret = DVB_CA_EN50221_POLL_CAM_PRESENT |
DVB_CA_EN50221_POLL_CAM_READY ;
}
mutex_unlock ( & state - > ca_mutex ) ;
kfree ( b ) ;
return ret ;
}
static void az6007_ci_uninit ( struct dvb_usb_device * d )
{
struct az6007_device_state * state ;
deb_info ( " %s " , __func__ ) ;
if ( NULL = = d )
return ;
state = ( struct az6007_device_state * ) d - > priv ;
if ( NULL = = state )
return ;
if ( NULL = = state - > ca . data )
return ;
dvb_ca_en50221_release ( & state - > ca ) ;
memset ( & state - > ca , 0 , sizeof ( state - > ca ) ) ;
}
static int az6007_ci_init ( struct dvb_usb_adapter * a )
{
struct dvb_usb_device * d = a - > dev ;
struct az6007_device_state * state = ( struct az6007_device_state * ) d - > priv ;
int ret ;
deb_info ( " %s " , __func__ ) ;
mutex_init ( & state - > ca_mutex ) ;
state - > ca . owner = THIS_MODULE ;
state - > ca . read_attribute_mem = az6007_ci_read_attribute_mem ;
state - > ca . write_attribute_mem = az6007_ci_write_attribute_mem ;
state - > ca . read_cam_control = az6007_ci_read_cam_control ;
state - > ca . write_cam_control = az6007_ci_write_cam_control ;
state - > ca . slot_reset = az6007_ci_slot_reset ;
state - > ca . slot_shutdown = az6007_ci_slot_shutdown ;
state - > ca . slot_ts_enable = az6007_ci_slot_ts_enable ;
state - > ca . poll_slot_status = az6007_ci_poll_slot_status ;
state - > ca . data = d ;
ret = dvb_ca_en50221_init ( & a - > dvb_adap ,
& state - > ca ,
0 , /* flags */
1 ) ; /* n_slots */
if ( ret ! = 0 ) {
err ( " Cannot initialize CI: Error %d. " , ret ) ;
memset ( & state - > ca , 0 , sizeof ( state - > ca ) ) ;
return ret ;
}
deb_info ( " CI initialized. " ) ;
return 0 ;
}
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
{
2012-01-21 11:53:18 -03:00
struct az6007_device_state * st = d - > priv ;
2011-07-25 12:45:16 -03:00
int ret ;
2012-01-21 11:53:18 -03:00
ret = az6007_read ( d , AZ6007_READ_DATA , 6 , 0 , st - > data , 6 ) ;
memcpy ( mac , st - > data , sizeof ( mac ) ) ;
2011-07-21 17:46:41 -03:00
2011-07-25 12:45:16 -03:00
if ( ret > 0 )
2012-07-06 11:31:51 -03:00
deb_info ( " %s: mac is %pM \n " , __func__ , mac ) ;
2011-07-25 12:45:16 -03:00
return ret ;
}
2011-07-25 11:07:20 -03:00
2011-07-21 17:46:41 -03:00
static int az6007_frontend_attach ( struct dvb_usb_adapter * adap )
{
2012-01-16 20:37:13 -03:00
struct az6007_device_state * st = adap - > dev - > priv ;
2011-07-21 18:31:14 -03:00
2012-01-20 18:37:01 -03:00
deb_info ( " attaching demod drxk " ) ;
2011-07-21 17:46:41 -03:00
2012-01-16 18:57:51 -03:00
adap - > fe_adap [ 0 ] . fe = dvb_attach ( drxk_attach , & terratec_h7_drxk ,
& adap - > dev - > i2c_adap ) ;
if ( ! adap - > fe_adap [ 0 ] . fe )
2011-07-31 10:11:32 -03:00
return - EINVAL ;
2011-07-22 10:31:25 -03:00
2012-01-16 18:57:51 -03:00
adap - > fe_adap [ 0 ] . fe - > sec_priv = adap ;
st - > gate_ctrl = adap - > fe_adap [ 0 ] . fe - > ops . i2c_gate_ctrl ;
adap - > fe_adap [ 0 ] . fe - > ops . i2c_gate_ctrl = drxk_gate_ctrl ;
2011-07-21 18:31:14 -03:00
2012-03-04 19:22:05 -03:00
az6007_ci_init ( adap ) ;
2011-07-31 10:11:32 -03:00
return 0 ;
}
static int az6007_tuner_attach ( struct dvb_usb_adapter * adap )
{
2012-01-20 18:37:01 -03:00
deb_info ( " attaching tuner mt2063 " ) ;
2012-01-21 10:35:12 -03:00
2011-07-21 18:31:14 -03:00
/* Attach mt2063 to DVB-C frontend */
2012-01-16 18:57:51 -03:00
if ( adap - > fe_adap [ 0 ] . fe - > ops . i2c_gate_ctrl )
adap - > fe_adap [ 0 ] . fe - > ops . i2c_gate_ctrl ( adap - > fe_adap [ 0 ] . fe , 1 ) ;
2012-01-20 18:37:01 -03:00
if ( ! dvb_attach ( mt2063_attach , adap - > fe_adap [ 0 ] . fe ,
2012-01-16 18:57:51 -03:00
& az6007_mt2063_config ,
2011-07-31 10:11:32 -03:00
& adap - > dev - > i2c_adap ) )
return - EINVAL ;
2011-07-21 18:31:14 -03:00
2012-01-16 18:57:51 -03:00
if ( adap - > fe_adap [ 0 ] . fe - > ops . i2c_gate_ctrl )
adap - > fe_adap [ 0 ] . fe - > ops . i2c_gate_ctrl ( adap - > fe_adap [ 0 ] . fe , 0 ) ;
2011-07-24 09:25:39 -03:00
2011-07-21 17:46:41 -03:00
return 0 ;
}
2011-07-25 11:07:20 -03:00
int az6007_power_ctrl ( struct dvb_usb_device * d , int onoff )
{
2012-01-20 18:37:01 -03:00
struct az6007_device_state * st = d - > priv ;
int ret ;
deb_info ( " %s() \n " , __func__ ) ;
if ( ! st - > warm ) {
2012-01-21 11:19:16 -03:00
mutex_init ( & st - > mutex ) ;
2012-01-20 18:37:01 -03:00
2012-01-21 11:19:16 -03:00
ret = az6007_write ( d , AZ6007_POWER , 0 , 2 , NULL , 0 ) ;
2012-01-20 18:37:01 -03:00
if ( ret < 0 )
return ret ;
msleep ( 60 ) ;
2012-01-21 11:19:16 -03:00
ret = az6007_write ( d , AZ6007_POWER , 1 , 4 , NULL , 0 ) ;
2012-01-20 18:37:01 -03:00
if ( ret < 0 )
return ret ;
msleep ( 100 ) ;
2012-01-21 11:19:16 -03:00
ret = az6007_write ( d , AZ6007_POWER , 1 , 3 , NULL , 0 ) ;
2012-01-20 18:37:01 -03:00
if ( ret < 0 )
return ret ;
msleep ( 20 ) ;
2012-01-21 11:19:16 -03:00
ret = az6007_write ( d , AZ6007_POWER , 1 , 4 , NULL , 0 ) ;
2012-01-20 18:37:01 -03:00
if ( ret < 0 )
return ret ;
msleep ( 400 ) ;
2012-01-21 11:19:16 -03:00
ret = az6007_write ( d , FX2_SCON1 , 0 , 3 , NULL , 0 ) ;
2012-01-20 18:37:01 -03:00
if ( ret < 0 )
return ret ;
2012-01-21 13:52:39 -02:00
msleep ( 150 ) ;
2012-01-21 11:19:16 -03:00
ret = az6007_write ( d , FX2_SCON1 , 1 , 3 , NULL , 0 ) ;
2012-01-20 18:37:01 -03:00
if ( ret < 0 )
return ret ;
2012-01-21 13:52:39 -02:00
msleep ( 430 ) ;
2012-01-21 11:19:16 -03:00
ret = az6007_write ( d , AZ6007_POWER , 0 , 0 , NULL , 0 ) ;
2012-01-20 18:37:01 -03:00
if ( ret < 0 )
return ret ;
2011-07-25 11:07:20 -03:00
2012-01-20 18:37:01 -03:00
st - > warm = true ;
2011-07-25 11:07:20 -03:00
2012-01-20 18:37:01 -03:00
return 0 ;
}
2011-07-25 11:07:20 -03:00
2012-01-20 18:37:01 -03:00
if ( ! onoff )
return 0 ;
2012-01-21 11:19:16 -03:00
az6007_write ( d , AZ6007_POWER , 0 , 0 , NULL , 0 ) ;
az6007_write ( d , AZ6007_TS_THROUGH , 0 , 0 , NULL , 0 ) ;
2011-07-25 11:07:20 -03:00
return 0 ;
}
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 ) ;
2012-01-20 18:37:01 -03:00
struct az6007_device_state * st = d - > priv ;
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 18:31:14 -03:00
2012-01-21 11:19:16 -03:00
if ( mutex_lock_interruptible ( & st - > mutex ) < 0 )
2011-07-21 17:46:41 -03:00
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-25 12:45:16 -03:00
req = AZ6007_I2C_RD ;
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 ;
2012-01-21 13:52:39 -02:00
ret = __az6007_read ( d - > udev , req , value , index ,
st - > data , length ) ;
2011-07-22 10:31:25 -03:00
if ( ret > = len ) {
for ( j = 0 ; j < len ; j + + ) {
2012-01-20 18:37:01 -03:00
msgs [ i + 1 ] . buf [ j ] = st - > 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-25 12:45:16 -03:00
req = AZ6007_I2C_WR ;
2011-07-22 10:31:25 -03:00
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 + + ) {
2012-01-20 18:37:01 -03:00
st - > data [ j ] = msgs [ i ] . buf [ j + 1 ] ;
2011-07-23 09:51:12 -03:00
if ( dvb_usb_az6007_debug & 2 )
2012-01-21 13:52:39 -02:00
printk ( KERN_CONT " 0x%02x " ,
st - > data [ j ] ) ;
2011-07-21 17:46:41 -03:00
}
2012-01-21 13:52:39 -02:00
ret = __az6007_write ( d - > udev , req , value , index ,
st - > 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-25 12:45:16 -03:00
req = AZ6007_I2C_RD ;
2011-07-22 10:31:25 -03:00
index = msgs [ i ] . buf [ 0 ] ;
value = addr ;
length = msgs [ i ] . len + 6 ;
len = msgs [ i ] . len ;
2012-01-21 13:52:39 -02:00
ret = __az6007_read ( d - > udev , req , value , index ,
st - > data , length ) ;
2011-07-23 10:40:08 -03:00
for ( j = 0 ; j < len ; j + + ) {
2012-01-20 18:37:01 -03:00
msgs [ i ] . buf [ j ] = st - > data [ j + 5 ] ;
2011-07-23 09:51:12 -03:00
if ( dvb_usb_az6007_debug & 2 )
printk ( KERN_CONT
2012-01-20 18:37:01 -03:00
" 0x%02x " , st - > 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 :
2012-01-21 11:19:16 -03:00
mutex_unlock ( & st - > 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
{
2011-07-25 12:45:16 -03:00
int ret ;
2012-01-21 11:53:18 -03:00
u8 * mac ;
mac = kmalloc ( 6 , GFP_ATOMIC ) ;
if ( ! mac )
return - ENOMEM ;
2011-07-21 17:46:41 -03:00
2011-07-25 12:45:16 -03:00
/* Try to read the mac address */
2012-01-21 11:19:16 -03:00
ret = __az6007_read ( udev , AZ6007_READ_DATA , 6 , 0 , mac , 6 ) ;
2011-07-25 12:45:16 -03:00
if ( ret = = 6 )
* cold = 0 ;
else
* cold = 1 ;
2011-07-21 17:46:41 -03:00
2012-01-21 11:53:18 -03:00
kfree ( mac ) ;
2012-01-20 18:37:01 -03:00
if ( * cold ) {
2012-01-21 11:19:16 -03:00
__az6007_write ( udev , 0x09 , 1 , 0 , NULL , 0 ) ;
__az6007_write ( udev , 0x00 , 0 , 0 , NULL , 0 ) ;
__az6007_write ( udev , 0x00 , 0 , 0 , NULL , 0 ) ;
2012-01-20 18:37:01 -03:00
}
2012-01-21 13:52:39 -02:00
deb_info ( " Device is on %s state \n " , * cold ? " warm " : " cold " ) ;
2011-07-21 17:46:41 -03:00
return 0 ;
}
2012-01-21 10:35:12 -03:00
static struct dvb_usb_device_properties az6007_properties ;
2012-03-04 19:22:05 -03:00
static void az6007_usb_disconnect ( struct usb_interface * intf )
{
struct dvb_usb_device * d = usb_get_intfdata ( intf ) ;
az6007_ci_uninit ( d ) ;
dvb_usb_device_exit ( intf ) ;
}
2011-07-21 17:46:41 -03:00
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
{
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 ) } ,
2012-01-26 20:02:52 -03:00
{ USB_DEVICE ( USB_VID_TERRATEC , USB_PID_TERRATEC_H7_2 ) } ,
2011-07-23 10:40:08 -03:00
{ 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 ,
2011-07-25 11:07:20 -03:00
. firmware = " dvb-usb-terratec-h7-az6007.fw " ,
2011-07-21 17:46:41 -03:00
. no_reconnect = 1 ,
2012-01-16 20:37:13 -03:00
. size_of_priv = sizeof ( struct az6007_device_state ) ,
. identify_state = az6007_identify_state ,
2011-07-21 17:46:41 -03:00
. num_adapters = 1 ,
. adapter = {
{
2012-01-16 18:57:51 -03:00
. num_frontends = 1 ,
. fe = { {
2011-07-21 17:46:41 -03:00
. streaming_ctrl = az6007_streaming_ctrl ,
2011-07-31 10:11:32 -03:00
. tuner_attach = az6007_tuner_attach ,
2011-07-21 17:46:41 -03:00
. frontend_attach = az6007_frontend_attach ,
/* parameter for the MPEG2-data transfer */
. stream = {
. type = USB_BULK ,
. count = 10 ,
. endpoint = 0x02 ,
. u = {
. bulk = {
. buffersize = 4096 ,
}
}
} ,
2012-01-21 13:52:39 -02:00
} }
2012-01-16 18:57:51 -03:00
} } ,
2011-07-25 11:07:20 -03:00
. power_ctrl = az6007_power_ctrl ,
2011-07-21 17:46:41 -03:00
. read_mac_address = az6007_read_mac_addr ,
2012-01-21 12:20:30 -03:00
. rc . core = {
2011-07-21 18:31:14 -03:00
. rc_interval = 400 ,
2012-01-21 12:41:21 -03:00
. rc_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS ,
2012-01-21 12:20:30 -03:00
. module_name = " az6007 " ,
2011-07-21 18:31:14 -03:00
. rc_query = az6007_rc_query ,
2012-01-21 12:20:30 -03:00
. allowed_protos = RC_TYPE_NEC ,
2011-07-21 18:31:14 -03:00
} ,
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) " ,
2012-01-26 20:02:52 -03:00
. cold_ids = { & az6007_usb_table [ 1 ] , & az6007_usb_table [ 2 ] , NULL } ,
2011-07-21 17:46:41 -03:00
. 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 ,
2012-03-04 19:22:05 -03:00
. disconnect = az6007_usb_disconnect ,
2011-07-23 10:40:08 -03:00
. 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> " ) ;
2012-01-21 10:35:12 -03:00
MODULE_AUTHOR ( " Mauro Carvalho Chehab <mchehab@redhat.com> " ) ;
2011-07-21 17:46:41 -03:00
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 " ) ;