2019-05-31 11:09:32 +03:00
// SPDX-License-Identifier: GPL-2.0-only
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
*
2016-01-24 17:56:58 +03:00
* Copyright ( C ) 2004 - 6 Patrick Boettcher ( patrick . boettcher @ posteo . de )
2005-06-24 09:02:35 +04:00
*
2020-03-04 17:54:10 +03:00
* see Documentation / driver - api / media / drivers / dvb - usb . rst for more information
2005-06-24 09:02:35 +04:00
*/
# include "dvb-usb-common.h"
/* debug */
int dvb_usb_debug ;
2010-07-01 08:50:04 +04:00
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 ;
2011-09-06 16:31:57 +04:00
int ret , n , o ;
2006-09-30 13:53:48 +04:00
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 ) ) ;
2012-12-11 00:37:09 +04:00
for ( o = 0 ; o < adap - > props . num_frontends ; o + + ) {
struct dvb_usb_adapter_fe_properties * props = & adap - > props . fe [ o ] ;
/* speed - when running at FULL speed we need a HW PID filter */
if ( d - > udev - > speed = = USB_SPEED_FULL & & ! ( 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 ;
}
2006-09-30 13:53:48 +04:00
2012-12-11 00:37:09 +04:00
if ( ( d - > udev - > speed = = USB_SPEED_FULL & & props - > caps & DVB_USB_ADAP_HAS_PID_FILTER ) | |
( props - > caps & DVB_USB_ADAP_NEED_PID_FILTERING ) ) {
info ( " will use the device's hardware PID filter (table count: %d). " , props - > pid_filter_count ) ;
adap - > fe_adap [ o ] . pid_filtering = 1 ;
adap - > fe_adap [ o ] . max_feed_count = props - > pid_filter_count ;
} else {
info ( " will pass the complete MPEG2 transport stream to the software demuxer. " ) ;
adap - > fe_adap [ o ] . pid_filtering = 0 ;
adap - > fe_adap [ o ] . max_feed_count = 255 ;
}
2006-09-30 13:53:48 +04:00
2012-12-11 00:37:09 +04:00
if ( ! adap - > fe_adap [ o ] . pid_filtering & &
dvb_usb_force_pid_filter_usage & &
props - > caps & DVB_USB_ADAP_HAS_PID_FILTER ) {
info ( " pid filter enabled by module option. " ) ;
adap - > fe_adap [ o ] . pid_filtering = 1 ;
adap - > fe_adap [ o ] . max_feed_count = props - > pid_filter_count ;
}
2006-09-30 13:53:48 +04:00
2012-12-11 00:37:09 +04:00
if ( props - > size_of_priv > 0 ) {
adap - > fe_adap [ o ] . priv = kzalloc ( props - > size_of_priv , GFP_KERNEL ) ;
if ( adap - > fe_adap [ o ] . priv = = NULL ) {
err ( " no memory for priv for adapter %d fe %d. " , n , o ) ;
return - ENOMEM ;
}
2011-09-06 16:31:57 +04:00
}
}
2006-09-30 13:53:48 +04:00
if ( adap - > props . size_of_priv > 0 ) {
2010-07-01 08:50:04 +04:00
adap - > priv = kzalloc ( adap - > props . size_of_priv , GFP_KERNEL ) ;
2006-09-30 13:53:48 +04:00
if ( adap - > priv = = NULL ) {
2010-07-01 08:50:04 +04:00
err ( " no memory for priv for adapter %d. " , n ) ;
2006-09-30 13:53:48 +04:00
return - ENOMEM ;
}
}
2021-03-28 22:32:19 +03:00
ret = dvb_usb_adapter_stream_init ( adap ) ;
if ( ret )
2006-09-30 13:53:48 +04:00
return ret ;
2021-03-28 22:32:19 +03:00
ret = dvb_usb_adapter_dvb_init ( adap , adapter_nrs ) ;
if ( ret )
goto dvb_init_err ;
ret = dvb_usb_adapter_frontend_init ( adap ) ;
if ( ret )
goto frontend_init_err ;
2006-09-30 13:53:48 +04:00
2011-07-26 03:16:13 +04:00
/* use exclusive FE lock if there is multiple shared FEs */
2011-09-06 16:31:57 +04:00
if ( adap - > fe_adap [ 1 ] . fe )
2011-07-26 03:16:13 +04:00
adap - > dvb_adap . mfe_shared = 1 ;
2006-09-30 13:53:48 +04:00
d - > num_adapters_initialized + + ;
d - > state | = DVB_USB_STATE_DVB ;
}
/*
* when reloading the driver w / o replugging the device
2019-02-18 22:29:03 +03:00
* sometimes a timeout occurs , this helps
2006-09-30 13:53:48 +04:00
*/
if ( d - > props . generic_bulk_ctrl_endpoint ! = 0 ) {
2010-07-01 08:50:04 +04:00
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 ) ) ;
2006-09-30 13:53:48 +04:00
}
return 0 ;
2021-03-28 22:32:19 +03:00
frontend_init_err :
dvb_usb_adapter_dvb_exit ( adap ) ;
dvb_init_err :
dvb_usb_adapter_stream_exit ( adap ) ;
return ret ;
2006-09-30 13:53:48 +04:00
}
static int dvb_usb_adapter_exit ( struct dvb_usb_device * d )
{
int n ;
2010-07-01 08:50:04 +04:00
2006-09-30 13:53:48 +04:00
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
{
2010-07-01 08:50:04 +04:00
deb_info ( " state before exiting everything: %x \n " , d - > state ) ;
2005-06-24 09:02:35 +04:00
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 ) ;
2010-07-01 08:50:04 +04:00
deb_info ( " state should be zero now: %x \n " , d - > state ) ;
2005-06-24 09:02:35 +04:00
d - > state = DVB_USB_STATE_INIT ;
2019-04-29 19:16:57 +03:00
if ( d - > priv ! = NULL & & d - > props . priv_destroy ! = NULL )
d - > props . priv_destroy ( d ) ;
2005-06-24 09:02:35 +04:00
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 ;
2016-11-12 17:46:26 +03:00
mutex_init ( & d - > data_mutex ) ;
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 ) {
2010-07-01 08:50:04 +04:00
d - > priv = kzalloc ( d - > props . size_of_priv , GFP_KERNEL ) ;
2006-09-30 13:53:48 +04:00
if ( d - > priv = = NULL ) {
err ( " no memory for priv in 'struct dvb_usb_device' " ) ;
return - ENOMEM ;
2006-09-20 13:06:11 +04:00
}
2019-04-29 19:16:57 +03:00
if ( d - > props . priv_init ! = NULL ) {
ret = d - > props . priv_init ( d ) ;
2021-02-01 11:32:46 +03:00
if ( ret ! = 0 )
goto err_priv_init ;
2019-04-29 19:16:57 +03:00
}
2005-06-24 09:02:35 +04:00
}
2010-07-01 08:50:04 +04:00
/* check the capabilities and set appropriate variables */
2006-09-30 13:53:48 +04:00
dvb_usb_device_power_ctrl ( d , 1 ) ;
2005-06-24 09:02:35 +04:00
2021-02-01 11:32:46 +03:00
ret = dvb_usb_i2c_init ( d ) ;
if ( ret )
goto err_i2c_init ;
ret = dvb_usb_adapter_init ( d , adapter_nums ) ;
if ( ret )
goto err_adapter_init ;
2005-06-24 09:02:35 +04:00
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 ;
2021-02-01 11:32:46 +03:00
err_adapter_init :
dvb_usb_adapter_exit ( d ) ;
dvb_usb_i2c_exit ( d ) ;
2021-06-21 08:07:28 +03:00
err_i2c_init :
2021-02-01 11:32:46 +03:00
if ( d - > priv & & d - > props . priv_destroy )
d - > props . priv_destroy ( d ) ;
err_priv_init :
kfree ( d - > priv ) ;
d - > priv = NULL ;
return ret ;
2005-06-24 09:02:35 +04:00
}
/* determine the name and the state of the just found USB device */
2020-04-14 13:10:43 +03:00
static const struct dvb_usb_device_description * dvb_usb_find_device ( struct usb_device * udev , const struct dvb_usb_device_properties * props , int * cold )
2005-06-24 09:02:35 +04:00
{
2010-07-01 08:50:04 +04:00
int i , j ;
2020-04-14 13:10:43 +03:00
const struct dvb_usb_device_description * desc = NULL ;
2010-07-01 08:50:04 +04:00
2005-06-24 09:02:35 +04:00
* 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 + + ) {
2010-07-01 08:50:04 +04:00
deb_info ( " check for cold %x %x \n " , props - > devices [ i ] . cold_ids [ j ] - > idVendor , props - > devices [ i ] . cold_ids [ j ] - > idProduct ) ;
2005-06-24 09:02:35 +04:00
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 + + ) {
2010-07-01 08:50:04 +04:00
deb_info ( " check for warm %x %x \n " , props - > devices [ i ] . warm_ids [ j ] - > idVendor , props - > devices [ i ] . warm_ids [ j ] - > idProduct ) ;
2005-06-24 09:02:35 +04:00
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 )
2010-07-01 08:50:04 +04:00
props - > identify_state ( udev , props , & desc , cold ) ;
2005-06-24 09:02:35 +04:00
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 - - ;
2010-07-01 08:50:04 +04:00
if ( d - > powered = = 0 | | ( onoff & & d - > powered = = 1 ) ) { /* when switching from 1 to 0 or from 0 to 1 */
2006-09-20 13:06:11 +04:00
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 ,
2020-04-14 13:10:43 +03:00
const struct dvb_usb_device_properties * props ,
2008-04-10 02:13:13 +04:00
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 ;
2020-04-14 13:10:43 +03:00
const struct dvb_usb_device_description * desc = NULL ;
2005-06-24 09:02:35 +04:00
2010-07-01 08:50:04 +04:00
int ret = - ENOMEM , cold = 0 ;
2005-06-24 09:02:35 +04:00
2006-01-09 20:25:33 +03:00
if ( du ! = NULL )
* du = NULL ;
2021-02-01 11:32:47 +03:00
d = kzalloc ( sizeof ( * d ) , GFP_KERNEL ) ;
if ( ! d ) {
err ( " no memory for 'struct dvb_usb_device' " ) ;
return - ENOMEM ;
}
memcpy ( & d - > props , props , sizeof ( struct dvb_usb_device_properties ) ) ;
desc = dvb_usb_find_device ( udev , & d - > props , & cold ) ;
if ( ! desc ) {
2005-06-24 09:02:35 +04:00
deb_err ( " something went very wrong, device was not found in current device list - let's see what comes next. \n " ) ;
2021-02-01 11:32:47 +03:00
ret = - ENODEV ;
goto error ;
2005-06-24 09:02:35 +04:00
}
if ( cold ) {
2010-07-01 08:50:04 +04:00
info ( " found a '%s' in cold state, will try to load a firmware " , desc - > name ) ;
ret = dvb_usb_download_firmware ( udev , props ) ;
2006-09-19 19:51:46 +04:00
if ( ! props - > no_reconnect | | ret ! = 0 )
2021-02-01 11:32:47 +03:00
goto error ;
2006-01-09 20:25:04 +03:00
}
2010-07-01 08:50:04 +04:00
info ( " found a '%s' in warm state. " , desc - > name ) ;
2006-01-09 20:25:04 +03:00
d - > udev = udev ;
d - > desc = desc ;
d - > owner = owner ;
usb_set_intfdata ( intf , d ) ;
2005-06-24 09:02:35 +04:00
2021-02-01 11:32:46 +03:00
ret = dvb_usb_init ( d , adapter_nums ) ;
if ( ret ) {
info ( " %s error while loading driver (%d) " , desc - > name , ret ) ;
goto error ;
}
if ( du )
2006-01-09 20:25:04 +03:00
* du = d ;
2005-09-10 00:02:47 +04:00
2021-02-01 11:32:46 +03:00
info ( " %s successfully initialized and connected. " , desc - > name ) ;
return 0 ;
2005-06-24 09:02:35 +04:00
2021-02-01 11:32:46 +03:00
error :
usb_set_intfdata ( intf , NULL ) ;
kfree ( d ) ;
2005-06-24 09:02:35 +04:00
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 ) ;
2019-04-30 16:07:36 +03:00
const char * default_name = " generic DVB-USB module " ;
char name [ 40 ] ;
2005-06-24 09:02:35 +04:00
2010-07-01 08:50:04 +04:00
usb_set_intfdata ( intf , NULL ) ;
2005-06-24 09:02:35 +04:00
if ( d ! = NULL & & d - > desc ! = NULL ) {
2019-04-30 16:07:36 +03:00
strscpy ( name , d - > desc - > name , sizeof ( name ) ) ;
2005-06-24 09:02:35 +04:00
dvb_usb_exit ( d ) ;
2019-04-30 16:07:36 +03:00
} else {
strscpy ( name , default_name , sizeof ( name ) ) ;
2005-06-24 09:02:35 +04:00
}
2010-07-01 08:50:04 +04:00
info ( " %s successfully deinitialized and disconnected. " , name ) ;
2005-06-24 09:02:35 +04:00
}
EXPORT_SYMBOL ( dvb_usb_device_exit ) ;
2006-09-30 13:53:48 +04:00
MODULE_VERSION ( " 1.0 " ) ;
2016-01-24 17:56:58 +03:00
MODULE_AUTHOR ( " Patrick Boettcher <patrick.boettcher@posteo.de> " ) ;
2005-06-24 09:02:35 +04:00
MODULE_DESCRIPTION ( " A library module containing commonly used USB and DVB function USB DVB devices " ) ;
MODULE_LICENSE ( " GPL " ) ;