2005-06-23 22:02:35 -07:00
/* DVB USB compliant linux driver for Nebula Electronics uDigiTV DVB-T USB2.0
* receiver
*
2005-07-07 17:58:13 -07:00
* Copyright ( C ) 2005 Patrick Boettcher ( patrick . boettcher @ desy . de )
2005-06-23 22:02:35 -07:00
*
2005-07-07 17:58:13 -07:00
* partly based on the SDK published by Nebula Electronics
2005-06-23 22:02:35 -07: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 , version 2.
*
* see Documentation / dvb / README . dvb - usb for more information
*/
# include "digitv.h"
# include "mt352.h"
# include "nxt6000.h"
/* debug */
int dvb_usb_digitv_debug ;
module_param_named ( debug , dvb_usb_digitv_debug , int , 0644 ) ;
MODULE_PARM_DESC ( debug , " set debugging level (1=rc (or-able)). " DVB_USB_DEBUG_STATUS ) ;
static int digitv_ctrl_msg ( struct dvb_usb_device * d ,
u8 cmd , u8 vv , u8 * wbuf , int wlen , u8 * rbuf , int rlen )
{
int wo = ( rbuf = = NULL | | rlen = = 0 ) ; /* write-only */
u8 sndbuf [ 7 ] , rcvbuf [ 7 ] ;
memset ( sndbuf , 0 , 7 ) ; memset ( rcvbuf , 0 , 7 ) ;
sndbuf [ 0 ] = cmd ;
sndbuf [ 1 ] = vv ;
sndbuf [ 2 ] = wo ? wlen : rlen ;
2006-01-09 15:25:22 -02:00
if ( wo ) {
2005-06-23 22:02:35 -07:00
memcpy ( & sndbuf [ 3 ] , wbuf , wlen ) ;
dvb_usb_generic_write ( d , sndbuf , 7 ) ;
} else {
dvb_usb_generic_rw ( d , sndbuf , 7 , rcvbuf , 7 , 10 ) ;
2005-07-07 17:58:17 -07:00
memcpy ( rbuf , & rcvbuf [ 3 ] , rlen ) ;
2005-06-23 22:02:35 -07:00
}
return 0 ;
}
/* I2C */
static int digitv_i2c_xfer ( struct i2c_adapter * adap , struct i2c_msg msg [ ] , int num )
{
struct dvb_usb_device * d = i2c_get_adapdata ( adap ) ;
int i ;
2006-02-07 06:49:14 -02:00
if ( mutex_lock_interruptible ( & d - > i2c_mutex ) < 0 )
2005-06-23 22:02:35 -07:00
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 + + ) {
/* write/read request */
if ( i + 1 < num & & ( msg [ i + 1 ] . flags & I2C_M_RD ) ) {
if ( digitv_ctrl_msg ( d , USB_READ_COFDM , msg [ i ] . buf [ 0 ] , NULL , 0 ,
msg [ i + 1 ] . buf , msg [ i + 1 ] . len ) < 0 )
break ;
i + + ;
} else
if ( digitv_ctrl_msg ( d , USB_WRITE_COFDM , msg [ i ] . buf [ 0 ] ,
& msg [ i ] . buf [ 1 ] , msg [ i ] . len - 1 , NULL , 0 ) < 0 )
break ;
}
2006-02-07 06:49:14 -02:00
mutex_unlock ( & d - > i2c_mutex ) ;
2005-06-23 22:02:35 -07:00
return i ;
}
static u32 digitv_i2c_func ( struct i2c_adapter * adapter )
{
return I2C_FUNC_I2C ;
}
static struct i2c_algorithm digitv_i2c_algo = {
. master_xfer = digitv_i2c_xfer ,
. functionality = digitv_i2c_func ,
} ;
/* Callbacks for DVB USB */
static int digitv_identify_state ( struct usb_device * udev , struct
dvb_usb_properties * props , struct dvb_usb_device_description * * desc ,
int * cold )
{
* cold = udev - > descriptor . iManufacturer = = 0 & & udev - > descriptor . iProduct = = 0 ;
return 0 ;
}
static int digitv_mt352_demod_init ( struct dvb_frontend * fe )
{
2005-07-07 17:58:13 -07:00
static u8 reset_buf [ ] = { 0x89 , 0x38 , 0x8a , 0x2d , 0x50 , 0x80 } ;
static u8 init_buf [ ] = { 0x68 , 0xa0 , 0x8e , 0x40 , 0x53 , 0x50 ,
0x67 , 0x20 , 0x7d , 0x01 , 0x7c , 0x00 , 0x7a , 0x00 ,
0x79 , 0x20 , 0x57 , 0x05 , 0x56 , 0x31 , 0x88 , 0x0f ,
0x75 , 0x32 } ;
int i ;
2005-06-23 22:02:35 -07:00
2005-07-07 17:58:13 -07:00
for ( i = 0 ; i < ARRAY_SIZE ( reset_buf ) ; i + = 2 )
mt352_write ( fe , & reset_buf [ i ] , 2 ) ;
2005-06-23 22:02:35 -07:00
msleep ( 1 ) ;
2005-07-07 17:58:13 -07:00
for ( i = 0 ; i < ARRAY_SIZE ( init_buf ) ; i + = 2 )
mt352_write ( fe , & init_buf [ i ] , 2 ) ;
2005-06-23 22:02:35 -07:00
return 0 ;
}
static struct mt352_config digitv_mt352_config = {
. demod_init = digitv_mt352_demod_init ,
2005-07-07 17:58:13 -07:00
. pll_set = dvb_usb_pll_set ,
2005-06-23 22:02:35 -07:00
} ;
2005-09-09 13:02:48 -07:00
static int digitv_nxt6000_pll_set ( struct dvb_frontend * fe , struct dvb_frontend_parameters * fep )
{
struct dvb_usb_device * d = fe - > dvb - > priv ;
u8 b [ 5 ] ;
dvb_usb_pll_set ( fe , fep , b ) ;
return digitv_ctrl_msg ( d , USB_WRITE_TUNER , 0 , & b [ 1 ] , 4 , NULL , 0 ) ;
}
2005-06-23 22:02:35 -07:00
2005-09-09 13:02:48 -07:00
static struct nxt6000_config digitv_nxt6000_config = {
. clock_inversion = 1 ,
. pll_set = digitv_nxt6000_pll_set ,
2005-06-23 22:02:35 -07:00
} ;
static int digitv_frontend_attach ( struct dvb_usb_device * d )
{
2005-09-09 13:02:48 -07:00
if ( ( d - > fe = mt352_attach ( & digitv_mt352_config , & d - > i2c_adap ) ) ! = NULL | |
( d - > fe = nxt6000_attach ( & digitv_nxt6000_config , & d - > i2c_adap ) ) ! = NULL )
2005-06-23 22:02:35 -07:00
return 0 ;
return - EIO ;
}
2005-07-07 17:58:13 -07:00
static int digitv_tuner_attach ( struct dvb_usb_device * d )
{
d - > pll_addr = 0x60 ;
d - > pll_desc = & dvb_pll_tded4 ;
return 0 ;
}
2005-06-23 22:02:35 -07:00
static struct dvb_usb_rc_key digitv_rc_keys [ ] = {
{ 0x00 , 0x16 , KEY_POWER } , /* dummy key */
} ;
/* TODO is it really the NEC protocol ? */
2005-12-01 00:51:53 -08:00
static int digitv_rc_query ( struct dvb_usb_device * d , u32 * event , int * state )
2005-06-23 22:02:35 -07:00
{
u8 key [ 5 ] ;
digitv_ctrl_msg ( d , USB_READ_REMOTE , 0 , NULL , 0 , & key [ 1 ] , 4 ) ;
/* TODO state, maybe it is VV ? */
if ( key [ 1 ] ! = 0 )
key [ 0 ] = 0x01 ; /* if something is inside the buffer, simulate key press */
/* call the universal NEC remote processor, to find out the key's state and event */
dvb_usb_nec_rc_key_to_event ( d , key , event , state ) ;
if ( key [ 0 ] ! = 0 )
deb_rc ( " key: %x %x %x %x %x \n " , key [ 0 ] , key [ 1 ] , key [ 2 ] , key [ 3 ] , key [ 4 ] ) ;
return 0 ;
}
/* DVB USB Driver stuff */
static struct dvb_usb_properties digitv_properties ;
static int digitv_probe ( struct usb_interface * intf ,
const struct usb_device_id * id )
{
2005-09-09 13:02:48 -07:00
struct dvb_usb_device * d ;
int ret ;
if ( ( ret = dvb_usb_device_init ( intf , & digitv_properties , THIS_MODULE , & d ) ) = = 0 ) {
u8 b [ 4 ] = { 0 } ;
2006-02-07 06:49:12 -02:00
if ( d ! = NULL ) { /* do that only when the firmware is loaded */
b [ 0 ] = 1 ;
digitv_ctrl_msg ( d , USB_WRITE_REMOTE_TYPE , 0 , b , 4 , NULL , 0 ) ;
2005-09-09 13:02:48 -07:00
2006-02-07 06:49:12 -02:00
b [ 0 ] = 0 ;
digitv_ctrl_msg ( d , USB_WRITE_REMOTE , 0 , b , 4 , NULL , 0 ) ;
}
2005-09-09 13:02:48 -07:00
}
return ret ;
2005-06-23 22:02:35 -07:00
}
static struct usb_device_id digitv_table [ ] = {
{ USB_DEVICE ( USB_VID_ANCHOR , USB_PID_NEBULA_DIGITV ) } ,
{ } /* Terminating entry */
} ;
MODULE_DEVICE_TABLE ( usb , digitv_table ) ;
static struct dvb_usb_properties digitv_properties = {
. caps = DVB_USB_IS_AN_I2C_ADAPTER ,
. usb_ctrl = CYPRESS_FX2 ,
2006-02-07 06:49:12 -02:00
. firmware = " dvb-usb-digitv-02.fw " ,
2005-06-23 22:02:35 -07:00
. size_of_priv = 0 ,
. frontend_attach = digitv_frontend_attach ,
2005-07-07 17:58:13 -07:00
. tuner_attach = digitv_tuner_attach ,
2005-06-23 22:02:35 -07:00
. rc_interval = 1000 ,
. rc_key_map = digitv_rc_keys ,
. rc_key_map_size = ARRAY_SIZE ( digitv_rc_keys ) ,
. rc_query = digitv_rc_query ,
. identify_state = digitv_identify_state ,
. i2c_algo = & digitv_i2c_algo ,
. generic_bulk_ctrl_endpoint = 0x01 ,
/* parameter for the MPEG2-data transfer */
. urb = {
. type = DVB_USB_BULK ,
. count = 7 ,
. endpoint = 0x02 ,
. u = {
. bulk = {
. buffersize = 4096 ,
}
}
} ,
2005-07-07 17:58:13 -07:00
. num_device_descs = 1 ,
2005-06-23 22:02:35 -07:00
. devices = {
{ " Nebula Electronics uDigiTV DVB-T USB2.0) " ,
{ & digitv_table [ 0 ] , NULL } ,
{ NULL } ,
} ,
2006-02-07 06:49:12 -02:00
{ NULL } ,
2005-06-23 22:02:35 -07:00
}
} ;
static struct usb_driver digitv_driver = {
2005-07-07 17:58:30 -07:00
. name = " dvb_usb_digitv " ,
2005-06-23 22:02:35 -07:00
. probe = digitv_probe ,
. disconnect = dvb_usb_device_exit ,
. id_table = digitv_table ,
} ;
/* module stuff */
static int __init digitv_module_init ( void )
{
int result ;
if ( ( result = usb_register ( & digitv_driver ) ) ) {
err ( " usb_register failed. Error number %d " , result ) ;
return result ;
}
return 0 ;
}
static void __exit digitv_module_exit ( void )
{
/* deregister this driver from the USB subsystem */
usb_deregister ( & digitv_driver ) ;
}
module_init ( digitv_module_init ) ;
module_exit ( digitv_module_exit ) ;
MODULE_AUTHOR ( " Patrick Boettcher <patrick.boettcher@desy.de> " ) ;
MODULE_DESCRIPTION ( " Driver for Nebula Electronics uDigiTV DVB-T USB2.0 " ) ;
MODULE_VERSION ( " 1.0-alpha " ) ;
MODULE_LICENSE ( " GPL " ) ;