1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * The Virtual DVB test driver serves as a reference DVB driver and helps
4*4882a593Smuzhiyun * validate the existing APIs in the media subsystem. It can also aid
5*4882a593Smuzhiyun * developers working on userspace applications.
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Copyright (C) 2020 Daniel W. S. Almeida
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ":%s, %d: " fmt, __func__, __LINE__
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #include <linux/math64.h>
13*4882a593Smuzhiyun #include <linux/printk.h>
14*4882a593Smuzhiyun #include <linux/ratelimit.h>
15*4882a593Smuzhiyun #include <linux/types.h>
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #include "vidtv_common.h"
18*4882a593Smuzhiyun #include "vidtv_ts.h"
19*4882a593Smuzhiyun
vidtv_ts_write_pcr_bits(u8 * to,u32 to_offset,u64 pcr)20*4882a593Smuzhiyun static u32 vidtv_ts_write_pcr_bits(u8 *to, u32 to_offset, u64 pcr)
21*4882a593Smuzhiyun {
22*4882a593Smuzhiyun /* Exact same from ffmpeg. PCR is a counter driven by a 27Mhz clock */
23*4882a593Smuzhiyun u64 div;
24*4882a593Smuzhiyun u64 rem;
25*4882a593Smuzhiyun u8 *buf = to + to_offset;
26*4882a593Smuzhiyun u64 pcr_low;
27*4882a593Smuzhiyun u64 pcr_high;
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun div = div64_u64_rem(pcr, 300, &rem);
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun pcr_low = rem; /* pcr_low = pcr % 300 */
32*4882a593Smuzhiyun pcr_high = div; /* pcr_high = pcr / 300 */
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun *buf++ = pcr_high >> 25;
35*4882a593Smuzhiyun *buf++ = pcr_high >> 17;
36*4882a593Smuzhiyun *buf++ = pcr_high >> 9;
37*4882a593Smuzhiyun *buf++ = pcr_high >> 1;
38*4882a593Smuzhiyun *buf++ = pcr_high << 7 | pcr_low >> 8 | 0x7e;
39*4882a593Smuzhiyun *buf++ = pcr_low;
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun return 6;
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun
vidtv_ts_inc_cc(u8 * continuity_counter)44*4882a593Smuzhiyun void vidtv_ts_inc_cc(u8 *continuity_counter)
45*4882a593Smuzhiyun {
46*4882a593Smuzhiyun ++*continuity_counter;
47*4882a593Smuzhiyun if (*continuity_counter > TS_CC_MAX_VAL)
48*4882a593Smuzhiyun *continuity_counter = 0;
49*4882a593Smuzhiyun }
50*4882a593Smuzhiyun
vidtv_ts_null_write_into(struct null_packet_write_args args)51*4882a593Smuzhiyun u32 vidtv_ts_null_write_into(struct null_packet_write_args args)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun u32 nbytes = 0;
54*4882a593Smuzhiyun struct vidtv_mpeg_ts ts_header = {};
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun ts_header.sync_byte = TS_SYNC_BYTE;
57*4882a593Smuzhiyun ts_header.bitfield = cpu_to_be16(TS_NULL_PACKET_PID);
58*4882a593Smuzhiyun ts_header.payload = 1;
59*4882a593Smuzhiyun ts_header.continuity_counter = *args.continuity_counter;
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun /* copy TS header */
62*4882a593Smuzhiyun nbytes += vidtv_memcpy(args.dest_buf,
63*4882a593Smuzhiyun args.dest_offset + nbytes,
64*4882a593Smuzhiyun args.buf_sz,
65*4882a593Smuzhiyun &ts_header,
66*4882a593Smuzhiyun sizeof(ts_header));
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun vidtv_ts_inc_cc(args.continuity_counter);
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun /* fill the rest with empty data */
71*4882a593Smuzhiyun nbytes += vidtv_memset(args.dest_buf,
72*4882a593Smuzhiyun args.dest_offset + nbytes,
73*4882a593Smuzhiyun args.buf_sz,
74*4882a593Smuzhiyun TS_FILL_BYTE,
75*4882a593Smuzhiyun TS_PACKET_LEN - nbytes);
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun /* we should have written exactly _one_ 188byte packet */
78*4882a593Smuzhiyun if (nbytes != TS_PACKET_LEN)
79*4882a593Smuzhiyun pr_warn_ratelimited("Expected exactly %d bytes, got %d\n",
80*4882a593Smuzhiyun TS_PACKET_LEN,
81*4882a593Smuzhiyun nbytes);
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun return nbytes;
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun
vidtv_ts_pcr_write_into(struct pcr_write_args args)86*4882a593Smuzhiyun u32 vidtv_ts_pcr_write_into(struct pcr_write_args args)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun u32 nbytes = 0;
89*4882a593Smuzhiyun struct vidtv_mpeg_ts ts_header = {};
90*4882a593Smuzhiyun struct vidtv_mpeg_ts_adaption ts_adap = {};
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun ts_header.sync_byte = TS_SYNC_BYTE;
93*4882a593Smuzhiyun ts_header.bitfield = cpu_to_be16(args.pid);
94*4882a593Smuzhiyun ts_header.scrambling = 0;
95*4882a593Smuzhiyun /* cc is not incremented, but it is needed. see 13818-1 clause 2.4.3.3 */
96*4882a593Smuzhiyun ts_header.continuity_counter = *args.continuity_counter;
97*4882a593Smuzhiyun ts_header.payload = 0;
98*4882a593Smuzhiyun ts_header.adaptation_field = 1;
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun /* 13818-1 clause 2.4.3.5 */
101*4882a593Smuzhiyun ts_adap.length = 183;
102*4882a593Smuzhiyun ts_adap.PCR = 1;
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun /* copy TS header */
105*4882a593Smuzhiyun nbytes += vidtv_memcpy(args.dest_buf,
106*4882a593Smuzhiyun args.dest_offset + nbytes,
107*4882a593Smuzhiyun args.buf_sz,
108*4882a593Smuzhiyun &ts_header,
109*4882a593Smuzhiyun sizeof(ts_header));
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun /* write the adap after the TS header */
112*4882a593Smuzhiyun nbytes += vidtv_memcpy(args.dest_buf,
113*4882a593Smuzhiyun args.dest_offset + nbytes,
114*4882a593Smuzhiyun args.buf_sz,
115*4882a593Smuzhiyun &ts_adap,
116*4882a593Smuzhiyun sizeof(ts_adap));
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun /* write the PCR optional */
119*4882a593Smuzhiyun nbytes += vidtv_ts_write_pcr_bits(args.dest_buf,
120*4882a593Smuzhiyun args.dest_offset + nbytes,
121*4882a593Smuzhiyun args.pcr);
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun nbytes += vidtv_memset(args.dest_buf,
124*4882a593Smuzhiyun args.dest_offset + nbytes,
125*4882a593Smuzhiyun args.buf_sz,
126*4882a593Smuzhiyun TS_FILL_BYTE,
127*4882a593Smuzhiyun TS_PACKET_LEN - nbytes);
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun /* we should have written exactly _one_ 188byte packet */
130*4882a593Smuzhiyun if (nbytes != TS_PACKET_LEN)
131*4882a593Smuzhiyun pr_warn_ratelimited("Expected exactly %d bytes, got %d\n",
132*4882a593Smuzhiyun TS_PACKET_LEN,
133*4882a593Smuzhiyun nbytes);
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun return nbytes;
136*4882a593Smuzhiyun }
137