The Digital TV Frontend kABI defines a driver-internal interface for
registering low-level, hardware specific driver to a hardware independent
frontend layer. It is only of interest for Digital TV device driver writers.
The header file for this API is named dvb_frontend.h and located in
include/media/.
The demodulator driver is responsible for talking with the decoding part of the
hardware. Such driver should implement dvb_frontend_ops, which
tells what type of digital TV standards are supported, and points to a
series of functions that allow the DVB core to command the hardware via
the code under include/media/dvb_frontend.c.
A typical example of such struct in a driver foo is:
For satellite digital TV standards (DVB-S, DVB-S2, ISDB-S), the
frequencies are specified in kHz, while, for terrestrial and cable
standards, they’re specified in Hz. Due to that, if the same frontend
supports both types, you’ll need to have two separate
dvb_frontend_ops structures, one for each standard.
The .i2c_gate_ctrl field is present only when the hardware has
allows controlling an I2C gate (either directly of via some GPIO pin),
in order to remove the tuner from the I2C bus after a channel is
tuned.
All new drivers should implement the
DVBv5 statistics via .read_status.
Yet, there are a number of callbacks meant to get statistics for
signal strength, S/N and UCB. Those are there to provide backward
compatibility with legacy applications that don’t support the DVBv5
API. Implementing those callbacks are optional. Those callbacks may be
removed in the future, after we have all existing drivers supporting
DVBv5 stats.
Other callbacks are required for satellite TV standards, in order to
control LNBf and DiSEqC: .diseqc_send_master_cmd,
.diseqc_send_burst, .set_tone, .set_voltage.
The include/media/dvb_frontend.c has a kernel thread which is
responsible for tuning the device. It supports multiple algorithms to
detect a channel, as defined at enum dvbfe_algo().
The algorithm to be used is obtained via .get_frontend_algo. If the driver
doesn’t fill its field at structdvb_frontend_ops, it will default to
DVBFE_ALGO_SW, meaning that the dvb-core will do a zigzag when tuning,
e. g. it will try first to use the specified center frequency f,
then, it will do f + Δ, f - Δ, f + 2 x Δ,
f - 2 x Δ and so on.
If the hardware has internally a some sort of zigzag algorithm, you should
define a .get_frontend_algo function that would return DVBFE_ALGO_HW.
Note
The core frontend support also supports
a third type (DVBFE_ALGO_CUSTOM), in order to allow the driver to
define its own hardware-assisted algorithm. Very few hardware need to
use it nowadays. Using DVBFE_ALGO_CUSTOM require to provide other
function callbacks at structdvb_frontend_ops.
3.2.1.2. Attaching frontend driver to the bridge driver¶
Before using the Digital TV frontend core, the bridge driver should attach
the frontend demod, tuner and SEC devices and call
dvb_register_frontend(),
in order to register the new frontend at the subsystem. At device
detach/removal, the bridge driver should call
dvb_unregister_frontend() to
remove the frontend from the core and then dvb_frontend_detach()
to free the memory allocated by the frontend drivers.
Digital TV frontends provide a range of
statistics meant to help tuning the device
and measuring the quality of service.
For each statistics measurement, the driver should set the type of scale used,
or FE_SCALE_NOT_AVAILABLE if the statistics is not available on a given
time. Drivers should also provide the number of statistics for each type.
that’s usually 1 for most video standards [1].
Drivers should initialize each statistic counters with length and
scale at its init code. For example, if the frontend provides signal
strength, it should have, on its init code:
Measures the signal strength level at the analog part of the tuner or
demod.
Typically obtained from the gain applied to the tuner and/or frontend
in order to detect the carrier. When no carrier is detected, the gain is
at the maximum value (so, strength is on its minimal).
As the gain is visible through the set of registers that adjust the gain,
typically, this statistics is always available [2].
Drivers should try to make it available all the times, as these statistics
can be used when adjusting an antenna position and to check for troubles
at the cabling.
Signal to Noise measurement depends on the device. On some hardware, it is
available when the main carrier is detected. On those hardware, CNR
measurement usually comes from the tuner (e. g. after FE_HAS_CARRIER,
see fe_status).
On other devices, it requires inner FEC decoding,
as the frontend measures it indirectly from other parameters (e. g. after
FE_HAS_VITERBI, see fe_status).
Having it available after inner FEC is more common.
Those counters measure the number of bits and bit errors after
the forward error correction (FEC) on the inner coding block
(after Viterbi, LDPC or other inner code).
Due to its nature, those statistics depend on full coding lock
(e. g. after FE_HAS_SYNC or after FE_HAS_LOCK,
see fe_status).
Those counters measure the number of bits and bit errors before
the forward error correction (FEC) on the inner coding block
(before Viterbi, LDPC or other inner code).
Not all frontends provide this kind of statistics.
Due to its nature, those statistics depend on inner coding lock (e. g.
after FE_HAS_VITERBI, see fe_status).
Those counters measure the number of blocks and block errors after
the forward error correction (FEC) on the inner coding block
(before Viterbi, LDPC or other inner code).
Due to its nature, those statistics depend on full coding lock
(e. g. after FE_HAS_SYNC or after
FE_HAS_LOCK, see fe_status).
Note
All counters should be monotonically increased as they’re
collected from the hardware.
A typical example of the logic that handle status and statistics is:
static int foo_get_status_and_stats(struct dvb_frontend *fe)
{
struct foo_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int rc;
enum fe_status *status;
/* Both status and strength are always available */
rc = foo_read_status(fe, &status);
if (rc < 0)
return rc;
rc = foo_read_strength(fe);
if (rc < 0)
return rc;
/* Check if CNR is available */
if (!(fe->status & FE_HAS_CARRIER))
return 0;
rc = foo_read_cnr(fe);
if (rc < 0)
return rc;
/* Check if pre-BER stats are available */
if (!(fe->status & FE_HAS_VITERBI))
return 0;
rc = foo_get_pre_ber(fe);
if (rc < 0)
return rc;
/* Check if post-BER stats are available */
if (!(fe->status & FE_HAS_SYNC))
return 0;
rc = foo_get_post_ber(fe);
if (rc < 0)
return rc;
}
static const struct dvb_frontend_ops ops = {
/* ... */
.read_status = foo_get_status_and_stats,
};
On almost all frontend hardware, the bit and byte counts are stored by
the hardware after a certain amount of time or after the total bit/block
counter reaches a certain value (usually programmable), for example, on
every 1000 ms or after receiving 1,000,000 bits.
So, if you read the registers too soon, you’ll end by reading the same
value as in the previous reading, causing the monotonic value to be
incremented too often.
Drivers should take the responsibility to avoid too often reads. That
can be done using two approaches:
3.2.2.3.1. if the driver have a bit that indicates when a collected data is ready¶
Driver should check such bit before making the statistics available.
An example of such behavior can be found at this code snippet (adapted
from mb86a20s driver’s logic):
static int foo_get_pre_ber(struct dvb_frontend *fe)
{
struct foo_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int rc, bit_error;
/* Check if the BER measures are already available */
rc = foo_read_u8(state, 0x54);
if (rc < 0)
return rc;
if (!rc)
return 0;
/* Read Bit Error Count */
bit_error = foo_read_u32(state, 0x55);
if (bit_error < 0)
return bit_error;
/* Read Total Bit Count */
rc = foo_read_u32(state, 0x51);
if (rc < 0)
return rc;
c->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER;
c->pre_bit_error.stat[0].uvalue += bit_error;
c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER;
c->pre_bit_count.stat[0].uvalue += rc;
return 0;
}
3.2.2.3.2. If the driver doesn’t provide a statistics available check bit¶
A few devices, however, may not provide a way to check if the stats are
available (or the way to check it is unknown). They may not even provide
a way to directly read the total number of bits or blocks.
On those devices, the driver need to ensure that it won’t be reading from
the register too often and/or estimate the total number of bits/blocks.
On such drivers, a typical routine to get statistics would be like
(adapted from dib8000 driver’s logic):
struct foo_state {
/* ... */
unsigned long per_jiffies_stats;
}
static int foo_get_pre_ber(struct dvb_frontend *fe)
{
struct foo_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int rc, bit_error;
u64 bits;
/* Check if time for stats was elapsed */
if (!time_after(jiffies, state->per_jiffies_stats))
return 0;
/* Next stat should be collected in 1000 ms */
state->per_jiffies_stats = jiffies + msecs_to_jiffies(1000);
/* Read Bit Error Count */
bit_error = foo_read_u32(state, 0x55);
if (bit_error < 0)
return bit_error;
/*
* On this particular frontend, there's no register that
* would provide the number of bits per 1000ms sample. So,
* some function would calculate it based on DTV properties
*/
bits = get_number_of_bits_per_1000ms(fe);
c->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER;
c->pre_bit_error.stat[0].uvalue += bit_error;
c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER;
c->pre_bit_count.stat[0].uvalue += bits;
return 0;
}
Please notice that, on both cases, we’re getting the statistics using the
dvb_frontend_ops.read_status callback. The rationale is that
the frontend core will automatically call this function periodically
(usually, 3 times per second, when the frontend is locked).
That warrants that we won’t miss to collect a counter and increment the
monotonic stats at the right time.
struct analog_parameters {
unsigned int frequency;
unsigned int mode;
unsigned int audmode;
u64 std;
};
Members
frequency
Frequency used by analog TV tuner (either in 62.5 kHz step,
for TV, or 62.5 Hz for radio)
mode
Tuner mode, as defined on enum v4l2_tuner_type
audmode
Audio mode as defined for the rxsubchans field at videodev2.h,
e. g. V4L2_TUNER_MODE_*
std
TV standard bitmap as defined at videodev2.h, e. g. V4L2_STD_*
Description
Hybrid tuners should be supported by both V4L2 and DVB APIs. This
struct contains the data that are used by the V4L2 side. To avoid
dependencies from V4L2 headers, all enums here are declared as integers.
Hardware Algorithm -
Devices that support this algorithm do everything in hardware
and no software support is needed to handle them.
Requesting these devices to LOCK is the only thing required,
device is supposed to do everything in the hardware.
DVBFE_ALGO_SW
Software Algorithm -
These are dumb devices, that require software to do everything
DVBFE_ALGO_CUSTOM
Customizable Agorithm -
Devices having this algorithm can be customized to have specific
algorithms in the frontend driver, rather than simply doing a
software zig-zag. In this case the zigzag maybe hardware assisted
or it maybe completely done in hardware. In all cases, usage of
this algorithm, in conjunction with the search and track
callbacks, utilizes the driver specific algorithm.
DVBFE_ALGO_RECOVERY
Recovery Algorithm -
These devices have AUTO recovery capabilities from LOCK failure
callback function called when frontend is detached.
drivers should free any allocated memory.
init
callback function used to initialize the tuner device.
sleep
callback function used to put the tuner to sleep.
suspend
callback function used to inform that the Kernel will
suspend.
resume
callback function used to inform that the Kernel is
resuming from suspend.
set_params
callback function used to inform the tuner to tune
into a digital TV channel. The properties to be used
are stored at structdvb_frontend.dtv_property_cache.
The tuner demod can change the parameters to reflect
the changes needed for the channel to be tuned, and
update statistics. This is the recommended way to set
the tuner parameters and should be used on newer
drivers.
set_analog_params
callback function used to tune into an analog TV
channel on hybrid tuners. It passes analog_parameters
to the driver.
set_config
callback function used to send some tuner-specific
parameters.
get_frequency
get the actual tuned frequency
get_bandwidth
get the bandwidth used by the low pass filters
get_if_frequency
get the Intermediate Frequency, in Hz. For baseband,
should return 0.
get_status
returns the frontend lock status
get_rf_strength
returns the RF signal strength. Used mostly to support
analog TV and radio. Digital TV should report, instead,
via DVBv5 API (structdvb_frontend.dtv_property_cache).
get_afc
Used only by analog TV core. Reports the frequency
drift due to AFC.
calc_regs
callback function used to pass register data settings
for simple tuners. Shouldn’t be used on newer drivers.
set_frequency
Set a new frequency. Shouldn’t be used on newer drivers.
set_bandwidth
Set a new frequency. Shouldn’t be used on newer drivers.
NOTE
frequencies used on get_frequency and set_frequency are in Hz for
terrestrial/cable or kHz for satellite.
callback function used to inform the demod to set the
demodulator parameters needed to decode an analog or
radio channel. The properties are passed via
structanalog_params.
has_signal
returns 0xffff if has signal, or 0 if it doesn’t.
get_afc
Used only by analog TV core. Reports the frequency
drift due to AFC.
tuner_status
callback function that returns tuner status bits, e. g.
TUNER_STATUS_LOCKED and TUNER_STATUS_STEREO.
standby
set the tuner to standby mode.
release
callback function called when frontend is detached.
drivers should free any allocated memory.
i2c_gate_ctrl
controls the I2C gate. Newer drivers should use I2C
mux support instead.
set_config
callback function used to send some tuner-specific
parameters.
callback function called when frontend is detached.
drivers should clean up, but not yet free the structdvb_frontend allocation.
release
callback function called when frontend is ready to be
freed.
drivers should free any allocated memory.
release_sec
callback function requesting that the Satellite Equipment
Control (SEC) driver to release and free any memory
allocated by the driver.
init
callback function used to initialize the tuner device.
sleep
callback function used to put the tuner to sleep.
suspend
callback function used to inform that the Kernel will
suspend.
resume
callback function used to inform that the Kernel is
resuming from suspend.
write
callback function used by some demod legacy drivers to
allow other drivers to write data into their registers.
Should not be used on new drivers.
tune
callback function used by demod drivers that use
DVBFE_ALGO_HW to tune into a frequency.
get_frontend_algo
returns the desired hardware algorithm.
set_frontend
callback function used to inform the demod to set the
parameters for demodulating a digital TV channel.
The properties to be used are stored at structdvb_frontend.dtv_property_cache. The demod can change
the parameters to reflect the changes needed for the
channel to be decoded, and update statistics.
get_tune_settings
callback function
get_frontend
callback function used to inform the parameters
actuall in use. The properties to be used are stored at
structdvb_frontend.dtv_property_cache and update
statistics. Please notice that it should not return
an error code if the statistics are not available
because the demog is not locked.
read_status
returns the locking status of the frontend.
read_ber
legacy callback function to return the bit error rate.
Newer drivers should provide such info via DVBv5 API,
e. g. set_frontend;/get_frontend, implementing this
callback only if DVBv3 API compatibility is wanted.
read_signal_strength
legacy callback function to return the signal
strength. Newer drivers should provide such info via
DVBv5 API, e. g. set_frontend/get_frontend,
implementing this callback only if DVBv3 API
compatibility is wanted.
read_snr
legacy callback function to return the Signal/Noise
rate. Newer drivers should provide such info via
DVBv5 API, e. g. set_frontend/get_frontend,
implementing this callback only if DVBv3 API
compatibility is wanted.
read_ucblocks
legacy callback function to return the Uncorrected Error
Blocks. Newer drivers should provide such info via
DVBv5 API, e. g. set_frontend/get_frontend,
implementing this callback only if DVBv3 API
compatibility is wanted.
diseqc_reset_overload
callback function to implement the
FE_DISEQC_RESET_OVERLOAD() ioctl (only Satellite)
diseqc_send_master_cmd
callback function to implement the
FE_DISEQC_SEND_MASTER_CMD() ioctl (only Satellite).
diseqc_recv_slave_reply
callback function to implement the
FE_DISEQC_RECV_SLAVE_REPLY() ioctl (only Satellite)
diseqc_send_burst
callback function to implement the
FE_DISEQC_SEND_BURST() ioctl (only Satellite).
set_tone
callback function to implement the
FE_SET_TONE() ioctl (only Satellite).
set_voltage
callback function to implement the
FE_SET_VOLTAGE() ioctl (only Satellite).
enable_high_lnb_voltage
callback function to implement the
FE_ENABLE_HIGH_LNB_VOLTAGE() ioctl (only Satellite).
dishnetwork_send_legacy_command
callback function to implement the
FE_DISHNETWORK_SEND_LEGACY_CMD() ioctl (only Satellite).
Drivers should not use this, except when the DVB
core emulation fails to provide proper support (e.g.
if set_voltage takes more than 8ms to work), and
when backward compatibility with this legacy API is
required.
i2c_gate_ctrl
controls the I2C gate. Newer drivers should use I2C
mux support instead.
ts_bus_ctrl
callback function used to take control of the TS bus.
set_lna
callback function to power on/off/auto the LNA.
search
callback function used on some custom algo search algos.
If different than zero, enable substream filtering, if
hardware supports (DVB-S2 and DVB-T2).
scrambling_sequence_index
Carries the index of the DVB-S2 physical layer
scrambling sequence.
atscmh_fic_ver
Version number of the FIC (Fast Information Channel)
signaling data (only ATSC-M/H)
atscmh_parade_id
Parade identification number (only ATSC-M/H)
atscmh_nog
Number of MH groups per MH subframe for a designated
parade (only ATSC-M/H)
atscmh_tnog
Total number of MH groups including all MH groups
belonging to all MH parades in one MH subframe
(only ATSC-M/H)
atscmh_sgn
Start group number (only ATSC-M/H)
atscmh_prc
Parade repetition cycle (only ATSC-M/H)
atscmh_rs_frame_mode
Reed Solomon (RS) frame mode (only ATSC-M/H)
atscmh_rs_frame_ensemble
RS frame ensemble (only ATSC-M/H)
atscmh_rs_code_mode_pri
RS code mode pri (only ATSC-M/H)
atscmh_rs_code_mode_sec
RS code mode sec (only ATSC-M/H)
atscmh_sccc_block_mode
Series Concatenated Convolutional Code (SCCC)
Block Mode (only ATSC-M/H)
atscmh_sccc_code_mode_a
SCCC code mode A (only ATSC-M/H)
atscmh_sccc_code_mode_b
SCCC code mode B (only ATSC-M/H)
atscmh_sccc_code_mode_c
SCCC code mode C (only ATSC-M/H)
atscmh_sccc_code_mode_d
SCCC code mode D (only ATSC-M/H)
lna
Power ON/OFF/AUTO the Linear Now-noise Amplifier (LNA)
strength
DVBv5 API statistics: Signal Strength
cnr
DVBv5 API statistics: Signal to Noise ratio of the
(main) carrier
pre_bit_error
DVBv5 API statistics: pre-Viterbi bit error count
pre_bit_count
DVBv5 API statistics: pre-Viterbi bit count
post_bit_error
DVBv5 API statistics: post-Viterbi bit error count
post_bit_count
DVBv5 API statistics: post-Viterbi bit count
block_error
DVBv5 API statistics: block error count
block_count
DVBv5 API statistics: block count
NOTE
derivated statistics like Uncorrected Error blocks (UCE) are
calculated on userspace.
Description
Only a subset of the properties are needed for a given delivery system.
For more info, consult the media_api.html with the documentation of the
Userspace API.
Allocate and initialize the private data needed by the frontend core to
manage the frontend and calls dvb_register_device() to register a new
frontend. It also cleans the property cache that stores the frontend
parameters and selects the first available delivery system.
This function doesn’t frees the memory allocated by the demod,
by the SEC driver and by the tuner. In order to free it, an explicit call to
dvb_frontend_detach() is needed, after calling this function.
If the driver is compiled with CONFIG_MEDIA_ATTACH, it also decreases
the module reference count, needed to allow userspace to remove the
previously used DVB frontend modules.
Once tuner and demods are resumed, it will enforce that the SEC voltage and
tone are restored to their previous values and wake up the frontend’s
kthread in order to retune the frontend.
Sleep for the amount of time given by add_usec parameter
Parameters
ktime_t*waketime
pointer to structktime_t
u32add_usec
time to sleep, in microseconds
Description
This function is used to measure the time required for the
FE_DISHNETWORK_SEND_LEGACY_CMD() ioctl to work. It needs to be as precise
as possible, as it affects the detection of the dish tone command at the
satellite subsystem.
Its used internally by the DVB frontend core, in order to emulate
FE_DISHNETWORK_SEND_LEGACY_CMD() using the dvb_frontend_ops.set_voltage()
callback.
NOTE
it should not be used at the drivers, as the emulation for the
legacy callback is provided by the Kernel. The only situation where this
should be at the drivers is when there are some bugs at the hardware that
would prevent the core emulation to work. On such cases, the driver would
be writing a dvb_frontend_ops.dishnetwork_send_legacy_command() and
calling this function directly.