2005-06-23 22:02:35 -07:00
/* DVB USB compliant Linux driver for the
* - TwinhanDTV Alpha / MagicBoxII USB2 .0 DVB - T receiver
* - DigitalNow TinyUSB2 DVB - t receiver
*
* Copyright ( C ) 2004 - 5 Patrick Boettcher ( patrick . boettcher @ desy . de )
*
* Thanks to Twinhan who kindly provided hardware and information .
*
* 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 "vp7045.h"
/* debug */
2007-11-05 14:07:06 -03:00
static int dvb_usb_vp7045_debug ;
2005-06-23 22:02:35 -07:00
module_param_named ( debug , dvb_usb_vp7045_debug , int , 0644 ) ;
MODULE_PARM_DESC ( debug , " set debugging level (1=info,xfer=2,rc=4 (or-able)). " DVB_USB_DEBUG_STATUS ) ;
2008-04-09 19:13:13 -03:00
DVB_DEFINE_MOD_OPT_ADAPTER_NR ( adapter_nr ) ;
2007-11-05 14:07:06 -03:00
# define deb_info(args...) dprintk(dvb_usb_vp7045_debug,0x01,args)
# define deb_xfer(args...) dprintk(dvb_usb_vp7045_debug,0x02,args)
# define deb_rc(args...) dprintk(dvb_usb_vp7045_debug,0x04,args)
2005-06-23 22:02:35 -07:00
int vp7045_usb_op ( struct dvb_usb_device * d , u8 cmd , u8 * out , int outlen , u8 * in , int inlen , int msec )
{
int ret = 0 ;
u8 inbuf [ 12 ] = { 0 } , outbuf [ 20 ] = { 0 } ;
outbuf [ 0 ] = cmd ;
if ( outlen > 19 )
outlen = 19 ;
if ( inlen > 11 )
inlen = 11 ;
if ( out ! = NULL & & outlen > 0 )
memcpy ( & outbuf [ 1 ] , out , outlen ) ;
deb_xfer ( " out buffer: " ) ;
debug_dump ( outbuf , outlen + 1 , deb_xfer ) ;
2006-02-07 06:49:14 -02:00
if ( ( ret = mutex_lock_interruptible ( & d - > usb_mutex ) ) )
2005-06-23 22:02:35 -07:00
return ret ;
if ( usb_control_msg ( d - > udev ,
usb_sndctrlpipe ( d - > udev , 0 ) ,
TH_COMMAND_OUT , USB_TYPE_VENDOR | USB_DIR_OUT , 0 , 0 ,
2005-07-07 17:58:30 -07:00
outbuf , 20 , 2000 ) ! = 20 ) {
2005-06-23 22:02:35 -07:00
err ( " USB control message 'out' went wrong. " ) ;
ret = - EIO ;
goto unlock ;
}
msleep ( msec ) ;
if ( usb_control_msg ( d - > udev ,
usb_rcvctrlpipe ( d - > udev , 0 ) ,
TH_COMMAND_IN , USB_TYPE_VENDOR | USB_DIR_IN , 0 , 0 ,
2005-07-07 17:58:30 -07:00
inbuf , 12 , 2000 ) ! = 12 ) {
2005-06-23 22:02:35 -07:00
err ( " USB control message 'in' went wrong. " ) ;
ret = - EIO ;
goto unlock ;
}
deb_xfer ( " in buffer: " ) ;
debug_dump ( inbuf , 12 , deb_xfer ) ;
if ( in ! = NULL & & inlen > 0 )
memcpy ( in , & inbuf [ 1 ] , inlen ) ;
unlock :
2006-02-07 06:49:14 -02:00
mutex_unlock ( & d - > usb_mutex ) ;
2005-06-23 22:02:35 -07:00
return ret ;
}
u8 vp7045_read_reg ( struct dvb_usb_device * d , u8 reg )
{
u8 obuf [ 2 ] = { 0 } , v ;
obuf [ 1 ] = reg ;
vp7045_usb_op ( d , TUNER_REG_READ , obuf , 2 , & v , 1 , 30 ) ;
return v ;
}
static int vp7045_power_ctrl ( struct dvb_usb_device * d , int onoff )
{
u8 v = onoff ;
return vp7045_usb_op ( d , SET_TUNER_POWER , & v , 1 , NULL , 0 , 150 ) ;
}
/* remote control stuff */
/* The keymapping struct. Somehow this should be loaded to the driver, but
* currently it is hardcoded . */
static struct dvb_usb_rc_key vp7045_rc_keys [ ] = {
2009-08-29 15:19:31 -03:00
{ 0x0016 , KEY_POWER } ,
{ 0x0010 , KEY_MUTE } ,
{ 0x0003 , KEY_1 } ,
{ 0x0001 , KEY_2 } ,
{ 0x0006 , KEY_3 } ,
{ 0x0009 , KEY_4 } ,
{ 0x001d , KEY_5 } ,
{ 0x001f , KEY_6 } ,
{ 0x000d , KEY_7 } ,
{ 0x0019 , KEY_8 } ,
{ 0x001b , KEY_9 } ,
{ 0x0015 , KEY_0 } ,
{ 0x0005 , KEY_CHANNELUP } ,
{ 0x0002 , KEY_CHANNELDOWN } ,
{ 0x001e , KEY_VOLUMEUP } ,
{ 0x000a , KEY_VOLUMEDOWN } ,
{ 0x0011 , KEY_RECORD } ,
{ 0x0017 , KEY_FAVORITES } , /* Heart symbol - Channel list. */
{ 0x0014 , KEY_PLAY } ,
{ 0x001a , KEY_STOP } ,
{ 0x0040 , KEY_REWIND } ,
{ 0x0012 , KEY_FASTFORWARD } ,
{ 0x000e , KEY_PREVIOUS } , /* Recall - Previous channel. */
{ 0x004c , KEY_PAUSE } ,
{ 0x004d , KEY_SCREEN } , /* Full screen mode. */
{ 0x0054 , KEY_AUDIO } , /* MTS - Switch to secondary audio. */
{ 0x000c , KEY_CANCEL } , /* Cancel */
{ 0x001c , KEY_EPG } , /* EPG */
{ 0x0000 , KEY_TAB } , /* Tab */
{ 0x0048 , KEY_INFO } , /* Preview */
{ 0x0004 , KEY_LIST } , /* RecordList */
{ 0x000f , KEY_TEXT } , /* Teletext */
{ 0x0041 , KEY_PREVIOUSSONG } ,
{ 0x0042 , KEY_NEXTSONG } ,
{ 0x004b , KEY_UP } ,
{ 0x0051 , KEY_DOWN } ,
{ 0x004e , KEY_LEFT } ,
{ 0x0052 , KEY_RIGHT } ,
{ 0x004f , KEY_ENTER } ,
{ 0x0013 , KEY_CANCEL } ,
{ 0x004a , KEY_CLEAR } ,
{ 0x0054 , KEY_PRINT } , /* Capture */
{ 0x0043 , KEY_SUBTITLE } , /* Subtitle/CC */
{ 0x0008 , KEY_VIDEO } , /* A/V */
{ 0x0007 , KEY_SLEEP } , /* Hibernate */
{ 0x0045 , KEY_ZOOM } , /* Zoom+ */
{ 0x0018 , KEY_RED } ,
{ 0x0053 , KEY_GREEN } ,
{ 0x005e , KEY_YELLOW } ,
{ 0x005f , KEY_BLUE }
2005-06-23 22:02:35 -07:00
} ;
2005-07-12 13:58:38 -07:00
static int vp7045_rc_query ( struct dvb_usb_device * d , u32 * event , int * state )
2005-06-23 22:02:35 -07:00
{
u8 key ;
int i ;
vp7045_usb_op ( d , RC_VAL_READ , NULL , 0 , & key , 1 , 20 ) ;
deb_rc ( " remote query key: %x %d \n " , key , key ) ;
if ( key = = 0x44 ) {
* state = REMOTE_NO_KEY_PRESSED ;
return 0 ;
}
2007-07-30 11:49:51 -03:00
for ( i = 0 ; i < ARRAY_SIZE ( vp7045_rc_keys ) ; i + + )
2009-08-29 15:19:31 -03:00
if ( rc5_data ( & vp7045_rc_keys [ i ] ) = = key ) {
2005-06-23 22:02:35 -07:00
* state = REMOTE_KEY_PRESSED ;
2005-07-12 13:58:38 -07:00
* event = vp7045_rc_keys [ i ] . event ;
2005-06-23 22:02:35 -07:00
break ;
}
return 0 ;
}
static int vp7045_read_eeprom ( struct dvb_usb_device * d , u8 * buf , int len , int offset )
{
int i = 0 ;
u8 v , br [ 2 ] ;
for ( i = 0 ; i < len ; i + + ) {
v = offset + i ;
vp7045_usb_op ( d , GET_EE_VALUE , & v , 1 , br , 2 , 5 ) ;
buf [ i ] = br [ 1 ] ;
}
deb_info ( " VP7045 EEPROM read (offs: %d, len: %d) : " , offset , i ) ;
debug_dump ( buf , i , deb_info ) ;
return 0 ;
}
static int vp7045_read_mac_addr ( struct dvb_usb_device * d , u8 mac [ 6 ] )
{
return vp7045_read_eeprom ( d , mac , 6 , MAC_0_ADDR ) ;
}
2006-09-30 06:53:48 -03:00
static int vp7045_frontend_attach ( struct dvb_usb_adapter * adap )
2005-06-23 22:02:35 -07:00
{
u8 buf [ 255 ] = { 0 } ;
2006-09-30 06:53:48 -03:00
vp7045_usb_op ( adap - > dev , VENDOR_STRING_READ , NULL , 0 , buf , 20 , 0 ) ;
2005-06-23 22:02:35 -07:00
buf [ 10 ] = ' \0 ' ;
deb_info ( " firmware says: %s " , buf ) ;
2006-09-30 06:53:48 -03:00
vp7045_usb_op ( adap - > dev , PRODUCT_STRING_READ , NULL , 0 , buf , 20 , 0 ) ;
2005-06-23 22:02:35 -07:00
buf [ 10 ] = ' \0 ' ;
deb_info ( " %s " , buf ) ;
2006-09-30 06:53:48 -03:00
vp7045_usb_op ( adap - > dev , FW_VERSION_READ , NULL , 0 , buf , 20 , 0 ) ;
2005-06-23 22:02:35 -07:00
buf [ 10 ] = ' \0 ' ;
deb_info ( " v%s \n " , buf ) ;
/* Dump the EEPROM */
/* vp7045_read_eeprom(d,buf, 255, FX2_ID_ADDR); */
2006-09-30 06:53:48 -03:00
adap - > fe = vp7045_fe_attach ( adap - > dev ) ;
2005-06-23 22:02:35 -07:00
return 0 ;
}
2006-09-30 06:53:48 -03:00
static struct dvb_usb_device_properties vp7045_properties ;
2005-06-23 22:02:35 -07:00
static int vp7045_usb_probe ( struct usb_interface * intf ,
const struct usb_device_id * id )
{
2008-04-09 19:13:13 -03:00
return dvb_usb_device_init ( intf , & vp7045_properties ,
THIS_MODULE , NULL , adapter_nr ) ;
2005-06-23 22:02:35 -07:00
}
static struct usb_device_id vp7045_usb_table [ ] = {
{ USB_DEVICE ( USB_VID_VISIONPLUS , USB_PID_TWINHAN_VP7045_COLD ) } ,
{ USB_DEVICE ( USB_VID_VISIONPLUS , USB_PID_TWINHAN_VP7045_WARM ) } ,
{ USB_DEVICE ( USB_VID_VISIONPLUS , USB_PID_DNTV_TINYUSB2_COLD ) } ,
{ USB_DEVICE ( USB_VID_VISIONPLUS , USB_PID_DNTV_TINYUSB2_WARM ) } ,
{ 0 } ,
} ;
MODULE_DEVICE_TABLE ( usb , vp7045_usb_table ) ;
2006-09-30 06:53:48 -03:00
static struct dvb_usb_device_properties vp7045_properties = {
2005-06-23 22:02:35 -07:00
. usb_ctrl = CYPRESS_FX2 ,
. firmware = " dvb-usb-vp7045-01.fw " ,
2006-09-30 06:53:48 -03:00
. num_adapters = 1 ,
. adapter = {
{
2006-10-13 11:34:46 -03:00
. frontend_attach = vp7045_frontend_attach ,
/* parameter for the MPEG2-data transfer */
2006-09-30 06:53:48 -03:00
. stream = {
. type = USB_BULK ,
2006-10-13 11:34:46 -03:00
. count = 7 ,
. endpoint = 0x02 ,
. u = {
. bulk = {
. buffersize = 4096 ,
}
}
} ,
2006-09-30 06:53:48 -03:00
}
} ,
. power_ctrl = vp7045_power_ctrl ,
. read_mac_address = vp7045_read_mac_addr ,
. rc_interval = 400 ,
. rc_key_map = vp7045_rc_keys ,
. rc_key_map_size = ARRAY_SIZE ( vp7045_rc_keys ) ,
. rc_query = vp7045_rc_query ,
2005-06-23 22:02:35 -07:00
. num_device_descs = 2 ,
. devices = {
{ . name = " Twinhan USB2.0 DVB-T receiver (TwinhanDTV Alpha/MagicBox II) " ,
. cold_ids = { & vp7045_usb_table [ 0 ] , NULL } ,
. warm_ids = { & vp7045_usb_table [ 1 ] , NULL } ,
} ,
{ . name = " DigitalNow TinyUSB 2 DVB-t Receiver " ,
. cold_ids = { & vp7045_usb_table [ 2 ] , NULL } ,
. warm_ids = { & vp7045_usb_table [ 3 ] , NULL } ,
} ,
2006-02-01 06:02:50 -05:00
{ NULL } ,
2005-06-23 22:02:35 -07:00
}
} ;
/* usb specific object needed to register this driver with the usb subsystem */
static struct usb_driver vp7045_usb_driver = {
2005-07-07 17:58:30 -07:00
. name = " dvb_usb_vp7045 " ,
2005-09-09 13:02:50 -07:00
. probe = vp7045_usb_probe ,
2005-06-23 22:02:35 -07:00
. disconnect = dvb_usb_device_exit ,
2005-09-09 13:02:50 -07:00
. id_table = vp7045_usb_table ,
2005-06-23 22:02:35 -07:00
} ;
/* module stuff */
static int __init vp7045_usb_module_init ( void )
{
int result ;
if ( ( result = usb_register ( & vp7045_usb_driver ) ) ) {
err ( " usb_register failed. (%d) " , result ) ;
return result ;
}
return 0 ;
}
static void __exit vp7045_usb_module_exit ( void )
{
/* deregister this driver from the USB subsystem */
usb_deregister ( & vp7045_usb_driver ) ;
}
module_init ( vp7045_usb_module_init ) ;
module_exit ( vp7045_usb_module_exit ) ;
MODULE_AUTHOR ( " Patrick Boettcher <patrick.boettcher@desy.de> " ) ;
MODULE_DESCRIPTION ( " Driver for Twinhan MagicBox/Alpha and DNTV tinyUSB2 DVB-T USB2.0 " ) ;
MODULE_VERSION ( " 1.0 " ) ;
MODULE_LICENSE ( " GPL " ) ;