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 ( )
*
2014-02-07 08:03:07 -02:00
* Copyright ( c ) 2010 - 2012 Mauro Carvalho Chehab
2012-01-21 10:35:12 -03:00
* Driver modified by in order to work with upstream drxk driver , and
2012-08-05 09:35:02 -03:00
* tons of bugs got fixed , and converted to use dvb - usb - v2 .
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"
2012-08-04 16:05:34 -03:00
# include "dvb_usb.h"
# include "cypress_firmware.h"
2011-07-23 10:55:10 -03:00
2012-08-04 16:05:34 -03:00
# define AZ6007_FIRMWARE "dvb-usb-terratec-h7-az6007.fw"
2011-07-21 17:46:41 -03:00
2012-08-04 16:05:34 -03:00
static int az6007_xfer_debug ;
module_param_named ( xfer_debug , az6007_xfer_debug , int , 0644 ) ;
MODULE_PARM_DESC ( xfer_debug , " Enable xfer debug " ) ;
2011-07-23 10:55:10 -03:00
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-08-05 00:10:13 -03:00
. qam_demod_parameter_count = 2 ,
2012-01-20 18:37:01 -03:00
. microcode_name = " dvb-usb-terratec-h7-drxk.fw " ,
2011-07-21 17:46:41 -03:00
} ;
2013-11-02 16:49:32 -03:00
static struct drxk_config cablestar_hdci_drxk = {
. adr = 0x29 ,
. parallel_ts = true ,
. dynamic_clk = true ,
. single_master = true ,
. enable_merr_cfg = true ,
. no_i2c_bridge = false ,
. chunk_size = 64 ,
. mpeg_out_clk_strength = 0x02 ,
. qam_demod_parameter_count = 2 ,
. microcode_name = " dvb-usb-technisat-cablestar-hdci-drxk.fw " ,
} ;
2011-07-21 18:31:14 -03:00
static int drxk_gate_ctrl ( struct dvb_frontend * fe , int enable )
{
2012-08-04 16:05:34 -03:00
struct az6007_device_state * st = fe_to_priv ( fe ) ;
2011-07-21 18:31:14 -03:00
struct dvb_usb_adapter * adap = fe - > sec_priv ;
2011-07-23 11:54:40 -03:00
int status = 0 ;
2011-07-21 18:31:14 -03:00
2012-08-04 16:05:34 -03:00
pr_debug ( " %s: %s \n " , __func__ , enable ? " enable " : " disable " ) ;
2011-07-22 10:31:25 -03:00
2012-08-04 16:05:34 -03:00
if ( ! adap | | ! 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 ) {
2012-08-04 16:05:34 -03:00
pr_warn ( " usb read operation failed. (%d) \n " , ret ) ;
2011-07-22 10:31:25 -03:00
return - EIO ;
}
2011-07-21 17:46:41 -03:00
2012-08-04 16:05:34 -03:00
if ( az6007_xfer_debug ) {
printk ( KERN_DEBUG " az6007: IN req: %02x, value: %04x, index: %04x \n " ,
req , value , index ) ;
print_hex_dump_bytes ( " az6007: payload: " ,
DUMP_PREFIX_NONE , b , blen ) ;
}
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 ;
2012-08-04 16:05:34 -03:00
if ( az6007_xfer_debug ) {
printk ( KERN_DEBUG " az6007: OUT req: %02x, value: %04x, index: %04x \n " ,
req , value , index ) ;
print_hex_dump_bytes ( " az6007: payload: " ,
DUMP_PREFIX_NONE , b , blen ) ;
}
2011-07-21 17:46:41 -03:00
2011-07-23 10:12:12 -03:00
if ( blen > 64 ) {
2012-08-04 16:05:34 -03:00
pr_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 ) {
2012-08-04 16:05:34 -03:00
pr_err ( " usb write operation failed. (%d) \n " , 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 ;
}
2012-08-04 16:05:34 -03:00
static int az6007_streaming_ctrl ( struct dvb_frontend * fe , int onoff )
2011-07-21 17:46:41 -03:00
{
2012-08-04 16:05:34 -03:00
struct dvb_usb_device * d = fe_to_d ( fe ) ;
2012-01-21 11:19:16 -03:00
2012-08-04 16:05:34 -03:00
pr_debug ( " %s: %s \n " , __func__ , onoff ? " enable " : " disable " ) ;
2012-01-20 18:37:01 -03:00
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
}
2013-01-04 15:21:26 -03:00
# if IS_ENABLED(CONFIG_RC_CORE)
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-08-04 16:05:34 -03:00
struct az6007_device_state * st = d_to_priv ( d ) ;
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-12-09 20:23:22 -03:00
static int az6007_get_rc_config ( struct dvb_usb_device * d , struct dvb_usb_rc * rc )
{
pr_debug ( " Getting az6007 Remote Control properties \n " ) ;
rc - > allowed_protos = RC_BIT_NEC ;
rc - > query = az6007_rc_query ;
rc - > interval = 400 ;
return 0 ;
}
# else
# define az6007_get_rc_config NULL
# endif
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 ;
2012-08-04 16:05:34 -03:00
struct az6007_device_state * state = d_to_priv ( d ) ;
2012-03-04 19:22:05 -03:00
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 ) {
2012-08-04 16:05:34 -03:00
pr_warn ( " usb in operation failed. (%d) \n " , ret ) ;
2012-03-04 19:22:05 -03:00
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 ;
2012-08-04 16:05:34 -03:00
struct az6007_device_state * state = d_to_priv ( d ) ;
2012-03-04 19:22:05 -03:00
int ret ;
u8 req ;
u16 value1 ;
u16 index ;
int blen ;
2012-08-04 16:05:34 -03:00
pr_debug ( " %s(), slot %d \n " , __func__ , slot ) ;
2012-03-04 19:22:05 -03:00
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 )
2012-08-04 16:05:34 -03:00
pr_warn ( " usb out operation failed. (%d) \n " , ret ) ;
2012-03-04 19:22:05 -03:00
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 ;
2012-08-04 16:05:34 -03:00
struct az6007_device_state * state = d_to_priv ( d ) ;
2012-03-04 19:22:05 -03:00
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 ) {
2012-08-04 16:05:34 -03:00
pr_warn ( " usb in operation failed. (%d) \n " , ret ) ;
2012-03-04 19:22:05 -03:00
ret = - EINVAL ;
} else {
if ( b [ 0 ] = = 0 )
2012-08-04 16:05:34 -03:00
pr_warn ( " Read CI IO error \n " ) ;
2012-03-04 19:22:05 -03:00
ret = b [ 1 ] ;
2012-08-04 16:05:34 -03:00
pr_debug ( " read cam data = %x from 0x%x \n " , b [ 1 ] , value ) ;
2012-03-04 19:22:05 -03:00
}
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 ;
2012-08-04 16:05:34 -03:00
struct az6007_device_state * state = d_to_priv ( d ) ;
2012-03-04 19:22:05 -03:00
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 ) {
2012-08-04 16:05:34 -03:00
pr_warn ( " usb out operation failed. (%d) \n " , ret ) ;
2012-03-04 19:22:05 -03:00
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 ) {
2012-08-04 16:05:34 -03:00
pr_warn ( " usb in operation failed. (%d) \n " , ret ) ;
2012-03-04 19:22:05 -03:00
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 ;
2012-08-04 16:05:34 -03:00
struct az6007_device_state * state = d_to_priv ( d ) ;
2012-03-04 19:22:05 -03:00
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 ) {
2012-08-04 16:05:34 -03:00
pr_warn ( " usb out operation failed. (%d) \n " , ret ) ;
2012-03-04 19:22:05 -03:00
goto failed ;
}
msleep ( 500 ) ;
req = 0xC6 ;
value = 0 ;
index = 0 ;
blen = 0 ;
ret = az6007_write ( d , req , value , index , NULL , blen ) ;
if ( ret ! = 0 ) {
2012-08-04 16:05:34 -03:00
pr_warn ( " usb out operation failed. (%d) \n " , ret ) ;
2012-03-04 19:22:05 -03:00
goto failed ;
}
for ( i = 0 ; i < 15 ; i + + ) {
msleep ( 100 ) ;
if ( CI_CamReady ( ca , slot ) ) {
2012-08-04 16:05:34 -03:00
pr_debug ( " CAM Ready \n " ) ;
2012-03-04 19:22:05 -03:00
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 ;
2012-08-04 16:05:34 -03:00
struct az6007_device_state * state = d_to_priv ( d ) ;
2012-03-04 19:22:05 -03:00
int ret ;
u8 req ;
u16 value ;
u16 index ;
int blen ;
2012-08-04 16:05:34 -03:00
pr_debug ( " %s() \n " , __func__ ) ;
2012-03-04 19:22:05 -03:00
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 ) {
2012-08-04 16:05:34 -03:00
pr_warn ( " usb out operation failed. (%d) \n " , ret ) ;
2012-03-04 19:22:05 -03:00
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 ;
2012-08-04 16:05:34 -03:00
struct az6007_device_state * state = d_to_priv ( d ) ;
2012-03-04 19:22:05 -03:00
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 ) {
2012-08-04 16:05:34 -03:00
pr_warn ( " usb in operation failed. (%d) \n " , ret ) ;
2012-03-04 19:22:05 -03:00
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 ;
2012-08-04 16:05:34 -03:00
pr_debug ( " %s() \n " , __func__ ) ;
2012-03-04 19:22:05 -03:00
if ( NULL = = d )
return ;
2012-08-04 16:05:34 -03:00
state = d_to_priv ( d ) ;
2012-03-04 19:22:05 -03:00
if ( NULL = = state )
return ;
if ( NULL = = state - > ca . data )
return ;
dvb_ca_en50221_release ( & state - > ca ) ;
memset ( & state - > ca , 0 , sizeof ( state - > ca ) ) ;
}
2012-08-04 16:05:34 -03:00
static int az6007_ci_init ( struct dvb_usb_adapter * adap )
2012-03-04 19:22:05 -03:00
{
2012-08-04 16:05:34 -03:00
struct dvb_usb_device * d = adap_to_d ( adap ) ;
struct az6007_device_state * state = adap_to_priv ( adap ) ;
2012-03-04 19:22:05 -03:00
int ret ;
2012-08-04 16:05:34 -03:00
pr_debug ( " %s() \n " , __func__ ) ;
2012-03-04 19:22:05 -03:00
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 ;
2012-08-04 16:05:34 -03:00
ret = dvb_ca_en50221_init ( & adap - > dvb_adap ,
2012-03-04 19:22:05 -03:00
& state - > ca ,
0 , /* flags */
1 ) ; /* n_slots */
if ( ret ! = 0 ) {
2012-08-04 16:05:34 -03:00
pr_err ( " Cannot initialize CI: Error %d. \n " , ret ) ;
2012-03-04 19:22:05 -03:00
memset ( & state - > ca , 0 , sizeof ( state - > ca ) ) ;
return ret ;
}
2012-08-04 16:05:34 -03:00
pr_debug ( " CI initialized. \n " ) ;
2012-03-04 19:22:05 -03:00
return 0 ;
}
2012-08-04 16:05:34 -03:00
static int az6007_read_mac_addr ( struct dvb_usb_adapter * adap , u8 mac [ 6 ] )
2011-07-21 17:46:41 -03:00
{
2012-08-04 16:05:34 -03:00
struct dvb_usb_device * d = adap_to_d ( adap ) ;
struct az6007_device_state * st = adap_to_priv ( adap ) ;
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 ) ;
2012-07-24 12:02:46 -03:00
memcpy ( mac , st - > data , 6 ) ;
2011-07-21 17:46:41 -03:00
2011-07-25 12:45:16 -03:00
if ( ret > 0 )
2012-08-04 16:05:34 -03:00
pr_debug ( " %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-08-04 16:05:34 -03:00
struct az6007_device_state * st = adap_to_priv ( adap ) ;
struct dvb_usb_device * d = adap_to_d ( adap ) ;
2011-07-21 18:31:14 -03:00
2012-08-04 16:05:34 -03:00
pr_debug ( " attaching demod drxk \n " ) ;
2011-07-21 17:46:41 -03:00
2012-08-04 16:05:34 -03:00
adap - > fe [ 0 ] = dvb_attach ( drxk_attach , & terratec_h7_drxk ,
& d - > i2c_adap ) ;
if ( ! adap - > fe [ 0 ] )
2011-07-31 10:11:32 -03:00
return - EINVAL ;
2011-07-22 10:31:25 -03:00
2012-08-04 16:05:34 -03:00
adap - > fe [ 0 ] - > sec_priv = adap ;
st - > gate_ctrl = adap - > fe [ 0 ] - > ops . i2c_gate_ctrl ;
adap - > fe [ 0 ] - > 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 ;
}
2013-11-02 16:49:32 -03:00
static int az6007_cablestar_hdci_frontend_attach ( struct dvb_usb_adapter * adap )
{
struct az6007_device_state * st = adap_to_priv ( adap ) ;
struct dvb_usb_device * d = adap_to_d ( adap ) ;
pr_debug ( " attaching demod drxk \n " ) ;
adap - > fe [ 0 ] = dvb_attach ( drxk_attach , & cablestar_hdci_drxk ,
& d - > i2c_adap ) ;
if ( ! adap - > fe [ 0 ] )
return - EINVAL ;
adap - > fe [ 0 ] - > sec_priv = adap ;
st - > gate_ctrl = adap - > fe [ 0 ] - > ops . i2c_gate_ctrl ;
adap - > fe [ 0 ] - > ops . i2c_gate_ctrl = drxk_gate_ctrl ;
az6007_ci_init ( adap ) ;
return 0 ;
}
2011-07-31 10:11:32 -03:00
static int az6007_tuner_attach ( struct dvb_usb_adapter * adap )
{
2012-08-04 16:05:34 -03:00
struct dvb_usb_device * d = adap_to_d ( adap ) ;
pr_debug ( " attaching tuner mt2063 \n " ) ;
2012-01-21 10:35:12 -03:00
2011-07-21 18:31:14 -03:00
/* Attach mt2063 to DVB-C frontend */
2012-08-04 16:05:34 -03:00
if ( adap - > fe [ 0 ] - > ops . i2c_gate_ctrl )
adap - > fe [ 0 ] - > ops . i2c_gate_ctrl ( adap - > fe [ 0 ] , 1 ) ;
if ( ! dvb_attach ( mt2063_attach , adap - > fe [ 0 ] ,
2012-01-16 18:57:51 -03:00
& az6007_mt2063_config ,
2012-08-04 16:05:34 -03:00
& d - > i2c_adap ) )
2011-07-31 10:11:32 -03:00
return - EINVAL ;
2011-07-21 18:31:14 -03:00
2012-08-04 16:05:34 -03:00
if ( adap - > fe [ 0 ] - > ops . i2c_gate_ctrl )
adap - > fe [ 0 ] - > ops . i2c_gate_ctrl ( adap - > fe [ 0 ] , 0 ) ;
2011-07-24 09:25:39 -03:00
2011-07-21 17:46:41 -03:00
return 0 ;
}
2012-08-05 09:23:17 -03:00
static int az6007_power_ctrl ( struct dvb_usb_device * d , int onoff )
2011-07-25 11:07:20 -03:00
{
2012-08-05 09:22:23 -03:00
struct az6007_device_state * state = d_to_priv ( d ) ;
2012-01-20 18:37:01 -03:00
int ret ;
2012-08-04 16:05:34 -03:00
pr_debug ( " %s() \n " , __func__ ) ;
2012-01-20 18:37:01 -03:00
2012-08-05 09:22:23 -03:00
if ( ! state - > warm ) {
mutex_init ( & state - > 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-08-05 09:22:23 -03:00
state - > 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-08-04 16:05:34 -03:00
struct az6007_device_state * st = d_to_priv ( d ) ;
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 )
2012-08-04 21:39:41 -03:00
& & ( ( msgs [ i ] . flags & I2C_M_RD ) ! = I2C_M_RD )
2011-07-22 10:31:25 -03:00
& & ( 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
*/
2012-08-04 16:05:34 -03:00
if ( az6007_xfer_debug )
printk ( KERN_DEBUG " az6007: I2C W/R addr=0x%x len=%d/%d \n " ,
2011-07-23 09:51:12 -03:00
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 ) {
2012-08-04 16:05:34 -03:00
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-22 10:31:25 -03:00
} else
ret = - EIO ;
i + + ;
} else if ( ! ( msgs [ i ] . flags & I2C_M_RD ) ) {
/* write bytes */
2012-08-04 16:05:34 -03:00
if ( az6007_xfer_debug )
printk ( KERN_DEBUG " az6007: I2C W addr=0x%x len=%d \n " ,
2011-07-23 09:51:12 -03:00
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 ;
2012-08-04 16:05:34 -03:00
for ( j = 0 ; j < len ; j + + )
2012-01-20 18:37:01 -03:00
st - > data [ j ] = msgs [ i ] . buf [ j + 1 ] ;
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 */
2012-08-04 16:05:34 -03:00
if ( az6007_xfer_debug )
printk ( KERN_DEBUG " az6007: I2C R addr=0x%x len=%d \n " ,
2011-07-23 09:51:12 -03:00
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 ) ;
2012-08-04 16:05:34 -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-21 17:46:41 -03:00
}
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 ) {
2012-08-04 16:05:34 -03:00
pr_info ( " %s ERROR: %i \n " , __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 ,
} ;
2012-08-05 09:23:17 -03:00
static int az6007_identify_state ( struct dvb_usb_device * d , const char * * name )
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 ;
2012-08-04 16:05:34 -03:00
pr_debug ( " Identifying az6007 state \n " ) ;
2012-01-21 11:53:18 -03:00
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-08-04 16:05:34 -03:00
ret = __az6007_read ( d - > udev , AZ6007_READ_DATA , 6 , 0 , mac , 6 ) ;
2011-07-25 12:45:16 -03:00
if ( ret = = 6 )
2012-08-04 16:05:34 -03:00
ret = WARM ;
2011-07-25 12:45:16 -03:00
else
2012-08-04 16:05:34 -03:00
ret = COLD ;
2011-07-21 17:46:41 -03:00
2012-01-21 11:53:18 -03:00
kfree ( mac ) ;
2012-08-04 16:05:34 -03:00
if ( ret = = COLD ) {
__az6007_write ( d - > udev , 0x09 , 1 , 0 , NULL , 0 ) ;
__az6007_write ( d - > udev , 0x00 , 0 , 0 , NULL , 0 ) ;
__az6007_write ( d - > udev , 0x00 , 0 , 0 , NULL , 0 ) ;
2012-01-20 18:37:01 -03:00
}
2012-08-04 16:05:34 -03:00
pr_debug ( " Device is on %s state \n " ,
ret = = WARM ? " warm " : " cold " ) ;
return ret ;
2011-07-21 17:46:41 -03:00
}
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 ) ;
2012-08-04 16:05:34 -03:00
dvb_usbv2_disconnect ( intf ) ;
2012-03-04 19:22:05 -03:00
}
2012-08-04 16:05:34 -03:00
static int az6007_download_firmware ( struct dvb_usb_device * d ,
const struct firmware * fw )
{
pr_debug ( " Loading az6007 firmware \n " ) ;
2011-07-21 17:46:41 -03:00
2013-03-25 06:43:12 -03:00
return cypress_load_firmware ( d - > udev , fw , CYPRESS_FX2 ) ;
2012-08-04 16:05:34 -03:00
}
2011-07-21 17:46:41 -03:00
2012-08-04 16:05:34 -03:00
/* DVB USB Driver stuff */
static struct dvb_usb_device_properties az6007_props = {
. driver_name = KBUILD_MODNAME ,
. owner = THIS_MODULE ,
. firmware = AZ6007_FIRMWARE ,
. adapter_nr = adapter_nr ,
2012-01-16 20:37:13 -03:00
. size_of_priv = sizeof ( struct az6007_device_state ) ,
2012-08-04 16:05:34 -03:00
. i2c_algo = & az6007_i2c_algo ,
. tuner_attach = az6007_tuner_attach ,
. frontend_attach = az6007_frontend_attach ,
. streaming_ctrl = az6007_streaming_ctrl ,
. get_rc_config = az6007_get_rc_config ,
. read_mac_address = az6007_read_mac_addr ,
. download_firmware = az6007_download_firmware ,
2012-01-16 20:37:13 -03:00
. identify_state = az6007_identify_state ,
2012-08-04 16:05:34 -03:00
. power_ctrl = az6007_power_ctrl ,
. num_adapters = 1 ,
. adapter = {
{ . stream = DVB_USB_STREAM_BULK ( 0x02 , 10 , 4096 ) , }
2011-07-21 17:46:41 -03:00
}
} ;
2011-07-21 18:31:14 -03:00
2013-11-02 16:49:32 -03:00
static struct dvb_usb_device_properties az6007_cablestar_hdci_props = {
. driver_name = KBUILD_MODNAME ,
. owner = THIS_MODULE ,
. firmware = AZ6007_FIRMWARE ,
. adapter_nr = adapter_nr ,
. size_of_priv = sizeof ( struct az6007_device_state ) ,
. i2c_algo = & az6007_i2c_algo ,
. tuner_attach = az6007_tuner_attach ,
. frontend_attach = az6007_cablestar_hdci_frontend_attach ,
. streaming_ctrl = az6007_streaming_ctrl ,
/* ditch get_rc_config as it can't work (TS35 remote, I believe it's rc5) */
. get_rc_config = NULL ,
. read_mac_address = az6007_read_mac_addr ,
. download_firmware = az6007_download_firmware ,
. identify_state = az6007_identify_state ,
. power_ctrl = az6007_power_ctrl ,
. num_adapters = 1 ,
. adapter = {
{ . stream = DVB_USB_STREAM_BULK ( 0x02 , 10 , 4096 ) , }
}
} ;
2012-08-04 16:05:34 -03:00
static struct usb_device_id az6007_usb_table [ ] = {
{ DVB_USB_DEVICE ( USB_VID_AZUREWAVE , USB_PID_AZUREWAVE_6007 ,
& az6007_props , " Azurewave 6007 " , RC_MAP_EMPTY ) } ,
{ DVB_USB_DEVICE ( USB_VID_TERRATEC , USB_PID_TERRATEC_H7 ,
& az6007_props , " Terratec H7 " , RC_MAP_NEC_TERRATEC_CINERGY_XS ) } ,
{ DVB_USB_DEVICE ( USB_VID_TERRATEC , USB_PID_TERRATEC_H7_2 ,
& az6007_props , " Terratec H7 " , RC_MAP_NEC_TERRATEC_CINERGY_XS ) } ,
2013-11-02 16:49:32 -03:00
{ DVB_USB_DEVICE ( USB_VID_TECHNISAT , USB_PID_TECHNISAT_USB2_CABLESTAR_HDCI ,
& az6007_cablestar_hdci_props , " Technisat CableStar Combo HD CI " , RC_MAP_EMPTY ) } ,
2012-08-04 16:05:34 -03:00
{ 0 } ,
} ;
MODULE_DEVICE_TABLE ( usb , az6007_usb_table ) ;
2012-08-05 09:25:34 -03:00
static int az6007_suspend ( struct usb_interface * intf , pm_message_t msg )
{
struct dvb_usb_device * d = usb_get_intfdata ( intf ) ;
az6007_ci_uninit ( d ) ;
return dvb_usbv2_suspend ( intf , msg ) ;
}
static int az6007_resume ( struct usb_interface * intf )
{
struct dvb_usb_device * d = usb_get_intfdata ( intf ) ;
struct dvb_usb_adapter * adap = & d - > adapter [ 0 ] ;
az6007_ci_init ( adap ) ;
return dvb_usbv2_resume ( intf ) ;
}
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 = {
2012-08-04 16:05:34 -03:00
. name = KBUILD_MODNAME ,
2011-07-23 10:40:08 -03:00
. id_table = az6007_usb_table ,
2012-08-04 16:05:34 -03:00
. probe = dvb_usbv2_probe ,
. disconnect = az6007_usb_disconnect ,
. no_dynamic_id = 1 ,
. soft_unbind = 1 ,
2012-08-05 09:25:34 -03:00
/*
* FIXME : need to implement reset_resume , likely with
* dvb - usb - v2 core support
*/
. suspend = az6007_suspend ,
. resume = az6007_resume ,
2011-07-21 17:46:41 -03:00
} ;
2012-08-04 16:05:34 -03:00
module_usb_driver ( az6007_usb_driver ) ;
2011-07-21 17:46:41 -03:00
MODULE_AUTHOR ( " Henry Wang <Henry.wang@AzureWave.com> " ) ;
2014-02-07 08:03:07 -02:00
MODULE_AUTHOR ( " Mauro Carvalho Chehab " ) ;
2011-07-21 17:46:41 -03:00
MODULE_DESCRIPTION ( " Driver for AzureWave 6007 DVB-C/T USB2.0 and clones " ) ;
2012-08-04 16:05:34 -03:00
MODULE_VERSION ( " 2.0 " ) ;
2011-07-21 17:46:41 -03:00
MODULE_LICENSE ( " GPL " ) ;
2012-08-04 16:05:34 -03:00
MODULE_FIRMWARE ( AZ6007_FIRMWARE ) ;