162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * The Virtual DVB test driver serves as a reference DVB driver and helps 462306a36Sopenharmony_ci * validate the existing APIs in the media subsystem. It can also aid 562306a36Sopenharmony_ci * developers working on userspace applications. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 2020 Daniel W. S. Almeida 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ":%s, %d: " fmt, __func__, __LINE__ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/math64.h> 1362306a36Sopenharmony_ci#include <linux/printk.h> 1462306a36Sopenharmony_ci#include <linux/ratelimit.h> 1562306a36Sopenharmony_ci#include <linux/types.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "vidtv_common.h" 1862306a36Sopenharmony_ci#include "vidtv_ts.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic u32 vidtv_ts_write_pcr_bits(u8 *to, u32 to_offset, u64 pcr) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci /* Exact same from ffmpeg. PCR is a counter driven by a 27Mhz clock */ 2362306a36Sopenharmony_ci u64 div; 2462306a36Sopenharmony_ci u64 rem; 2562306a36Sopenharmony_ci u8 *buf = to + to_offset; 2662306a36Sopenharmony_ci u64 pcr_low; 2762306a36Sopenharmony_ci u64 pcr_high; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci div = div64_u64_rem(pcr, 300, &rem); 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci pcr_low = rem; /* pcr_low = pcr % 300 */ 3262306a36Sopenharmony_ci pcr_high = div; /* pcr_high = pcr / 300 */ 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci *buf++ = pcr_high >> 25; 3562306a36Sopenharmony_ci *buf++ = pcr_high >> 17; 3662306a36Sopenharmony_ci *buf++ = pcr_high >> 9; 3762306a36Sopenharmony_ci *buf++ = pcr_high >> 1; 3862306a36Sopenharmony_ci *buf++ = pcr_high << 7 | pcr_low >> 8 | 0x7e; 3962306a36Sopenharmony_ci *buf++ = pcr_low; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci return 6; 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_civoid vidtv_ts_inc_cc(u8 *continuity_counter) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci ++*continuity_counter; 4762306a36Sopenharmony_ci if (*continuity_counter > TS_CC_MAX_VAL) 4862306a36Sopenharmony_ci *continuity_counter = 0; 4962306a36Sopenharmony_ci} 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ciu32 vidtv_ts_null_write_into(struct null_packet_write_args args) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci u32 nbytes = 0; 5462306a36Sopenharmony_ci struct vidtv_mpeg_ts ts_header = {}; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci ts_header.sync_byte = TS_SYNC_BYTE; 5762306a36Sopenharmony_ci ts_header.bitfield = cpu_to_be16(TS_NULL_PACKET_PID); 5862306a36Sopenharmony_ci ts_header.payload = 1; 5962306a36Sopenharmony_ci ts_header.continuity_counter = *args.continuity_counter; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci /* copy TS header */ 6262306a36Sopenharmony_ci nbytes += vidtv_memcpy(args.dest_buf, 6362306a36Sopenharmony_ci args.dest_offset + nbytes, 6462306a36Sopenharmony_ci args.buf_sz, 6562306a36Sopenharmony_ci &ts_header, 6662306a36Sopenharmony_ci sizeof(ts_header)); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci vidtv_ts_inc_cc(args.continuity_counter); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci /* fill the rest with empty data */ 7162306a36Sopenharmony_ci nbytes += vidtv_memset(args.dest_buf, 7262306a36Sopenharmony_ci args.dest_offset + nbytes, 7362306a36Sopenharmony_ci args.buf_sz, 7462306a36Sopenharmony_ci TS_FILL_BYTE, 7562306a36Sopenharmony_ci TS_PACKET_LEN - nbytes); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci /* we should have written exactly _one_ 188byte packet */ 7862306a36Sopenharmony_ci if (nbytes != TS_PACKET_LEN) 7962306a36Sopenharmony_ci pr_warn_ratelimited("Expected exactly %d bytes, got %d\n", 8062306a36Sopenharmony_ci TS_PACKET_LEN, 8162306a36Sopenharmony_ci nbytes); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci return nbytes; 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ciu32 vidtv_ts_pcr_write_into(struct pcr_write_args args) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci u32 nbytes = 0; 8962306a36Sopenharmony_ci struct vidtv_mpeg_ts ts_header = {}; 9062306a36Sopenharmony_ci struct vidtv_mpeg_ts_adaption ts_adap = {}; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci ts_header.sync_byte = TS_SYNC_BYTE; 9362306a36Sopenharmony_ci ts_header.bitfield = cpu_to_be16(args.pid); 9462306a36Sopenharmony_ci ts_header.scrambling = 0; 9562306a36Sopenharmony_ci /* cc is not incremented, but it is needed. see 13818-1 clause 2.4.3.3 */ 9662306a36Sopenharmony_ci ts_header.continuity_counter = *args.continuity_counter; 9762306a36Sopenharmony_ci ts_header.payload = 0; 9862306a36Sopenharmony_ci ts_header.adaptation_field = 1; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci /* 13818-1 clause 2.4.3.5 */ 10162306a36Sopenharmony_ci ts_adap.length = 183; 10262306a36Sopenharmony_ci ts_adap.PCR = 1; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci /* copy TS header */ 10562306a36Sopenharmony_ci nbytes += vidtv_memcpy(args.dest_buf, 10662306a36Sopenharmony_ci args.dest_offset + nbytes, 10762306a36Sopenharmony_ci args.buf_sz, 10862306a36Sopenharmony_ci &ts_header, 10962306a36Sopenharmony_ci sizeof(ts_header)); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci /* write the adap after the TS header */ 11262306a36Sopenharmony_ci nbytes += vidtv_memcpy(args.dest_buf, 11362306a36Sopenharmony_ci args.dest_offset + nbytes, 11462306a36Sopenharmony_ci args.buf_sz, 11562306a36Sopenharmony_ci &ts_adap, 11662306a36Sopenharmony_ci sizeof(ts_adap)); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci /* write the PCR optional */ 11962306a36Sopenharmony_ci nbytes += vidtv_ts_write_pcr_bits(args.dest_buf, 12062306a36Sopenharmony_ci args.dest_offset + nbytes, 12162306a36Sopenharmony_ci args.pcr); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci nbytes += vidtv_memset(args.dest_buf, 12462306a36Sopenharmony_ci args.dest_offset + nbytes, 12562306a36Sopenharmony_ci args.buf_sz, 12662306a36Sopenharmony_ci TS_FILL_BYTE, 12762306a36Sopenharmony_ci TS_PACKET_LEN - nbytes); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci /* we should have written exactly _one_ 188byte packet */ 13062306a36Sopenharmony_ci if (nbytes != TS_PACKET_LEN) 13162306a36Sopenharmony_ci pr_warn_ratelimited("Expected exactly %d bytes, got %d\n", 13262306a36Sopenharmony_ci TS_PACKET_LEN, 13362306a36Sopenharmony_ci nbytes); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci return nbytes; 13662306a36Sopenharmony_ci} 137