2010-09-02 17:29:30 -03:00
/* DVB USB compliant linux driver for
*
* DM04 / QQBOX DVB - S USB BOX LME2510C + SHARP : BS2F7HZ7395
2010-10-16 16:44:43 -03:00
* LME2510C + LG TDQY - P001F
* LME2510 + LG TDQY - P001F
2010-09-02 17:29:30 -03:00
*
* MVB7395 ( LME2510C + SHARP : BS2F7HZ7395 )
* SHARP : BS2F7HZ7395 = ( STV0288 + Sharp IX2505V )
*
2010-10-16 16:44:43 -03:00
* MV001F ( LME2510 + LGTDQY - P001F )
2010-09-02 17:29:30 -03:00
* LG TDQY - P001F = ( TDA8263 + TDA10086H )
*
2010-10-16 16:44:43 -03:00
* MVB0001F ( LME2510C + LGTDQT - P001F )
*
2010-09-02 17:29:30 -03:00
* For firmware see Documentation / dvb / lmedm04 . txt
*
* I2C addresses :
* 0xd0 - STV0288 - Demodulator
* 0xc0 - Sharp IX2505V - Tuner
* - - or - -
* 0x1c - TDA10086 - Demodulator
* 0xc0 - TDA8263 - Tuner
*
* * * * Please Note * * *
* There are other variants of the DM04
* * * * NOT SUPPORTED * * *
* MV0194 ( LME2510 + SHARP0194 )
* MVB0194 ( LME2510C + SHARP0194 )
*
*
* VID = 3344 PID LME2510 = 1122 LME2510C = 1120
*
* Copyright ( C ) 2010 Malcolm Priestley ( tvboxspy @ gmail . com )
* LME2510 ( C ) ( C ) Leaguerme ( Shenzhen ) MicroElectronics Co . , Ltd .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License Version 2 , as
* published by the Free Software Foundation .
*
* 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 .
*
*
* see Documentation / dvb / README . dvb - usb for more information
*
* Known Issues :
* LME2510 : Non Intel USB chipsets fail to maintain High Speed on
* Boot or Hot Plug .
*
2010-10-16 16:44:43 -03:00
* QQbox suffers from noise on LNB voltage .
2010-09-02 17:29:30 -03:00
*
* PID functions have been removed from this driver version due to
* problems with different firmware and application versions .
*/
# define DVB_USB_LOG_PREFIX "LME2510(C)"
# include <linux/usb.h>
# include <linux/usb/input.h>
# include <media/ir-core.h>
# include "dvb-usb.h"
# include "lmedm04.h"
# include "tda826x.h"
# include "tda10086.h"
# include "stv0288.h"
# include "ix2505v.h"
/* debug */
static int dvb_usb_lme2510_debug ;
# define l_dprintk(var, level, args...) do { \
if ( ( var > = level ) ) \
printk ( KERN_DEBUG DVB_USB_LOG_PREFIX " : " args ) ; \
} while ( 0 )
# define deb_info(level, args...) l_dprintk(dvb_usb_lme2510_debug, level, args)
# define debug_data_snipet(level, name, p) \
deb_info ( level , name " (%02x%02x%02x%02x%02x%02x%02x%02x) " , \
* p , * ( p + 1 ) , * ( p + 2 ) , * ( p + 3 ) , * ( p + 4 ) , \
* ( p + 5 ) , * ( p + 6 ) , * ( p + 7 ) ) ;
module_param_named ( debug , dvb_usb_lme2510_debug , int , 0644 ) ;
MODULE_PARM_DESC ( debug , " set debugging level (1=info (or-able)). "
DVB_USB_DEBUG_STATUS ) ;
2010-10-16 16:44:43 -03:00
static int dvb_usb_lme2510_firmware ;
module_param_named ( firmware , dvb_usb_lme2510_firmware , int , 0644 ) ;
MODULE_PARM_DESC ( firmware , " set default firmware 0=Sharp7395 1=LG " ) ;
2010-09-02 17:29:30 -03:00
DVB_DEFINE_MOD_OPT_ADAPTER_NR ( adapter_nr ) ;
2010-10-16 16:44:43 -03:00
# define TUNER_LG 0x1
# define TUNER_S7395 0x2
2010-09-02 17:29:30 -03:00
struct lme2510_state {
u8 id ;
u8 tuner_config ;
u8 signal_lock ;
u8 signal_level ;
u8 signal_sn ;
u8 time_key ;
u8 i2c_talk_onoff ;
u8 i2c_gate ;
u8 i2c_tuner_gate_w ;
u8 i2c_tuner_gate_r ;
u8 i2c_tuner_addr ;
2010-10-16 16:44:43 -03:00
u8 stream_on ;
2010-09-02 17:29:30 -03:00
void * buffer ;
struct urb * lme_urb ;
void * usb_buffer ;
} ;
static int lme2510_bulk_write ( struct usb_device * dev ,
u8 * snd , int len , u8 pipe )
{
int ret , actual_l ;
2010-10-16 16:44:43 -03:00
2010-09-02 17:29:30 -03:00
ret = usb_bulk_msg ( dev , usb_sndbulkpipe ( dev , pipe ) ,
snd , len , & actual_l , 500 ) ;
return ret ;
}
static int lme2510_bulk_read ( struct usb_device * dev ,
u8 * rev , int len , u8 pipe )
{
int ret , actual_l ;
ret = usb_bulk_msg ( dev , usb_rcvbulkpipe ( dev , pipe ) ,
rev , len , & actual_l , 500 ) ;
return ret ;
}
static int lme2510_usb_talk ( struct dvb_usb_device * d ,
u8 * wbuf , int wlen , u8 * rbuf , int rlen )
{
struct lme2510_state * st = d - > priv ;
u8 * buff ;
int ret = 0 ;
if ( st - > usb_buffer = = NULL ) {
st - > usb_buffer = kmalloc ( 512 , GFP_KERNEL ) ;
if ( st - > usb_buffer = = NULL ) {
info ( " MEM Error no memory " ) ;
return - ENOMEM ;
}
}
buff = st - > usb_buffer ;
/* the read/write capped at 512 */
memcpy ( buff , wbuf , ( wlen > 512 ) ? 512 : wlen ) ;
ret = mutex_lock_interruptible ( & d - > usb_mutex ) ;
if ( ret < 0 )
return - EAGAIN ;
ret | = usb_clear_halt ( d - > udev , usb_sndbulkpipe ( d - > udev , 0x01 ) ) ;
2010-10-16 16:44:43 -03:00
ret | = lme2510_bulk_write ( d - > udev , buff , wlen , 0x01 ) ;
msleep ( 12 ) ;
ret | = usb_clear_halt ( d - > udev , usb_rcvbulkpipe ( d - > udev , 0x01 ) ) ;
2010-09-02 17:29:30 -03:00
ret | = lme2510_bulk_read ( d - > udev , buff , ( rlen > 512 ) ?
2010-10-16 16:44:43 -03:00
512 : rlen , 0x01 ) ;
2010-09-02 17:29:30 -03:00
if ( rlen > 0 )
memcpy ( rbuf , buff , rlen ) ;
mutex_unlock ( & d - > usb_mutex ) ;
return ( ret < 0 ) ? - ENODEV : 0 ;
}
2010-10-27 19:50:36 -03:00
static int lme2510_stream_restart ( struct dvb_usb_device * d )
{
2010-10-16 16:44:43 -03:00
static u8 stream_on [ ] = LME_ST_ON_W ;
int ret ;
u8 rbuff [ 10 ] ;
/*Restart Stream Command*/
2010-10-27 19:50:36 -03:00
ret = lme2510_usb_talk ( d , stream_on , sizeof ( stream_on ) ,
2010-10-16 16:44:43 -03:00
rbuff , sizeof ( rbuff ) ) ;
return ret ;
}
2010-09-02 17:29:30 -03:00
static int lme2510_remote_keypress ( struct dvb_usb_adapter * adap , u16 keypress )
{
struct dvb_usb_device * d = adap - > dev ;
deb_info ( 1 , " INT Key Keypress =%04x " , keypress ) ;
if ( keypress > 0 )
ir_keydown ( d - > rc_input_dev , keypress , 0 ) ;
return 0 ;
}
static void lme2510_int_response ( struct urb * lme_urb )
{
struct dvb_usb_adapter * adap = lme_urb - > context ;
struct lme2510_state * st = adap - > dev - > priv ;
static u8 * ibuf , * rbuf ;
int i = 0 , offset ;
switch ( lme_urb - > status ) {
case 0 :
case - ETIMEDOUT :
break ;
case - ECONNRESET :
case - ENOENT :
case - ESHUTDOWN :
return ;
default :
info ( " Error %x " , lme_urb - > status ) ;
break ;
}
rbuf = ( u8 * ) lme_urb - > transfer_buffer ;
offset = ( ( lme_urb - > actual_length / 8 ) > 4 )
? 4 : ( lme_urb - > actual_length / 8 ) ;
for ( i = 0 ; i < offset ; + + i ) {
ibuf = ( u8 * ) & rbuf [ i * 8 ] ;
deb_info ( 5 , " INT O/S C =%02x C/O=%02x Type =%02x%02x " ,
offset , i , ibuf [ 0 ] , ibuf [ 1 ] ) ;
switch ( ibuf [ 0 ] ) {
case 0xaa :
debug_data_snipet ( 1 , " INT Remote data snipet in " , ibuf ) ;
lme2510_remote_keypress ( adap ,
( u16 ) ( ibuf [ 4 ] < < 8 ) + ibuf [ 5 ] ) ;
break ;
case 0xbb :
switch ( st - > tuner_config ) {
case TUNER_LG :
2010-10-16 16:44:43 -03:00
if ( ibuf [ 2 ] > 0 )
st - > signal_lock = ibuf [ 2 ] ;
2010-09-02 17:29:30 -03:00
st - > signal_level = ibuf [ 4 ] ;
st - > signal_sn = ibuf [ 3 ] ;
st - > time_key = ibuf [ 7 ] ;
break ;
case TUNER_S7395 :
/* Tweak for earlier firmware*/
if ( ibuf [ 1 ] = = 0x03 ) {
2010-10-27 19:50:36 -03:00
if ( ibuf [ 2 ] > 1 )
st - > signal_lock = ibuf [ 2 ] ;
2010-09-02 17:29:30 -03:00
st - > signal_level = ibuf [ 3 ] ;
2010-10-16 16:44:43 -03:00
st - > signal_sn = ibuf [ 4 ] ;
2010-09-02 17:29:30 -03:00
} else {
st - > signal_level = ibuf [ 4 ] ;
st - > signal_sn = ibuf [ 5 ] ;
2010-10-27 19:50:36 -03:00
st - > signal_lock =
( st - > signal_lock & 0xf7 ) +
( ( ibuf [ 2 ] & 0x01 ) < < 0x03 ) ;
2010-09-02 17:29:30 -03:00
}
break ;
default :
break ;
}
debug_data_snipet ( 5 , " INT Remote data snipet in " , ibuf ) ;
break ;
case 0xcc :
debug_data_snipet ( 1 , " INT Control data snipet " , ibuf ) ;
break ;
default :
debug_data_snipet ( 1 , " INT Unknown data snipet " , ibuf ) ;
break ;
}
}
usb_submit_urb ( lme_urb , GFP_ATOMIC ) ;
}
static int lme2510_int_read ( struct dvb_usb_adapter * adap )
{
struct lme2510_state * lme_int = adap - > dev - > priv ;
lme_int - > lme_urb = usb_alloc_urb ( 0 , GFP_ATOMIC ) ;
if ( lme_int - > lme_urb = = NULL )
return - ENOMEM ;
lme_int - > buffer = usb_alloc_coherent ( adap - > dev - > udev , 5000 , GFP_ATOMIC ,
& lme_int - > lme_urb - > transfer_dma ) ;
if ( lme_int - > buffer = = NULL )
return - ENOMEM ;
usb_fill_int_urb ( lme_int - > lme_urb ,
adap - > dev - > udev ,
usb_rcvintpipe ( adap - > dev - > udev , 0xa ) ,
lme_int - > buffer ,
4096 ,
lme2510_int_response ,
adap ,
11 ) ;
lme_int - > lme_urb - > transfer_flags | = URB_NO_TRANSFER_DMA_MAP ;
usb_submit_urb ( lme_int - > lme_urb , GFP_ATOMIC ) ;
info ( " INT Interupt Service Started " ) ;
return 0 ;
}
static int lme2510_return_status ( struct usb_device * dev )
{
int ret = 0 ;
u8 data [ 10 ] = { 0 } ;
2010-10-16 16:44:43 -03:00
2010-09-02 17:29:30 -03:00
ret | = usb_control_msg ( dev , usb_rcvctrlpipe ( dev , 0 ) ,
0x06 , 0x80 , 0x0302 , 0x00 , data , 0x0006 , 200 ) ;
info ( " Firmware Status: %x (%x) " , ret , data [ 2 ] ) ;
return ( ret < 0 ) ? - ENODEV : data [ 2 ] ;
}
static int lme2510_msg ( struct dvb_usb_device * d ,
u8 * wbuf , int wlen , u8 * rbuf , int rlen )
{
int ret = 0 ;
struct lme2510_state * st = d - > priv ;
2010-10-16 16:44:43 -03:00
if ( mutex_lock_interruptible ( & d - > i2c_mutex ) < 0 )
2010-09-02 17:29:30 -03:00
return - EAGAIN ;
2010-10-16 16:44:43 -03:00
if ( st - > i2c_talk_onoff = = 1 ) {
2010-09-02 17:29:30 -03:00
ret = lme2510_usb_talk ( d , wbuf , wlen , rbuf , rlen ) ;
switch ( st - > tuner_config ) {
2010-10-16 16:44:43 -03:00
case TUNER_LG :
if ( wbuf [ 2 ] = = 0x1c ) {
if ( wbuf [ 3 ] = = 0x0e ) {
st - > signal_lock = rbuf [ 1 ] ;
if ( ( st - > stream_on & 1 ) & &
( st - > signal_lock & 0x10 ) ) {
2010-10-27 19:50:36 -03:00
lme2510_stream_restart ( d ) ;
2010-10-16 16:44:43 -03:00
st - > i2c_talk_onoff = 0 ;
}
2010-10-27 19:50:36 -03:00
msleep ( 80 ) ;
2010-10-16 16:44:43 -03:00
}
}
break ;
2010-09-02 17:29:30 -03:00
case TUNER_S7395 :
2010-10-16 16:44:43 -03:00
if ( wbuf [ 2 ] = = 0xd0 ) {
if ( wbuf [ 3 ] = = 0x24 ) {
st - > signal_lock = rbuf [ 1 ] ;
if ( ( st - > stream_on & 1 ) & &
( st - > signal_lock & 0x8 ) ) {
2010-10-27 19:50:36 -03:00
lme2510_stream_restart ( d ) ;
2010-10-16 16:44:43 -03:00
st - > i2c_talk_onoff = 0 ;
}
}
if ( ( wbuf [ 3 ] ! = 0x6 ) & ( wbuf [ 3 ] ! = 0x5 ) )
msleep ( 5 ) ;
}
2010-09-02 17:29:30 -03:00
break ;
default :
break ;
}
} else {
switch ( st - > tuner_config ) {
case TUNER_LG :
switch ( wbuf [ 3 ] ) {
case 0x0e :
rbuf [ 0 ] = 0x55 ;
rbuf [ 1 ] = st - > signal_lock ;
break ;
case 0x43 :
rbuf [ 0 ] = 0x55 ;
rbuf [ 1 ] = st - > signal_level ;
break ;
case 0x1c :
rbuf [ 0 ] = 0x55 ;
rbuf [ 1 ] = st - > signal_sn ;
break ;
2010-10-27 19:50:36 -03:00
case 0x15 :
case 0x16 :
case 0x17 :
case 0x18 :
rbuf [ 0 ] = 0x55 ;
rbuf [ 1 ] = 0x00 ;
break ;
2010-09-02 17:29:30 -03:00
default :
2010-10-27 19:50:36 -03:00
lme2510_usb_talk ( d , wbuf , wlen , rbuf , rlen ) ;
st - > i2c_talk_onoff = 1 ;
2010-09-02 17:29:30 -03:00
break ;
}
break ;
case TUNER_S7395 :
switch ( wbuf [ 3 ] ) {
case 0x10 :
rbuf [ 0 ] = 0x55 ;
rbuf [ 1 ] = ( st - > signal_level & 0x80 )
? 0 : ( st - > signal_level * 2 ) ;
break ;
case 0x2d :
rbuf [ 0 ] = 0x55 ;
rbuf [ 1 ] = st - > signal_sn ;
break ;
case 0x24 :
rbuf [ 0 ] = 0x55 ;
2010-10-27 19:50:36 -03:00
rbuf [ 1 ] = st - > signal_lock ;
2010-10-16 16:44:43 -03:00
break ;
2010-10-27 19:50:36 -03:00
case 0x2e :
case 0x26 :
case 0x27 :
2010-10-16 16:44:43 -03:00
rbuf [ 0 ] = 0x55 ;
rbuf [ 1 ] = 0x00 ;
2010-09-02 17:29:30 -03:00
break ;
2010-10-27 19:50:36 -03:00
default :
lme2510_usb_talk ( d , wbuf , wlen , rbuf , rlen ) ;
st - > i2c_talk_onoff = 1 ;
break ;
2010-09-02 17:29:30 -03:00
}
break ;
default :
break ;
}
deb_info ( 4 , " I2C From Interupt Message out(%02x) in(%02x) " ,
wbuf [ 3 ] , rbuf [ 1 ] ) ;
}
2010-10-16 16:44:43 -03:00
mutex_unlock ( & d - > i2c_mutex ) ;
2010-09-02 17:29:30 -03:00
return ret ;
}
static int lme2510_i2c_xfer ( struct i2c_adapter * adap , struct i2c_msg msg [ ] ,
int num )
{
struct dvb_usb_device * d = i2c_get_adapdata ( adap ) ;
struct lme2510_state * st = d - > priv ;
static u8 obuf [ 64 ] , ibuf [ 512 ] ;
int i , read , read_o ;
u16 len ;
u8 gate = st - > i2c_gate ;
if ( gate = = 0 )
gate = 5 ;
if ( num > 2 )
warn ( " more than 2 i2c messages "
" at a time is not handled yet. TODO. " ) ;
for ( i = 0 ; i < num ; i + + ) {
read_o = 1 & ( msg [ i ] . flags & I2C_M_RD ) ;
read = i + 1 < num & & ( msg [ i + 1 ] . flags & I2C_M_RD ) ;
read | = read_o ;
gate = ( msg [ i ] . addr = = st - > i2c_tuner_addr )
? ( read ) ? st - > i2c_tuner_gate_r
: st - > i2c_tuner_gate_w
: st - > i2c_gate ;
obuf [ 0 ] = gate | ( read < < 7 ) ;
if ( gate = = 5 )
obuf [ 1 ] = ( read ) ? 2 : msg [ i ] . len + 1 ;
else
obuf [ 1 ] = msg [ i ] . len + read + 1 ;
obuf [ 2 ] = msg [ i ] . addr ;
if ( read ) {
if ( read_o )
len = 3 ;
else {
memcpy ( & obuf [ 3 ] , msg [ i ] . buf , msg [ i ] . len ) ;
obuf [ msg [ i ] . len + 3 ] = msg [ i + 1 ] . len ;
len = msg [ i ] . len + 4 ;
}
} else {
memcpy ( & obuf [ 3 ] , msg [ i ] . buf , msg [ i ] . len ) ;
len = msg [ i ] . len + 3 ;
}
if ( lme2510_msg ( d , obuf , len , ibuf , 512 ) < 0 ) {
deb_info ( 1 , " i2c transfer failed. " ) ;
return - EAGAIN ;
}
if ( read ) {
if ( read_o )
memcpy ( msg [ i ] . buf , & ibuf [ 1 ] , msg [ i ] . len ) ;
else {
memcpy ( msg [ i + 1 ] . buf , & ibuf [ 1 ] , msg [ i + 1 ] . len ) ;
i + + ;
}
}
}
return i ;
}
static u32 lme2510_i2c_func ( struct i2c_adapter * adapter )
{
return I2C_FUNC_I2C ;
}
static struct i2c_algorithm lme2510_i2c_algo = {
. master_xfer = lme2510_i2c_xfer ,
. functionality = lme2510_i2c_func ,
} ;
/* Callbacks for DVB USB */
static int lme2510_identify_state ( struct usb_device * udev ,
struct dvb_usb_device_properties * props ,
struct dvb_usb_device_description * * desc ,
int * cold )
{
if ( lme2510_return_status ( udev ) = = 0x44 )
* cold = 1 ;
else
* cold = 0 ;
return 0 ;
}
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 rbuf [ 1 ] ;
2010-10-27 19:50:36 -03:00
int ret = 0 , rlen = sizeof ( rbuf ) ;
2010-09-02 17:29:30 -03:00
deb_info ( 1 , " STM (%02x) " , onoff ) ;
2010-10-27 19:50:36 -03:00
/* Streaming is started by FE_HAS_LOCK */
if ( onoff = = 1 )
2010-10-16 16:44:43 -03:00
st - > stream_on = 1 ;
2010-10-27 19:50:36 -03:00
else {
2010-09-02 17:29:30 -03:00
deb_info ( 1 , " STM Steam Off " ) ;
2010-10-27 19:50:36 -03:00
/* mutex is here only to avoid collision with I2C */
ret = mutex_lock_interruptible ( & adap - > dev - > i2c_mutex ) ;
2010-10-16 16:44:43 -03:00
ret | = lme2510_usb_talk ( adap - > dev , clear_reg_3 ,
2010-09-02 17:29:30 -03:00
sizeof ( clear_reg_3 ) , rbuf , rlen ) ;
2010-10-16 16:44:43 -03:00
st - > stream_on = 0 ;
2010-09-02 17:29:30 -03:00
st - > i2c_talk_onoff = 1 ;
2010-10-27 19:50:36 -03:00
mutex_unlock ( & adap - > dev - > i2c_mutex ) ;
2010-09-02 17:29:30 -03:00
}
return ( ret < 0 ) ? - ENODEV : 0 ;
}
static int lme2510_int_service ( struct dvb_usb_adapter * adap )
{
struct dvb_usb_device * d = adap - > dev ;
struct input_dev * input_dev ;
char * ir_codes = RC_MAP_LME2510 ;
int ret = 0 ;
info ( " STA Configuring Remote " ) ;
usb_make_path ( d - > udev , d - > rc_phys , sizeof ( d - > rc_phys ) ) ;
strlcat ( d - > rc_phys , " /ir0 " , sizeof ( d - > rc_phys ) ) ;
input_dev = input_allocate_device ( ) ;
if ( ! input_dev )
return - ENOMEM ;
input_dev - > name = " LME2510 Remote Control " ;
input_dev - > phys = d - > rc_phys ;
usb_to_input_id ( d - > udev , & input_dev - > id ) ;
ret | = ir_input_register ( input_dev , ir_codes , NULL , " LME 2510 " ) ;
if ( ret ) {
input_free_device ( input_dev ) ;
return ret ;
}
d - > rc_input_dev = input_dev ;
/* Start the Interupt */
ret = lme2510_int_read ( adap ) ;
if ( ret < 0 ) {
ir_input_unregister ( input_dev ) ;
input_free_device ( input_dev ) ;
}
2010-10-27 19:50:36 -03:00
2010-09-02 17:29:30 -03:00
return ( ret < 0 ) ? - ENODEV : 0 ;
}
static u8 check_sum ( u8 * p , u8 len )
{
u8 sum = 0 ;
while ( len - - )
sum + = * p + + ;
return sum ;
}
static int lme2510_download_firmware ( struct usb_device * dev ,
const struct firmware * fw )
{
int ret = 0 ;
u8 data [ 512 ] = { 0 } ;
u16 j , wlen , len_in , start , end ;
u8 packet_size , dlen , i ;
u8 * fw_data ;
packet_size = 0x31 ;
len_in = 1 ;
info ( " FRM Starting Firmware Download " ) ;
for ( i = 1 ; i < 3 ; i + + ) {
start = ( i = = 1 ) ? 0 : 512 ;
end = ( i = = 1 ) ? 512 : fw - > size ;
for ( j = start ; j < end ; j + = ( packet_size + 1 ) ) {
fw_data = ( u8 * ) ( fw - > data + j ) ;
if ( ( end - j ) > packet_size ) {
data [ 0 ] = i ;
dlen = packet_size ;
} else {
data [ 0 ] = i | 0x80 ;
dlen = ( u8 ) ( end - j ) - 1 ;
}
data [ 1 ] = dlen ;
memcpy ( & data [ 2 ] , fw_data , dlen + 1 ) ;
wlen = ( u8 ) dlen + 4 ;
data [ wlen - 1 ] = check_sum ( fw_data , dlen + 1 ) ;
deb_info ( 1 , " Data S=%02x:E=%02x CS= %02x " , data [ 3 ] ,
data [ dlen + 2 ] , data [ dlen + 3 ] ) ;
ret | = lme2510_bulk_write ( dev , data , wlen , 1 ) ;
ret | = lme2510_bulk_read ( dev , data , len_in , 1 ) ;
ret | = ( data [ 0 ] = = 0x88 ) ? 0 : - 1 ;
}
}
2010-10-27 19:50:36 -03:00
2010-09-02 17:29:30 -03:00
usb_control_msg ( dev , usb_rcvctrlpipe ( dev , 0 ) ,
0x06 , 0x80 , 0x0200 , 0x00 , data , 0x0109 , 1000 ) ;
data [ 0 ] = 0x8a ;
len_in = 1 ;
msleep ( 2000 ) ;
ret | = lme2510_bulk_write ( dev , data , len_in , 1 ) ; /*Resetting*/
ret | = lme2510_bulk_read ( dev , data , len_in , 1 ) ;
msleep ( 400 ) ;
if ( ret < 0 )
info ( " FRM Firmware Download Failed (%04x) " , ret ) ;
else
info ( " FRM Firmware Download Completed - Resetting Device " ) ;
return ( ret < 0 ) ? - ENODEV : 0 ;
}
2010-10-16 16:44:43 -03:00
/* Default firmware for LME2510C */
const char lme_firmware [ 50 ] = " dvb-usb-lme2510c-s7395.fw " ;
static void lme_coldreset ( struct usb_device * dev )
{
int ret = 0 , len_in ;
u8 data [ 512 ] = { 0 } ;
data [ 0 ] = 0x0a ;
len_in = 1 ;
info ( " FRM Firmware Cold Reset " ) ;
ret | = lme2510_bulk_write ( dev , data , len_in , 1 ) ; /*Cold Resetting*/
ret | = lme2510_bulk_read ( dev , data , len_in , 1 ) ;
2010-10-27 19:50:36 -03:00
2010-10-16 16:44:43 -03:00
return ;
}
static void lme_firmware_switch ( struct usb_device * udev , int cold )
{
const struct firmware * fw = NULL ;
char lme2510c_s7395 [ ] = " dvb-usb-lme2510c-s7395.fw " ;
char lme2510c_lg [ ] = " dvb-usb-lme2510c-lg.fw " ;
char * firm_msg [ ] = { " Loading " , " Switching to " } ;
int ret ;
2010-10-27 19:50:36 -03:00
cold = ( cold > 0 ) ? ( cold & 1 ) : 0 ;
2010-10-16 16:44:43 -03:00
if ( udev - > descriptor . idProduct = = 0x1122 )
return ;
switch ( dvb_usb_lme2510_firmware ) {
case 0 :
default :
memcpy ( & lme_firmware , lme2510c_s7395 , sizeof ( lme2510c_s7395 ) ) ;
ret = request_firmware ( & fw , lme_firmware , & udev - > dev ) ;
if ( ret = = 0 ) {
info ( " FRM %s S7395 Firmware " , firm_msg [ cold ] ) ;
break ;
}
if ( cold = = 0 )
dvb_usb_lme2510_firmware = 1 ;
else
cold = 0 ;
case 1 :
memcpy ( & lme_firmware , lme2510c_lg , sizeof ( lme2510c_lg ) ) ;
ret = request_firmware ( & fw , lme_firmware , & udev - > dev ) ;
if ( ret = = 0 ) {
info ( " FRM %s LG Firmware " , firm_msg [ cold ] ) ;
break ;
}
info ( " FRM No Firmware Found - please install " ) ;
dvb_usb_lme2510_firmware = 0 ;
cold = 0 ;
break ;
}
2010-10-27 19:50:36 -03:00
2010-10-16 16:44:43 -03:00
release_firmware ( fw ) ;
2010-10-27 19:50:36 -03:00
2010-10-16 16:44:43 -03:00
if ( cold )
lme_coldreset ( udev ) ;
2010-10-27 19:50:36 -03:00
2010-10-16 16:44:43 -03:00
return ;
}
2010-09-02 17:29:30 -03:00
static int lme2510_kill_urb ( struct usb_data_stream * stream )
{
int i ;
2010-10-27 19:50:36 -03:00
2010-09-02 17:29:30 -03:00
for ( i = 0 ; i < stream - > urbs_submitted ; i + + ) {
deb_info ( 3 , " killing URB no. %d. " , i ) ;
/* stop the URB */
usb_kill_urb ( stream - > urb_list [ i ] ) ;
}
stream - > urbs_submitted = 0 ;
2010-10-27 19:50:36 -03:00
2010-09-02 17:29:30 -03:00
return 0 ;
}
static struct tda10086_config tda10086_config = {
. demod_address = 0x1c ,
. invert = 0 ,
. diseqc_tone = 1 ,
. xtal_freq = TDA10086_XTAL_16M ,
} ;
static struct stv0288_config lme_config = {
. demod_address = 0xd0 ,
. min_delay_ms = 15 ,
. inittab = s7395_inittab ,
} ;
static struct ix2505v_config lme_tuner = {
. tuner_address = 0xc0 ,
. min_delay_ms = 100 ,
. tuner_gain = 0x0 ,
. tuner_chargepump = 0x3 ,
} ;
static int dm04_lme2510_set_voltage ( struct dvb_frontend * fe ,
fe_sec_voltage_t voltage )
{
struct dvb_usb_adapter * adap = fe - > dvb - > priv ;
static u8 voltage_low [ ] = LME_VOLTAGE_L ;
static u8 voltage_high [ ] = LME_VOLTAGE_H ;
static u8 rbuf [ 1 ] ;
int ret = 0 , len = 3 , rlen = 1 ;
2010-10-27 19:50:36 -03:00
if ( mutex_lock_interruptible ( & adap - > dev - > i2c_mutex ) < 0 )
return - EAGAIN ;
2010-09-02 17:29:30 -03:00
2010-10-16 16:44:43 -03:00
switch ( voltage ) {
case SEC_VOLTAGE_18 :
ret | = lme2510_usb_talk ( adap - > dev ,
voltage_high , len , rbuf , rlen ) ;
2010-09-02 17:29:30 -03:00
break ;
2010-10-16 16:44:43 -03:00
case SEC_VOLTAGE_OFF :
case SEC_VOLTAGE_13 :
default :
ret | = lme2510_usb_talk ( adap - > dev ,
2010-09-02 17:29:30 -03:00
voltage_low , len , rbuf , rlen ) ;
break ;
2010-10-27 19:50:36 -03:00
}
2010-09-02 17:29:30 -03:00
2010-10-27 19:50:36 -03:00
mutex_unlock ( & adap - > dev - > i2c_mutex ) ;
2010-09-02 17:29:30 -03:00
return ( ret < 0 ) ? - ENODEV : 0 ;
}
static int dm04_lme2510_frontend_attach ( struct dvb_usb_adapter * adap )
{
int ret = 0 ;
struct lme2510_state * st = adap - > dev - > priv ;
/* Interupt Start */
ret = lme2510_int_service ( adap ) ;
if ( ret < 0 ) {
info ( " INT Unable to start Interupt Service " ) ;
return - ENODEV ;
}
st - > i2c_talk_onoff = 1 ;
st - > i2c_gate = 4 ;
adap - > fe = dvb_attach ( tda10086_attach , & tda10086_config ,
& adap - > dev - > i2c_adap ) ;
if ( adap - > fe ) {
info ( " TUN Found Frontend TDA10086 " ) ;
memcpy ( & adap - > fe - > ops . info . name ,
& " DM04_LG_TDQY-P001F DVB-S " , 24 ) ;
adap - > fe - > ops . set_voltage = dm04_lme2510_set_voltage ;
st - > i2c_tuner_gate_w = 4 ;
st - > i2c_tuner_gate_r = 4 ;
st - > i2c_tuner_addr = 0xc0 ;
if ( dvb_attach ( tda826x_attach , adap - > fe , 0xc0 ,
& adap - > dev - > i2c_adap , 1 ) ) {
info ( " TUN TDA8263 Found " ) ;
st - > tuner_config = TUNER_LG ;
2010-10-16 16:44:43 -03:00
if ( dvb_usb_lme2510_firmware ! = 1 ) {
dvb_usb_lme2510_firmware = 1 ;
lme_firmware_switch ( adap - > dev - > udev , 1 ) ;
2010-10-27 19:50:36 -03:00
} else /*stops LG/Sharp multi tuner problems*/
dvb_usb_lme2510_firmware = 0 ;
2010-09-02 17:29:30 -03:00
return 0 ;
}
kfree ( adap - > fe ) ;
adap - > fe = NULL ;
}
2010-10-27 19:50:36 -03:00
2010-09-02 17:29:30 -03:00
st - > i2c_gate = 5 ;
adap - > fe = dvb_attach ( stv0288_attach , & lme_config ,
& adap - > dev - > i2c_adap ) ;
if ( adap - > fe ) {
info ( " FE Found Stv0288 " ) ;
memcpy ( & adap - > fe - > ops . info . name ,
& " DM04_SHARP:BS2F7HZ7395 " , 22 ) ;
adap - > fe - > ops . set_voltage = dm04_lme2510_set_voltage ;
st - > i2c_tuner_gate_w = 4 ;
st - > i2c_tuner_gate_r = 5 ;
st - > i2c_tuner_addr = 0xc0 ;
if ( dvb_attach ( ix2505v_attach , adap - > fe , & lme_tuner ,
& adap - > dev - > i2c_adap ) ) {
st - > tuner_config = TUNER_S7395 ;
info ( " TUN Sharp IX2505V silicon tuner " ) ;
2010-10-16 16:44:43 -03:00
if ( dvb_usb_lme2510_firmware ! = 0 ) {
dvb_usb_lme2510_firmware = 0 ;
lme_firmware_switch ( adap - > dev - > udev , 1 ) ;
}
2010-09-02 17:29:30 -03:00
return 0 ;
}
kfree ( adap - > fe ) ;
adap - > fe = NULL ;
}
info ( " DM04 Not Supported " ) ;
return - ENODEV ;
}
static int lme2510_powerup ( struct dvb_usb_device * d , int onoff )
{
struct lme2510_state * st = d - > priv ;
2010-10-27 19:50:36 -03:00
static u8 lnb_on [ ] = LNB_ON ;
static u8 lnb_off [ ] = LNB_OFF ;
static u8 rbuf [ 1 ] ;
int ret , len = 3 , rlen = 1 ;
ret = mutex_lock_interruptible ( & d - > i2c_mutex ) ;
if ( onoff )
ret | = lme2510_usb_talk ( d , lnb_on , len , rbuf , rlen ) ;
else
ret | = lme2510_usb_talk ( d , lnb_off , len , rbuf , rlen ) ;
2010-09-02 17:29:30 -03:00
st - > i2c_talk_onoff = 1 ;
2010-10-27 19:50:36 -03:00
mutex_unlock ( & d - > i2c_mutex ) ;
return ret ;
2010-09-02 17:29:30 -03:00
}
/* DVB USB Driver stuff */
static struct dvb_usb_device_properties lme2510_properties ;
static struct dvb_usb_device_properties lme2510c_properties ;
static int lme2510_probe ( struct usb_interface * intf ,
const struct usb_device_id * id )
{
struct usb_device * udev = interface_to_usbdev ( intf ) ;
int ret = 0 ;
usb_reset_configuration ( udev ) ;
usb_set_interface ( udev , intf - > cur_altsetting - > desc . bInterfaceNumber , 1 ) ;
if ( udev - > speed ! = USB_SPEED_HIGH ) {
ret = usb_reset_device ( udev ) ;
info ( " DEV Failed to connect in HIGH SPEED mode " ) ;
return - ENODEV ;
}
2010-10-16 16:44:43 -03:00
lme_firmware_switch ( udev , 0 ) ;
2010-09-02 17:29:30 -03:00
if ( 0 = = dvb_usb_device_init ( intf , & lme2510_properties ,
THIS_MODULE , NULL , adapter_nr ) ) {
info ( " DEV registering device driver " ) ;
return 0 ;
}
if ( 0 = = dvb_usb_device_init ( intf , & lme2510c_properties ,
THIS_MODULE , NULL , adapter_nr ) ) {
info ( " DEV registering device driver " ) ;
return 0 ;
}
info ( " DEV lme2510 Error " ) ;
return - ENODEV ;
}
static struct usb_device_id lme2510_table [ ] = {
{ USB_DEVICE ( 0x3344 , 0x1122 ) } , /* LME2510 */
{ USB_DEVICE ( 0x3344 , 0x1120 ) } , /* LME2510C */
{ } /* Terminating entry */
} ;
MODULE_DEVICE_TABLE ( usb , lme2510_table ) ;
static struct dvb_usb_device_properties lme2510_properties = {
. caps = DVB_USB_IS_AN_I2C_ADAPTER ,
. usb_ctrl = DEVICE_SPECIFIC ,
. download_firmware = lme2510_download_firmware ,
. firmware = " dvb-usb-lme2510-lg.fw " ,
. size_of_priv = sizeof ( struct lme2510_state ) ,
. num_adapters = 1 ,
. adapter = {
{
. streaming_ctrl = lme2510_streaming_ctrl ,
. frontend_attach = dm04_lme2510_frontend_attach ,
/* parameter for the MPEG2-data transfer */
. stream = {
. type = USB_BULK ,
. count = 10 ,
. endpoint = 0x06 ,
. u = {
. bulk = {
. buffersize = 4096 ,
}
}
}
}
} ,
. power_ctrl = lme2510_powerup ,
. identify_state = lme2510_identify_state ,
. i2c_algo = & lme2510_i2c_algo ,
. generic_bulk_ctrl_endpoint = 0 ,
. num_device_descs = 1 ,
. devices = {
{ " DM04 LME2510 DVB-S USB 2.0 " ,
{ & lme2510_table [ 0 ] , NULL } ,
} ,
}
} ;
static struct dvb_usb_device_properties lme2510c_properties = {
. caps = DVB_USB_IS_AN_I2C_ADAPTER ,
. usb_ctrl = DEVICE_SPECIFIC ,
. download_firmware = lme2510_download_firmware ,
2010-10-16 16:44:43 -03:00
. firmware = lme_firmware ,
2010-09-02 17:29:30 -03:00
. size_of_priv = sizeof ( struct lme2510_state ) ,
. num_adapters = 1 ,
. adapter = {
{
. streaming_ctrl = lme2510_streaming_ctrl ,
. frontend_attach = dm04_lme2510_frontend_attach ,
/* parameter for the MPEG2-data transfer */
. stream = {
. type = USB_BULK ,
2010-10-16 16:44:43 -03:00
. count = 10 ,
2010-09-02 17:29:30 -03:00
. endpoint = 0x8 ,
. u = {
. bulk = {
. buffersize = 4096 ,
}
}
}
}
} ,
. power_ctrl = lme2510_powerup ,
. identify_state = lme2510_identify_state ,
. i2c_algo = & lme2510_i2c_algo ,
. generic_bulk_ctrl_endpoint = 0 ,
. num_device_descs = 1 ,
. devices = {
{ " DM04 LME2510C USB2.0 " ,
{ & lme2510_table [ 1 ] , NULL } ,
} ,
}
} ;
2010-10-16 16:44:43 -03:00
void * lme2510_exit_int ( struct dvb_usb_device * d )
2010-09-02 17:29:30 -03:00
{
struct lme2510_state * st = d - > priv ;
2010-10-16 16:44:43 -03:00
struct dvb_usb_adapter * adap = & d - > adapter [ 0 ] ;
void * buffer = NULL ;
if ( adap ! = NULL ) {
lme2510_kill_urb ( & adap - > stream ) ;
adap - > feedcount = 0 ;
}
2010-09-02 17:29:30 -03:00
if ( st - > lme_urb ! = NULL ) {
2010-10-16 16:44:43 -03:00
st - > i2c_talk_onoff = 1 ;
2010-09-02 17:29:30 -03:00
st - > signal_lock = 0 ;
st - > signal_level = 0 ;
st - > signal_sn = 0 ;
2010-10-16 16:44:43 -03:00
buffer = st - > usb_buffer ;
2010-09-02 17:29:30 -03:00
usb_kill_urb ( st - > lme_urb ) ;
usb_free_coherent ( d - > udev , 5000 , st - > buffer ,
st - > lme_urb - > transfer_dma ) ;
info ( " Interupt Service Stopped " ) ;
ir_input_unregister ( d - > rc_input_dev ) ;
info ( " Remote Stopped " ) ;
}
2010-10-16 16:44:43 -03:00
return buffer ;
2010-09-02 17:29:30 -03:00
}
void lme2510_exit ( struct usb_interface * intf )
{
struct dvb_usb_device * d = usb_get_intfdata ( intf ) ;
2010-10-16 16:44:43 -03:00
void * usb_buffer ;
2010-09-02 17:29:30 -03:00
if ( d ! = NULL ) {
2010-10-16 16:44:43 -03:00
usb_buffer = lme2510_exit_int ( d ) ;
2010-09-02 17:29:30 -03:00
dvb_usb_device_exit ( intf ) ;
2010-10-16 16:44:43 -03:00
kfree ( usb_buffer ) ;
2010-09-02 17:29:30 -03:00
}
}
static struct usb_driver lme2510_driver = {
. name = " LME2510C_DVBS " ,
. probe = lme2510_probe ,
. disconnect = lme2510_exit ,
. id_table = lme2510_table ,
} ;
/* module stuff */
static int __init lme2510_module_init ( void )
{
int result = usb_register ( & lme2510_driver ) ;
if ( result ) {
err ( " usb_register failed. Error number %d " , result ) ;
return result ;
}
return 0 ;
}
static void __exit lme2510_module_exit ( void )
{
/* deregister this driver from the USB subsystem */
usb_deregister ( & lme2510_driver ) ;
}
module_init ( lme2510_module_init ) ;
module_exit ( lme2510_module_exit ) ;
MODULE_AUTHOR ( " Malcolm Priestley <tvboxspy@gmail.com> " ) ;
MODULE_DESCRIPTION ( " LM2510(C) DVB-S USB2.0 " ) ;
2010-10-27 19:50:36 -03:00
MODULE_VERSION ( " 1.70 " ) ;
2010-09-02 17:29:30 -03:00
MODULE_LICENSE ( " GPL " ) ;