2008-05-17 23:05:48 -03:00
/*
* DVB USB Linux driver for Anysee E30 DVB - C & DVB - T USB2 .0 receiver
*
* Copyright ( C ) 2007 Antti Palosaari < crope @ iki . fi >
*
* 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 ; either version 2 of the License , or
* ( at your option ) any later version .
*
* 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 .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*
* TODO :
* - add smart card reader support for Conditional Access ( CA )
*
* Card reader in Anysee is nothing more than ISO 7816 card reader .
* There is no hardware CAM in any Anysee device sold .
* In my understanding it should be implemented by making own module
2008-06-11 11:43:19 -03:00
* for ISO 7816 card reader , like dvb_ca_en50221 is implemented . This
* module registers serial interface that can be used to communicate
2008-05-17 23:05:48 -03:00
* with any ISO 7816 smart card .
*
* Any help according to implement serial smart card reader support
* is highly welcome !
*/
# include "anysee.h"
# include "tda1002x.h"
# include "mt352.h"
# include "mt352_priv.h"
# include "zl10353.h"
/* debug */
static int dvb_usb_anysee_debug ;
module_param_named ( debug , dvb_usb_anysee_debug , int , 0644 ) ;
MODULE_PARM_DESC ( debug , " set debugging level " DVB_USB_DEBUG_STATUS ) ;
2008-08-11 10:54:16 -03:00
int dvb_usb_anysee_delsys ;
module_param_named ( delsys , dvb_usb_anysee_delsys , int , 0644 ) ;
MODULE_PARM_DESC ( delsys , " select delivery mode (0=DVB-C, 1=DVB-T) " ) ;
2008-05-17 23:05:48 -03:00
DVB_DEFINE_MOD_OPT_ADAPTER_NR ( adapter_nr ) ;
2008-07-21 16:33:42 -03:00
static struct mutex anysee_usb_mutex ;
2008-05-17 23:05:48 -03:00
static int anysee_ctrl_msg ( struct dvb_usb_device * d , u8 * sbuf , u8 slen ,
u8 * rbuf , u8 rlen )
{
struct anysee_state * state = d - > priv ;
int act_len , ret ;
u8 buf [ 64 ] ;
if ( slen > sizeof ( buf ) )
slen = sizeof ( buf ) ;
memcpy ( & buf [ 0 ] , sbuf , slen ) ;
buf [ 60 ] = state - > seq + + ;
if ( mutex_lock_interruptible ( & anysee_usb_mutex ) < 0 )
return - EAGAIN ;
/* We need receive one message more after dvb_usb_generic_rw due
to weird transaction flow , which is 1 x send + 2 x receive . */
ret = dvb_usb_generic_rw ( d , buf , sizeof ( buf ) , buf , sizeof ( buf ) , 0 ) ;
if ( ! ret ) {
/* receive 2nd answer */
ret = usb_bulk_msg ( d - > udev , usb_rcvbulkpipe ( d - > udev ,
d - > props . generic_bulk_ctrl_endpoint ) , buf , sizeof ( buf ) ,
& act_len , 2000 ) ;
if ( ret )
err ( " %s: recv bulk message failed: %d " , __func__ , ret ) ;
else {
deb_xfer ( " <<< " ) ;
debug_dump ( buf , act_len , deb_xfer ) ;
}
}
/* read request, copy returned data to return buf */
if ( ! ret & & rbuf & & rlen )
memcpy ( rbuf , buf , rlen ) ;
mutex_unlock ( & anysee_usb_mutex ) ;
return ret ;
}
static int anysee_read_reg ( struct dvb_usb_device * d , u16 reg , u8 * val )
{
u8 buf [ ] = { CMD_REG_READ , reg > > 8 , reg & 0xff , 0x01 } ;
int ret ;
ret = anysee_ctrl_msg ( d , buf , sizeof ( buf ) , val , 1 ) ;
deb_info ( " %s: reg:%04x val:%02x \n " , __func__ , reg , * val ) ;
return ret ;
}
static int anysee_write_reg ( struct dvb_usb_device * d , u16 reg , u8 val )
{
u8 buf [ ] = { CMD_REG_WRITE , reg > > 8 , reg & 0xff , 0x01 , val } ;
deb_info ( " %s: reg:%04x val:%02x \n " , __func__ , reg , val ) ;
return anysee_ctrl_msg ( d , buf , sizeof ( buf ) , NULL , 0 ) ;
}
static int anysee_get_hw_info ( struct dvb_usb_device * d , u8 * id )
{
u8 buf [ ] = { CMD_GET_HW_INFO } ;
return anysee_ctrl_msg ( d , buf , sizeof ( buf ) , id , 3 ) ;
}
static int anysee_streaming_ctrl ( struct dvb_usb_adapter * adap , int onoff )
{
u8 buf [ ] = { CMD_STREAMING_CTRL , ( u8 ) onoff , 0x00 } ;
deb_info ( " %s: onoff:%02x \n " , __func__ , onoff ) ;
return anysee_ctrl_msg ( adap - > dev , buf , sizeof ( buf ) , NULL , 0 ) ;
}
static int anysee_led_ctrl ( struct dvb_usb_device * d , u8 mode , u8 interval )
{
u8 buf [ ] = { CMD_LED_AND_IR_CTRL , 0x01 , mode , interval } ;
deb_info ( " %s: state:%02x interval:%02x \n " , __func__ , mode , interval ) ;
return anysee_ctrl_msg ( d , buf , sizeof ( buf ) , NULL , 0 ) ;
}
static int anysee_ir_ctrl ( struct dvb_usb_device * d , u8 onoff )
{
u8 buf [ ] = { CMD_LED_AND_IR_CTRL , 0x02 , onoff } ;
deb_info ( " %s: onoff:%02x \n " , __func__ , onoff ) ;
return anysee_ctrl_msg ( d , buf , sizeof ( buf ) , NULL , 0 ) ;
}
static int anysee_init ( struct dvb_usb_device * d )
{
int ret ;
/* LED light */
ret = anysee_led_ctrl ( d , 0x01 , 0x03 ) ;
if ( ret )
return ret ;
/* enable IR */
ret = anysee_ir_ctrl ( d , 1 ) ;
if ( ret )
return ret ;
return 0 ;
}
/* I2C */
static int anysee_master_xfer ( struct i2c_adapter * adap , struct i2c_msg * msg ,
int num )
{
struct dvb_usb_device * d = i2c_get_adapdata ( adap ) ;
int ret , inc , i = 0 ;
if ( mutex_lock_interruptible ( & d - > i2c_mutex ) < 0 )
return - EAGAIN ;
while ( i < num ) {
if ( num > i + 1 & & ( msg [ i + 1 ] . flags & I2C_M_RD ) ) {
u8 buf [ 6 ] ;
buf [ 0 ] = CMD_I2C_READ ;
buf [ 1 ] = msg [ i ] . addr + 1 ;
buf [ 2 ] = msg [ i ] . buf [ 0 ] ;
buf [ 3 ] = 0x00 ;
buf [ 4 ] = 0x00 ;
buf [ 5 ] = 0x01 ;
ret = anysee_ctrl_msg ( d , buf , sizeof ( buf ) , msg [ i + 1 ] . buf ,
msg [ i + 1 ] . len ) ;
inc = 2 ;
} else {
u8 buf [ 4 + msg [ i ] . len ] ;
buf [ 0 ] = CMD_I2C_WRITE ;
buf [ 1 ] = msg [ i ] . addr ;
buf [ 2 ] = msg [ i ] . len ;
buf [ 3 ] = 0x01 ;
memcpy ( & buf [ 4 ] , msg [ i ] . buf , msg [ i ] . len ) ;
ret = anysee_ctrl_msg ( d , buf , sizeof ( buf ) , NULL , 0 ) ;
inc = 1 ;
}
if ( ret )
2008-08-11 10:36:43 -03:00
break ;
2008-05-17 23:05:48 -03:00
i + = inc ;
}
mutex_unlock ( & d - > i2c_mutex ) ;
2008-08-11 10:36:43 -03:00
return ret ? ret : i ;
2008-05-17 23:05:48 -03:00
}
static u32 anysee_i2c_func ( struct i2c_adapter * adapter )
{
return I2C_FUNC_I2C ;
}
static struct i2c_algorithm anysee_i2c_algo = {
. master_xfer = anysee_master_xfer ,
. functionality = anysee_i2c_func ,
} ;
static int anysee_mt352_demod_init ( struct dvb_frontend * fe )
{
static u8 clock_config [ ] = { CLOCK_CTL , 0x38 , 0x28 } ;
static u8 reset [ ] = { RESET , 0x80 } ;
static u8 adc_ctl_1_cfg [ ] = { ADC_CTL_1 , 0x40 } ;
static u8 agc_cfg [ ] = { AGC_TARGET , 0x28 , 0x20 } ;
static u8 gpp_ctl_cfg [ ] = { GPP_CTL , 0x33 } ;
static u8 capt_range_cfg [ ] = { CAPT_RANGE , 0x32 } ;
mt352_write ( fe , clock_config , sizeof ( clock_config ) ) ;
udelay ( 200 ) ;
mt352_write ( fe , reset , sizeof ( reset ) ) ;
mt352_write ( fe , adc_ctl_1_cfg , sizeof ( adc_ctl_1_cfg ) ) ;
mt352_write ( fe , agc_cfg , sizeof ( agc_cfg ) ) ;
mt352_write ( fe , gpp_ctl_cfg , sizeof ( gpp_ctl_cfg ) ) ;
mt352_write ( fe , capt_range_cfg , sizeof ( capt_range_cfg ) ) ;
return 0 ;
}
/* Callbacks for DVB USB */
static struct tda10023_config anysee_tda10023_config = {
. demod_address = 0x1a ,
. invert = 0 ,
. xtal = 16000000 ,
. pll_m = 11 ,
. pll_p = 3 ,
. pll_n = 1 ,
2008-06-09 22:58:22 -03:00
. output_mode = TDA10023_OUTPUT_MODE_PARALLEL_C ,
. deltaf = 0xfeeb ,
2008-05-17 23:05:48 -03:00
} ;
static struct mt352_config anysee_mt352_config = {
. demod_address = 0x1e ,
. demod_init = anysee_mt352_demod_init ,
} ;
static struct zl10353_config anysee_zl10353_config = {
. demod_address = 0x1e ,
. parallel_ts = 1 ,
} ;
static int anysee_frontend_attach ( struct dvb_usb_adapter * adap )
{
int ret ;
struct anysee_state * state = adap - > dev - > priv ;
u8 hw_info [ 3 ] ;
u8 io_d ; /* IO port D */
/* check which hardware we have
We must do this call two times to get reliable values ( hw bug ) . */
ret = anysee_get_hw_info ( adap - > dev , hw_info ) ;
if ( ret )
return ret ;
ret = anysee_get_hw_info ( adap - > dev , hw_info ) ;
if ( ret )
return ret ;
/* Meaning of these info bytes are guessed. */
info ( " firmware version:%d.%d.%d hardware id:%d " ,
0 , hw_info [ 1 ] , hw_info [ 2 ] , hw_info [ 0 ] ) ;
ret = anysee_read_reg ( adap - > dev , 0xb0 , & io_d ) ; /* IO port D */
if ( ret )
return ret ;
deb_info ( " %s: IO port D:%02x \n " , __func__ , io_d ) ;
/* Select demod using trial and error method. */
/* Try to attach demodulator in following order:
model demod hw firmware
1. E30 MT352 02 0.2 .1
2. E30 ZL10353 02 0.2 .1
2008-08-11 10:54:16 -03:00
3. E30 Combo ZL10353 0f 0.1 .2 DVB - T / C combo
4. E30 Plus ZL10353 06 0.1 .0
5. E30C Plus TDA10023 0 a 0.1 .0 rev 0.2
E30C Plus TDA10023 0f 0.1 .2 rev 0.4
E30 Combo TDA10023 0f 0.1 .2 DVB - T / C combo
2008-05-17 23:05:48 -03:00
*/
/* Zarlink MT352 DVB-T demod inside of Samsung DNOS404ZH102A NIM */
adap - > fe = dvb_attach ( mt352_attach , & anysee_mt352_config ,
& adap - > dev - > i2c_adap ) ;
if ( adap - > fe ! = NULL ) {
state - > tuner = DVB_PLL_THOMSON_DTT7579 ;
return 0 ;
}
/* Zarlink ZL10353 DVB-T demod inside of Samsung DNOS404ZH103A NIM */
adap - > fe = dvb_attach ( zl10353_attach , & anysee_zl10353_config ,
& adap - > dev - > i2c_adap ) ;
if ( adap - > fe ! = NULL ) {
state - > tuner = DVB_PLL_THOMSON_DTT7579 ;
return 0 ;
}
2008-08-11 10:54:16 -03:00
/* for E30 Combo Plus DVB-T demodulator */
if ( dvb_usb_anysee_delsys ) {
ret = anysee_write_reg ( adap - > dev , 0xb0 , 0x01 ) ;
if ( ret )
return ret ;
/* Zarlink ZL10353 DVB-T demod */
adap - > fe = dvb_attach ( zl10353_attach , & anysee_zl10353_config ,
& adap - > dev - > i2c_adap ) ;
if ( adap - > fe ! = NULL ) {
state - > tuner = DVB_PLL_SAMSUNG_DTOS403IH102A ;
return 0 ;
}
}
2008-05-17 23:05:48 -03:00
/* connect demod on IO port D for TDA10023 & ZL10353 */
ret = anysee_write_reg ( adap - > dev , 0xb0 , 0x25 ) ;
if ( ret )
return ret ;
/* Zarlink ZL10353 DVB-T demod inside of Samsung DNOS404ZH103A NIM */
adap - > fe = dvb_attach ( zl10353_attach , & anysee_zl10353_config ,
& adap - > dev - > i2c_adap ) ;
if ( adap - > fe ! = NULL ) {
state - > tuner = DVB_PLL_THOMSON_DTT7579 ;
return 0 ;
}
2008-06-09 22:58:22 -03:00
/* IO port E - E30C rev 0.4 board requires this */
ret = anysee_write_reg ( adap - > dev , 0xb1 , 0xa7 ) ;
if ( ret )
return ret ;
2008-05-17 23:05:48 -03:00
/* Philips TDA10023 DVB-C demod */
adap - > fe = dvb_attach ( tda10023_attach , & anysee_tda10023_config ,
& adap - > dev - > i2c_adap , 0x48 ) ;
if ( adap - > fe ! = NULL ) {
state - > tuner = DVB_PLL_SAMSUNG_DTOS403IH102A ;
return 0 ;
}
/* return IO port D to init value for safe */
ret = anysee_write_reg ( adap - > dev , 0xb0 , io_d ) ;
if ( ret )
return ret ;
err ( " Unkown Anysee version: %02x %02x %02x. " \
" Please report the <linux-dvb@linuxtv.org>. " ,
hw_info [ 0 ] , hw_info [ 1 ] , hw_info [ 2 ] ) ;
return - ENODEV ;
}
static int anysee_tuner_attach ( struct dvb_usb_adapter * adap )
{
struct anysee_state * state = adap - > dev - > priv ;
deb_info ( " %s: \n " , __func__ ) ;
switch ( state - > tuner ) {
case DVB_PLL_THOMSON_DTT7579 :
/* Thomson dtt7579 (not sure) PLL inside of:
Samsung DNOS404ZH102A NIM
Samsung DNOS404ZH103A NIM */
dvb_attach ( dvb_pll_attach , adap - > fe , 0x61 ,
NULL , DVB_PLL_THOMSON_DTT7579 ) ;
break ;
case DVB_PLL_SAMSUNG_DTOS403IH102A :
/* Unknown PLL inside of Samsung DTOS403IH102A tuner module */
dvb_attach ( dvb_pll_attach , adap - > fe , 0xc0 ,
& adap - > dev - > i2c_adap , DVB_PLL_SAMSUNG_DTOS403IH102A ) ;
break ;
}
return 0 ;
}
static int anysee_rc_query ( struct dvb_usb_device * d , u32 * event , int * state )
{
u8 buf [ ] = { CMD_GET_IR_CODE } ;
struct dvb_usb_rc_key * keymap = d - > props . rc_key_map ;
u8 ircode [ 2 ] ;
int i , ret ;
ret = anysee_ctrl_msg ( d , buf , sizeof ( buf ) , & ircode [ 0 ] , 2 ) ;
if ( ret )
return ret ;
* event = 0 ;
* state = REMOTE_NO_KEY_PRESSED ;
for ( i = 0 ; i < d - > props . rc_key_map_size ; i + + ) {
if ( keymap [ i ] . custom = = ircode [ 0 ] & &
keymap [ i ] . data = = ircode [ 1 ] ) {
* event = keymap [ i ] . event ;
* state = REMOTE_KEY_PRESSED ;
return 0 ;
}
}
return 0 ;
}
static struct dvb_usb_rc_key anysee_rc_keys [ ] = {
{ 0x01 , 0x00 , KEY_0 } ,
{ 0x01 , 0x01 , KEY_1 } ,
{ 0x01 , 0x02 , KEY_2 } ,
{ 0x01 , 0x03 , KEY_3 } ,
{ 0x01 , 0x04 , KEY_4 } ,
{ 0x01 , 0x05 , KEY_5 } ,
{ 0x01 , 0x06 , KEY_6 } ,
{ 0x01 , 0x07 , KEY_7 } ,
{ 0x01 , 0x08 , KEY_8 } ,
{ 0x01 , 0x09 , KEY_9 } ,
{ 0x01 , 0x0a , KEY_POWER } ,
{ 0x01 , 0x0b , KEY_DOCUMENTS } , /* * */
{ 0x01 , 0x19 , KEY_FAVORITES } ,
{ 0x01 , 0x20 , KEY_SLEEP } ,
{ 0x01 , 0x21 , KEY_MODE } , /* 4:3 / 16:9 select */
{ 0x01 , 0x22 , KEY_ZOOM } ,
{ 0x01 , 0x47 , KEY_TEXT } ,
{ 0x01 , 0x16 , KEY_TV } , /* TV / radio select */
{ 0x01 , 0x1e , KEY_LANGUAGE } , /* Second Audio Program */
{ 0x01 , 0x1a , KEY_SUBTITLE } ,
{ 0x01 , 0x1b , KEY_CAMERA } , /* screenshot */
{ 0x01 , 0x42 , KEY_MUTE } ,
{ 0x01 , 0x0e , KEY_MENU } ,
{ 0x01 , 0x0f , KEY_EPG } ,
{ 0x01 , 0x17 , KEY_INFO } ,
{ 0x01 , 0x10 , KEY_EXIT } ,
{ 0x01 , 0x13 , KEY_VOLUMEUP } ,
{ 0x01 , 0x12 , KEY_VOLUMEDOWN } ,
{ 0x01 , 0x11 , KEY_CHANNELUP } ,
{ 0x01 , 0x14 , KEY_CHANNELDOWN } ,
{ 0x01 , 0x15 , KEY_OK } ,
{ 0x01 , 0x1d , KEY_RED } ,
{ 0x01 , 0x1f , KEY_GREEN } ,
{ 0x01 , 0x1c , KEY_YELLOW } ,
{ 0x01 , 0x44 , KEY_BLUE } ,
{ 0x01 , 0x0c , KEY_SHUFFLE } , /* snapshot */
{ 0x01 , 0x48 , KEY_STOP } ,
{ 0x01 , 0x50 , KEY_PLAY } ,
{ 0x01 , 0x51 , KEY_PAUSE } ,
{ 0x01 , 0x49 , KEY_RECORD } ,
{ 0x01 , 0x18 , KEY_PREVIOUS } , /* |<< */
{ 0x01 , 0x0d , KEY_NEXT } , /* >>| */
{ 0x01 , 0x24 , KEY_PROG1 } , /* F1 */
{ 0x01 , 0x25 , KEY_PROG2 } , /* F2 */
} ;
/* DVB USB Driver stuff */
static struct dvb_usb_device_properties anysee_properties ;
static int anysee_probe ( struct usb_interface * intf ,
const struct usb_device_id * id )
{
struct dvb_usb_device * d ;
struct usb_host_interface * alt ;
int ret ;
mutex_init ( & anysee_usb_mutex ) ;
/* There is one interface with two alternate settings.
Alternate setting 0 is for bulk transfer .
Alternate setting 1 is for isochronous transfer .
We use bulk transfer ( alternate setting 0 ) . */
if ( intf - > num_altsetting < 1 )
return - ENODEV ;
ret = dvb_usb_device_init ( intf , & anysee_properties , THIS_MODULE , & d ,
adapter_nr ) ;
if ( ret )
return ret ;
alt = usb_altnum_to_altsetting ( intf , 0 ) ;
if ( alt = = NULL ) {
deb_info ( " %s: no alt found! \n " , __func__ ) ;
return - ENODEV ;
}
ret = usb_set_interface ( d - > udev , alt - > desc . bInterfaceNumber ,
alt - > desc . bAlternateSetting ) ;
if ( ret )
return ret ;
if ( d )
ret = anysee_init ( d ) ;
return ret ;
}
static struct usb_device_id anysee_table [ ] = {
{ USB_DEVICE ( USB_VID_CYPRESS , USB_PID_ANYSEE ) } ,
{ USB_DEVICE ( USB_VID_AMT , USB_PID_ANYSEE ) } ,
{ } /* Terminating entry */
} ;
MODULE_DEVICE_TABLE ( usb , anysee_table ) ;
static struct dvb_usb_device_properties anysee_properties = {
. caps = DVB_USB_IS_AN_I2C_ADAPTER ,
. usb_ctrl = DEVICE_SPECIFIC ,
. size_of_priv = sizeof ( struct anysee_state ) ,
. num_adapters = 1 ,
. adapter = {
{
. streaming_ctrl = anysee_streaming_ctrl ,
. frontend_attach = anysee_frontend_attach ,
. tuner_attach = anysee_tuner_attach ,
. stream = {
. type = USB_BULK ,
. count = 8 ,
. endpoint = 0x82 ,
. u = {
. bulk = {
. buffersize = 512 ,
}
}
} ,
}
} ,
. rc_key_map = anysee_rc_keys ,
. rc_key_map_size = ARRAY_SIZE ( anysee_rc_keys ) ,
. rc_query = anysee_rc_query ,
. rc_interval = 200 , /* windows driver uses 500ms */
. i2c_algo = & anysee_i2c_algo ,
. generic_bulk_ctrl_endpoint = 1 ,
. num_device_descs = 1 ,
. devices = {
{
. name = " Anysee DVB USB2.0 " ,
. cold_ids = { NULL } ,
. warm_ids = { & anysee_table [ 0 ] ,
& anysee_table [ 1 ] , NULL } ,
} ,
}
} ;
static struct usb_driver anysee_driver = {
. name = " dvb_usb_anysee " ,
. probe = anysee_probe ,
. disconnect = dvb_usb_device_exit ,
. id_table = anysee_table ,
} ;
/* module stuff */
static int __init anysee_module_init ( void )
{
int ret ;
ret = usb_register ( & anysee_driver ) ;
if ( ret )
err ( " %s: usb_register failed. Error number %d " , __func__ , ret ) ;
return ret ;
}
static void __exit anysee_module_exit ( void )
{
/* deregister this driver from the USB subsystem */
usb_deregister ( & anysee_driver ) ;
}
module_init ( anysee_module_init ) ;
module_exit ( anysee_module_exit ) ;
MODULE_AUTHOR ( " Antti Palosaari <crope@iki.fi> " ) ;
MODULE_DESCRIPTION ( " Driver Anysee E30 DVB-C & DVB-T USB2.0 " ) ;
MODULE_LICENSE ( " GPL " ) ;