2005-07-08 04:58:23 +04:00
/* Frontend part of the Linux driver for the WideView/ Yakumo/ Hama/
* Typhoon / Yuan DVB - T USB2 .0 receiver .
2005-06-24 09:02:35 +04:00
*
2016-01-24 17:56:58 +03:00
* Copyright ( C ) 2005 Patrick Boettcher < patrick . boettcher @ posteo . 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 "dtt200u.h"
struct dtt200u_fe_state {
struct dvb_usb_device * d ;
2015-06-07 20:53:52 +03:00
enum fe_status stat ;
2005-07-08 04:58:33 +04:00
2011-12-26 22:44:27 +04:00
struct dtv_frontend_properties fep ;
2005-06-24 09:02:35 +04:00
struct dvb_frontend frontend ;
2016-10-07 14:06:57 +03:00
unsigned char data [ 80 ] ;
struct mutex data_mutex ;
2005-06-24 09:02:35 +04:00
} ;
2015-06-07 20:53:52 +03:00
static int dtt200u_fe_read_status ( struct dvb_frontend * fe ,
enum fe_status * stat )
2005-06-24 09:02:35 +04:00
{
struct dtt200u_fe_state * state = fe - > demodulator_priv ;
2016-10-07 19:44:09 +03:00
int ret ;
2005-07-08 04:58:33 +04:00
2016-10-07 14:06:57 +03:00
mutex_lock ( & state - > data_mutex ) ;
state - > data [ 0 ] = GET_TUNE_STATUS ;
2016-10-07 19:44:09 +03:00
ret = dvb_usb_generic_rw ( state - > d , state - > data , 1 , state - > data , 3 , 0 ) ;
if ( ret < 0 ) {
* stat = 0 ;
mutex_unlock ( & state - > data_mutex ) ;
return ret ;
}
2005-06-24 09:02:35 +04:00
2016-10-07 14:06:57 +03:00
switch ( state - > data [ 0 ] ) {
2005-06-24 09:02:35 +04:00
case 0x01 :
2005-07-08 04:58:33 +04:00
* stat = FE_HAS_SIGNAL | FE_HAS_CARRIER |
FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK ;
2005-06-24 09:02:35 +04:00
break ;
2005-07-08 04:58:33 +04:00
case 0x00 : /* pending */
* stat = FE_TIMEDOUT ; /* during set_frontend */
2005-06-24 09:02:35 +04:00
break ;
default :
2005-07-08 04:58:33 +04:00
case 0x02 : /* failed */
* stat = 0 ;
2005-06-24 09:02:35 +04:00
break ;
}
2016-10-07 14:06:57 +03:00
mutex_unlock ( & state - > data_mutex ) ;
2005-06-24 09:02:35 +04:00
return 0 ;
}
2005-07-08 04:58:33 +04:00
2005-06-24 09:02:35 +04:00
static int dtt200u_fe_read_ber ( struct dvb_frontend * fe , u32 * ber )
{
struct dtt200u_fe_state * state = fe - > demodulator_priv ;
2016-10-07 19:44:09 +03:00
int ret ;
2016-10-07 14:06:57 +03:00
mutex_lock ( & state - > data_mutex ) ;
state - > data [ 0 ] = GET_VIT_ERR_CNT ;
2016-10-07 19:44:09 +03:00
ret = dvb_usb_generic_rw ( state - > d , state - > data , 1 , state - > data , 3 , 0 ) ;
if ( ret > = 0 )
* ber = ( state - > data [ 0 ] < < 16 ) | ( state - > data [ 1 ] < < 8 ) | state - > data [ 2 ] ;
2016-10-07 14:06:57 +03:00
mutex_unlock ( & state - > data_mutex ) ;
2016-10-07 19:44:09 +03:00
return ret ;
2005-06-24 09:02:35 +04:00
}
static int dtt200u_fe_read_unc_blocks ( struct dvb_frontend * fe , u32 * unc )
{
struct dtt200u_fe_state * state = fe - > demodulator_priv ;
2016-10-07 19:44:09 +03:00
int ret ;
2005-07-08 04:58:33 +04:00
2016-10-07 14:06:57 +03:00
mutex_lock ( & state - > data_mutex ) ;
state - > data [ 0 ] = GET_RS_UNCOR_BLK_CNT ;
2016-10-07 19:44:09 +03:00
ret = dvb_usb_generic_rw ( state - > d , state - > data , 1 , state - > data , 2 , 0 ) ;
if ( ret > = 0 )
* unc = ( state - > data [ 0 ] < < 8 ) | state - > data [ 1 ] ;
2016-10-07 14:06:57 +03:00
mutex_unlock ( & state - > data_mutex ) ;
return ret ;
2005-06-24 09:02:35 +04:00
}
static int dtt200u_fe_read_signal_strength ( struct dvb_frontend * fe , u16 * strength )
{
struct dtt200u_fe_state * state = fe - > demodulator_priv ;
2016-10-07 19:44:09 +03:00
int ret ;
2016-10-07 14:06:57 +03:00
mutex_lock ( & state - > data_mutex ) ;
state - > data [ 0 ] = GET_AGC ;
2016-10-07 19:44:09 +03:00
ret = dvb_usb_generic_rw ( state - > d , state - > data , 1 , state - > data , 1 , 0 ) ;
if ( ret > = 0 )
* strength = ( state - > data [ 0 ] < < 8 ) | state - > data [ 0 ] ;
2016-10-07 14:06:57 +03:00
mutex_unlock ( & state - > data_mutex ) ;
return ret ;
2005-06-24 09:02:35 +04:00
}
static int dtt200u_fe_read_snr ( struct dvb_frontend * fe , u16 * snr )
{
struct dtt200u_fe_state * state = fe - > demodulator_priv ;
2016-10-07 19:44:09 +03:00
int ret ;
2016-10-07 14:06:57 +03:00
mutex_lock ( & state - > data_mutex ) ;
state - > data [ 0 ] = GET_SNR ;
2016-10-07 19:44:09 +03:00
ret = dvb_usb_generic_rw ( state - > d , state - > data , 1 , state - > data , 1 , 0 ) ;
if ( ret > = 0 )
* snr = ~ ( ( state - > data [ 0 ] < < 8 ) | state - > data [ 0 ] ) ;
2016-10-07 14:06:57 +03:00
mutex_unlock ( & state - > data_mutex ) ;
return ret ;
2005-06-24 09:02:35 +04:00
}
static int dtt200u_fe_init ( struct dvb_frontend * fe )
{
struct dtt200u_fe_state * state = fe - > demodulator_priv ;
2016-10-07 14:06:57 +03:00
int ret ;
mutex_lock ( & state - > data_mutex ) ;
state - > data [ 0 ] = SET_INIT ;
ret = dvb_usb_generic_write ( state - > d , state - > data , 1 ) ;
mutex_unlock ( & state - > data_mutex ) ;
return ret ;
2005-06-24 09:02:35 +04:00
}
static int dtt200u_fe_sleep ( struct dvb_frontend * fe )
{
return dtt200u_fe_init ( fe ) ;
}
static int dtt200u_fe_get_tune_settings ( struct dvb_frontend * fe , struct dvb_frontend_tune_settings * tune )
{
tune - > min_delay_ms = 1500 ;
2005-07-08 04:58:33 +04:00
tune - > step_size = 0 ;
tune - > max_drift = 0 ;
2005-06-24 09:02:35 +04:00
return 0 ;
}
2011-12-26 22:44:27 +04:00
static int dtt200u_fe_set_frontend ( struct dvb_frontend * fe )
2005-06-24 09:02:35 +04:00
{
2011-12-26 22:44:27 +04:00
struct dtv_frontend_properties * fep = & fe - > dtv_property_cache ;
2005-06-24 09:02:35 +04:00
struct dtt200u_fe_state * state = fe - > demodulator_priv ;
2016-10-07 19:44:09 +03:00
int ret ;
2005-06-24 09:02:35 +04:00
u16 freq = fep - > frequency / 250000 ;
2016-10-07 14:06:57 +03:00
mutex_lock ( & state - > data_mutex ) ;
state - > data [ 0 ] = SET_BANDWIDTH ;
2011-12-26 22:44:27 +04:00
switch ( fep - > bandwidth_hz ) {
case 8000000 :
2016-10-07 14:06:57 +03:00
state - > data [ 1 ] = 8 ;
2011-12-26 22:44:27 +04:00
break ;
case 7000000 :
2016-10-07 14:06:57 +03:00
state - > data [ 1 ] = 7 ;
2011-12-26 22:44:27 +04:00
break ;
case 6000000 :
2016-10-07 14:06:57 +03:00
state - > data [ 1 ] = 6 ;
2011-12-26 22:44:27 +04:00
break ;
default :
2016-10-07 14:06:57 +03:00
ret = - EINVAL ;
goto ret ;
2005-06-24 09:02:35 +04:00
}
2016-10-07 19:44:09 +03:00
ret = dvb_usb_generic_write ( state - > d , state - > data , 2 ) ;
if ( ret < 0 )
goto ret ;
2005-06-24 09:02:35 +04:00
2016-10-07 14:06:57 +03:00
state - > data [ 0 ] = SET_RF_FREQ ;
state - > data [ 1 ] = freq & 0xff ;
state - > data [ 2 ] = ( freq > > 8 ) & 0xff ;
2016-10-07 19:44:09 +03:00
ret = dvb_usb_generic_write ( state - > d , state - > data , 3 ) ;
if ( ret < 0 )
goto ret ;
2005-06-24 09:02:35 +04:00
2016-10-07 14:06:57 +03:00
ret :
mutex_unlock ( & state - > data_mutex ) ;
return ret ;
2005-06-24 09:02:35 +04:00
}
2016-02-04 17:58:30 +03:00
static int dtt200u_fe_get_frontend ( struct dvb_frontend * fe ,
struct dtv_frontend_properties * fep )
2005-06-24 09:02:35 +04:00
{
struct dtt200u_fe_state * state = fe - > demodulator_priv ;
2016-02-04 17:58:30 +03:00
2011-12-26 22:44:27 +04:00
memcpy ( fep , & state - > fep , sizeof ( struct dtv_frontend_properties ) ) ;
2005-06-24 09:02:35 +04:00
return 0 ;
}
static void dtt200u_fe_release ( struct dvb_frontend * fe )
{
struct dtt200u_fe_state * state = ( struct dtt200u_fe_state * ) fe - > demodulator_priv ;
kfree ( state ) ;
}
2016-08-10 00:32:21 +03:00
static const struct dvb_frontend_ops dtt200u_fe_ops ;
2005-06-24 09:02:35 +04:00
struct dvb_frontend * dtt200u_fe_attach ( struct dvb_usb_device * d )
{
struct dtt200u_fe_state * state = NULL ;
/* allocate memory for the internal state */
2006-01-12 00:40:56 +03:00
state = kzalloc ( sizeof ( struct dtt200u_fe_state ) , GFP_KERNEL ) ;
2005-06-24 09:02:35 +04:00
if ( state = = NULL )
goto error ;
deb_info ( " attaching frontend dtt200u \n " ) ;
state - > d = d ;
2016-10-07 14:06:57 +03:00
mutex_init ( & state - > data_mutex ) ;
2005-06-24 09:02:35 +04:00
2006-05-14 12:01:31 +04:00
memcpy ( & state - > frontend . ops , & dtt200u_fe_ops , sizeof ( struct dvb_frontend_ops ) ) ;
2005-06-24 09:02:35 +04:00
state - > frontend . demodulator_priv = state ;
2006-05-13 03:36:24 +04:00
return & state - > frontend ;
2005-06-24 09:02:35 +04:00
error :
return NULL ;
}
2016-08-10 00:32:21 +03:00
static const struct dvb_frontend_ops dtt200u_fe_ops = {
2011-12-26 22:44:27 +04:00
. delsys = { SYS_DVBT } ,
2005-06-24 09:02:35 +04:00
. info = {
2005-07-08 04:58:33 +04:00
. name = " WideView USB DVB-T " ,
2005-06-24 09:02:35 +04:00
. frequency_min = 44250000 ,
. frequency_max = 867250000 ,
. frequency_stepsize = 250000 ,
. caps = FE_CAN_INVERSION_AUTO |
FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
FE_CAN_TRANSMISSION_MODE_AUTO |
FE_CAN_GUARD_INTERVAL_AUTO |
FE_CAN_RECOVER |
FE_CAN_HIERARCHY_AUTO ,
} ,
. release = dtt200u_fe_release ,
. init = dtt200u_fe_init ,
. sleep = dtt200u_fe_sleep ,
2011-12-26 22:44:27 +04:00
. set_frontend = dtt200u_fe_set_frontend ,
. get_frontend = dtt200u_fe_get_frontend ,
2005-06-24 09:02:35 +04:00
. get_tune_settings = dtt200u_fe_get_tune_settings ,
. read_status = dtt200u_fe_read_status ,
. read_ber = dtt200u_fe_read_ber ,
. read_signal_strength = dtt200u_fe_read_signal_strength ,
. read_snr = dtt200u_fe_read_snr ,
. read_ucblocks = dtt200u_fe_read_unc_blocks ,
} ;