@ -77,6 +77,7 @@
# include "stv0299.h"
# include "dvb-pll.h"
# include "z0194a.h"
# include "m88rs2000.h"
@ -106,12 +107,14 @@ static int pid_filter;
module_param_named ( pid , pid_filter , int , 0644 ) ;
MODULE_PARM_DESC ( pid , " set default 0=default 1=off 2=on " ) ;
DVB_DEFINE_MOD_OPT_ADAPTER_NR ( adapter_nr ) ;
# define TUNER_DEFAULT 0x0
# define TUNER_LG 0x1
# define TUNER_S7395 0x2
# define TUNER_S0194 0x3
# define TUNER_RS2000 0x4
struct lme2510_state {
u8 id ;
@ -120,6 +123,8 @@ struct lme2510_state {
u8 signal_level ;
u8 signal_sn ;
u8 time_key ;
u8 last_key ;
u8 key_timeout ;
u8 i2c_talk_onoff ;
u8 i2c_gate ;
u8 i2c_tuner_gate_w ;
@ -127,6 +132,7 @@ struct lme2510_state {
u8 i2c_tuner_addr ;
u8 stream_on ;
u8 pid_size ;
u8 pid_off ;
void * buffer ;
struct urb * lme_urb ;
void * usb_buffer ;
@ -192,9 +198,14 @@ static int lme2510_usb_talk(struct dvb_usb_device *d,
static int lme2510_stream_restart ( struct dvb_usb_device * d )
{
static u8 stream_on [ ] = LME_ST_ON_W ;
struct lme2510_state * st = d - > priv ;
u8 all_pids [ ] = LME_ALL_PIDS ;
u8 stream_on [ ] = LME_ST_ON_W ;
int ret ;
u8 rbuff [ 10 ] ;
u8 rbuff [ 1 ] ;
if ( st - > pid_off )
ret = lme2510_usb_talk ( d , all_pids , sizeof ( all_pids ) ,
rbuff , sizeof ( rbuff ) ) ;
/*Restart Stream Command*/
ret = lme2510_usb_talk ( d , stream_on , sizeof ( stream_on ) ,
rbuff , sizeof ( rbuff ) ) ;
@ -301,6 +312,14 @@ static void lme2510_int_response(struct urb *lme_urb)
( ( ibuf [ 2 ] & 0x01 ) < < 0x03 ) ;
}
break ;
case TUNER_RS2000 :
if ( ibuf [ 2 ] > 0 )
st - > signal_lock = 0xff ;
else
st - > signal_lock = 0xf0 ;
st - > signal_level = ibuf [ 4 ] ;
st - > signal_sn = ibuf [ 5 ] ;
st - > time_key = ibuf [ 7 ] ;
default :
break ;
}
@ -352,19 +371,20 @@ static int lme2510_int_read(struct dvb_usb_adapter *adap)
static int lme2510_pid_filter_ctrl ( struct dvb_usb_adapter * adap , int onoff )
{
struct lme2510_state * st = adap - > dev - > priv ;
static u8 clear_pid_reg [ ] = LME_CLEAR_PID ;
static u8 clear_pid_reg [ ] = LME_ALL_PIDS ;
static u8 rbuf [ 1 ] ;
int ret ;
deb_info ( 1 , " PID Clearing Filter " ) ;
ret = mutex_lock_interruptible ( & adap - > dev - > i2c_mutex ) ;
if ( ret < 0 )
return - EAGAIN ;
mutex_lock ( & adap - > dev - > i2c_mutex ) ;
if ( ! onoff )
if ( ! onoff ) {
ret | = lme2510_usb_talk ( adap - > dev , clear_pid_reg ,
sizeof ( clear_pid_reg ) , rbuf , sizeof ( rbuf ) ) ;
st - > pid_off = true ;
} else
st - > pid_off = false ;
st - > pid_size = 0 ;
@ -382,11 +402,9 @@ static int lme2510_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
pid , index , onoff ) ;
if ( onoff ) {
ret = mutex_lock_interruptible ( & adap - > dev - > i2c_mutex ) ;
if ( ret < 0 )
return - EAGAIN ;
ret | = lme2510_enable_pid ( adap - > dev , index , pid ) ;
mutex_unlock ( & adap - > dev - > i2c_mutex ) ;
mutex_lock ( & adap - > dev - > i2c_mutex ) ;
ret | = lme2510_enable_pid ( adap - > dev , index , pid ) ;
mutex_unlock ( & adap - > dev - > i2c_mutex ) ;
}
@ -418,9 +436,6 @@ static int lme2510_msg(struct dvb_usb_device *d,
int ret = 0 ;
struct lme2510_state * st = d - > priv ;
if ( mutex_lock_interruptible ( & d - > i2c_mutex ) < 0 )
return - EAGAIN ;
if ( st - > i2c_talk_onoff = = 1 ) {
ret = lme2510_usb_talk ( d , wbuf , wlen , rbuf , rlen ) ;
@ -463,10 +478,12 @@ static int lme2510_msg(struct dvb_usb_device *d,
}
}
break ;
case TUNER_RS2000 :
default :
break ;
}
} else {
/* TODO rewrite this section */
switch ( st - > tuner_config ) {
case TUNER_LG :
switch ( wbuf [ 3 ] ) {
@ -550,6 +567,24 @@ static int lme2510_msg(struct dvb_usb_device *d,
break ;
}
break ;
case TUNER_RS2000 :
switch ( wbuf [ 3 ] ) {
case 0x8c :
rbuf [ 0 ] = 0x55 ;
rbuf [ 1 ] = 0xff ;
if ( st - > last_key = = st - > time_key ) {
st - > key_timeout + + ;
if ( st - > key_timeout > 5 )
rbuf [ 1 ] = 0 ;
} else
st - > key_timeout = 0 ;
st - > last_key = st - > time_key ;
break ;
default :
lme2510_usb_talk ( d , wbuf , wlen , rbuf , rlen ) ;
st - > i2c_talk_onoff = 1 ;
break ;
}
default :
break ;
}
@ -559,8 +594,6 @@ static int lme2510_msg(struct dvb_usb_device *d,
}
mutex_unlock ( & d - > i2c_mutex ) ;
return ret ;
}
@ -575,6 +608,8 @@ static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
u16 len ;
u8 gate = st - > i2c_gate ;
mutex_lock ( & d - > i2c_mutex ) ;
if ( gate = = 0 )
gate = 5 ;
@ -613,6 +648,7 @@ static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
if ( lme2510_msg ( d , obuf , len , ibuf , 64 ) < 0 ) {
deb_info ( 1 , " i2c transfer failed. " ) ;
mutex_unlock ( & d - > i2c_mutex ) ;
return - EAGAIN ;
}
@ -625,6 +661,8 @@ static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
}
}
}
mutex_unlock ( & d - > i2c_mutex ) ;
return i ;
}
@ -654,7 +692,7 @@ static int lme2510_identify_state(struct usb_device *udev,
static int lme2510_streaming_ctrl ( struct dvb_usb_adapter * adap , int onoff )
{
struct lme2510_state * st = adap - > dev - > priv ;
static u8 clear_reg_3 [ ] = LME_CLEAR_PID ;
static u8 clear_reg_3 [ ] = LME_ALL_PIDS ;
static u8 rbuf [ 1 ] ;
int ret = 0 , rlen = sizeof ( rbuf ) ;
@ -666,8 +704,7 @@ static int lme2510_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
else {
deb_info ( 1 , " STM Steam Off " ) ;
/* mutex is here only to avoid collision with I2C */
if ( mutex_lock_interruptible ( & adap - > dev - > i2c_mutex ) < 0 )
return - EAGAIN ;
mutex_lock ( & adap - > dev - > i2c_mutex ) ;
ret = lme2510_usb_talk ( adap - > dev , clear_reg_3 ,
sizeof ( clear_reg_3 ) , rbuf , rlen ) ;
@ -772,16 +809,18 @@ static int lme_firmware_switch(struct usb_device *udev, int cold)
const char fw_c_s7395 [ ] = " dvb-usb-lme2510c-s7395.fw " ;
const char fw_c_lg [ ] = " dvb-usb-lme2510c-lg.fw " ;
const char fw_c_s0194 [ ] = " dvb-usb-lme2510c-s0194.fw " ;
const char fw_c_rs2000 [ ] = " dvb-usb-lme2510c-rs2000.fw " ;
const char fw_lg [ ] = " dvb-usb-lme2510-lg.fw " ;
const char fw_s0194 [ ] = " dvb-usb-lme2510-s0194.fw " ;
const char * fw_lme ;
int ret , cold_fw ;
int ret = 0 , cold_fw ;
cold = ( cold > 0 ) ? ( cold & 1 ) : 0 ;
cold_fw = ! cold ;
if ( le16_to_cpu ( udev - > descriptor . idProduct ) = = 0x1122 ) {
switch ( le16_to_cpu ( udev - > descriptor . idProduct ) ) {
case 0x1122 :
switch ( dvb_usb_lme2510_firmware ) {
default :
dvb_usb_lme2510_firmware = TUNER_S0194 ;
@ -804,7 +843,8 @@ static int lme_firmware_switch(struct usb_device *udev, int cold)
cold_fw = 0 ;
break ;
}
} else {
break ;
case 0x1120 :
switch ( dvb_usb_lme2510_firmware ) {
default :
dvb_usb_lme2510_firmware = TUNER_S7395 ;
@ -833,8 +873,17 @@ static int lme_firmware_switch(struct usb_device *udev, int cold)
cold_fw = 0 ;
break ;
}
break ;
case 0x22f0 :
fw_lme = fw_c_rs2000 ;
ret = request_firmware ( & fw , fw_lme , & udev - > dev ) ;
dvb_usb_lme2510_firmware = TUNER_RS2000 ;
break ;
default :
fw_lme = fw_c_s7395 ;
}
if ( cold_fw ) {
info ( " FRM Loading %s file " , fw_lme ) ;
ret = lme2510_download_firmware ( udev , fw ) ;
@ -897,6 +946,29 @@ static struct stv0299_config sharp_z0194_config = {
. set_symbol_rate = sharp_z0194a_set_symbol_rate ,
} ;
static int dm04_rs2000_set_ts_param ( struct dvb_frontend * fe ,
int caller )
{
struct dvb_usb_adapter * adap = fe - > dvb - > priv ;
struct dvb_usb_device * d = adap - > dev ;
struct lme2510_state * st = d - > priv ;
mutex_lock ( & d - > i2c_mutex ) ;
if ( ( st - > i2c_talk_onoff = = 1 ) & & ( st - > stream_on & 1 ) ) {
st - > i2c_talk_onoff = 0 ;
lme2510_stream_restart ( d ) ;
}
mutex_unlock ( & d - > i2c_mutex ) ;
return 0 ;
}
static struct m88rs2000_config m88rs2000_config = {
. demod_addr = 0xd0 ,
. tuner_addr = 0xc0 ,
. set_ts_params = dm04_rs2000_set_ts_param ,
} ;
static int dm04_lme2510_set_voltage ( struct dvb_frontend * fe ,
fe_sec_voltage_t voltage )
{
@ -906,8 +978,7 @@ static int dm04_lme2510_set_voltage(struct dvb_frontend *fe,
static u8 rbuf [ 1 ] ;
int ret = 0 , len = 3 , rlen = 1 ;
if ( mutex_lock_interruptible ( & adap - > dev - > i2c_mutex ) < 0 )
return - EAGAIN ;
mutex_lock ( & adap - > dev - > i2c_mutex ) ;
switch ( voltage ) {
case SEC_VOLTAGE_18 :
@ -928,12 +999,31 @@ static int dm04_lme2510_set_voltage(struct dvb_frontend *fe,
return ( ret < 0 ) ? - ENODEV : 0 ;
}
static int dm04_rs2000_read_signal_strength ( struct dvb_frontend * fe ,
u16 * strength )
{
struct dvb_usb_adapter * adap = fe - > dvb - > priv ;
struct lme2510_state * st = adap - > dev - > priv ;
* strength = ( u16 ) ( ( u32 ) st - > signal_level * 0xffff / 0x7f ) ;
return 0 ;
}
static int dm04_rs2000_read_snr ( struct dvb_frontend * fe , u16 * snr )
{
struct dvb_usb_adapter * adap = fe - > dvb - > priv ;
struct lme2510_state * st = adap - > dev - > priv ;
* snr = ( u16 ) ( ( u32 ) st - > signal_sn * 0xffff / 0xff ) ;
return 0 ;
}
static int lme_name ( struct dvb_usb_adapter * adap )
{
struct lme2510_state * st = adap - > dev - > priv ;
const char * desc = adap - > dev - > desc - > name ;
char * fe_name [ ] = { " " , " LG TDQY-P001F " , " SHARP:BS2F7HZ7395 " ,
" SHARP:BS2F7HZ0194 " } ;
" SHARP:BS2F7HZ0194 " , " RS2000 " } ;
char * name = adap - > fe_adap [ 0 ] . fe - > ops . info . name ;
strlcpy ( name , desc , 128 ) ;
@ -949,60 +1039,82 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
int ret = 0 ;
st - > i2c_talk_onoff = 1 ;
switch ( le16_to_cpu ( adap - > dev - > udev - > descriptor . idProduct ) ) {
case 0x1122 :
case 0x1120 :
st - > i2c_gate = 4 ;
adap - > fe_adap [ 0 ] . fe = dvb_attach ( tda10086_attach ,
& tda10086_config , & adap - > dev - > i2c_adap ) ;
if ( adap - > fe_adap [ 0 ] . fe ) {
info ( " TUN Found Frontend TDA10086 " ) ;
st - > i2c_tuner_gate_w = 4 ;
st - > i2c_tuner_gate_r = 4 ;
st - > i2c_tuner_addr = 0xc0 ;
st - > tuner_config = TUNER_LG ;
if ( dvb_usb_lme2510_firmware ! = TUNER_LG ) {
dvb_usb_lme2510_firmware = TUNER_LG ;
ret = lme_firmware_switch ( adap - > dev - > udev , 1 ) ;
}
break ;
}
st - > i2c_gate = 4 ;
adap - > fe_adap [ 0 ] . fe = dvb_attach ( tda10086_attach , & tda10086_config ,
& adap - > dev - > i2c_adap ) ;
if ( adap - > fe_adap [ 0 ] . fe ) {
info ( " TUN Found Frontend TDA10086 " ) ;
st - > i2c_tuner_gate_w = 4 ;
st - > i2c_tuner_gate_r = 4 ;
st - > i2c_tuner_addr = 0xc0 ;
st - > tuner_config = TUNER_LG ;
if ( dvb_usb_lme2510_firmware ! = TUNER_LG ) {
dvb_usb_lme2510_firmware = TUNER_LG ;
ret = lme_firmware_switch ( adap - > dev - > udev , 1 ) ;
st - > i2c_gate = 4 ;
adap - > fe_adap [ 0 ] . fe = dvb_attach ( stv0299_attach ,
& sharp_z0194_config , & adap - > dev - > i2c_adap ) ;
if ( adap - > fe_adap [ 0 ] . fe ) {
info ( " FE Found Stv0299 " ) ;
st - > i2c_tuner_gate_w = 4 ;
st - > i2c_tuner_gate_r = 5 ;
st - > i2c_tuner_addr = 0xc0 ;
st - > tuner_config = TUNER_S0194 ;
if ( dvb_usb_lme2510_firmware ! = TUNER_S0194 ) {
dvb_usb_lme2510_firmware = TUNER_S0194 ;
ret = lme_firmware_switch ( adap - > dev - > udev , 1 ) ;
}
break ;
}
goto end ;
}
st - > i2c_gate = 4 ;
adap - > fe_adap [ 0 ] . fe = dvb_attach ( stv0299_attach , & sharp_z0194 _config ,
st - > i2c_gate = 5 ;
adap - > fe_adap [ 0 ] . fe = dvb_attach ( stv0288_attach , & lme _config ,
& adap - > dev - > i2c_adap ) ;
if ( adap - > fe_adap [ 0 ] . fe ) {
info ( " FE Found Stv0299 " ) ;
st - > i2c_tuner_gate_w = 4 ;
st - > i2c_tuner_gate_r = 5 ;
st - > i2c_tuner_addr = 0xc0 ;
st - > tuner_config = TUNER_S0194 ;
if ( dvb_usb_lme2510_firmware ! = TUNER_S0194 ) {
dvb_usb_lme2510_firmware = TUNER_S0194 ;
ret = lme_firmware_switch ( adap - > dev - > udev , 1 ) ;
if ( adap - > fe_adap [ 0 ] . fe ) {
info ( " FE Found Stv0288 " ) ;
st - > i2c_tuner_gate_w = 4 ;
st - > i2c_tuner_gate_r = 5 ;
st - > i2c_tuner_addr = 0xc0 ;
st - > tuner_config = TUNER_S7395 ;
if ( dvb_usb_lme2510_firmware ! = TUNER_S7395 ) {
dvb_usb_lme2510_firmware = TUNER_S7395 ;
ret = lme_firmware_switch ( adap - > dev - > udev , 1 ) ;
}
break ;
}
goto end ;
}
case 0x22f0 :
st - > i2c_gate = 5 ;
adap - > fe_adap [ 0 ] . fe = dvb_attach ( m88rs2000_attach ,
& m88rs2000_config , & adap - > dev - > i2c_adap ) ;
st - > i2c_gate = 5 ;
adap - > fe_adap [ 0 ] . fe = dvb_attach ( stv0288_attach , & lme_config ,
& adap - > dev - > i2c_adap ) ;
if ( adap - > fe_adap [ 0 ] . fe ) {
info ( " FE Found Stv0288 " ) ;
st - > i2c_tuner_gate_w = 4 ;
st - > i2c_tuner_gate_r = 5 ;
st - > i2c_tuner_addr = 0xc0 ;
st - > tuner_config = TUNER_S7395 ;
if ( dvb_usb_lme2510_firmware ! = TUNER_S7395 ) {
dvb_usb_lme2510_firmware = TUNER_S7395 ;
ret = lme_firmware_switch ( adap - > dev - > udev , 1 ) ;
if ( adap - > fe_adap [ 0 ] . fe ) {
info ( " FE Found M88RS2000 " ) ;
st - > i2c_tuner_gate_w = 5 ;
st - > i2c_tuner_gate_r = 5 ;
st - > i2c_tuner_addr = 0xc0 ;
st - > tuner_config = TUNER_RS2000 ;
adap - > fe_adap [ 0 ] . fe - > ops . read_signal_strength =
dm04_rs2000_read_signal_strength ;
adap - > fe_adap [ 0 ] . fe - > ops . read_snr =
dm04_rs2000_read_snr ;
}
} else {
info ( " DM04 Not Supported " ) ;
return - ENODEV ;
break ;
}
if ( adap - > fe_adap [ 0 ] . fe = = NULL ) {
info ( " DM04/QQBOX Not Powered up or not Supported " ) ;
return - ENODEV ;
}
end : if ( ret ) {
if ( ret ) {
if ( adap - > fe_adap [ 0 ] . fe ) {
dvb_frontend_detach ( adap - > fe_adap [ 0 ] . fe ) ;
adap - > fe_adap [ 0 ] . fe = NULL ;
@ -1019,7 +1131,7 @@ end: if (ret) {
static int dm04_lme2510_tuner ( struct dvb_usb_adapter * adap )
{
struct lme2510_state * st = adap - > dev - > priv ;
char * tun_msg [ ] = { " " , " TDA8263 " , " IX2505V " , " DVB_PLL_OPERA " } ;
char * tun_msg [ ] = { " " , " TDA8263 " , " IX2505V " , " DVB_PLL_OPERA " , " RS2000 " } ;
int ret = 0 ;
switch ( st - > tuner_config ) {
@ -1038,6 +1150,9 @@ static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap)
& adap - > dev - > i2c_adap , DVB_PLL_OPERA1 ) )
ret = st - > tuner_config ;
break ;
case TUNER_RS2000 :
ret = st - > tuner_config ;
break ;
default :
break ;
}
@ -1066,10 +1181,9 @@ static int lme2510_powerup(struct dvb_usb_device *d, int onoff)
static u8 lnb_on [ ] = LNB_ON ;
static u8 lnb_off [ ] = LNB_OFF ;
static u8 rbuf [ 1 ] ;
int ret , len = 3 , rlen = 1 ;
int ret = 0 , len = 3 , rlen = 1 ;
if ( mutex_lock_interruptible ( & d - > i2c_mutex ) < 0 )
return - EAGAIN ;
mutex_lock ( & d - > i2c_mutex ) ;
if ( onoff )
ret = lme2510_usb_talk ( d , lnb_on , len , rbuf , rlen ) ;
@ -1127,6 +1241,7 @@ static int lme2510_probe(struct usb_interface *intf,
static struct usb_device_id lme2510_table [ ] = {
{ USB_DEVICE ( 0x3344 , 0x1122 ) } , /* LME2510 */
{ USB_DEVICE ( 0x3344 , 0x1120 ) } , /* LME2510C */
{ USB_DEVICE ( 0x3344 , 0x22f0 ) } , /* LME2510C RS2000 */
{ } /* Terminating entry */
} ;
@ -1144,7 +1259,7 @@ static struct dvb_usb_device_properties lme2510_properties = {
DVB_USB_ADAP_NEED_PID_FILTERING |
DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF ,
. streaming_ctrl = lme2510_streaming_ctrl ,
. pid_filter_count = 15 ,
. pid_filter_count = 32 ,
. pid_filter = lme2510_pid_filter ,
. pid_filter_ctrl = lme2510_pid_filter_ctrl ,
. frontend_attach = dm04_lme2510_frontend_attach ,
@ -1195,7 +1310,7 @@ static struct dvb_usb_device_properties lme2510c_properties = {
DVB_USB_ADAP_NEED_PID_FILTERING |
DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF ,
. streaming_ctrl = lme2510_streaming_ctrl ,
. pid_filter_count = 15 ,
. pid_filter_count = 32 ,
. pid_filter = lme2510_pid_filter ,
. pid_filter_ctrl = lme2510_pid_filter_ctrl ,
. frontend_attach = dm04_lme2510_frontend_attach ,
@ -1225,11 +1340,14 @@ static struct dvb_usb_device_properties lme2510c_properties = {
. identify_state = lme2510_identify_state ,
. i2c_algo = & lme2510_i2c_algo ,
. generic_bulk_ctrl_endpoint = 0 ,
. num_device_descs = 1 ,
. num_device_descs = 2 ,
. devices = {
{ " DM04_LME2510C_DVB-S " ,
{ & lme2510_table [ 1 ] , NULL } ,
} ,
{ " DM04_LME2510C_DVB-S RS2000 " ,
{ & lme2510_table [ 2 ] , NULL } ,
} ,
}
} ;
@ -1286,5 +1404,5 @@ module_usb_driver(lme2510_driver);
MODULE_AUTHOR ( " Malcolm Priestley <tvboxspy@gmail.com> " ) ;
MODULE_DESCRIPTION ( " LME2510(C) DVB-S USB2.0 " ) ;
MODULE_VERSION ( " 1.98 " ) ;
MODULE_VERSION ( " 1.99 " ) ;
MODULE_LICENSE ( " GPL " ) ;