Commit f594139d authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull virtual digital TV driver fixes from Mauro Carvalho Chehab:
 "A series of fixes for the new virtual digital TV driver (vidtv), which
  is meant to help doing tests with the digital TV core and media
  userspace apps and libraries.

  They cover a series of issues I found on it, together with a few new
  things in order to make it easier to detect problems at the DVB core"

* tag 'media/v5.10-3' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (36 commits)
  media: vidtv.rst: add kernel-doc markups
  media: vidtv.rst: update vidtv documentation
  media: vidtv: simplify EIT write function
  media: vidtv: simplify NIT write function
  media: vidtv: simplify SDT write function
  media: vidtv: cleanup PMT write table function
  media: vidtv: cleanup PAT write function
  media: vidtv: cleanup PSI table header function
  media: vidtv: cleanup PSI descriptor write function
  media: vidtv: simplify the crc writing logic
  media: vidtv: simplify PSI write function
  media: vidtv: add date to the current event
  media: vidtv: fix service_id at SDT table
  media: vidtv: fix service type
  media: vidtv: add a PID entry for the NIT table
  media: vidtv: properly fill EIT service_id
  media: vidtv: fix the network ID range
  media: vidtv: improve EIT data
  media: vidtv: cleanup null packet initialization logic
  media: vidtv: pre-initialize mux arrays
  ...
parents 6910b676 44f28934
Loading
Loading
Loading
Loading
+104 −16
Original line number Diff line number Diff line
@@ -149,11 +149,11 @@ vidtv_psi.[ch]
	Because the generator is implemented in a separate file, it can be
	reused elsewhere in the media subsystem.

	Currently vidtv supports working with 3 PSI tables: PAT, PMT and
	SDT.
	Currently vidtv supports working with 5 PSI tables: PAT, PMT,
	SDT, NIT and EIT.

	The specification for PAT and PMT can be found in *ISO 13818-1:
	Systems*, while the specification for the SDT can be found in *ETSI
	Systems*, while the specification for the SDT, NIT, EIT can be found in *ETSI
	EN 300 468: Specification for Service Information (SI) in DVB
	systems*.

@@ -197,6 +197,8 @@ vidtv_channel.[ch]

	#. Their programs will be concatenated to populate the PAT

	#. Their events will be concatenated to populate the EIT

	#. For each program in the PAT, a PMT section will be created

	#. The PMT section for a channel will be assigned its streams.
@@ -256,6 +258,42 @@ Using dvb-fe-tool
The first step to check whether the demod loaded successfully is to run::

	$ dvb-fe-tool
	Device Dummy demod for DVB-T/T2/C/S/S2 (/dev/dvb/adapter0/frontend0) capabilities:
	    CAN_FEC_1_2
	    CAN_FEC_2_3
	    CAN_FEC_3_4
	    CAN_FEC_4_5
	    CAN_FEC_5_6
	    CAN_FEC_6_7
	    CAN_FEC_7_8
	    CAN_FEC_8_9
	    CAN_FEC_AUTO
	    CAN_GUARD_INTERVAL_AUTO
	    CAN_HIERARCHY_AUTO
	    CAN_INVERSION_AUTO
	    CAN_QAM_16
	    CAN_QAM_32
	    CAN_QAM_64
	    CAN_QAM_128
	    CAN_QAM_256
	    CAN_QAM_AUTO
	    CAN_QPSK
	    CAN_TRANSMISSION_MODE_AUTO
	DVB API Version 5.11, Current v5 delivery system: DVBC/ANNEX_A
	Supported delivery systems:
	    DVBT
	    DVBT2
	    [DVBC/ANNEX_A]
	    DVBS
	    DVBS2
	Frequency range for the current standard:
	From:            51.0 MHz
	To:              2.15 GHz
	Step:            62.5 kHz
	Tolerance:       29.5 MHz
	Symbol rate ranges for the current standard:
	From:            1.00 MBauds
	To:              45.0 MBauds

This should return what is currently set up at the demod struct, i.e.::

@@ -314,7 +352,7 @@ For this, one should provide a configuration file known as a 'scan file',
here's an example::

	[Channel]
	FREQUENCY = 330000000
	FREQUENCY = 474000000
	MODULATION = QAM/AUTO
	SYMBOL_RATE = 6940000
	INNER_FEC = AUTO
@@ -335,6 +373,14 @@ You can browse scan tables online here: `dvb-scan-tables
Assuming this channel is named 'channel.conf', you can then run::

	$ dvbv5-scan channel.conf
	dvbv5-scan ~/vidtv.conf
	ERROR    command BANDWIDTH_HZ (5) not found during retrieve
	Cannot calc frequency shift. Either bandwidth/symbol-rate is unavailable (yet).
	Scanning frequency #1 330000000
	    (0x00) Signal= -68.00dBm
	Scanning frequency #2 474000000
	Lock   (0x1f) Signal= -34.45dBm C/N= 33.74dB UCB= 0
	Service Beethoven, provider LinuxTV.org: digital television

For more information on dvb-scan, check its documentation online here:
`dvb-scan Documentation <https://www.linuxtv.org/wiki/index.php/Dvbscan>`_.
@@ -344,23 +390,38 @@ Using dvb-zap

dvbv5-zap is a command line tool that can be used to record MPEG-TS to disk. The
typical use is to tune into a channel and put it into record mode. The example
below - which is taken from the documentation - illustrates that::
below - which is taken from the documentation - illustrates that\ [1]_::

	$ dvbv5-zap -c dvb_channel.conf "trilhas sonoras" -r
	using demux '/dev/dvb/adapter0/demux0'
	$ dvbv5-zap -c dvb_channel.conf "beethoven" -o music.ts -P -t 10
	using demux 'dvb0.demux0'
	reading channels from file 'dvb_channel.conf'
	service has pid type 05:  204
	tuning to 573000000 Hz
	audio pid 104
	  dvb_set_pesfilter 104
	Lock   (0x1f) Quality= Good Signal= 100.00% C/N= -13.80dB UCB= 70 postBER= 3.14x10^-3 PER= 0
	DVR interface '/dev/dvb/adapter0/dvr0' can now be opened
	tuning to 474000000 Hz
	pass all PID's to TS
	dvb_set_pesfilter 8192
	dvb_dev_set_bufsize: buffer set to 6160384
	Lock   (0x1f) Quality= Good Signal= -34.66dBm C/N= 33.41dB UCB= 0 postBER= 0 preBER= 1.05x10^-3 PER= 0
	Lock   (0x1f) Quality= Good Signal= -34.57dBm C/N= 33.46dB UCB= 0 postBER= 0 preBER= 1.05x10^-3 PER= 0
	Record to file 'music.ts' started
	received 24587768 bytes (2401 Kbytes/sec)
	Lock   (0x1f) Quality= Good Signal= -34.42dBm C/N= 33.89dB UCB= 0 postBER= 0 preBER= 2.44x10^-3 PER= 0

.. [1] In this example, it records 10 seconds with all program ID's stored
       at the music.ts file.


The channel can be watched by playing the contents of the DVR interface, with
some player that recognizes the MPEG-TS format, such as *mplayer* or *vlc*.
The channel can be watched by playing the contents of the stream with some
player that  recognizes the MPEG-TS format, such as ``mplayer`` or ``vlc``.

By playing the contents of the stream one can visually inspect the workings of
vidtv, e.g.::
vidtv, e.g., to play a recorded TS file with::

	$ mplayer music.ts

or, alternatively, running this command on one terminal::

	$ dvbv5-zap -c dvb_channel.conf "beethoven" -P -r &

And, on a second terminal, playing the contents from DVR interface with::

	$ mplayer /dev/dvb/adapter0/dvr0

@@ -423,3 +484,30 @@ A nice addition is to simulate some noise when the signal quality is bad by:
- Updating the error statistics accordingly (e.g. BER, etc).

- Simulating some noise in the encoded data.

Functions and structs used within vidtv
---------------------------------------

.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_bridge.h

.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_channel.h

.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_demod.h

.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_encoder.h

.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_mux.h

.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_pes.h

.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_psi.h

.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_s302m.h

.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_ts.h

.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_tuner.h

.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_common.c

.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_tuner.c
+65 −51
Original line number Diff line number Diff line
@@ -4,36 +4,43 @@
 * validate the existing APIs in the media subsystem. It can also aid
 * developers working on userspace applications.
 *
 * When this module is loaded, it will attempt to modprobe 'dvb_vidtv_tuner' and 'dvb_vidtv_demod'.
 * When this module is loaded, it will attempt to modprobe 'dvb_vidtv_tuner'
 * and 'dvb_vidtv_demod'.
 *
 * Copyright (C) 2020 Daniel W. S. Almeida
 */

#include <linux/dev_printk.h>
#include <linux/moduleparam.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/dev_printk.h>
#include <linux/time.h>
#include <linux/types.h>
#include <linux/workqueue.h>

#include "vidtv_bridge.h"
#include "vidtv_common.h"
#include "vidtv_demod.h"
#include "vidtv_tuner.h"
#include "vidtv_ts.h"
#include "vidtv_mux.h"
#include "vidtv_common.h"
#include "vidtv_ts.h"
#include "vidtv_tuner.h"

//#define MUX_BUF_MAX_SZ
//#define MUX_BUF_MIN_SZ
#define MUX_BUF_MIN_SZ 90164
#define MUX_BUF_MAX_SZ (MUX_BUF_MIN_SZ * 10)
#define TUNER_DEFAULT_ADDR 0x68
#define DEMOD_DEFAULT_ADDR 0x60
#define VIDTV_DEFAULT_NETWORK_ID 0xff44
#define VIDTV_DEFAULT_NETWORK_NAME "LinuxTV.org"
#define VIDTV_DEFAULT_TS_ID 0x4081

/* LNBf fake parameters: ranges used by an Universal (extended) European LNBf */
#define LNB_CUT_FREQUENCY	11700000
#define LNB_LOW_FREQ		9750000
#define LNB_HIGH_FREQ		10600000

/*
 * The LNBf fake parameters here are the ranges used by an
 * Universal (extended) European LNBf, which is likely the most common LNBf
 * found on Satellite digital TV system nowadays.
 */
#define LNB_CUT_FREQUENCY	11700000	/* high IF frequency */
#define LNB_LOW_FREQ		9750000		/* low IF frequency */
#define LNB_HIGH_FREQ		10600000	/* transition frequency */

static unsigned int drop_tslock_prob_on_low_snr;
module_param(drop_tslock_prob_on_low_snr, uint, 0);
@@ -92,7 +99,8 @@ MODULE_PARM_DESC(si_period_msec, "How often to send SI packets. Default: 40ms");

static unsigned int pcr_period_msec = 40;
module_param(pcr_period_msec, uint, 0);
MODULE_PARM_DESC(pcr_period_msec, "How often to send PCR packets. Default: 40ms");
MODULE_PARM_DESC(pcr_period_msec,
		 "How often to send PCR packets. Default: 40ms");

static unsigned int mux_rate_kbytes_sec = 4096;
module_param(mux_rate_kbytes_sec, uint, 0);
@@ -104,16 +112,14 @@ MODULE_PARM_DESC(pcr_pid, "PCR PID for all channels: defaults to 0x200");

static unsigned int mux_buf_sz_pkts;
module_param(mux_buf_sz_pkts, uint, 0);
MODULE_PARM_DESC(mux_buf_sz_pkts, "Size for the internal mux buffer in multiples of 188 bytes");

#define MUX_BUF_MIN_SZ 90164
#define MUX_BUF_MAX_SZ (MUX_BUF_MIN_SZ * 10)
MODULE_PARM_DESC(mux_buf_sz_pkts,
		 "Size for the internal mux buffer in multiples of 188 bytes");

static u32 vidtv_bridge_mux_buf_sz_for_mux_rate(void)
{
	u32 max_elapsed_time_msecs =  VIDTV_MAX_SLEEP_USECS / USEC_PER_MSEC;
	u32 nbytes_expected;
	u32 mux_buf_sz = mux_buf_sz_pkts * TS_PACKET_LEN;
	u32 nbytes_expected;

	nbytes_expected = mux_rate_kbytes_sec;
	nbytes_expected *= max_elapsed_time_msecs;
@@ -143,14 +149,12 @@ static bool vidtv_bridge_check_demod_lock(struct vidtv_dvb *dvb, u32 n)
			  FE_HAS_LOCK);
}

static void
vidtv_bridge_on_new_pkts_avail(void *priv, u8 *buf, u32 npkts)
{
/*
	 * called on a separate thread by the mux when new packets become
	 * available
 * called on a separate thread by the mux when new packets become available
 */
	struct vidtv_dvb *dvb = (struct vidtv_dvb *)priv;
static void vidtv_bridge_on_new_pkts_avail(void *priv, u8 *buf, u32 npkts)
{
	struct vidtv_dvb *dvb = priv;

	/* drop packets if we lose the lock */
	if (vidtv_bridge_check_demod_lock(dvb, 0))
@@ -159,7 +163,17 @@ vidtv_bridge_on_new_pkts_avail(void *priv, u8 *buf, u32 npkts)

static int vidtv_start_streaming(struct vidtv_dvb *dvb)
{
	struct vidtv_mux_init_args mux_args = {0};
	struct vidtv_mux_init_args mux_args = {
		.mux_rate_kbytes_sec         = mux_rate_kbytes_sec,
		.on_new_packets_available_cb = vidtv_bridge_on_new_pkts_avail,
		.pcr_period_usecs            = pcr_period_msec * USEC_PER_MSEC,
		.si_period_usecs             = si_period_msec * USEC_PER_MSEC,
		.pcr_pid                     = pcr_pid,
		.transport_stream_id         = VIDTV_DEFAULT_TS_ID,
		.network_id                  = VIDTV_DEFAULT_NETWORK_ID,
		.network_name                = VIDTV_DEFAULT_NETWORK_NAME,
		.priv                        = dvb,
	};
	struct device *dev = &dvb->pdev->dev;
	u32 mux_buf_sz;

@@ -168,19 +182,17 @@ static int vidtv_start_streaming(struct vidtv_dvb *dvb)
		return 0;
	}

	mux_buf_sz = (mux_buf_sz_pkts) ? mux_buf_sz_pkts : vidtv_bridge_mux_buf_sz_for_mux_rate();
	if (mux_buf_sz_pkts)
		mux_buf_sz = mux_buf_sz_pkts;
	else
		mux_buf_sz = vidtv_bridge_mux_buf_sz_for_mux_rate();

	mux_args.mux_rate_kbytes_sec         = mux_rate_kbytes_sec;
	mux_args.on_new_packets_available_cb = vidtv_bridge_on_new_pkts_avail;
	mux_args.mux_buf_sz  = mux_buf_sz;
	mux_args.pcr_period_usecs            = pcr_period_msec * 1000;
	mux_args.si_period_usecs             = si_period_msec * 1000;
	mux_args.pcr_pid                     = pcr_pid;
	mux_args.transport_stream_id         = VIDTV_DEFAULT_TS_ID;
	mux_args.priv                        = dvb;

	dvb->streaming = true;
	dvb->mux = vidtv_mux_init(dvb->fe[0], dev, mux_args);
	dvb->mux = vidtv_mux_init(dvb->fe[0], dev, &mux_args);
	if (!dvb->mux)
		return -ENOMEM;
	vidtv_mux_start_thread(dvb->mux);

	dev_dbg_ratelimited(dev, "Started streaming\n");
@@ -204,8 +216,8 @@ static int vidtv_start_feed(struct dvb_demux_feed *feed)
{
	struct dvb_demux *demux = feed->demux;
	struct vidtv_dvb *dvb   = demux->priv;
	int rc;
	int ret;
	int rc;

	if (!demux->dmx.frontend)
		return -EINVAL;
@@ -243,9 +255,9 @@ static int vidtv_stop_feed(struct dvb_demux_feed *feed)

static struct dvb_frontend *vidtv_get_frontend_ptr(struct i2c_client *c)
{
	/* the demod will set this when its probe function runs */
	struct vidtv_demod_state *state = i2c_get_clientdata(c);

	/* the demod will set this when its probe function runs */
	return &state->frontend;
}

@@ -253,6 +265,11 @@ static int vidtv_master_xfer(struct i2c_adapter *i2c_adap,
			     struct i2c_msg msgs[],
			     int num)
{
	/*
	 * Right now, this virtual driver doesn't really send or receive
	 * messages from I2C. A real driver will require an implementation
	 * here.
	 */
	return 0;
}

@@ -320,11 +337,10 @@ static int vidtv_bridge_dmxdev_init(struct vidtv_dvb *dvb)

static int vidtv_bridge_probe_demod(struct vidtv_dvb *dvb, u32 n)
{
	struct vidtv_demod_config cfg = {};

	cfg.drop_tslock_prob_on_low_snr     = drop_tslock_prob_on_low_snr;
	cfg.recover_tslock_prob_on_good_snr = recover_tslock_prob_on_good_snr;

	struct vidtv_demod_config cfg = {
		.drop_tslock_prob_on_low_snr     = drop_tslock_prob_on_low_snr,
		.recover_tslock_prob_on_good_snr = recover_tslock_prob_on_good_snr,
	};
	dvb->i2c_client_demod[n] = dvb_module_probe("dvb_vidtv_demod",
						    NULL,
						    &dvb->i2c_adapter,
@@ -343,14 +359,14 @@ static int vidtv_bridge_probe_demod(struct vidtv_dvb *dvb, u32 n)

static int vidtv_bridge_probe_tuner(struct vidtv_dvb *dvb, u32 n)
{
	struct vidtv_tuner_config cfg = {};
	struct vidtv_tuner_config cfg = {
		.fe                       = dvb->fe[n],
		.mock_power_up_delay_msec = mock_power_up_delay_msec,
		.mock_tune_delay_msec     = mock_tune_delay_msec,
	};
	u32 freq;
	int i;

	cfg.fe                       = dvb->fe[n];
	cfg.mock_power_up_delay_msec = mock_power_up_delay_msec;
	cfg.mock_tune_delay_msec     = mock_tune_delay_msec;

	/* TODO: check if the frequencies are at a valid range */

	memcpy(cfg.vidtv_valid_dvb_t_freqs,
@@ -389,9 +405,7 @@ static int vidtv_bridge_probe_tuner(struct vidtv_dvb *dvb, u32 n)

static int vidtv_bridge_dvb_init(struct vidtv_dvb *dvb)
{
	int ret;
	int i;
	int j;
	int ret, i, j;

	ret = vidtv_bridge_i2c_register_adap(dvb);
	if (ret < 0)
+3 −1
Original line number Diff line number Diff line
@@ -20,9 +20,11 @@
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/types.h>

#include <media/dmxdev.h>
#include <media/dvb_demux.h>
#include <media/dvb_frontend.h>

#include "vidtv_mux.h"

/**
@@ -32,7 +34,7 @@
 * @adapter: Represents a DTV adapter. See 'dvb_register_adapter'.
 * @demux: The demux used by the dvb_dmx_swfilter_packets() call.
 * @dmx_dev: Represents a demux device.
 * @dmx_frontend: The frontends associated with the demux.
 * @dmx_fe: The frontends associated with the demux.
 * @i2c_adapter: The i2c_adapter associated with the bridge driver.
 * @i2c_client_demod: The i2c_clients associated with the demodulator modules.
 * @i2c_client_tuner: The i2c_clients associated with the tuner modules.
+274 −38

File changed.

Preview size limit exceeded, changes collapsed.

+8 −3
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@
 * When vidtv boots, it will create some hardcoded channels.
 * Their services will be concatenated to populate the SDT.
 * Their programs will be concatenated to populate the PAT
 * Their events will be concatenated to populate the EIT
 * For each program in the PAT, a PMT section will be created
 * The PMT section for a channel will be assigned its streams.
 * Every stream will have its corresponding encoder polled to produce TS packets
@@ -22,9 +23,10 @@
#define VIDTV_CHANNEL_H

#include <linux/types.h>
#include "vidtv_psi.h"

#include "vidtv_encoder.h"
#include "vidtv_mux.h"
#include "vidtv_psi.h"

/**
 * struct vidtv_channel - A 'channel' abstraction
@@ -37,6 +39,7 @@
 * Every stream will have its corresponding encoder polled to produce TS packets
 * These packets may be interleaved by the mux and then delivered to the bridge
 *
 * @name: name of the channel
 * @transport_stream_id: a number to identify the TS, chosen at will.
 * @service: A _single_ service. Will be concatenated into the SDT.
 * @program_num: The link between PAT, PMT and SDT.
@@ -44,6 +47,7 @@
 * Will be concatenated into the PAT.
 * @streams: A stream loop used to populate the PMT section for 'program'
 * @encoders: A encoder loop. There must be one encoder for each stream.
 * @events: Optional event information. This will feed into the EIT.
 * @next: Optionally chain this channel.
 */
struct vidtv_channel {
@@ -54,6 +58,7 @@ struct vidtv_channel {
	struct vidtv_psi_table_pat_program *program;
	struct vidtv_psi_table_pmt_stream *streams;
	struct vidtv_encoder *encoders;
	struct vidtv_psi_table_eit_event *events;
	struct vidtv_channel *next;
};

@@ -61,14 +66,14 @@ struct vidtv_channel {
 * vidtv_channel_si_init - Init the PSI tables from the channels in the mux
 * @m: The mux containing the channels.
 */
void vidtv_channel_si_init(struct vidtv_mux *m);
int vidtv_channel_si_init(struct vidtv_mux *m);
void vidtv_channel_si_destroy(struct vidtv_mux *m);

/**
 * vidtv_channels_init - Init hardcoded, fake 'channels'.
 * @m: The mux to store the channels into.
 */
void vidtv_channels_init(struct vidtv_mux *m);
int vidtv_channels_init(struct vidtv_mux *m);
struct vidtv_channel
*vidtv_channel_s302m_init(struct vidtv_channel *head, u16 transport_stream_id);
void vidtv_channels_destroy(struct vidtv_mux *m);
Loading