2019-05-23 11:14:55 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2011-10-31 12:24:39 -03:00
/*
* Abilis Systems Single DVB - T Receiver
* Copyright ( C ) 2008 Pierrick Hascoet < pierrick . hascoet @ abilis . com >
2011-10-31 12:24:40 -03:00
* Copyright ( C ) 2010 Devin Heitmueller < dheitmueller @ kernellabs . com >
2011-10-31 12:24:39 -03:00
*/
# include <linux/kernel.h>
# include <linux/errno.h>
# include <linux/slab.h>
# include <linux/module.h>
# include <linux/mm.h>
# include <linux/kref.h>
2011-11-06 16:31:47 -03:00
# include <linux/uaccess.h>
2011-10-31 12:24:39 -03:00
# include <linux/usb.h>
2012-03-05 11:49:26 -03:00
/* header file for usb device driver*/
2011-10-31 12:24:39 -03:00
# include "as102_drv.h"
2014-08-12 18:50:22 -03:00
# include "as10x_cmd.h"
# include "as102_fe.h"
2011-10-31 12:24:39 -03:00
# include "as102_fw.h"
2017-12-28 13:03:51 -05:00
# include <media/dvbdev.h>
2011-10-31 12:24:39 -03:00
2011-10-31 12:24:40 -03:00
int dual_tuner ;
2011-10-31 12:24:39 -03:00
module_param_named ( dual_tuner , dual_tuner , int , 0644 ) ;
2011-10-31 12:24:40 -03:00
MODULE_PARM_DESC ( dual_tuner , " Activate Dual-Tuner config (default: off) " ) ;
2011-10-31 12:24:39 -03:00
static int fw_upload = 1 ;
module_param_named ( fw_upload , fw_upload , int , 0644 ) ;
MODULE_PARM_DESC ( fw_upload , " Turn on/off default FW upload (default: on) " ) ;
2011-10-31 12:24:40 -03:00
static int pid_filtering ;
2011-10-31 12:24:39 -03:00
module_param_named ( pid_filtering , pid_filtering , int , 0644 ) ;
MODULE_PARM_DESC ( pid_filtering , " Activate HW PID filtering (default: off) " ) ;
2011-10-31 12:24:40 -03:00
static int ts_auto_disable ;
2011-10-31 12:24:39 -03:00
module_param_named ( ts_auto_disable , ts_auto_disable , int , 0644 ) ;
MODULE_PARM_DESC ( ts_auto_disable , " Stream Auto Enable on FW (default: off) " ) ;
int elna_enable = 1 ;
module_param_named ( elna_enable , elna_enable , int , 0644 ) ;
MODULE_PARM_DESC ( elna_enable , " Activate eLNA (default: on) " ) ;
DVB_DEFINE_MOD_OPT_ADAPTER_NR ( adapter_nr ) ;
2011-10-31 12:24:40 -03:00
static void as102_stop_stream ( struct as102_dev_t * dev )
{
2011-11-06 16:31:50 -03:00
struct as10x_bus_adapter_t * bus_adap ;
2011-10-31 12:24:39 -03:00
if ( dev ! = NULL )
bus_adap = & dev - > bus_adap ;
else
return ;
if ( bus_adap - > ops - > stop_stream ! = NULL )
bus_adap - > ops - > stop_stream ( dev ) ;
if ( ts_auto_disable ) {
if ( mutex_lock_interruptible ( & dev - > bus_adap . lock ) )
return ;
2011-10-31 12:24:40 -03:00
if ( as10x_cmd_stop_streaming ( bus_adap ) < 0 )
2014-08-04 08:13:16 -03:00
dev_dbg ( & dev - > bus_adap . usb_dev - > dev ,
" as10x_cmd_stop_streaming failed \n " ) ;
2011-10-31 12:24:39 -03:00
mutex_unlock ( & dev - > bus_adap . lock ) ;
}
}
2011-10-31 12:24:40 -03:00
static int as102_start_stream ( struct as102_dev_t * dev )
{
2011-11-06 16:31:50 -03:00
struct as10x_bus_adapter_t * bus_adap ;
2011-10-31 12:24:39 -03:00
int ret = - EFAULT ;
if ( dev ! = NULL )
bus_adap = & dev - > bus_adap ;
else
return ret ;
2011-10-31 12:24:40 -03:00
if ( bus_adap - > ops - > start_stream ! = NULL )
2011-10-31 12:24:39 -03:00
ret = bus_adap - > ops - > start_stream ( dev ) ;
if ( ts_auto_disable ) {
if ( mutex_lock_interruptible ( & dev - > bus_adap . lock ) )
return - EFAULT ;
ret = as10x_cmd_start_streaming ( bus_adap ) ;
mutex_unlock ( & dev - > bus_adap . lock ) ;
}
return ret ;
}
static int as10x_pid_filter ( struct as102_dev_t * dev ,
int index , u16 pid , int onoff ) {
2011-11-06 16:31:50 -03:00
struct as10x_bus_adapter_t * bus_adap = & dev - > bus_adap ;
2011-10-31 12:24:39 -03:00
int ret = - EFAULT ;
if ( mutex_lock_interruptible ( & dev - > bus_adap . lock ) ) {
2014-08-04 08:13:16 -03:00
dev_dbg ( & dev - > bus_adap . usb_dev - > dev ,
" amutex_lock_interruptible(lock) failed ! \n " ) ;
2011-10-31 12:24:39 -03:00
return - EBUSY ;
}
2011-10-31 12:24:40 -03:00
switch ( onoff ) {
case 0 :
2011-11-06 16:31:44 -03:00
ret = as10x_cmd_del_PID_filter ( bus_adap , ( uint16_t ) pid ) ;
2014-08-04 08:13:16 -03:00
dev_dbg ( & dev - > bus_adap . usb_dev - > dev ,
" DEL_PID_FILTER([%02d] 0x%04x) ret = %d \n " ,
2011-11-06 16:31:44 -03:00
index , pid , ret ) ;
break ;
2011-10-31 12:24:40 -03:00
case 1 :
{
2011-11-06 16:31:44 -03:00
struct as10x_ts_filter filter ;
2011-10-31 12:24:40 -03:00
2011-11-06 16:31:44 -03:00
filter . type = TS_PID_TYPE_TS ;
filter . idx = 0xFF ;
filter . pid = pid ;
2011-10-31 12:24:40 -03:00
2011-11-06 16:31:44 -03:00
ret = as10x_cmd_add_PID_filter ( bus_adap , & filter ) ;
2014-08-04 08:13:16 -03:00
dev_dbg ( & dev - > bus_adap . usb_dev - > dev ,
2014-01-14 11:27:08 -03:00
" ADD_PID_FILTER([%02d -> %02d], 0x%04x) ret = %d \n " ,
2011-11-06 16:31:44 -03:00
index , filter . idx , filter . pid , ret ) ;
break ;
2011-10-31 12:24:40 -03:00
}
2011-10-31 12:24:39 -03:00
}
mutex_unlock ( & dev - > bus_adap . lock ) ;
return ret ;
}
2011-10-31 12:24:40 -03:00
static int as102_dvb_dmx_start_feed ( struct dvb_demux_feed * dvbdmxfeed )
{
2011-10-31 12:24:39 -03:00
int ret = 0 ;
struct dvb_demux * demux = dvbdmxfeed - > demux ;
struct as102_dev_t * as102_dev = demux - > priv ;
if ( mutex_lock_interruptible ( & as102_dev - > sem ) )
return - ERESTARTSYS ;
2011-11-06 16:31:44 -03:00
if ( pid_filtering )
as10x_pid_filter ( as102_dev , dvbdmxfeed - > index ,
dvbdmxfeed - > pid , 1 ) ;
2011-10-31 12:24:39 -03:00
2011-10-31 12:24:40 -03:00
if ( as102_dev - > streaming + + = = 0 )
2011-10-31 12:24:39 -03:00
ret = as102_start_stream ( as102_dev ) ;
mutex_unlock ( & as102_dev - > sem ) ;
return ret ;
}
2011-10-31 12:24:40 -03:00
static int as102_dvb_dmx_stop_feed ( struct dvb_demux_feed * dvbdmxfeed )
{
2011-10-31 12:24:39 -03:00
struct dvb_demux * demux = dvbdmxfeed - > demux ;
struct as102_dev_t * as102_dev = demux - > priv ;
if ( mutex_lock_interruptible ( & as102_dev - > sem ) )
return - ERESTARTSYS ;
2011-10-31 12:24:40 -03:00
if ( - - as102_dev - > streaming = = 0 )
2011-10-31 12:24:39 -03:00
as102_stop_stream ( as102_dev ) ;
2011-11-06 16:31:44 -03:00
if ( pid_filtering )
as10x_pid_filter ( as102_dev , dvbdmxfeed - > index ,
dvbdmxfeed - > pid , 0 ) ;
2011-10-31 12:24:39 -03:00
mutex_unlock ( & as102_dev - > sem ) ;
return 0 ;
}
2014-08-12 18:50:22 -03:00
static int as102_set_tune ( void * priv , struct as10x_tune_args * tune_args )
{
struct as10x_bus_adapter_t * bus_adap = priv ;
int ret ;
/* Set frontend arguments */
if ( mutex_lock_interruptible ( & bus_adap - > lock ) )
return - EBUSY ;
ret = as10x_cmd_set_tune ( bus_adap , tune_args ) ;
if ( ret ! = 0 )
dev_dbg ( & bus_adap - > usb_dev - > dev ,
" as10x_cmd_set_tune failed. (err = %d) \n " , ret ) ;
mutex_unlock ( & bus_adap - > lock ) ;
return ret ;
}
static int as102_get_tps ( void * priv , struct as10x_tps * tps )
{
struct as10x_bus_adapter_t * bus_adap = priv ;
int ret ;
if ( mutex_lock_interruptible ( & bus_adap - > lock ) )
return - EBUSY ;
/* send abilis command: GET_TPS */
ret = as10x_cmd_get_tps ( bus_adap , tps ) ;
mutex_unlock ( & bus_adap - > lock ) ;
return ret ;
}
static int as102_get_status ( void * priv , struct as10x_tune_status * tstate )
{
struct as10x_bus_adapter_t * bus_adap = priv ;
int ret ;
if ( mutex_lock_interruptible ( & bus_adap - > lock ) )
return - EBUSY ;
/* send abilis command: GET_TUNE_STATUS */
ret = as10x_cmd_get_tune_status ( bus_adap , tstate ) ;
if ( ret < 0 ) {
dev_dbg ( & bus_adap - > usb_dev - > dev ,
" as10x_cmd_get_tune_status failed (err = %d) \n " ,
ret ) ;
}
mutex_unlock ( & bus_adap - > lock ) ;
return ret ;
}
static int as102_get_stats ( void * priv , struct as10x_demod_stats * demod_stats )
{
struct as10x_bus_adapter_t * bus_adap = priv ;
int ret ;
if ( mutex_lock_interruptible ( & bus_adap - > lock ) )
return - EBUSY ;
/* send abilis command: GET_TUNE_STATUS */
ret = as10x_cmd_get_demod_stats ( bus_adap , demod_stats ) ;
if ( ret < 0 ) {
dev_dbg ( & bus_adap - > usb_dev - > dev ,
" as10x_cmd_get_demod_stats failed (probably not tuned) \n " ) ;
} else {
dev_dbg ( & bus_adap - > usb_dev - > dev ,
" demod status: fc: 0x%08x, bad fc: 0x%08x, bytes corrected: 0x%08x , MER: 0x%04x \n " ,
demod_stats - > frame_count ,
demod_stats - > bad_frame_count ,
demod_stats - > bytes_fixed_by_rs ,
demod_stats - > mer ) ;
}
mutex_unlock ( & bus_adap - > lock ) ;
return ret ;
}
static int as102_stream_ctrl ( void * priv , int acquire , uint32_t elna_cfg )
{
struct as10x_bus_adapter_t * bus_adap = priv ;
int ret ;
if ( mutex_lock_interruptible ( & bus_adap - > lock ) )
return - EBUSY ;
if ( acquire ) {
if ( elna_enable )
as10x_cmd_set_context ( bus_adap ,
CONTEXT_LNA , elna_cfg ) ;
ret = as10x_cmd_turn_on ( bus_adap ) ;
} else {
ret = as10x_cmd_turn_off ( bus_adap ) ;
}
mutex_unlock ( & bus_adap - > lock ) ;
return ret ;
}
static const struct as102_fe_ops as102_fe_ops = {
. set_tune = as102_set_tune ,
. get_tps = as102_get_tps ,
. get_status = as102_get_status ,
. get_stats = as102_get_stats ,
. stream_ctrl = as102_stream_ctrl ,
} ;
2011-10-31 12:24:40 -03:00
int as102_dvb_register ( struct as102_dev_t * as102_dev )
{
2011-11-06 16:31:43 -03:00
struct device * dev = & as102_dev - > bus_adap . usb_dev - > dev ;
int ret ;
2011-10-31 12:24:39 -03:00
ret = dvb_register_adapter ( & as102_dev - > dvb_adap ,
2011-11-06 16:31:43 -03:00
as102_dev - > name , THIS_MODULE ,
dev , adapter_nr ) ;
2011-10-31 12:24:39 -03:00
if ( ret < 0 ) {
2011-11-06 16:31:43 -03:00
dev_err ( dev , " %s: dvb_register_adapter() failed: %d \n " ,
__func__ , ret ) ;
return ret ;
2011-10-31 12:24:39 -03:00
}
as102_dev - > dvb_dmx . priv = as102_dev ;
as102_dev - > dvb_dmx . filternum = pid_filtering ? 16 : 256 ;
as102_dev - > dvb_dmx . feednum = 256 ;
as102_dev - > dvb_dmx . start_feed = as102_dvb_dmx_start_feed ;
as102_dev - > dvb_dmx . stop_feed = as102_dvb_dmx_stop_feed ;
as102_dev - > dvb_dmx . dmx . capabilities = DMX_TS_FILTERING |
DMX_SECTION_FILTERING ;
as102_dev - > dvb_dmxdev . filternum = as102_dev - > dvb_dmx . filternum ;
as102_dev - > dvb_dmxdev . demux = & as102_dev - > dvb_dmx . dmx ;
as102_dev - > dvb_dmxdev . capabilities = 0 ;
2011-10-31 12:24:40 -03:00
ret = dvb_dmx_init ( & as102_dev - > dvb_dmx ) ;
if ( ret < 0 ) {
2011-11-08 19:16:04 -03:00
dev_err ( dev , " %s: dvb_dmx_init() failed: %d \n " , __func__ , ret ) ;
2011-11-06 16:31:43 -03:00
goto edmxinit ;
2011-10-31 12:24:39 -03:00
}
ret = dvb_dmxdev_init ( & as102_dev - > dvb_dmxdev , & as102_dev - > dvb_adap ) ;
if ( ret < 0 ) {
2011-11-06 16:31:43 -03:00
dev_err ( dev , " %s: dvb_dmxdev_init() failed: %d \n " ,
__func__ , ret ) ;
goto edmxdinit ;
2011-10-31 12:24:39 -03:00
}
2014-08-12 18:50:19 -03:00
/* Attach the frontend */
as102_dev - > dvb_fe = dvb_attach ( as102_attach , as102_dev - > name ,
2014-08-12 18:50:22 -03:00
& as102_fe_ops ,
2014-08-12 18:50:19 -03:00
& as102_dev - > bus_adap ,
as102_dev - > elna_cfg ) ;
if ( ! as102_dev - > dvb_fe ) {
2015-04-05 09:06:23 -03:00
ret = - ENODEV ;
2014-08-12 18:50:19 -03:00
dev_err ( dev , " %s: as102_attach() failed: %d " ,
__func__ , ret ) ;
goto efereg ;
}
ret = dvb_register_frontend ( & as102_dev - > dvb_adap , as102_dev - > dvb_fe ) ;
2011-10-31 12:24:39 -03:00
if ( ret < 0 ) {
2011-11-06 16:31:43 -03:00
dev_err ( dev , " %s: as102_dvb_register_frontend() failed: %d " ,
2011-10-31 12:24:40 -03:00
__func__ , ret ) ;
2011-11-06 16:31:43 -03:00
goto efereg ;
2011-10-31 12:24:39 -03:00
}
/* init bus mutex for token locking */
mutex_init ( & as102_dev - > bus_adap . lock ) ;
/* init start / stop stream mutex */
mutex_init ( & as102_dev - > sem ) ;
/*
* try to load as102 firmware . If firmware upload failed , we ' ll be
* able to upload it later .
*/
if ( fw_upload )
try_then_request_module ( as102_fw_upload ( & as102_dev - > bus_adap ) ,
" firmware_class " ) ;
2011-11-06 16:31:43 -03:00
pr_info ( " Registered device %s " , as102_dev - > name ) ;
return 0 ;
efereg :
dvb_dmxdev_release ( & as102_dev - > dvb_dmxdev ) ;
edmxdinit :
dvb_dmx_release ( & as102_dev - > dvb_dmx ) ;
edmxinit :
dvb_unregister_adapter ( & as102_dev - > dvb_adap ) ;
2011-10-31 12:24:39 -03:00
return ret ;
}
2011-10-31 12:24:40 -03:00
void as102_dvb_unregister ( struct as102_dev_t * as102_dev )
{
2011-10-31 12:24:39 -03:00
/* unregister as102 frontend */
2014-08-12 18:50:19 -03:00
dvb_unregister_frontend ( as102_dev - > dvb_fe ) ;
/* detach frontend */
dvb_frontend_detach ( as102_dev - > dvb_fe ) ;
2011-10-31 12:24:39 -03:00
/* unregister demux device */
dvb_dmxdev_release ( & as102_dev - > dvb_dmxdev ) ;
dvb_dmx_release ( & as102_dev - > dvb_dmx ) ;
/* unregister dvb adapter */
dvb_unregister_adapter ( & as102_dev - > dvb_adap ) ;
2011-10-31 12:24:54 -03:00
2011-11-06 16:31:43 -03:00
pr_info ( " Unregistered device %s " , as102_dev - > name ) ;
2011-10-31 12:24:39 -03:00
}
2012-04-25 14:33:06 -07:00
module_usb_driver ( as102_usb_driver ) ;
2011-10-31 12:24:39 -03:00
/* modinfo details */
MODULE_DESCRIPTION ( DRIVER_FULL_NAME ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Pierrick Hascoet <pierrick.hascoet@abilis.com> " ) ;