2006-09-24 03:00:41 +04:00
/* DVB USB compliant linux driver for MSI Mega Sky 580 DVB-T USB2.0 receiver
*
* Copyright ( C ) 2006 Aapo Tahkola ( aet @ rasterburn . 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
*/
2006-09-24 03:01:29 +04:00
2006-09-24 03:00:42 +04:00
# include "m920x.h"
2006-09-24 03:00:41 +04:00
# include "mt352.h"
# include "mt352_priv.h"
2006-09-24 03:40:20 +04:00
# include "qt1010.h"
2006-09-24 03:00:41 +04:00
/* debug */
2006-09-28 08:46:49 +04:00
static int dvb_usb_m920x_debug ;
2006-09-24 03:01:29 +04:00
module_param_named ( debug , dvb_usb_m920x_debug , int , 0644 ) ;
2006-09-24 03:00:41 +04:00
MODULE_PARM_DESC ( debug , " set debugging level (1=rc (or-able)). " DVB_USB_DEBUG_STATUS ) ;
static struct dvb_usb_rc_key megasky_rc_keys [ ] = {
{ 0x0 , 0x12 , KEY_POWER } ,
{ 0x0 , 0x1e , KEY_CYCLEWINDOWS } , /* min/max */
{ 0x0 , 0x02 , KEY_CHANNELUP } ,
{ 0x0 , 0x05 , KEY_CHANNELDOWN } ,
{ 0x0 , 0x03 , KEY_VOLUMEUP } ,
{ 0x0 , 0x06 , KEY_VOLUMEDOWN } ,
{ 0x0 , 0x04 , KEY_MUTE } ,
{ 0x0 , 0x07 , KEY_OK } , /* TS */
{ 0x0 , 0x08 , KEY_STOP } ,
{ 0x0 , 0x09 , KEY_MENU } , /* swap */
{ 0x0 , 0x0a , KEY_REWIND } ,
{ 0x0 , 0x1b , KEY_PAUSE } ,
{ 0x0 , 0x1f , KEY_FASTFORWARD } ,
{ 0x0 , 0x0c , KEY_RECORD } ,
{ 0x0 , 0x0d , KEY_CAMERA } , /* screenshot */
{ 0x0 , 0x0e , KEY_COFFEE } , /* "MTS" */
} ;
2007-01-21 21:57:48 +03:00
static inline int m9206_read ( struct usb_device * udev , u8 request , u16 value , \
u16 index , void * data , int size )
2006-09-24 03:00:41 +04:00
{
int ret ;
ret = usb_control_msg ( udev , usb_rcvctrlpipe ( udev , 0 ) ,
request , USB_TYPE_VENDOR | USB_DIR_IN ,
value , index , data , size , 2000 ) ;
2007-03-15 19:24:29 +03:00
if ( ret < 0 ) {
printk ( KERN_INFO " m920x_read = error: %d \n " , ret ) ;
2006-09-24 03:00:41 +04:00
return ret ;
2007-03-15 19:24:29 +03:00
}
2006-09-24 03:00:41 +04:00
2007-03-15 19:24:29 +03:00
if ( ret ! = size ) {
deb_rc ( " m920x_read = no data \n " ) ;
2006-09-24 03:00:41 +04:00
return - EIO ;
2007-03-15 19:24:29 +03:00
}
2006-09-24 03:00:41 +04:00
return 0 ;
}
2007-01-21 21:57:48 +03:00
static inline int m9206_write ( struct usb_device * udev , u8 request ,
u16 value , u16 index )
2006-09-24 03:00:41 +04:00
{
int ret ;
ret = usb_control_msg ( udev , usb_sndctrlpipe ( udev , 0 ) ,
request , USB_TYPE_VENDOR | USB_DIR_OUT ,
value , index , NULL , 0 , 2000 ) ;
2007-03-15 19:24:29 +03:00
2006-09-28 07:47:51 +04:00
return ret ;
}
2007-03-06 00:54:27 +03:00
static int m9206_init ( struct dvb_usb_device * d )
2006-09-28 07:47:51 +04:00
{
int ret = 0 ;
/* Remote controller init. */
2007-03-06 00:54:27 +03:00
if ( d - > props . rc_query ) {
if ( ( ret = m9206_write ( d - > udev , M9206_CORE , 0xa8 , M9206_RC_INIT2 ) ) ! = 0 )
return ret ;
2006-09-28 07:47:51 +04:00
2007-03-06 00:54:27 +03:00
if ( ( ret = m9206_write ( d - > udev , M9206_CORE , 0x51 , M9206_RC_INIT1 ) ) ! = 0 )
return ret ;
}
2006-09-24 03:00:41 +04:00
return ret ;
}
static int m9206_rc_query ( struct dvb_usb_device * d , u32 * event , int * state )
{
2006-09-28 07:47:51 +04:00
struct m9206_state * m = d - > priv ;
2006-09-24 03:00:41 +04:00
int i , ret = 0 ;
u8 rc_state [ 2 ] ;
2006-09-28 07:47:51 +04:00
if ( ( ret = m9206_read ( d - > udev , M9206_CORE , 0x0 , M9206_RC_STATE , rc_state , 1 ) ) ! = 0 )
2006-09-24 03:00:41 +04:00
goto unlock ;
2006-09-28 07:47:51 +04:00
if ( ( ret = m9206_read ( d - > udev , M9206_CORE , 0x0 , M9206_RC_KEY , rc_state + 1 , 1 ) ) ! = 0 )
2006-09-24 03:00:41 +04:00
goto unlock ;
2007-03-06 00:54:27 +03:00
for ( i = 0 ; i < d - > props . rc_key_map_size ; i + + )
if ( d - > props . rc_key_map [ i ] . data = = rc_state [ 1 ] ) {
* event = d - > props . rc_key_map [ i ] . event ;
2006-09-24 03:00:41 +04:00
switch ( rc_state [ 0 ] ) {
case 0x80 :
* state = REMOTE_NO_KEY_PRESSED ;
goto unlock ;
case 0x93 :
case 0x92 :
2006-09-28 07:47:51 +04:00
m - > rep_count = 0 ;
2006-09-24 03:00:41 +04:00
* state = REMOTE_KEY_PRESSED ;
goto unlock ;
case 0x91 :
2006-09-28 07:47:51 +04:00
/* For comfort. */
if ( + + m - > rep_count > 2 )
* state = REMOTE_KEY_REPEAT ;
2006-09-24 03:00:41 +04:00
goto unlock ;
default :
deb_rc ( " Unexpected rc response %x \n " , rc_state [ 0 ] ) ;
* state = REMOTE_NO_KEY_PRESSED ;
goto unlock ;
}
}
if ( rc_state [ 1 ] ! = 0 )
deb_rc ( " Unknown rc key %x \n " , rc_state [ 1 ] ) ;
* state = REMOTE_NO_KEY_PRESSED ;
unlock :
return ret ;
}
/* I2C */
2007-01-21 21:57:48 +03:00
static int m9206_i2c_xfer ( struct i2c_adapter * adap , struct i2c_msg msg [ ] ,
int num )
2006-09-24 03:00:41 +04:00
{
struct dvb_usb_device * d = i2c_get_adapdata ( adap ) ;
2007-03-06 00:23:19 +03:00
int i , j ;
2006-09-24 03:00:41 +04:00
int ret = 0 ;
2007-03-06 05:55:00 +03:00
if ( ! num )
return - EINVAL ;
2006-09-24 03:00:41 +04:00
if ( mutex_lock_interruptible ( & d - > i2c_mutex ) < 0 )
return - EAGAIN ;
for ( i = 0 ; i < num ; i + + ) {
2007-03-12 18:13:12 +03:00
if ( msg [ i ] . flags & ( I2C_M_NO_RD_ACK | I2C_M_IGNORE_NAK | I2C_M_TEN ) | |
msg [ i ] . len = = 0 ) {
/* For a 0 byte message, I think sending the address to index 0x80|0x40
* would be the correct thing to do . However , zero byte messages are
* only used for probing , and since we don ' t know how to get the slave ' s
* ack , we can ' t probe . */
2007-03-06 05:55:00 +03:00
ret = - ENOTSUPP ;
goto unlock ;
}
/* Send START & address/RW bit */
if ( ! ( msg [ i ] . flags & I2C_M_NOSTART ) ) {
2007-03-12 18:13:12 +03:00
if ( ( ret = m9206_write ( d - > udev , M9206_I2C , ( msg [ i ] . addr < < 1 ) | ( msg [ i ] . flags & I2C_M_RD ? 0x01 : 0 ) , 0x80 ) ) ! = 0 )
2007-01-21 21:57:20 +03:00
goto unlock ;
2007-03-06 05:55:00 +03:00
/* Should check for ack here, if we knew how. */
}
if ( msg [ i ] . flags & I2C_M_RD ) {
for ( j = 0 ; j < msg [ i ] . len ; j + + ) {
/* Last byte of transaction? Send STOP, otherwise send ACK. */
int stop = ( i + 1 = = num & & j + 1 = = msg [ i ] . len ) ? 0x40 : 0x01 ;
if ( ( ret = m9206_read ( d - > udev , M9206_I2C , 0x0 , 0x20 | stop , & msg [ i ] . buf [ j ] , 1 ) ) ! = 0 )
goto unlock ;
2007-01-21 21:57:20 +03:00
}
2007-03-06 00:23:19 +03:00
} else {
2007-03-06 05:55:00 +03:00
for ( j = 0 ; j < msg [ i ] . len ; j + + ) {
/* Last byte of transaction? Then send STOP. */
int stop = ( i + 1 = = num & & j + 1 = = msg [ i ] . len ) ? 0x40 : 0x00 ;
if ( ( ret = m9206_write ( d - > udev , M9206_I2C , msg [ i ] . buf [ j ] , stop ) ) ! = 0 )
goto unlock ;
/* Should check for ack here too. */
2007-03-06 00:23:19 +03:00
}
2006-09-24 03:00:41 +04:00
}
}
2007-03-06 00:23:19 +03:00
ret = num ;
2007-03-06 05:55:00 +03:00
unlock :
2006-09-24 03:00:41 +04:00
mutex_unlock ( & d - > i2c_mutex ) ;
return ret ;
}
static u32 m9206_i2c_func ( struct i2c_adapter * adapter )
{
return I2C_FUNC_I2C ;
}
static struct i2c_algorithm m9206_i2c_algo = {
. master_xfer = m9206_i2c_xfer ,
. functionality = m9206_i2c_func ,
} ;
2007-01-21 21:57:48 +03:00
static int m9206_set_filter ( struct dvb_usb_adapter * adap , int type , int idx ,
int pid )
2006-09-24 03:00:41 +04:00
{
int ret = 0 ;
if ( pid > = 0x8000 )
return - EINVAL ;
pid | = 0x8000 ;
2006-09-28 07:47:51 +04:00
if ( ( ret = m9206_write ( adap - > dev - > udev , M9206_FILTER , pid , ( type < < 8 ) | ( idx * 4 ) ) ) ! = 0 )
2006-09-24 03:00:41 +04:00
return ret ;
2006-09-28 07:47:51 +04:00
if ( ( ret = m9206_write ( adap - > dev - > udev , M9206_FILTER , 0 , ( type < < 8 ) | ( idx * 4 ) ) ) ! = 0 )
2006-09-24 03:00:41 +04:00
return ret ;
return ret ;
}
2006-09-28 07:47:51 +04:00
static int m9206_update_filters ( struct dvb_usb_adapter * adap )
2006-09-24 03:00:41 +04:00
{
2006-09-28 07:47:51 +04:00
struct m9206_state * m = adap - > dev - > priv ;
int enabled = m - > filtering_enabled ;
int i , ret = 0 , filter = 0 ;
2006-09-24 03:00:41 +04:00
2006-09-28 07:47:51 +04:00
for ( i = 0 ; i < M9206_MAX_FILTERS ; i + + )
if ( m - > filters [ i ] = = 8192 )
enabled = 0 ;
2006-09-24 03:00:41 +04:00
2006-09-28 07:47:51 +04:00
/* Disable all filters */
2006-09-28 08:46:49 +04:00
if ( ( ret = m9206_set_filter ( adap , 0x81 , 1 , enabled ) ) ! = 0 )
2006-09-28 07:47:51 +04:00
return ret ;
2006-09-24 03:00:41 +04:00
2006-09-28 07:47:51 +04:00
for ( i = 0 ; i < M9206_MAX_FILTERS ; i + + )
2006-09-28 08:46:49 +04:00
if ( ( ret = m9206_set_filter ( adap , 0x81 , i + 2 , 0 ) ) ! = 0 )
2006-09-28 07:47:51 +04:00
return ret ;
2006-09-28 08:46:49 +04:00
if ( ( ret = m9206_set_filter ( adap , 0x82 , 0 , 0x0 ) ) ! = 0 )
2006-09-28 07:47:51 +04:00
return ret ;
/* Set */
if ( enabled ) {
for ( i = 0 ; i < M9206_MAX_FILTERS ; i + + ) {
if ( m - > filters [ i ] = = 0 )
continue ;
2006-09-28 08:46:49 +04:00
if ( ( ret = m9206_set_filter ( adap , 0x81 , filter + 2 , m - > filters [ i ] ) ) ! = 0 )
2006-09-28 07:47:51 +04:00
return ret ;
filter + + ;
}
2006-09-24 03:00:41 +04:00
}
2006-09-28 07:47:51 +04:00
2006-09-28 08:46:49 +04:00
if ( ( ret = m9206_set_filter ( adap , 0x82 , 0 , 0x02f5 ) ) ! = 0 )
2006-09-28 07:47:51 +04:00
return ret ;
2006-09-24 03:00:41 +04:00
return ret ;
}
2006-09-28 07:47:51 +04:00
static int m9206_pid_filter_ctrl ( struct dvb_usb_adapter * adap , int onoff )
2006-09-24 03:00:41 +04:00
{
2006-09-28 07:47:51 +04:00
struct m9206_state * m = adap - > dev - > priv ;
2006-09-24 03:00:41 +04:00
2006-09-28 07:47:51 +04:00
m - > filtering_enabled = onoff ? 1 : 0 ;
2006-09-24 03:00:41 +04:00
2006-09-28 07:47:51 +04:00
return m9206_update_filters ( adap ) ;
}
2006-09-24 03:00:41 +04:00
2007-01-21 21:57:48 +03:00
static int m9206_pid_filter ( struct dvb_usb_adapter * adap , int index , u16 pid ,
int onoff )
2006-09-28 07:47:51 +04:00
{
struct m9206_state * m = adap - > dev - > priv ;
2006-09-24 03:00:41 +04:00
2006-09-28 07:47:51 +04:00
m - > filters [ index ] = onoff ? pid : 0 ;
2006-09-24 03:00:41 +04:00
2006-09-28 07:47:51 +04:00
return m9206_update_filters ( adap ) ;
2006-09-24 03:00:41 +04:00
}
2007-01-21 21:57:48 +03:00
static int m9206_firmware_download ( struct usb_device * udev ,
const struct firmware * fw )
2006-09-24 03:00:41 +04:00
{
u16 value , index , size ;
u8 read [ 4 ] , * buff ;
int i , pass , ret = 0 ;
buff = kmalloc ( 65536 , GFP_KERNEL ) ;
2006-09-28 07:47:51 +04:00
if ( ( ret = m9206_read ( udev , M9206_FILTER , 0x0 , 0x8000 , read , 4 ) ) ! = 0 )
2006-09-24 03:00:41 +04:00
goto done ;
deb_rc ( " %x %x %x %x \n " , read [ 0 ] , read [ 1 ] , read [ 2 ] , read [ 3 ] ) ;
2006-09-28 07:47:51 +04:00
if ( ( ret = m9206_read ( udev , M9206_FW , 0x0 , 0x0 , read , 1 ) ) ! = 0 )
2006-09-24 03:00:41 +04:00
goto done ;
deb_rc ( " %x \n " , read [ 0 ] ) ;
for ( pass = 0 ; pass < 2 ; pass + + ) {
for ( i = 0 ; i + ( sizeof ( u16 ) * 3 ) < fw - > size ; ) {
value = le16_to_cpu ( * ( u16 * ) ( fw - > data + i ) ) ;
i + = sizeof ( u16 ) ;
index = le16_to_cpu ( * ( u16 * ) ( fw - > data + i ) ) ;
i + = sizeof ( u16 ) ;
size = le16_to_cpu ( * ( u16 * ) ( fw - > data + i ) ) ;
i + = sizeof ( u16 ) ;
if ( pass = = 1 ) {
/* Will stall if using fw->data ... */
memcpy ( buff , fw - > data + i , size ) ;
ret = usb_control_msg ( udev , usb_sndctrlpipe ( udev , 0 ) ,
2006-09-28 07:47:51 +04:00
M9206_FW ,
USB_TYPE_VENDOR | USB_DIR_OUT ,
2006-09-24 03:00:41 +04:00
value , index , buff , size , 20 ) ;
if ( ret ! = size ) {
deb_rc ( " error while uploading fw! \n " ) ;
ret = - EIO ;
goto done ;
}
msleep ( 3 ) ;
}
i + = size ;
}
if ( i ! = fw - > size ) {
2007-03-15 19:24:29 +03:00
deb_rc ( " bad firmware file! \n " ) ;
2006-09-24 03:00:41 +04:00
ret = - EINVAL ;
goto done ;
}
}
msleep ( 36 ) ;
/* m9206 will disconnect itself from the bus after this. */
2006-09-28 07:47:51 +04:00
( void ) m9206_write ( udev , M9206_CORE , 0x01 , M9206_FW_GO ) ;
2006-09-24 03:00:41 +04:00
deb_rc ( " firmware uploaded! \n " ) ;
done :
kfree ( buff ) ;
return ret ;
}
2007-01-23 21:00:42 +03:00
/* Callbacks for DVB USB */
2007-03-15 19:01:46 +03:00
static int m920x_identify_state ( struct usb_device * udev ,
struct dvb_usb_device_properties * props ,
struct dvb_usb_device_description * * desc ,
int * cold )
2007-01-23 21:00:42 +03:00
{
struct usb_host_interface * alt ;
alt = usb_altnum_to_altsetting ( usb_ifnum_to_if ( udev , 0 ) , 1 ) ;
* cold = ( alt = = NULL ) ? 1 : 0 ;
return 0 ;
}
static int megasky_mt352_demod_init ( struct dvb_frontend * fe )
{
u8 config [ ] = { CONFIG , 0x3d } ;
u8 clock [ ] = { CLOCK_CTL , 0x30 } ;
u8 reset [ ] = { RESET , 0x80 } ;
u8 adc_ctl [ ] = { ADC_CTL_1 , 0x40 } ;
u8 agc [ ] = { AGC_TARGET , 0x1c , 0x20 } ;
u8 sec_agc [ ] = { 0x69 , 0x00 , 0xff , 0xff , 0x40 , 0xff , 0x00 , 0x40 , 0x40 } ;
u8 unk1 [ ] = { 0x93 , 0x1a } ;
u8 unk2 [ ] = { 0xb5 , 0x7a } ;
mt352_write ( fe , config , ARRAY_SIZE ( config ) ) ;
mt352_write ( fe , clock , ARRAY_SIZE ( clock ) ) ;
mt352_write ( fe , reset , ARRAY_SIZE ( reset ) ) ;
mt352_write ( fe , adc_ctl , ARRAY_SIZE ( adc_ctl ) ) ;
mt352_write ( fe , agc , ARRAY_SIZE ( agc ) ) ;
mt352_write ( fe , sec_agc , ARRAY_SIZE ( sec_agc ) ) ;
mt352_write ( fe , unk1 , ARRAY_SIZE ( unk1 ) ) ;
mt352_write ( fe , unk2 , ARRAY_SIZE ( unk2 ) ) ;
deb_rc ( " Demod init! \n " ) ;
return 0 ;
}
static struct mt352_config megasky_mt352_config = {
2007-03-06 00:23:19 +03:00
. demod_address = 0x0f ,
2007-01-23 21:00:42 +03:00
. no_tuner = 1 ,
. demod_init = megasky_mt352_demod_init ,
} ;
static int megasky_mt352_frontend_attach ( struct dvb_usb_adapter * adap )
{
deb_rc ( " megasky_frontend_attach! \n " ) ;
if ( ( adap - > fe = dvb_attach ( mt352_attach , & megasky_mt352_config , & adap - > dev - > i2c_adap ) ) = = NULL )
return - EIO ;
return 0 ;
}
2007-01-21 21:56:10 +03:00
static struct qt1010_config megasky_qt1010_config = {
2007-03-06 00:23:19 +03:00
. i2c_address = 0x62
2007-01-21 21:56:10 +03:00
} ;
2007-01-23 21:00:42 +03:00
static int megasky_qt1010_tuner_attach ( struct dvb_usb_adapter * adap )
2007-01-21 21:56:10 +03:00
{
2007-01-21 21:57:20 +03:00
if ( dvb_attach ( qt1010_attach , adap - > fe , & adap - > dev - > i2c_adap ,
& megasky_qt1010_config ) = = NULL )
return - ENODEV ;
return 0 ;
2007-01-21 21:56:10 +03:00
}
2006-09-28 08:46:49 +04:00
/* DVB USB Driver stuff */
static struct dvb_usb_device_properties megasky_properties ;
2007-01-21 21:57:48 +03:00
static int m920x_probe ( struct usb_interface * intf ,
const struct usb_device_id * id )
2006-09-28 08:46:49 +04:00
{
struct dvb_usb_device * d ;
struct usb_host_interface * alt ;
int ret ;
2007-03-06 00:54:27 +03:00
deb_rc ( " Probed! \n " ) ;
2006-09-28 08:46:49 +04:00
2007-03-06 00:54:27 +03:00
if ( ( ret = dvb_usb_device_init ( intf , & megasky_properties , THIS_MODULE , & d ) ) = = 0 )
goto found ;
2006-09-28 08:46:49 +04:00
2007-03-06 00:54:27 +03:00
return ret ;
2006-09-28 08:46:49 +04:00
2007-03-06 00:54:27 +03:00
found :
alt = usb_altnum_to_altsetting ( intf , 1 ) ;
if ( alt = = NULL ) {
deb_rc ( " No alt found! \n " ) ;
return - ENODEV ;
2006-09-28 08:46:49 +04:00
}
2007-03-06 00:54:27 +03:00
ret = usb_set_interface ( d - > udev , alt - > desc . bInterfaceNumber ,
alt - > desc . bAlternateSetting ) ;
if ( ret < 0 )
return ret ;
if ( ( ret = m9206_init ( d ) ) ! = 0 )
return ret ;
2006-09-28 08:46:49 +04:00
return ret ;
}
static struct usb_device_id m920x_table [ ] = {
{ USB_DEVICE ( USB_VID_MSI , USB_PID_MSI_MEGASKY580 ) } ,
{ } /* Terminating entry */
} ;
MODULE_DEVICE_TABLE ( usb , m920x_table ) ;
2006-09-24 03:01:29 +04:00
static struct dvb_usb_device_properties megasky_properties = {
2007-01-23 21:34:10 +03:00
. caps = DVB_USB_IS_AN_I2C_ADAPTER ,
2006-10-07 22:03:04 +04:00
2006-09-24 03:00:41 +04:00
. usb_ctrl = DEVICE_SPECIFIC ,
. firmware = " dvb-usb-megasky-02.fw " ,
. download_firmware = m9206_firmware_download ,
2006-09-28 07:47:51 +04:00
. rc_interval = 100 ,
2006-09-24 03:00:41 +04:00
. rc_key_map = megasky_rc_keys ,
. rc_key_map_size = ARRAY_SIZE ( megasky_rc_keys ) ,
. rc_query = m9206_rc_query ,
2006-09-28 07:47:51 +04:00
. size_of_priv = sizeof ( struct m9206_state ) ,
2006-09-24 03:00:41 +04:00
2007-03-15 19:01:46 +03:00
. identify_state = m920x_identify_state ,
2006-09-24 03:01:29 +04:00
. num_adapters = 1 ,
. adapter = { {
2007-01-23 21:34:10 +03:00
. caps = DVB_USB_ADAP_HAS_PID_FILTER |
DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF ,
2006-09-24 03:01:29 +04:00
. pid_filter_count = 8 ,
. pid_filter = m9206_pid_filter ,
. pid_filter_ctrl = m9206_pid_filter_ctrl ,
2007-01-23 21:00:42 +03:00
. frontend_attach = megasky_mt352_frontend_attach ,
. tuner_attach = megasky_qt1010_tuner_attach ,
2006-09-24 03:01:29 +04:00
. stream = {
. type = USB_BULK ,
. count = 8 ,
. endpoint = 0x81 ,
. u = {
. bulk = {
. buffersize = 512 ,
}
}
} ,
} } ,
2006-09-24 03:00:41 +04:00
. i2c_algo = & m9206_i2c_algo ,
. num_device_descs = 1 ,
. devices = {
{ " MSI Mega Sky 580 DVB-T USB2.0 " ,
2006-09-24 03:01:29 +04:00
{ & m920x_table [ 0 ] , NULL } ,
2006-09-24 03:00:41 +04:00
{ NULL } ,
} ,
}
} ;
2006-09-24 03:01:29 +04:00
static struct usb_driver m920x_driver = {
. name = " dvb_usb_m920x " ,
2006-09-24 03:13:12 +04:00
. probe = m920x_probe ,
2006-09-24 03:00:41 +04:00
. disconnect = dvb_usb_device_exit ,
2006-09-24 03:01:29 +04:00
. id_table = m920x_table ,
2006-09-24 03:00:41 +04:00
} ;
/* module stuff */
2006-09-24 03:01:29 +04:00
static int __init m920x_module_init ( void )
2006-09-24 03:00:41 +04:00
{
int ret ;
2006-09-24 03:01:29 +04:00
if ( ( ret = usb_register ( & m920x_driver ) ) ) {
2006-09-24 03:00:41 +04:00
err ( " usb_register failed. Error number %d " , ret ) ;
return ret ;
}
return 0 ;
}
2006-09-24 03:01:29 +04:00
static void __exit m920x_module_exit ( void )
2006-09-24 03:00:41 +04:00
{
/* deregister this driver from the USB subsystem */
2006-09-24 03:01:29 +04:00
usb_deregister ( & m920x_driver ) ;
2006-09-24 03:00:41 +04:00
}
2006-09-24 03:01:29 +04:00
module_init ( m920x_module_init ) ;
module_exit ( m920x_module_exit ) ;
2006-09-24 03:00:41 +04:00
MODULE_AUTHOR ( " Aapo Tahkola <aet@rasterburn.org> " ) ;
2006-09-24 03:01:29 +04:00
MODULE_DESCRIPTION ( " Driver MSI Mega Sky 580 DVB-T USB2.0 / Uli m920x " ) ;
2006-09-24 03:00:41 +04:00
MODULE_VERSION ( " 0.1 " ) ;
MODULE_LICENSE ( " GPL " ) ;