1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Vidtv serves as a reference DVB driver and helps validate the existing APIs 4 * in the media subsystem. It can also aid developers working on userspace 5 * applications. 6 * 7 * This file contains the code for a 'channel' abstraction. 8 * 9 * When vidtv boots, it will create some hardcoded channels. 10 * Their services will be concatenated to populate the SDT. 11 * Their programs will be concatenated to populate the PAT 12 * For each program in the PAT, a PMT section will be created 13 * The PMT section for a channel will be assigned its streams. 14 * Every stream will have its corresponding encoder polled to produce TS packets 15 * These packets may be interleaved by the mux and then delivered to the bridge 16 * 17 * 18 * Copyright (C) 2020 Daniel W. S. Almeida 19 */ 20 21 #include <linux/types.h> 22 #include <linux/slab.h> 23 #include <linux/dev_printk.h> 24 #include <linux/ratelimit.h> 25 26 #include "vidtv_channel.h" 27 #include "vidtv_psi.h" 28 #include "vidtv_encoder.h" 29 #include "vidtv_mux.h" 30 #include "vidtv_common.h" 31 #include "vidtv_s302m.h" 32 33 static void vidtv_channel_encoder_destroy(struct vidtv_encoder *e) 34 { 35 struct vidtv_encoder *curr = e; 36 struct vidtv_encoder *tmp = NULL; 37 38 while (curr) { 39 /* forward the call to the derived type */ 40 tmp = curr; 41 curr = curr->next; 42 tmp->destroy(tmp); 43 } 44 } 45 46 #define ENCODING_ISO8859_15 "\x0b" 47 48 struct vidtv_channel 49 *vidtv_channel_s302m_init(struct vidtv_channel *head, u16 transport_stream_id) 50 { 51 /* 52 * init an audio only channel with a s302m encoder 53 */ 54 const u16 s302m_service_id = 0x880; 55 const u16 s302m_program_num = 0x880; 56 const u16 s302m_program_pid = 0x101; /* packet id for PMT*/ 57 const u16 s302m_es_pid = 0x111; /* packet id for the ES */ 58 const __be32 s302m_fid = cpu_to_be32(VIDTV_S302M_FORMAT_IDENTIFIER); 59 60 char *name = ENCODING_ISO8859_15 "Beethoven"; 61 char *provider = ENCODING_ISO8859_15 "LinuxTV.org"; 62 63 struct vidtv_channel *s302m = kzalloc(sizeof(*s302m), GFP_KERNEL); 64 struct vidtv_s302m_encoder_init_args encoder_args = {}; 65 66 s302m->name = kstrdup(name, GFP_KERNEL); 67 68 s302m->service = vidtv_psi_sdt_service_init(NULL, s302m_service_id); 69 70 s302m->service->descriptor = (struct vidtv_psi_desc *) 71 vidtv_psi_service_desc_init(NULL, 72 DIGITAL_TELEVISION_SERVICE, 73 name, 74 provider); 75 76 s302m->transport_stream_id = transport_stream_id; 77 78 s302m->program = vidtv_psi_pat_program_init(NULL, 79 s302m_service_id, 80 s302m_program_pid); 81 82 s302m->program_num = s302m_program_num; 83 84 s302m->streams = vidtv_psi_pmt_stream_init(NULL, 85 STREAM_PRIVATE_DATA, 86 s302m_es_pid); 87 88 s302m->streams->descriptor = (struct vidtv_psi_desc *) 89 vidtv_psi_registration_desc_init(NULL, 90 s302m_fid, 91 NULL, 92 0); 93 encoder_args.es_pid = s302m_es_pid; 94 95 s302m->encoders = vidtv_s302m_encoder_init(encoder_args); 96 97 if (head) { 98 while (head->next) 99 head = head->next; 100 101 head->next = s302m; 102 } 103 104 return s302m; 105 } 106 107 static struct vidtv_psi_table_sdt_service 108 *vidtv_channel_sdt_serv_cat_into_new(struct vidtv_mux *m) 109 { 110 /* Concatenate the services */ 111 const struct vidtv_channel *cur_chnl = m->channels; 112 113 struct vidtv_psi_table_sdt_service *curr = NULL; 114 struct vidtv_psi_table_sdt_service *head = NULL; 115 struct vidtv_psi_table_sdt_service *tail = NULL; 116 117 struct vidtv_psi_desc *desc = NULL; 118 u16 service_id; 119 120 if (!cur_chnl) 121 return NULL; 122 123 while (cur_chnl) { 124 curr = cur_chnl->service; 125 126 if (!curr) 127 dev_warn_ratelimited(m->dev, 128 "No services found for channel %s\n", cur_chnl->name); 129 130 while (curr) { 131 service_id = be16_to_cpu(curr->service_id); 132 tail = vidtv_psi_sdt_service_init(tail, service_id); 133 134 desc = vidtv_psi_desc_clone(curr->descriptor); 135 vidtv_psi_desc_assign(&tail->descriptor, desc); 136 137 if (!head) 138 head = tail; 139 140 curr = curr->next; 141 } 142 143 cur_chnl = cur_chnl->next; 144 } 145 146 return head; 147 } 148 149 static struct vidtv_psi_table_pat_program* 150 vidtv_channel_pat_prog_cat_into_new(struct vidtv_mux *m) 151 { 152 /* Concatenate the programs */ 153 const struct vidtv_channel *cur_chnl = m->channels; 154 struct vidtv_psi_table_pat_program *curr = NULL; 155 struct vidtv_psi_table_pat_program *head = NULL; 156 struct vidtv_psi_table_pat_program *tail = NULL; 157 u16 serv_id; 158 u16 pid; 159 160 if (!cur_chnl) 161 return NULL; 162 163 while (cur_chnl) { 164 curr = cur_chnl->program; 165 166 if (!curr) 167 dev_warn_ratelimited(m->dev, 168 "No programs found for channel %s\n", 169 cur_chnl->name); 170 171 while (curr) { 172 serv_id = be16_to_cpu(curr->service_id); 173 pid = vidtv_psi_get_pat_program_pid(curr); 174 tail = vidtv_psi_pat_program_init(tail, 175 serv_id, 176 pid); 177 178 if (!head) 179 head = tail; 180 181 curr = curr->next; 182 } 183 184 cur_chnl = cur_chnl->next; 185 } 186 187 return head; 188 } 189 190 static void 191 vidtv_channel_pmt_match_sections(struct vidtv_channel *channels, 192 struct vidtv_psi_table_pmt **sections, 193 u32 nsections) 194 { 195 /* 196 * Match channels to their respective PMT sections, then assign the 197 * streams 198 */ 199 struct vidtv_psi_table_pmt *curr_section = NULL; 200 struct vidtv_channel *cur_chnl = channels; 201 202 struct vidtv_psi_table_pmt_stream *s = NULL; 203 struct vidtv_psi_table_pmt_stream *head = NULL; 204 struct vidtv_psi_table_pmt_stream *tail = NULL; 205 206 struct vidtv_psi_desc *desc = NULL; 207 u32 j; 208 u16 curr_id; 209 u16 e_pid; /* elementary stream pid */ 210 211 while (cur_chnl) { 212 for (j = 0; j < nsections; ++j) { 213 curr_section = sections[j]; 214 215 if (!curr_section) 216 continue; 217 218 curr_id = be16_to_cpu(curr_section->header.id); 219 220 /* we got a match */ 221 if (curr_id == cur_chnl->program_num) { 222 s = cur_chnl->streams; 223 224 /* clone the streams for the PMT */ 225 while (s) { 226 e_pid = vidtv_psi_pmt_stream_get_elem_pid(s); 227 tail = vidtv_psi_pmt_stream_init(tail, 228 s->type, 229 e_pid); 230 231 if (!head) 232 head = tail; 233 234 desc = vidtv_psi_desc_clone(s->descriptor); 235 vidtv_psi_desc_assign(&tail->descriptor, desc); 236 237 s = s->next; 238 } 239 240 vidtv_psi_pmt_stream_assign(curr_section, head); 241 break; 242 } 243 } 244 245 cur_chnl = cur_chnl->next; 246 } 247 } 248 249 void vidtv_channel_si_init(struct vidtv_mux *m) 250 { 251 struct vidtv_psi_table_pat_program *programs = NULL; 252 struct vidtv_psi_table_sdt_service *services = NULL; 253 254 m->si.pat = vidtv_psi_pat_table_init(m->transport_stream_id); 255 256 m->si.sdt = vidtv_psi_sdt_table_init(m->transport_stream_id); 257 258 programs = vidtv_channel_pat_prog_cat_into_new(m); 259 services = vidtv_channel_sdt_serv_cat_into_new(m); 260 261 /* assemble all programs and assign to PAT */ 262 vidtv_psi_pat_program_assign(m->si.pat, programs); 263 264 /* assemble all services and assign to SDT */ 265 vidtv_psi_sdt_service_assign(m->si.sdt, services); 266 267 m->si.pmt_secs = vidtv_psi_pmt_create_sec_for_each_pat_entry(m->si.pat, m->pcr_pid); 268 269 vidtv_channel_pmt_match_sections(m->channels, 270 m->si.pmt_secs, 271 m->si.pat->programs); 272 } 273 274 void vidtv_channel_si_destroy(struct vidtv_mux *m) 275 { 276 u32 i; 277 u16 num_programs = m->si.pat->programs; 278 279 vidtv_psi_pat_table_destroy(m->si.pat); 280 281 for (i = 0; i < num_programs; ++i) 282 vidtv_psi_pmt_table_destroy(m->si.pmt_secs[i]); 283 284 kfree(m->si.pmt_secs); 285 vidtv_psi_sdt_table_destroy(m->si.sdt); 286 } 287 288 void vidtv_channels_init(struct vidtv_mux *m) 289 { 290 /* this is the place to add new 'channels' for vidtv */ 291 m->channels = vidtv_channel_s302m_init(NULL, m->transport_stream_id); 292 } 293 294 void vidtv_channels_destroy(struct vidtv_mux *m) 295 { 296 struct vidtv_channel *curr = m->channels; 297 struct vidtv_channel *tmp = NULL; 298 299 while (curr) { 300 kfree(curr->name); 301 vidtv_psi_sdt_service_destroy(curr->service); 302 vidtv_psi_pat_program_destroy(curr->program); 303 vidtv_psi_pmt_stream_destroy(curr->streams); 304 vidtv_channel_encoder_destroy(curr->encoders); 305 306 tmp = curr; 307 curr = curr->next; 308 kfree(tmp); 309 } 310 } 311