2005-06-24 09:02:35 +04:00
/*
* DVB USB library - provides a generic interface for a DVB USB device driver .
*
* dvb - usb - init . c
*
2006-09-30 13:53:48 +04:00
* Copyright ( C ) 2004 - 6 Patrick Boettcher ( patrick . boettcher @ desy . de )
2005-06-24 09:02:35 +04: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 "dvb-usb-common.h"
/* debug */
int dvb_usb_debug ;
module_param_named ( debug , dvb_usb_debug , int , 0644 ) ;
2006-09-30 13:53:48 +04:00
MODULE_PARM_DESC ( debug , " set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64,mem=128,uxfer=256 (or-able)). " DVB_USB_DEBUG_STATUS ) ;
2005-06-24 09:02:35 +04:00
2005-07-08 04:58:11 +04:00
int dvb_usb_disable_rc_polling ;
module_param_named ( disable_rc_polling , dvb_usb_disable_rc_polling , int , 0644 ) ;
MODULE_PARM_DESC ( disable_rc_polling , " disable remote control polling (default: 0). " ) ;
2006-09-30 13:53:48 +04:00
static int dvb_usb_force_pid_filter_usage ;
module_param_named ( force_pid_filter_usage , dvb_usb_force_pid_filter_usage , int , 0444 ) ;
2007-08-19 01:02:31 +04:00
MODULE_PARM_DESC ( force_pid_filter_usage , " force all dvb-usb-devices to use a PID filter, if any (default: 0). " ) ;
2006-09-30 13:53:48 +04:00
2008-04-10 02:13:13 +04:00
static int dvb_usb_adapter_init ( struct dvb_usb_device * d , short * adapter_nrs )
2006-09-30 13:53:48 +04:00
{
struct dvb_usb_adapter * adap ;
int ret , n ;
for ( n = 0 ; n < d - > props . num_adapters ; n + + ) {
adap = & d - > adapter [ n ] ;
adap - > dev = d ;
adap - > id = n ;
memcpy ( & adap - > props , & d - > props . adapter [ n ] , sizeof ( struct dvb_usb_adapter_properties ) ) ;
/* speed - when running at FULL speed we need a HW PID filter */
if ( d - > udev - > speed = = USB_SPEED_FULL & & ! ( adap - > props . caps & DVB_USB_ADAP_HAS_PID_FILTER ) ) {
err ( " This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter) " ) ;
return - ENODEV ;
}
if ( ( d - > udev - > speed = = USB_SPEED_FULL & & adap - > props . caps & DVB_USB_ADAP_HAS_PID_FILTER ) | |
( adap - > props . caps & DVB_USB_ADAP_NEED_PID_FILTERING ) ) {
info ( " will use the device's hardware PID filter (table count: %d). " , adap - > props . pid_filter_count ) ;
adap - > pid_filtering = 1 ;
adap - > max_feed_count = adap - > props . pid_filter_count ;
} else {
info ( " will pass the complete MPEG2 transport stream to the software demuxer. " ) ;
adap - > pid_filtering = 0 ;
adap - > max_feed_count = 255 ;
}
if ( ! adap - > pid_filtering & &
dvb_usb_force_pid_filter_usage & &
adap - > props . caps & DVB_USB_ADAP_HAS_PID_FILTER ) {
info ( " pid filter enabled by module option. " ) ;
adap - > pid_filtering = 1 ;
adap - > max_feed_count = adap - > props . pid_filter_count ;
}
if ( adap - > props . size_of_priv > 0 ) {
adap - > priv = kzalloc ( adap - > props . size_of_priv , GFP_KERNEL ) ;
if ( adap - > priv = = NULL ) {
err ( " no memory for priv for adapter %d. " , n ) ;
return - ENOMEM ;
}
}
if ( ( ret = dvb_usb_adapter_stream_init ( adap ) ) | |
2008-04-10 02:13:13 +04:00
( ret = dvb_usb_adapter_dvb_init ( adap , adapter_nrs ) ) | |
2006-09-30 13:53:48 +04:00
( ret = dvb_usb_adapter_frontend_init ( adap ) ) ) {
return ret ;
}
d - > num_adapters_initialized + + ;
d - > state | = DVB_USB_STATE_DVB ;
}
/*
* when reloading the driver w / o replugging the device
* sometimes a timeout occures , this helps
*/
if ( d - > props . generic_bulk_ctrl_endpoint ! = 0 ) {
usb_clear_halt ( d - > udev , usb_sndbulkpipe ( d - > udev , d - > props . generic_bulk_ctrl_endpoint ) ) ;
usb_clear_halt ( d - > udev , usb_rcvbulkpipe ( d - > udev , d - > props . generic_bulk_ctrl_endpoint ) ) ;
}
return 0 ;
}
static int dvb_usb_adapter_exit ( struct dvb_usb_device * d )
{
int n ;
for ( n = 0 ; n < d - > num_adapters_initialized ; n + + ) {
dvb_usb_adapter_frontend_exit ( & d - > adapter [ n ] ) ;
dvb_usb_adapter_dvb_exit ( & d - > adapter [ n ] ) ;
dvb_usb_adapter_stream_exit ( & d - > adapter [ n ] ) ;
kfree ( d - > adapter [ n ] . priv ) ;
}
d - > num_adapters_initialized = 0 ;
d - > state & = ~ DVB_USB_STATE_DVB ;
return 0 ;
}
2005-06-24 09:02:35 +04:00
/* general initialization functions */
2005-12-01 11:51:53 +03:00
static int dvb_usb_exit ( struct dvb_usb_device * d )
2005-06-24 09:02:35 +04:00
{
deb_info ( " state before exiting everything: %x \n " , d - > state ) ;
dvb_usb_remote_exit ( d ) ;
2006-09-30 13:53:48 +04:00
dvb_usb_adapter_exit ( d ) ;
2005-06-24 09:02:35 +04:00
dvb_usb_i2c_exit ( d ) ;
deb_info ( " state should be zero now: %x \n " , d - > state ) ;
d - > state = DVB_USB_STATE_INIT ;
kfree ( d - > priv ) ;
kfree ( d ) ;
return 0 ;
}
2008-04-10 02:13:13 +04:00
static int dvb_usb_init ( struct dvb_usb_device * d , short * adapter_nums )
2005-06-24 09:02:35 +04:00
{
int ret = 0 ;
2006-02-07 11:49:14 +03:00
mutex_init ( & d - > usb_mutex ) ;
mutex_init ( & d - > i2c_mutex ) ;
2005-06-24 09:02:35 +04:00
d - > state = DVB_USB_STATE_INIT ;
2006-09-30 13:53:48 +04:00
if ( d - > props . size_of_priv > 0 ) {
d - > priv = kzalloc ( d - > props . size_of_priv , GFP_KERNEL ) ;
if ( d - > priv = = NULL ) {
err ( " no memory for priv in 'struct dvb_usb_device' " ) ;
return - ENOMEM ;
2006-09-20 13:06:11 +04:00
}
2005-06-24 09:02:35 +04:00
}
2006-09-30 13:53:48 +04:00
/* check the capabilities and set appropriate variables */
dvb_usb_device_power_ctrl ( d , 1 ) ;
2005-06-24 09:02:35 +04:00
2006-09-30 13:53:48 +04:00
if ( ( ret = dvb_usb_i2c_init ( d ) ) | |
2008-04-10 02:13:13 +04:00
( ret = dvb_usb_adapter_init ( d , adapter_nums ) ) ) {
2005-06-24 09:02:35 +04:00
dvb_usb_exit ( d ) ;
return ret ;
}
if ( ( ret = dvb_usb_remote_init ( d ) ) )
err ( " could not initialize remote control. " ) ;
2006-09-30 13:53:48 +04:00
dvb_usb_device_power_ctrl ( d , 0 ) ;
2005-06-24 09:02:35 +04:00
return 0 ;
}
/* determine the name and the state of the just found USB device */
2006-09-30 13:53:48 +04:00
static struct dvb_usb_device_description * dvb_usb_find_device ( struct usb_device * udev , struct dvb_usb_device_properties * props , int * cold )
2005-06-24 09:02:35 +04:00
{
int i , j ;
struct dvb_usb_device_description * desc = NULL ;
* cold = - 1 ;
for ( i = 0 ; i < props - > num_device_descs ; i + + ) {
for ( j = 0 ; j < DVB_USB_ID_MAX_NUM & & props - > devices [ i ] . cold_ids [ j ] ! = NULL ; j + + ) {
deb_info ( " check for cold %x %x \n " , props - > devices [ i ] . cold_ids [ j ] - > idVendor , props - > devices [ i ] . cold_ids [ j ] - > idProduct ) ;
if ( props - > devices [ i ] . cold_ids [ j ] - > idVendor = = le16_to_cpu ( udev - > descriptor . idVendor ) & &
props - > devices [ i ] . cold_ids [ j ] - > idProduct = = le16_to_cpu ( udev - > descriptor . idProduct ) ) {
* cold = 1 ;
desc = & props - > devices [ i ] ;
break ;
}
}
if ( desc ! = NULL )
break ;
for ( j = 0 ; j < DVB_USB_ID_MAX_NUM & & props - > devices [ i ] . warm_ids [ j ] ! = NULL ; j + + ) {
deb_info ( " check for warm %x %x \n " , props - > devices [ i ] . warm_ids [ j ] - > idVendor , props - > devices [ i ] . warm_ids [ j ] - > idProduct ) ;
if ( props - > devices [ i ] . warm_ids [ j ] - > idVendor = = le16_to_cpu ( udev - > descriptor . idVendor ) & &
props - > devices [ i ] . warm_ids [ j ] - > idProduct = = le16_to_cpu ( udev - > descriptor . idProduct ) ) {
* cold = 0 ;
desc = & props - > devices [ i ] ;
break ;
}
}
}
if ( desc ! = NULL & & props - > identify_state ! = NULL )
props - > identify_state ( udev , props , & desc , cold ) ;
return desc ;
}
2006-09-30 13:53:48 +04:00
int dvb_usb_device_power_ctrl ( struct dvb_usb_device * d , int onoff )
{
2006-09-20 13:06:11 +04:00
if ( onoff )
d - > powered + + ;
else
d - > powered - - ;
if ( d - > powered = = 0 | | ( onoff & & d - > powered = = 1 ) ) { // when switching from 1 to 0 or from 0 to 1
deb_info ( " power control: %d \n " , onoff ) ;
2006-09-30 13:53:48 +04:00
if ( d - > props . power_ctrl )
return d - > props . power_ctrl ( d , onoff ) ;
}
return 0 ;
}
2005-06-24 09:02:35 +04:00
/*
* USB
*/
2008-04-10 02:13:13 +04:00
int dvb_usb_device_init ( struct usb_interface * intf ,
struct dvb_usb_device_properties * props ,
struct module * owner , struct dvb_usb_device * * du ,
short * adapter_nums )
2005-06-24 09:02:35 +04:00
{
struct usb_device * udev = interface_to_usbdev ( intf ) ;
struct dvb_usb_device * d = NULL ;
struct dvb_usb_device_description * desc = NULL ;
int ret = - ENOMEM , cold = 0 ;
2006-01-09 20:25:33 +03:00
if ( du ! = NULL )
* du = NULL ;
2005-06-24 09:02:35 +04:00
if ( ( desc = dvb_usb_find_device ( udev , props , & cold ) ) = = NULL ) {
deb_err ( " something went very wrong, device was not found in current device list - let's see what comes next. \n " ) ;
return - ENODEV ;
}
if ( cold ) {
info ( " found a '%s' in cold state, will try to load a firmware " , desc - > name ) ;
2006-01-09 20:25:04 +03:00
ret = dvb_usb_download_firmware ( udev , props ) ;
2006-09-19 19:51:46 +04:00
if ( ! props - > no_reconnect | | ret ! = 0 )
2005-06-24 09:02:35 +04:00
return ret ;
2006-01-09 20:25:04 +03:00
}
info ( " found a '%s' in warm state. " , desc - > name ) ;
2006-01-12 00:40:56 +03:00
d = kzalloc ( sizeof ( struct dvb_usb_device ) , GFP_KERNEL ) ;
2006-01-09 20:25:04 +03:00
if ( d = = NULL ) {
err ( " no memory for 'struct dvb_usb_device' " ) ;
return ret ;
}
d - > udev = udev ;
2006-09-30 13:53:48 +04:00
memcpy ( & d - > props , props , sizeof ( struct dvb_usb_device_properties ) ) ;
2006-01-09 20:25:04 +03:00
d - > desc = desc ;
d - > owner = owner ;
usb_set_intfdata ( intf , d ) ;
2005-06-24 09:02:35 +04:00
2006-01-09 20:25:04 +03:00
if ( du ! = NULL )
* du = d ;
2005-09-10 00:02:47 +04:00
2008-04-10 02:13:13 +04:00
ret = dvb_usb_init ( d , adapter_nums ) ;
2005-06-24 09:02:35 +04:00
if ( ret = = 0 )
info ( " %s successfully initialized and connected. " , desc - > name ) ;
else
info ( " %s error while loading driver (%d) " , desc - > name , ret ) ;
return ret ;
}
EXPORT_SYMBOL ( dvb_usb_device_init ) ;
void dvb_usb_device_exit ( struct usb_interface * intf )
{
struct dvb_usb_device * d = usb_get_intfdata ( intf ) ;
const char * name = " generic DVB-USB module " ;
usb_set_intfdata ( intf , NULL ) ;
if ( d ! = NULL & & d - > desc ! = NULL ) {
name = d - > desc - > name ;
dvb_usb_exit ( d ) ;
}
info ( " %s successfully deinitialized and disconnected. " , name ) ;
}
EXPORT_SYMBOL ( dvb_usb_device_exit ) ;
2006-09-30 13:53:48 +04:00
MODULE_VERSION ( " 1.0 " ) ;
2005-06-24 09:02:35 +04:00
MODULE_AUTHOR ( " Patrick Boettcher <patrick.boettcher@desy.de> " ) ;
MODULE_DESCRIPTION ( " A library module containing commonly used USB and DVB function USB DVB devices " ) ;
MODULE_LICENSE ( " GPL " ) ;