2006-12-03 02:16:04 +03:00
/* DVB USB compliant linux driver for Technotrend DVB USB boxes and clones
* ( e . g . Pinnacle 400 e DVB - S USB2 .0 ) .
*
* The Pinnacle 400 e uses the same protocol as the Technotrend USB1 .1 boxes .
*
* TDA8263 + TDA10086
*
* I2C addresses :
* 0x08 - LNBP21PD - LNB power supply
* 0x0e - TDA10086 - Demodulator
* 0x50 - FX2 eeprom
* 0x60 - TDA8263 - Tuner
* 0x78 ? ? ?
*
* Copyright ( c ) 2002 Holger Waechtler < holger @ convergence . de >
* Copyright ( c ) 2003 Felix Domke < tmbinc @ elitedvb . net >
* Copyright ( C ) 2005 - 6 Patrick Boettcher < pb @ linuxtv . org >
*
* 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 , version 2.
*
* see Documentation / dvb / README . dvb - usb for more information
*/
# define DVB_USB_LOG_PREFIX "ttusb2"
# include "dvb-usb.h"
# include "ttusb2.h"
# include "tda826x.h"
# include "tda10086.h"
# include "lnbp21.h"
/* debug */
static int dvb_usb_ttusb2_debug ;
# define deb_info(args...) dprintk(dvb_usb_ttusb2_debug,0x01,args)
module_param_named ( debug , dvb_usb_ttusb2_debug , int , 0644 ) ;
MODULE_PARM_DESC ( debug , " set debugging level (1=info (or-able)). " DVB_USB_DEBUG_STATUS ) ;
struct ttusb2_state {
u8 id ;
} ;
static int ttusb2_msg ( struct dvb_usb_device * d , u8 cmd ,
u8 * wbuf , int wlen , u8 * rbuf , int rlen )
{
struct ttusb2_state * st = d - > priv ;
u8 s [ wlen + 4 ] , r [ 64 ] = { 0 } ;
int ret = 0 ;
memset ( s , 0 , wlen + 4 ) ;
s [ 0 ] = 0xaa ;
s [ 1 ] = + + st - > id ;
s [ 2 ] = cmd ;
s [ 3 ] = wlen ;
memcpy ( & s [ 4 ] , wbuf , wlen ) ;
ret = dvb_usb_generic_rw ( d , s , wlen + 4 , r , 64 , 0 ) ;
if ( ret ! = 0 | |
r [ 0 ] ! = 0x55 | |
r [ 1 ] ! = s [ 1 ] | |
r [ 2 ] ! = cmd | |
( rlen > 0 & & r [ 3 ] ! = rlen ) ) {
warn ( " there might have been an error during control message transfer. (rlen = %d, was %d) " , rlen , r [ 3 ] ) ;
return - EIO ;
}
if ( rlen > 0 )
memcpy ( rbuf , & r [ 4 ] , rlen ) ;
return 0 ;
}
static int ttusb2_i2c_xfer ( struct i2c_adapter * adap , struct i2c_msg msg [ ] , int num )
{
struct dvb_usb_device * d = i2c_get_adapdata ( adap ) ;
static u8 obuf [ 60 ] , ibuf [ 60 ] ;
int i , read ;
if ( mutex_lock_interruptible ( & d - > i2c_mutex ) < 0 )
return - EAGAIN ;
if ( num > 2 )
warn ( " more than 2 i2c messages at a time is not handled yet. TODO. " ) ;
for ( i = 0 ; i < num ; i + + ) {
read = i + 1 < num & & ( msg [ i + 1 ] . flags & I2C_M_RD ) ;
obuf [ 0 ] = ( msg [ i ] . addr < < 1 ) | read ;
obuf [ 1 ] = msg [ i ] . len ;
/* read request */
if ( read )
obuf [ 2 ] = msg [ i + 1 ] . len ;
else
obuf [ 2 ] = 0 ;
memcpy ( & obuf [ 3 ] , msg [ i ] . buf , msg [ i ] . len ) ;
if ( ttusb2_msg ( d , CMD_I2C_XFER , obuf , msg [ i ] . len + 3 , ibuf , obuf [ 2 ] + 3 ) < 0 ) {
err ( " i2c transfer failed. " ) ;
break ;
}
if ( read ) {
memcpy ( msg [ i + 1 ] . buf , & ibuf [ 3 ] , msg [ i + 1 ] . len ) ;
i + + ;
}
}
mutex_unlock ( & d - > i2c_mutex ) ;
return i ;
}
static u32 ttusb2_i2c_func ( struct i2c_adapter * adapter )
{
return I2C_FUNC_I2C ;
}
static struct i2c_algorithm ttusb2_i2c_algo = {
. master_xfer = ttusb2_i2c_xfer ,
. functionality = ttusb2_i2c_func ,
} ;
/* Callbacks for DVB USB */
static int ttusb2_identify_state ( struct usb_device * udev , struct
dvb_usb_device_properties * props , struct dvb_usb_device_description * * desc ,
int * cold )
{
* cold = udev - > descriptor . iManufacturer = = 0 & & udev - > descriptor . iProduct = = 0 ;
return 0 ;
}
static int ttusb2_power_ctrl ( struct dvb_usb_device * d , int onoff )
{
u8 b = onoff ;
ttusb2_msg ( d , CMD_POWER , & b , 0 , NULL , 0 ) ;
return ttusb2_msg ( d , CMD_POWER , & b , 1 , NULL , 0 ) ;
}
static struct tda10086_config tda10086_config = {
. demod_address = 0x0e ,
. invert = 0 ,
} ;
static int ttusb2_frontend_attach ( struct dvb_usb_adapter * adap )
{
if ( usb_set_interface ( adap - > dev - > udev , 0 , 3 ) < 0 )
err ( " set interface to alts=3 failed " ) ;
if ( ( adap - > fe = dvb_attach ( tda10086_attach , & tda10086_config , & adap - > dev - > i2c_adap ) ) = = NULL ) {
deb_info ( " TDA10086 attach failed \n " ) ;
return - ENODEV ;
}
return 0 ;
}
static int ttusb2_tuner_attach ( struct dvb_usb_adapter * adap )
{
if ( dvb_attach ( tda826x_attach , adap - > fe , 0x60 , & adap - > dev - > i2c_adap , 0 ) = = NULL ) {
deb_info ( " TDA8263 attach failed \n " ) ;
return - ENODEV ;
}
if ( dvb_attach ( lnbp21_attach , adap - > fe , & adap - > dev - > i2c_adap , 0 , 0 ) = = NULL ) {
deb_info ( " LNBP21 attach failed \n " ) ;
return - ENODEV ;
}
return 0 ;
}
/* DVB USB Driver stuff */
static struct dvb_usb_device_properties ttusb2_properties ;
static int ttusb2_probe ( struct usb_interface * intf ,
const struct usb_device_id * id )
{
return dvb_usb_device_init ( intf , & ttusb2_properties , THIS_MODULE , NULL ) ;
}
static struct usb_device_id ttusb2_table [ ] = {
{ USB_DEVICE ( USB_VID_PINNACLE , USB_PID_PCTV_400E ) } ,
2007-04-27 19:31:32 +04:00
{ USB_DEVICE ( USB_VID_PINNACLE , USB_PID_PCTV_450E ) } ,
2006-12-03 02:16:04 +03:00
{ } /* Terminating entry */
} ;
MODULE_DEVICE_TABLE ( usb , ttusb2_table ) ;
static struct dvb_usb_device_properties ttusb2_properties = {
. caps = DVB_USB_IS_AN_I2C_ADAPTER ,
. usb_ctrl = CYPRESS_FX2 ,
. firmware = " dvb-usb-pctv-400e-01.fw " ,
. size_of_priv = sizeof ( struct ttusb2_state ) ,
. num_adapters = 1 ,
. adapter = {
{
. streaming_ctrl = NULL , // ttusb2_streaming_ctrl,
. frontend_attach = ttusb2_frontend_attach ,
. tuner_attach = ttusb2_tuner_attach ,
/* parameter for the MPEG2-data transfer */
. stream = {
. type = USB_ISOC ,
. count = 5 ,
. endpoint = 0x02 ,
. u = {
. isoc = {
. framesperurb = 4 ,
. framesize = 940 ,
. interval = 1 ,
}
}
}
}
} ,
. power_ctrl = ttusb2_power_ctrl ,
. identify_state = ttusb2_identify_state ,
. i2c_algo = & ttusb2_i2c_algo ,
. generic_bulk_ctrl_endpoint = 0x01 ,
2007-04-27 19:31:32 +04:00
. num_device_descs = 2 ,
2006-12-03 02:16:04 +03:00
. devices = {
{ " Pinnacle 400e DVB-S USB2.0 " ,
{ & ttusb2_table [ 0 ] , NULL } ,
{ NULL } ,
} ,
2007-04-27 19:31:32 +04:00
{ " Pinnacle 450e DVB-S USB2.0 " ,
{ & ttusb2_table [ 1 ] , NULL } ,
{ NULL } ,
} ,
2006-12-03 02:16:04 +03:00
}
} ;
static struct usb_driver ttusb2_driver = {
. name = " dvb_usb_ttusb2 " ,
. probe = ttusb2_probe ,
. disconnect = dvb_usb_device_exit ,
. id_table = ttusb2_table ,
} ;
/* module stuff */
static int __init ttusb2_module_init ( void )
{
int result ;
if ( ( result = usb_register ( & ttusb2_driver ) ) ) {
err ( " usb_register failed. Error number %d " , result ) ;
return result ;
}
return 0 ;
}
static void __exit ttusb2_module_exit ( void )
{
/* deregister this driver from the USB subsystem */
usb_deregister ( & ttusb2_driver ) ;
}
module_init ( ttusb2_module_init ) ;
module_exit ( ttusb2_module_exit ) ;
MODULE_AUTHOR ( " Patrick Boettcher <patrick.boettcher@desy.de> " ) ;
MODULE_DESCRIPTION ( " Driver for Pinnacle PCTV 400e DVB-S USB2.0 " ) ;
MODULE_VERSION ( " 1.0 " ) ;
MODULE_LICENSE ( " GPL " ) ;