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 * Their events will be concatenated to populate the EIT 13 * For each program in the PAT, a PMT section will be created 14 * The PMT section for a channel will be assigned its streams. 15 * Every stream will have its corresponding encoder polled to produce TS packets 16 * These packets may be interleaved by the mux and then delivered to the bridge 17 * 18 * 19 * Copyright (C) 2020 Daniel W. S. Almeida 20 */ 21 22 #include <linux/dev_printk.h> 23 #include <linux/ratelimit.h> 24 #include <linux/slab.h> 25 #include <linux/types.h> 26 27 #include "vidtv_channel.h" 28 #include "vidtv_common.h" 29 #include "vidtv_encoder.h" 30 #include "vidtv_mux.h" 31 #include "vidtv_psi.h" 32 #include "vidtv_s302m.h" 33 34 static void vidtv_channel_encoder_destroy(struct vidtv_encoder *e) 35 { 36 struct vidtv_encoder *tmp = NULL; 37 struct vidtv_encoder *curr = e; 38 39 while (curr) { 40 /* forward the call to the derived type */ 41 tmp = curr; 42 curr = curr->next; 43 tmp->destroy(tmp); 44 } 45 } 46 47 #define ENCODING_ISO8859_15 "\x0b" 48 #define TS_NIT_PID 0x10 49 50 /* 51 * init an audio only channel with a s302m encoder 52 */ 53 struct vidtv_channel 54 *vidtv_channel_s302m_init(struct vidtv_channel *head, u16 transport_stream_id) 55 { 56 const __be32 s302m_fid = cpu_to_be32(VIDTV_S302M_FORMAT_IDENTIFIER); 57 char *event_text = ENCODING_ISO8859_15 "Bagatelle No. 25 in A minor for solo piano, also known as F\xfcr Elise, composed by Ludwig van Beethoven"; 58 char *event_name = ENCODING_ISO8859_15 "Ludwig van Beethoven: F\xfcr Elise"; 59 struct vidtv_s302m_encoder_init_args encoder_args = {}; 60 char *iso_language_code = ENCODING_ISO8859_15 "eng"; 61 char *provider = ENCODING_ISO8859_15 "LinuxTV.org"; 62 char *name = ENCODING_ISO8859_15 "Beethoven"; 63 const u16 s302m_es_pid = 0x111; /* packet id for the ES */ 64 const u16 s302m_program_pid = 0x101; /* packet id for PMT*/ 65 const u16 s302m_service_id = 0x880; 66 const u16 s302m_program_num = 0x880; 67 const u16 s302m_beethoven_event_id = 1; 68 struct vidtv_channel *s302m; 69 70 s302m = kzalloc(sizeof(*s302m), GFP_KERNEL); 71 if (!s302m) 72 return NULL; 73 74 s302m->name = kstrdup(name, GFP_KERNEL); 75 if (!s302m->name) 76 goto free_s302m; 77 78 s302m->service = vidtv_psi_sdt_service_init(NULL, s302m_service_id, false, true); 79 if (!s302m->service) 80 goto free_name; 81 82 s302m->service->descriptor = (struct vidtv_psi_desc *) 83 vidtv_psi_service_desc_init(NULL, 84 DIGITAL_RADIO_SOUND_SERVICE, 85 name, 86 provider); 87 if (!s302m->service->descriptor) 88 goto free_service; 89 90 s302m->transport_stream_id = transport_stream_id; 91 92 s302m->program = vidtv_psi_pat_program_init(NULL, 93 s302m_service_id, 94 s302m_program_pid); 95 if (!s302m->program) 96 goto free_service; 97 98 s302m->program_num = s302m_program_num; 99 100 s302m->streams = vidtv_psi_pmt_stream_init(NULL, 101 STREAM_PRIVATE_DATA, 102 s302m_es_pid); 103 if (!s302m->streams) 104 goto free_program; 105 106 s302m->streams->descriptor = (struct vidtv_psi_desc *) 107 vidtv_psi_registration_desc_init(NULL, 108 s302m_fid, 109 NULL, 110 0); 111 if (!s302m->streams->descriptor) 112 goto free_streams; 113 114 encoder_args.es_pid = s302m_es_pid; 115 116 s302m->encoders = vidtv_s302m_encoder_init(encoder_args); 117 if (!s302m->encoders) 118 goto free_streams; 119 120 s302m->events = vidtv_psi_eit_event_init(NULL, s302m_beethoven_event_id); 121 if (!s302m->events) 122 goto free_encoders; 123 s302m->events->descriptor = (struct vidtv_psi_desc *) 124 vidtv_psi_short_event_desc_init(NULL, 125 iso_language_code, 126 event_name, 127 event_text); 128 if (!s302m->events->descriptor) 129 goto free_events; 130 131 if (head) { 132 while (head->next) 133 head = head->next; 134 135 head->next = s302m; 136 } 137 138 return s302m; 139 140 free_events: 141 vidtv_psi_eit_event_destroy(s302m->events); 142 free_encoders: 143 vidtv_s302m_encoder_destroy(s302m->encoders); 144 free_streams: 145 vidtv_psi_pmt_stream_destroy(s302m->streams); 146 free_program: 147 vidtv_psi_pat_program_destroy(s302m->program); 148 free_service: 149 vidtv_psi_sdt_service_destroy(s302m->service); 150 free_name: 151 kfree(s302m->name); 152 free_s302m: 153 kfree(s302m); 154 155 return NULL; 156 } 157 158 static struct vidtv_psi_table_eit_event 159 *vidtv_channel_eit_event_cat_into_new(struct vidtv_mux *m) 160 { 161 /* Concatenate the events */ 162 const struct vidtv_channel *cur_chnl = m->channels; 163 struct vidtv_psi_table_eit_event *curr = NULL; 164 struct vidtv_psi_table_eit_event *head = NULL; 165 struct vidtv_psi_table_eit_event *tail = NULL; 166 struct vidtv_psi_desc *desc = NULL; 167 u16 event_id; 168 169 if (!cur_chnl) 170 return NULL; 171 172 while (cur_chnl) { 173 curr = cur_chnl->events; 174 175 if (!curr) 176 dev_warn_ratelimited(m->dev, 177 "No events found for channel %s\n", 178 cur_chnl->name); 179 180 while (curr) { 181 event_id = be16_to_cpu(curr->event_id); 182 tail = vidtv_psi_eit_event_init(tail, event_id); 183 if (!tail) { 184 vidtv_psi_eit_event_destroy(head); 185 return NULL; 186 } 187 188 desc = vidtv_psi_desc_clone(curr->descriptor); 189 vidtv_psi_desc_assign(&tail->descriptor, desc); 190 191 if (!head) 192 head = tail; 193 194 curr = curr->next; 195 } 196 197 cur_chnl = cur_chnl->next; 198 } 199 200 return head; 201 } 202 203 static struct vidtv_psi_table_sdt_service 204 *vidtv_channel_sdt_serv_cat_into_new(struct vidtv_mux *m) 205 { 206 /* Concatenate the services */ 207 const struct vidtv_channel *cur_chnl = m->channels; 208 209 struct vidtv_psi_table_sdt_service *curr = NULL; 210 struct vidtv_psi_table_sdt_service *head = NULL; 211 struct vidtv_psi_table_sdt_service *tail = NULL; 212 213 struct vidtv_psi_desc *desc = NULL; 214 u16 service_id; 215 216 if (!cur_chnl) 217 return NULL; 218 219 while (cur_chnl) { 220 curr = cur_chnl->service; 221 222 if (!curr) 223 dev_warn_ratelimited(m->dev, 224 "No services found for channel %s\n", 225 cur_chnl->name); 226 227 while (curr) { 228 service_id = be16_to_cpu(curr->service_id); 229 tail = vidtv_psi_sdt_service_init(tail, 230 service_id, 231 curr->EIT_schedule, 232 curr->EIT_present_following); 233 if (!tail) 234 goto free; 235 236 desc = vidtv_psi_desc_clone(curr->descriptor); 237 if (!desc) 238 goto free_tail; 239 vidtv_psi_desc_assign(&tail->descriptor, desc); 240 241 if (!head) 242 head = tail; 243 244 curr = curr->next; 245 } 246 247 cur_chnl = cur_chnl->next; 248 } 249 250 return head; 251 252 free_tail: 253 vidtv_psi_sdt_service_destroy(tail); 254 free: 255 vidtv_psi_sdt_service_destroy(head); 256 return NULL; 257 } 258 259 static struct vidtv_psi_table_pat_program* 260 vidtv_channel_pat_prog_cat_into_new(struct vidtv_mux *m) 261 { 262 /* Concatenate the programs */ 263 const struct vidtv_channel *cur_chnl = m->channels; 264 struct vidtv_psi_table_pat_program *curr = NULL; 265 struct vidtv_psi_table_pat_program *head = NULL; 266 struct vidtv_psi_table_pat_program *tail = NULL; 267 u16 serv_id; 268 u16 pid; 269 270 if (!cur_chnl) 271 return NULL; 272 273 while (cur_chnl) { 274 curr = cur_chnl->program; 275 276 if (!curr) 277 dev_warn_ratelimited(m->dev, 278 "No programs found for channel %s\n", 279 cur_chnl->name); 280 281 while (curr) { 282 serv_id = be16_to_cpu(curr->service_id); 283 pid = vidtv_psi_get_pat_program_pid(curr); 284 tail = vidtv_psi_pat_program_init(tail, 285 serv_id, 286 pid); 287 if (!tail) { 288 vidtv_psi_pat_program_destroy(head); 289 return NULL; 290 } 291 292 if (!head) 293 head = tail; 294 295 curr = curr->next; 296 } 297 298 cur_chnl = cur_chnl->next; 299 } 300 /* Add the NIT table */ 301 vidtv_psi_pat_program_init(tail, 0, TS_NIT_PID); 302 303 return head; 304 } 305 306 /* 307 * Match channels to their respective PMT sections, then assign the 308 * streams 309 */ 310 static void 311 vidtv_channel_pmt_match_sections(struct vidtv_channel *channels, 312 struct vidtv_psi_table_pmt **sections, 313 u32 nsections) 314 { 315 struct vidtv_psi_table_pmt *curr_section = NULL; 316 struct vidtv_psi_table_pmt_stream *head = NULL; 317 struct vidtv_psi_table_pmt_stream *tail = NULL; 318 struct vidtv_psi_table_pmt_stream *s = NULL; 319 struct vidtv_channel *cur_chnl = channels; 320 struct vidtv_psi_desc *desc = NULL; 321 u16 e_pid; /* elementary stream pid */ 322 u16 curr_id; 323 u32 j; 324 325 while (cur_chnl) { 326 for (j = 0; j < nsections; ++j) { 327 curr_section = sections[j]; 328 329 if (!curr_section) 330 continue; 331 332 curr_id = be16_to_cpu(curr_section->header.id); 333 334 /* we got a match */ 335 if (curr_id == cur_chnl->program_num) { 336 s = cur_chnl->streams; 337 338 /* clone the streams for the PMT */ 339 while (s) { 340 e_pid = vidtv_psi_pmt_stream_get_elem_pid(s); 341 tail = vidtv_psi_pmt_stream_init(tail, 342 s->type, 343 e_pid); 344 345 if (!head) 346 head = tail; 347 348 desc = vidtv_psi_desc_clone(s->descriptor); 349 vidtv_psi_desc_assign(&tail->descriptor, 350 desc); 351 352 s = s->next; 353 } 354 355 vidtv_psi_pmt_stream_assign(curr_section, head); 356 break; 357 } 358 } 359 360 cur_chnl = cur_chnl->next; 361 } 362 } 363 364 static void 365 vidtv_channel_destroy_service_list(struct vidtv_psi_desc_service_list_entry *e) 366 { 367 struct vidtv_psi_desc_service_list_entry *tmp; 368 369 while (e) { 370 tmp = e; 371 e = e->next; 372 kfree(tmp); 373 } 374 } 375 376 static struct vidtv_psi_desc_service_list_entry 377 *vidtv_channel_build_service_list(struct vidtv_psi_table_sdt_service *s) 378 { 379 struct vidtv_psi_desc_service_list_entry *curr_e = NULL; 380 struct vidtv_psi_desc_service_list_entry *head_e = NULL; 381 struct vidtv_psi_desc_service_list_entry *prev_e = NULL; 382 struct vidtv_psi_desc *desc = s->descriptor; 383 struct vidtv_psi_desc_service *s_desc; 384 385 while (s) { 386 while (desc) { 387 if (s->descriptor->type != SERVICE_DESCRIPTOR) 388 goto next_desc; 389 390 s_desc = (struct vidtv_psi_desc_service *)desc; 391 392 curr_e = kzalloc(sizeof(*curr_e), GFP_KERNEL); 393 if (!curr_e) { 394 vidtv_channel_destroy_service_list(head_e); 395 return NULL; 396 } 397 398 curr_e->service_id = s->service_id; 399 curr_e->service_type = s_desc->service_type; 400 401 if (!head_e) 402 head_e = curr_e; 403 if (prev_e) 404 prev_e->next = curr_e; 405 406 prev_e = curr_e; 407 408 next_desc: 409 desc = desc->next; 410 } 411 s = s->next; 412 } 413 return head_e; 414 } 415 416 int vidtv_channel_si_init(struct vidtv_mux *m) 417 { 418 struct vidtv_psi_desc_service_list_entry *service_list = NULL; 419 struct vidtv_psi_table_pat_program *programs = NULL; 420 struct vidtv_psi_table_sdt_service *services = NULL; 421 struct vidtv_psi_table_eit_event *events = NULL; 422 423 m->si.pat = vidtv_psi_pat_table_init(m->transport_stream_id); 424 if (!m->si.pat) 425 return -ENOMEM; 426 427 m->si.sdt = vidtv_psi_sdt_table_init(m->network_id, 428 m->transport_stream_id); 429 if (!m->si.sdt) 430 goto free_pat; 431 432 programs = vidtv_channel_pat_prog_cat_into_new(m); 433 if (!programs) 434 goto free_sdt; 435 services = vidtv_channel_sdt_serv_cat_into_new(m); 436 if (!services) 437 goto free_programs; 438 439 events = vidtv_channel_eit_event_cat_into_new(m); 440 if (!events) 441 goto free_services; 442 443 /* look for a service descriptor for every service */ 444 service_list = vidtv_channel_build_service_list(services); 445 if (!service_list) 446 goto free_events; 447 448 /* use these descriptors to build the NIT */ 449 m->si.nit = vidtv_psi_nit_table_init(m->network_id, 450 m->transport_stream_id, 451 m->network_name, 452 service_list); 453 if (!m->si.nit) 454 goto free_service_list; 455 456 m->si.eit = vidtv_psi_eit_table_init(m->network_id, 457 m->transport_stream_id, 458 programs->service_id); 459 if (!m->si.eit) 460 goto free_nit; 461 462 /* assemble all programs and assign to PAT */ 463 vidtv_psi_pat_program_assign(m->si.pat, programs); 464 465 /* assemble all services and assign to SDT */ 466 vidtv_psi_sdt_service_assign(m->si.sdt, services); 467 468 /* assemble all events and assign to EIT */ 469 vidtv_psi_eit_event_assign(m->si.eit, events); 470 471 m->si.pmt_secs = vidtv_psi_pmt_create_sec_for_each_pat_entry(m->si.pat, 472 m->pcr_pid); 473 if (!m->si.pmt_secs) 474 goto free_eit; 475 476 vidtv_channel_pmt_match_sections(m->channels, 477 m->si.pmt_secs, 478 m->si.pat->num_pmt); 479 480 vidtv_channel_destroy_service_list(service_list); 481 482 return 0; 483 484 free_eit: 485 vidtv_psi_eit_table_destroy(m->si.eit); 486 free_nit: 487 vidtv_psi_nit_table_destroy(m->si.nit); 488 free_service_list: 489 vidtv_channel_destroy_service_list(service_list); 490 free_events: 491 vidtv_psi_eit_event_destroy(events); 492 free_services: 493 vidtv_psi_sdt_service_destroy(services); 494 free_programs: 495 vidtv_psi_pat_program_destroy(programs); 496 free_sdt: 497 vidtv_psi_sdt_table_destroy(m->si.sdt); 498 free_pat: 499 vidtv_psi_pat_table_destroy(m->si.pat); 500 return 0; 501 } 502 503 void vidtv_channel_si_destroy(struct vidtv_mux *m) 504 { 505 u32 i; 506 507 for (i = 0; i < m->si.pat->num_pmt; ++i) 508 vidtv_psi_pmt_table_destroy(m->si.pmt_secs[i]); 509 510 vidtv_psi_pat_table_destroy(m->si.pat); 511 512 kfree(m->si.pmt_secs); 513 vidtv_psi_sdt_table_destroy(m->si.sdt); 514 vidtv_psi_nit_table_destroy(m->si.nit); 515 vidtv_psi_eit_table_destroy(m->si.eit); 516 } 517 518 int vidtv_channels_init(struct vidtv_mux *m) 519 { 520 /* this is the place to add new 'channels' for vidtv */ 521 m->channels = vidtv_channel_s302m_init(NULL, m->transport_stream_id); 522 523 if (!m->channels) 524 return -ENOMEM; 525 526 return 0; 527 } 528 529 void vidtv_channels_destroy(struct vidtv_mux *m) 530 { 531 struct vidtv_channel *curr = m->channels; 532 struct vidtv_channel *tmp = NULL; 533 534 while (curr) { 535 kfree(curr->name); 536 vidtv_psi_sdt_service_destroy(curr->service); 537 vidtv_psi_pat_program_destroy(curr->program); 538 vidtv_psi_pmt_stream_destroy(curr->streams); 539 vidtv_channel_encoder_destroy(curr->encoders); 540 vidtv_psi_eit_event_destroy(curr->events); 541 542 tmp = curr; 543 curr = curr->next; 544 kfree(tmp); 545 } 546 } 547