18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Vidtv serves as a reference DVB driver and helps validate the existing APIs
48c2ecf20Sopenharmony_ci * in the media subsystem. It can also aid developers working on userspace
58c2ecf20Sopenharmony_ci * applications.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * This file contains the multiplexer logic for TS packets from different
88c2ecf20Sopenharmony_ci * elementary streams
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * Loosely based on libavcodec/mpegtsenc.c
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * Copyright (C) 2020 Daniel W. S. Almeida
138c2ecf20Sopenharmony_ci */
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include <linux/delay.h>
168c2ecf20Sopenharmony_ci#include <linux/dev_printk.h>
178c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
188c2ecf20Sopenharmony_ci#include <linux/kernel.h>
198c2ecf20Sopenharmony_ci#include <linux/math64.h>
208c2ecf20Sopenharmony_ci#include <linux/ratelimit.h>
218c2ecf20Sopenharmony_ci#include <linux/slab.h>
228c2ecf20Sopenharmony_ci#include <linux/types.h>
238c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#include "vidtv_channel.h"
268c2ecf20Sopenharmony_ci#include "vidtv_common.h"
278c2ecf20Sopenharmony_ci#include "vidtv_encoder.h"
288c2ecf20Sopenharmony_ci#include "vidtv_mux.h"
298c2ecf20Sopenharmony_ci#include "vidtv_pes.h"
308c2ecf20Sopenharmony_ci#include "vidtv_psi.h"
318c2ecf20Sopenharmony_ci#include "vidtv_ts.h"
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistatic struct vidtv_mux_pid_ctx
348c2ecf20Sopenharmony_ci*vidtv_mux_get_pid_ctx(struct vidtv_mux *m, u16 pid)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	struct vidtv_mux_pid_ctx *ctx;
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	hash_for_each_possible(m->pid_ctx, ctx, h, pid)
398c2ecf20Sopenharmony_ci		if (ctx->pid == pid)
408c2ecf20Sopenharmony_ci			return ctx;
418c2ecf20Sopenharmony_ci	return NULL;
428c2ecf20Sopenharmony_ci}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistatic struct vidtv_mux_pid_ctx
458c2ecf20Sopenharmony_ci*vidtv_mux_create_pid_ctx_once(struct vidtv_mux *m, u16 pid)
468c2ecf20Sopenharmony_ci{
478c2ecf20Sopenharmony_ci	struct vidtv_mux_pid_ctx *ctx;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	ctx = vidtv_mux_get_pid_ctx(m, pid);
508c2ecf20Sopenharmony_ci	if (ctx)
518c2ecf20Sopenharmony_ci		return ctx;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
548c2ecf20Sopenharmony_ci	if (!ctx)
558c2ecf20Sopenharmony_ci		return NULL;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	ctx->pid = pid;
588c2ecf20Sopenharmony_ci	ctx->cc  = 0;
598c2ecf20Sopenharmony_ci	hash_add(m->pid_ctx, &ctx->h, pid);
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	return ctx;
628c2ecf20Sopenharmony_ci}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic void vidtv_mux_pid_ctx_destroy(struct vidtv_mux *m)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	struct vidtv_mux_pid_ctx *ctx;
678c2ecf20Sopenharmony_ci	struct hlist_node *tmp;
688c2ecf20Sopenharmony_ci	int bkt;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	hash_for_each_safe(m->pid_ctx, bkt, tmp, ctx, h) {
718c2ecf20Sopenharmony_ci		hash_del(&ctx->h);
728c2ecf20Sopenharmony_ci		kfree(ctx);
738c2ecf20Sopenharmony_ci	}
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic int vidtv_mux_pid_ctx_init(struct vidtv_mux *m)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	struct vidtv_psi_table_pat_program *p = m->si.pat->program;
798c2ecf20Sopenharmony_ci	u16 pid;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	hash_init(m->pid_ctx);
828c2ecf20Sopenharmony_ci	/* push the pcr pid ctx */
838c2ecf20Sopenharmony_ci	if (!vidtv_mux_create_pid_ctx_once(m, m->pcr_pid))
848c2ecf20Sopenharmony_ci		return -ENOMEM;
858c2ecf20Sopenharmony_ci	/* push the NULL packet pid ctx */
868c2ecf20Sopenharmony_ci	if (!vidtv_mux_create_pid_ctx_once(m, TS_NULL_PACKET_PID))
878c2ecf20Sopenharmony_ci		goto free;
888c2ecf20Sopenharmony_ci	/* push the PAT pid ctx */
898c2ecf20Sopenharmony_ci	if (!vidtv_mux_create_pid_ctx_once(m, VIDTV_PAT_PID))
908c2ecf20Sopenharmony_ci		goto free;
918c2ecf20Sopenharmony_ci	/* push the SDT pid ctx */
928c2ecf20Sopenharmony_ci	if (!vidtv_mux_create_pid_ctx_once(m, VIDTV_SDT_PID))
938c2ecf20Sopenharmony_ci		goto free;
948c2ecf20Sopenharmony_ci	/* push the NIT pid ctx */
958c2ecf20Sopenharmony_ci	if (!vidtv_mux_create_pid_ctx_once(m, VIDTV_NIT_PID))
968c2ecf20Sopenharmony_ci		goto free;
978c2ecf20Sopenharmony_ci	/* push the EIT pid ctx */
988c2ecf20Sopenharmony_ci	if (!vidtv_mux_create_pid_ctx_once(m, VIDTV_EIT_PID))
998c2ecf20Sopenharmony_ci		goto free;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	/* add a ctx for all PMT sections */
1028c2ecf20Sopenharmony_ci	while (p) {
1038c2ecf20Sopenharmony_ci		pid = vidtv_psi_get_pat_program_pid(p);
1048c2ecf20Sopenharmony_ci		vidtv_mux_create_pid_ctx_once(m, pid);
1058c2ecf20Sopenharmony_ci		p = p->next;
1068c2ecf20Sopenharmony_ci	}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	return 0;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_cifree:
1118c2ecf20Sopenharmony_ci	vidtv_mux_pid_ctx_destroy(m);
1128c2ecf20Sopenharmony_ci	return -ENOMEM;
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cistatic void vidtv_mux_update_clk(struct vidtv_mux *m)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	/* call this at every thread iteration */
1188c2ecf20Sopenharmony_ci	u64 elapsed_time;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	m->timing.past_jiffies = m->timing.current_jiffies;
1218c2ecf20Sopenharmony_ci	m->timing.current_jiffies = get_jiffies_64();
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	elapsed_time = jiffies_to_usecs(m->timing.current_jiffies -
1248c2ecf20Sopenharmony_ci					m->timing.past_jiffies);
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	/* update the 27Mhz clock proportionally to the elapsed time */
1278c2ecf20Sopenharmony_ci	m->timing.clk += (CLOCK_UNIT_27MHZ / USEC_PER_SEC) * elapsed_time;
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic u32 vidtv_mux_push_si(struct vidtv_mux *m)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	struct vidtv_psi_pat_write_args pat_args = {
1338c2ecf20Sopenharmony_ci		.buf                = m->mux_buf,
1348c2ecf20Sopenharmony_ci		.buf_sz             = m->mux_buf_sz,
1358c2ecf20Sopenharmony_ci		.pat                = m->si.pat,
1368c2ecf20Sopenharmony_ci	};
1378c2ecf20Sopenharmony_ci	struct vidtv_psi_pmt_write_args pmt_args = {
1388c2ecf20Sopenharmony_ci		.buf                = m->mux_buf,
1398c2ecf20Sopenharmony_ci		.buf_sz             = m->mux_buf_sz,
1408c2ecf20Sopenharmony_ci		.pcr_pid            = m->pcr_pid,
1418c2ecf20Sopenharmony_ci	};
1428c2ecf20Sopenharmony_ci	struct vidtv_psi_sdt_write_args sdt_args = {
1438c2ecf20Sopenharmony_ci		.buf                = m->mux_buf,
1448c2ecf20Sopenharmony_ci		.buf_sz             = m->mux_buf_sz,
1458c2ecf20Sopenharmony_ci		.sdt                = m->si.sdt,
1468c2ecf20Sopenharmony_ci	};
1478c2ecf20Sopenharmony_ci	struct vidtv_psi_nit_write_args nit_args = {
1488c2ecf20Sopenharmony_ci		.buf                = m->mux_buf,
1498c2ecf20Sopenharmony_ci		.buf_sz             = m->mux_buf_sz,
1508c2ecf20Sopenharmony_ci		.nit                = m->si.nit,
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	};
1538c2ecf20Sopenharmony_ci	struct vidtv_psi_eit_write_args eit_args = {
1548c2ecf20Sopenharmony_ci		.buf                = m->mux_buf,
1558c2ecf20Sopenharmony_ci		.buf_sz             = m->mux_buf_sz,
1568c2ecf20Sopenharmony_ci		.eit                = m->si.eit,
1578c2ecf20Sopenharmony_ci	};
1588c2ecf20Sopenharmony_ci	u32 initial_offset = m->mux_buf_offset;
1598c2ecf20Sopenharmony_ci	struct vidtv_mux_pid_ctx *pat_ctx;
1608c2ecf20Sopenharmony_ci	struct vidtv_mux_pid_ctx *pmt_ctx;
1618c2ecf20Sopenharmony_ci	struct vidtv_mux_pid_ctx *sdt_ctx;
1628c2ecf20Sopenharmony_ci	struct vidtv_mux_pid_ctx *nit_ctx;
1638c2ecf20Sopenharmony_ci	struct vidtv_mux_pid_ctx *eit_ctx;
1648c2ecf20Sopenharmony_ci	u32 nbytes;
1658c2ecf20Sopenharmony_ci	u16 pmt_pid;
1668c2ecf20Sopenharmony_ci	u32 i;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	pat_ctx = vidtv_mux_get_pid_ctx(m, VIDTV_PAT_PID);
1698c2ecf20Sopenharmony_ci	sdt_ctx = vidtv_mux_get_pid_ctx(m, VIDTV_SDT_PID);
1708c2ecf20Sopenharmony_ci	nit_ctx = vidtv_mux_get_pid_ctx(m, VIDTV_NIT_PID);
1718c2ecf20Sopenharmony_ci	eit_ctx = vidtv_mux_get_pid_ctx(m, VIDTV_EIT_PID);
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	pat_args.offset             = m->mux_buf_offset;
1748c2ecf20Sopenharmony_ci	pat_args.continuity_counter = &pat_ctx->cc;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	m->mux_buf_offset += vidtv_psi_pat_write_into(&pat_args);
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	for (i = 0; i < m->si.pat->num_pmt; ++i) {
1798c2ecf20Sopenharmony_ci		pmt_pid = vidtv_psi_pmt_get_pid(m->si.pmt_secs[i],
1808c2ecf20Sopenharmony_ci						m->si.pat);
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci		if (pmt_pid > TS_LAST_VALID_PID) {
1838c2ecf20Sopenharmony_ci			dev_warn_ratelimited(m->dev,
1848c2ecf20Sopenharmony_ci					     "PID: %d not found\n", pmt_pid);
1858c2ecf20Sopenharmony_ci			continue;
1868c2ecf20Sopenharmony_ci		}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci		pmt_ctx = vidtv_mux_get_pid_ctx(m, pmt_pid);
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci		pmt_args.offset             = m->mux_buf_offset;
1918c2ecf20Sopenharmony_ci		pmt_args.pmt                = m->si.pmt_secs[i];
1928c2ecf20Sopenharmony_ci		pmt_args.pid                = pmt_pid;
1938c2ecf20Sopenharmony_ci		pmt_args.continuity_counter = &pmt_ctx->cc;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci		/* write each section into buffer */
1968c2ecf20Sopenharmony_ci		m->mux_buf_offset += vidtv_psi_pmt_write_into(&pmt_args);
1978c2ecf20Sopenharmony_ci	}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	sdt_args.offset             = m->mux_buf_offset;
2008c2ecf20Sopenharmony_ci	sdt_args.continuity_counter = &sdt_ctx->cc;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	m->mux_buf_offset += vidtv_psi_sdt_write_into(&sdt_args);
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	nit_args.offset             = m->mux_buf_offset;
2058c2ecf20Sopenharmony_ci	nit_args.continuity_counter = &nit_ctx->cc;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	m->mux_buf_offset += vidtv_psi_nit_write_into(&nit_args);
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	eit_args.offset             = m->mux_buf_offset;
2108c2ecf20Sopenharmony_ci	eit_args.continuity_counter = &eit_ctx->cc;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	m->mux_buf_offset += vidtv_psi_eit_write_into(&eit_args);
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	nbytes = m->mux_buf_offset - initial_offset;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	m->num_streamed_si++;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	return nbytes;
2198c2ecf20Sopenharmony_ci}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_cistatic u32 vidtv_mux_push_pcr(struct vidtv_mux *m)
2228c2ecf20Sopenharmony_ci{
2238c2ecf20Sopenharmony_ci	struct pcr_write_args args = {};
2248c2ecf20Sopenharmony_ci	struct vidtv_mux_pid_ctx *ctx;
2258c2ecf20Sopenharmony_ci	u32 nbytes = 0;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	ctx                     = vidtv_mux_get_pid_ctx(m, m->pcr_pid);
2288c2ecf20Sopenharmony_ci	args.dest_buf           = m->mux_buf;
2298c2ecf20Sopenharmony_ci	args.pid                = m->pcr_pid;
2308c2ecf20Sopenharmony_ci	args.buf_sz             = m->mux_buf_sz;
2318c2ecf20Sopenharmony_ci	args.continuity_counter = &ctx->cc;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	/* the 27Mhz clock will feed both parts of the PCR bitfield */
2348c2ecf20Sopenharmony_ci	args.pcr = m->timing.clk;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	nbytes += vidtv_ts_pcr_write_into(args);
2378c2ecf20Sopenharmony_ci	m->mux_buf_offset += nbytes;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	m->num_streamed_pcr++;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	return nbytes;
2428c2ecf20Sopenharmony_ci}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_cistatic bool vidtv_mux_should_push_pcr(struct vidtv_mux *m)
2458c2ecf20Sopenharmony_ci{
2468c2ecf20Sopenharmony_ci	u64 next_pcr_at;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	if (m->num_streamed_pcr == 0)
2498c2ecf20Sopenharmony_ci		return true;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	next_pcr_at = m->timing.start_jiffies +
2528c2ecf20Sopenharmony_ci		      usecs_to_jiffies(m->num_streamed_pcr *
2538c2ecf20Sopenharmony_ci				       m->timing.pcr_period_usecs);
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	return time_after64(m->timing.current_jiffies, next_pcr_at);
2568c2ecf20Sopenharmony_ci}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_cistatic bool vidtv_mux_should_push_si(struct vidtv_mux *m)
2598c2ecf20Sopenharmony_ci{
2608c2ecf20Sopenharmony_ci	u64 next_si_at;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	if (m->num_streamed_si == 0)
2638c2ecf20Sopenharmony_ci		return true;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	next_si_at = m->timing.start_jiffies +
2668c2ecf20Sopenharmony_ci		     usecs_to_jiffies(m->num_streamed_si *
2678c2ecf20Sopenharmony_ci				      m->timing.si_period_usecs);
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	return time_after64(m->timing.current_jiffies, next_si_at);
2708c2ecf20Sopenharmony_ci}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_cistatic u32 vidtv_mux_packetize_access_units(struct vidtv_mux *m,
2738c2ecf20Sopenharmony_ci					    struct vidtv_encoder *e)
2748c2ecf20Sopenharmony_ci{
2758c2ecf20Sopenharmony_ci	struct pes_write_args args = {
2768c2ecf20Sopenharmony_ci		.dest_buf           = m->mux_buf,
2778c2ecf20Sopenharmony_ci		.dest_buf_sz        = m->mux_buf_sz,
2788c2ecf20Sopenharmony_ci		.pid                = be16_to_cpu(e->es_pid),
2798c2ecf20Sopenharmony_ci		.encoder_id         = e->id,
2808c2ecf20Sopenharmony_ci		.stream_id          = be16_to_cpu(e->stream_id),
2818c2ecf20Sopenharmony_ci		.send_pts           = true,  /* forbidden value '01'... */
2828c2ecf20Sopenharmony_ci		.send_dts           = false, /* ...for PTS_DTS flags    */
2838c2ecf20Sopenharmony_ci	};
2848c2ecf20Sopenharmony_ci	struct vidtv_access_unit *au = e->access_units;
2858c2ecf20Sopenharmony_ci	u32 initial_offset = m->mux_buf_offset;
2868c2ecf20Sopenharmony_ci	struct vidtv_mux_pid_ctx *pid_ctx;
2878c2ecf20Sopenharmony_ci	u32 nbytes = 0;
2888c2ecf20Sopenharmony_ci	u8 *buf = NULL;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	/* see SMPTE 302M clause 6.4 */
2918c2ecf20Sopenharmony_ci	if (args.encoder_id == S302M) {
2928c2ecf20Sopenharmony_ci		args.send_dts = false;
2938c2ecf20Sopenharmony_ci		args.send_pts = true;
2948c2ecf20Sopenharmony_ci	}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	pid_ctx = vidtv_mux_create_pid_ctx_once(m, be16_to_cpu(e->es_pid));
2978c2ecf20Sopenharmony_ci	args.continuity_counter = &pid_ctx->cc;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	while (au) {
3008c2ecf20Sopenharmony_ci		buf                  = e->encoder_buf + au->offset;
3018c2ecf20Sopenharmony_ci		args.from            = buf;
3028c2ecf20Sopenharmony_ci		args.access_unit_len = au->nbytes;
3038c2ecf20Sopenharmony_ci		args.dest_offset     = m->mux_buf_offset;
3048c2ecf20Sopenharmony_ci		args.pts             = au->pts;
3058c2ecf20Sopenharmony_ci		args.pcr	     = m->timing.clk;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci		m->mux_buf_offset += vidtv_pes_write_into(&args);
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci		au = au->next;
3108c2ecf20Sopenharmony_ci	}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	/*
3138c2ecf20Sopenharmony_ci	 * clear the encoder state once the ES data has been written to the mux
3148c2ecf20Sopenharmony_ci	 * buffer
3158c2ecf20Sopenharmony_ci	 */
3168c2ecf20Sopenharmony_ci	e->clear(e);
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	nbytes = m->mux_buf_offset - initial_offset;
3198c2ecf20Sopenharmony_ci	return nbytes;
3208c2ecf20Sopenharmony_ci}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_cistatic u32 vidtv_mux_poll_encoders(struct vidtv_mux *m)
3238c2ecf20Sopenharmony_ci{
3248c2ecf20Sopenharmony_ci	struct vidtv_channel *cur_chnl = m->channels;
3258c2ecf20Sopenharmony_ci	struct vidtv_encoder *e = NULL;
3268c2ecf20Sopenharmony_ci	u32 nbytes = 0;
3278c2ecf20Sopenharmony_ci	u32 au_nbytes;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	while (cur_chnl) {
3308c2ecf20Sopenharmony_ci		e = cur_chnl->encoders;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci		while (e) {
3338c2ecf20Sopenharmony_ci			e->encode(e);
3348c2ecf20Sopenharmony_ci			/* get the TS packets into the mux buffer */
3358c2ecf20Sopenharmony_ci			au_nbytes = vidtv_mux_packetize_access_units(m, e);
3368c2ecf20Sopenharmony_ci			nbytes += au_nbytes;
3378c2ecf20Sopenharmony_ci			m->mux_buf_offset += au_nbytes;
3388c2ecf20Sopenharmony_ci			/* grab next encoder */
3398c2ecf20Sopenharmony_ci			e = e->next;
3408c2ecf20Sopenharmony_ci		}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci		/* grab the next channel */
3438c2ecf20Sopenharmony_ci		cur_chnl = cur_chnl->next;
3448c2ecf20Sopenharmony_ci	}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	return nbytes;
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_cistatic u32 vidtv_mux_pad_with_nulls(struct vidtv_mux *m, u32 npkts)
3508c2ecf20Sopenharmony_ci{
3518c2ecf20Sopenharmony_ci	struct null_packet_write_args args = {
3528c2ecf20Sopenharmony_ci		.dest_buf           = m->mux_buf,
3538c2ecf20Sopenharmony_ci		.buf_sz             = m->mux_buf_sz,
3548c2ecf20Sopenharmony_ci		.dest_offset        = m->mux_buf_offset,
3558c2ecf20Sopenharmony_ci	};
3568c2ecf20Sopenharmony_ci	u32 initial_offset = m->mux_buf_offset;
3578c2ecf20Sopenharmony_ci	struct vidtv_mux_pid_ctx *ctx;
3588c2ecf20Sopenharmony_ci	u32 nbytes;
3598c2ecf20Sopenharmony_ci	u32 i;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	ctx = vidtv_mux_get_pid_ctx(m, TS_NULL_PACKET_PID);
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	args.continuity_counter = &ctx->cc;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	for (i = 0; i < npkts; ++i) {
3668c2ecf20Sopenharmony_ci		m->mux_buf_offset += vidtv_ts_null_write_into(args);
3678c2ecf20Sopenharmony_ci		args.dest_offset  = m->mux_buf_offset;
3688c2ecf20Sopenharmony_ci	}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	nbytes = m->mux_buf_offset - initial_offset;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	/* sanity check */
3738c2ecf20Sopenharmony_ci	if (nbytes != npkts * TS_PACKET_LEN)
3748c2ecf20Sopenharmony_ci		dev_err_ratelimited(m->dev, "%d != %d\n",
3758c2ecf20Sopenharmony_ci				    nbytes, npkts * TS_PACKET_LEN);
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	return nbytes;
3788c2ecf20Sopenharmony_ci}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_cistatic void vidtv_mux_clear(struct vidtv_mux *m)
3818c2ecf20Sopenharmony_ci{
3828c2ecf20Sopenharmony_ci	/* clear the packets currently in the mux */
3838c2ecf20Sopenharmony_ci	memset(m->mux_buf, 0, m->mux_buf_sz * sizeof(*m->mux_buf));
3848c2ecf20Sopenharmony_ci	/* point to the beginning of the buffer again */
3858c2ecf20Sopenharmony_ci	m->mux_buf_offset = 0;
3868c2ecf20Sopenharmony_ci}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci#define ERR_RATE 10000000
3898c2ecf20Sopenharmony_cistatic void vidtv_mux_tick(struct work_struct *work)
3908c2ecf20Sopenharmony_ci{
3918c2ecf20Sopenharmony_ci	struct vidtv_mux *m = container_of(work,
3928c2ecf20Sopenharmony_ci					   struct vidtv_mux,
3938c2ecf20Sopenharmony_ci					   mpeg_thread);
3948c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *c = &m->fe->dtv_property_cache;
3958c2ecf20Sopenharmony_ci	u32 tot_bits = 0;
3968c2ecf20Sopenharmony_ci	u32 nbytes;
3978c2ecf20Sopenharmony_ci	u32 npkts;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	while (m->streaming) {
4008c2ecf20Sopenharmony_ci		nbytes = 0;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci		vidtv_mux_update_clk(m);
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci		if (vidtv_mux_should_push_pcr(m))
4058c2ecf20Sopenharmony_ci			nbytes += vidtv_mux_push_pcr(m);
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci		if (vidtv_mux_should_push_si(m))
4088c2ecf20Sopenharmony_ci			nbytes += vidtv_mux_push_si(m);
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci		nbytes += vidtv_mux_poll_encoders(m);
4118c2ecf20Sopenharmony_ci		nbytes += vidtv_mux_pad_with_nulls(m, 256);
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci		npkts = nbytes / TS_PACKET_LEN;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci		/* if the buffer is not aligned there is a bug somewhere */
4168c2ecf20Sopenharmony_ci		if (nbytes % TS_PACKET_LEN)
4178c2ecf20Sopenharmony_ci			dev_err_ratelimited(m->dev, "Misaligned buffer\n");
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci		if (m->on_new_packets_available_cb)
4208c2ecf20Sopenharmony_ci			m->on_new_packets_available_cb(m->priv,
4218c2ecf20Sopenharmony_ci						       m->mux_buf,
4228c2ecf20Sopenharmony_ci						       npkts);
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci		vidtv_mux_clear(m);
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci		/*
4278c2ecf20Sopenharmony_ci		 * Update bytes and packet counts at DVBv5 stats
4288c2ecf20Sopenharmony_ci		 *
4298c2ecf20Sopenharmony_ci		 * For now, both pre and post bit counts are identical,
4308c2ecf20Sopenharmony_ci		 * but post BER count can be lower than pre BER, if the error
4318c2ecf20Sopenharmony_ci		 * correction logic discards packages.
4328c2ecf20Sopenharmony_ci		 */
4338c2ecf20Sopenharmony_ci		c->pre_bit_count.stat[0].uvalue = nbytes * 8;
4348c2ecf20Sopenharmony_ci		c->post_bit_count.stat[0].uvalue = nbytes * 8;
4358c2ecf20Sopenharmony_ci		c->block_count.stat[0].uvalue += npkts;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci		/*
4388c2ecf20Sopenharmony_ci		 * Even without any visible errors for the user, the pre-BER
4398c2ecf20Sopenharmony_ci		 * stats usually have an error range up to 1E-6. So,
4408c2ecf20Sopenharmony_ci		 * add some random error increment count to it.
4418c2ecf20Sopenharmony_ci		 *
4428c2ecf20Sopenharmony_ci		 * Please notice that this is a poor guy's implementation,
4438c2ecf20Sopenharmony_ci		 * as it will produce one corrected bit error every time
4448c2ecf20Sopenharmony_ci		 * ceil(total bytes / ERR_RATE) is incremented, without
4458c2ecf20Sopenharmony_ci		 * any sort of (pseudo-)randomness.
4468c2ecf20Sopenharmony_ci		 */
4478c2ecf20Sopenharmony_ci		tot_bits += nbytes * 8;
4488c2ecf20Sopenharmony_ci		if (tot_bits > ERR_RATE) {
4498c2ecf20Sopenharmony_ci			c->pre_bit_error.stat[0].uvalue++;
4508c2ecf20Sopenharmony_ci			tot_bits -= ERR_RATE;
4518c2ecf20Sopenharmony_ci		}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci		usleep_range(VIDTV_SLEEP_USECS, VIDTV_MAX_SLEEP_USECS);
4548c2ecf20Sopenharmony_ci	}
4558c2ecf20Sopenharmony_ci}
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_civoid vidtv_mux_start_thread(struct vidtv_mux *m)
4588c2ecf20Sopenharmony_ci{
4598c2ecf20Sopenharmony_ci	if (m->streaming) {
4608c2ecf20Sopenharmony_ci		dev_warn_ratelimited(m->dev, "Already streaming. Skipping.\n");
4618c2ecf20Sopenharmony_ci		return;
4628c2ecf20Sopenharmony_ci	}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	m->streaming = true;
4658c2ecf20Sopenharmony_ci	m->timing.start_jiffies = get_jiffies_64();
4668c2ecf20Sopenharmony_ci	schedule_work(&m->mpeg_thread);
4678c2ecf20Sopenharmony_ci}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_civoid vidtv_mux_stop_thread(struct vidtv_mux *m)
4708c2ecf20Sopenharmony_ci{
4718c2ecf20Sopenharmony_ci	if (m->streaming) {
4728c2ecf20Sopenharmony_ci		m->streaming = false; /* thread will quit */
4738c2ecf20Sopenharmony_ci		cancel_work_sync(&m->mpeg_thread);
4748c2ecf20Sopenharmony_ci	}
4758c2ecf20Sopenharmony_ci}
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_cistruct vidtv_mux *vidtv_mux_init(struct dvb_frontend *fe,
4788c2ecf20Sopenharmony_ci				 struct device *dev,
4798c2ecf20Sopenharmony_ci				 struct vidtv_mux_init_args *args)
4808c2ecf20Sopenharmony_ci{
4818c2ecf20Sopenharmony_ci	struct vidtv_mux *m;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	m = kzalloc(sizeof(*m), GFP_KERNEL);
4848c2ecf20Sopenharmony_ci	if (!m)
4858c2ecf20Sopenharmony_ci		return NULL;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	m->dev = dev;
4888c2ecf20Sopenharmony_ci	m->fe = fe;
4898c2ecf20Sopenharmony_ci	m->timing.pcr_period_usecs = args->pcr_period_usecs;
4908c2ecf20Sopenharmony_ci	m->timing.si_period_usecs  = args->si_period_usecs;
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	m->mux_rate_kbytes_sec = args->mux_rate_kbytes_sec;
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	m->on_new_packets_available_cb = args->on_new_packets_available_cb;
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	m->mux_buf = vzalloc(args->mux_buf_sz);
4978c2ecf20Sopenharmony_ci	if (!m->mux_buf)
4988c2ecf20Sopenharmony_ci		goto free_mux;
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	m->mux_buf_sz = args->mux_buf_sz;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	m->pcr_pid = args->pcr_pid;
5038c2ecf20Sopenharmony_ci	m->transport_stream_id = args->transport_stream_id;
5048c2ecf20Sopenharmony_ci	m->priv = args->priv;
5058c2ecf20Sopenharmony_ci	m->network_id = args->network_id;
5068c2ecf20Sopenharmony_ci	m->network_name = kstrdup(args->network_name, GFP_KERNEL);
5078c2ecf20Sopenharmony_ci	if (!m->network_name)
5088c2ecf20Sopenharmony_ci		goto free_mux_buf;
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	m->timing.current_jiffies = get_jiffies_64();
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	if (args->channels)
5138c2ecf20Sopenharmony_ci		m->channels = args->channels;
5148c2ecf20Sopenharmony_ci	else
5158c2ecf20Sopenharmony_ci		if (vidtv_channels_init(m) < 0)
5168c2ecf20Sopenharmony_ci			goto free_mux_network_name;
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	/* will alloc data for pmt_sections after initializing pat */
5198c2ecf20Sopenharmony_ci	if (vidtv_channel_si_init(m) < 0)
5208c2ecf20Sopenharmony_ci		goto free_channels;
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	INIT_WORK(&m->mpeg_thread, vidtv_mux_tick);
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	if (vidtv_mux_pid_ctx_init(m) < 0)
5258c2ecf20Sopenharmony_ci		goto free_channel_si;
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	return m;
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_cifree_channel_si:
5308c2ecf20Sopenharmony_ci	vidtv_channel_si_destroy(m);
5318c2ecf20Sopenharmony_cifree_channels:
5328c2ecf20Sopenharmony_ci	vidtv_channels_destroy(m);
5338c2ecf20Sopenharmony_cifree_mux_network_name:
5348c2ecf20Sopenharmony_ci	kfree(m->network_name);
5358c2ecf20Sopenharmony_cifree_mux_buf:
5368c2ecf20Sopenharmony_ci	vfree(m->mux_buf);
5378c2ecf20Sopenharmony_cifree_mux:
5388c2ecf20Sopenharmony_ci	kfree(m);
5398c2ecf20Sopenharmony_ci	return NULL;
5408c2ecf20Sopenharmony_ci}
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_civoid vidtv_mux_destroy(struct vidtv_mux *m)
5438c2ecf20Sopenharmony_ci{
5448c2ecf20Sopenharmony_ci	vidtv_mux_stop_thread(m);
5458c2ecf20Sopenharmony_ci	vidtv_mux_pid_ctx_destroy(m);
5468c2ecf20Sopenharmony_ci	vidtv_channel_si_destroy(m);
5478c2ecf20Sopenharmony_ci	vidtv_channels_destroy(m);
5488c2ecf20Sopenharmony_ci	kfree(m->network_name);
5498c2ecf20Sopenharmony_ci	vfree(m->mux_buf);
5508c2ecf20Sopenharmony_ci	kfree(m);
5518c2ecf20Sopenharmony_ci}
552