1 // SPDX-License-Identifier: GPL-2.0
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
7 * This file contains the code for a 'channel' abstraction.
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
19 * Copyright (C) 2020 Daniel W. S. Almeida
22 #include <linux/dev_printk.h>
23 #include <linux/ratelimit.h>
24 #include <linux/slab.h>
25 #include <linux/types.h>
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"
34 static void vidtv_channel_encoder_destroy(struct vidtv_encoder *e)
36 struct vidtv_encoder *curr = e;
37 struct vidtv_encoder *tmp = NULL;
40 /* forward the call to the derived type */
47 #define ENCODING_ISO8859_15 "\x0b"
50 *vidtv_channel_s302m_init(struct vidtv_channel *head, u16 transport_stream_id)
53 * init an audio only channel with a s302m encoder
55 const u16 s302m_service_id = 0x880;
56 const u16 s302m_program_num = 0x880;
57 const u16 s302m_program_pid = 0x101; /* packet id for PMT*/
58 const u16 s302m_es_pid = 0x111; /* packet id for the ES */
59 const __be32 s302m_fid = cpu_to_be32(VIDTV_S302M_FORMAT_IDENTIFIER);
60 char *name = ENCODING_ISO8859_15 "Beethoven";
61 char *provider = ENCODING_ISO8859_15 "LinuxTV.org";
62 char *iso_language_code = ENCODING_ISO8859_15 "eng";
63 char *event_name = ENCODING_ISO8859_15 "Beethoven Music";
64 char *event_text = ENCODING_ISO8859_15 "Beethoven's 5th Symphony";
65 const u16 s302m_beethoven_event_id = 1;
66 struct vidtv_channel *s302m;
67 struct vidtv_s302m_encoder_init_args encoder_args = {};
69 s302m = kzalloc(sizeof(*s302m), GFP_KERNEL);
73 s302m->name = kstrdup(name, GFP_KERNEL);
77 s302m->service = vidtv_psi_sdt_service_init(NULL, s302m_service_id, false, true);
81 s302m->service->descriptor = (struct vidtv_psi_desc *)
82 vidtv_psi_service_desc_init(NULL,
83 DIGITAL_TELEVISION_SERVICE,
86 if (!s302m->service->descriptor)
89 s302m->transport_stream_id = transport_stream_id;
91 s302m->program = vidtv_psi_pat_program_init(NULL,
97 s302m->program_num = s302m_program_num;
99 s302m->streams = vidtv_psi_pmt_stream_init(NULL,
105 s302m->streams->descriptor = (struct vidtv_psi_desc *)
106 vidtv_psi_registration_desc_init(NULL,
110 if (!s302m->streams->descriptor)
113 encoder_args.es_pid = s302m_es_pid;
115 s302m->encoders = vidtv_s302m_encoder_init(encoder_args);
116 if (!s302m->encoders)
119 s302m->events = vidtv_psi_eit_event_init(NULL, s302m_beethoven_event_id);
122 s302m->events->descriptor = (struct vidtv_psi_desc *)
123 vidtv_psi_short_event_desc_init(NULL,
127 if (!s302m->events->descriptor)
140 vidtv_psi_eit_event_destroy(s302m->events);
142 vidtv_s302m_encoder_destroy(s302m->encoders);
144 vidtv_psi_pmt_stream_destroy(s302m->streams);
146 vidtv_psi_pat_program_destroy(s302m->program);
148 vidtv_psi_sdt_service_destroy(s302m->service);
157 static struct vidtv_psi_table_eit_event
158 *vidtv_channel_eit_event_cat_into_new(struct vidtv_mux *m)
160 /* Concatenate the events */
161 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;
167 struct vidtv_psi_desc *desc = NULL;
174 curr = cur_chnl->events;
177 dev_warn_ratelimited(m->dev,
178 "No events found for channel %s\n", cur_chnl->name);
181 event_id = be16_to_cpu(curr->event_id);
182 tail = vidtv_psi_eit_event_init(tail, event_id);
184 vidtv_psi_eit_event_destroy(head);
188 desc = vidtv_psi_desc_clone(curr->descriptor);
189 vidtv_psi_desc_assign(&tail->descriptor, desc);
197 cur_chnl = cur_chnl->next;
203 static struct vidtv_psi_table_sdt_service
204 *vidtv_channel_sdt_serv_cat_into_new(struct vidtv_mux *m)
206 /* Concatenate the services */
207 const struct vidtv_channel *cur_chnl = m->channels;
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;
213 struct vidtv_psi_desc *desc = NULL;
220 curr = cur_chnl->service;
223 dev_warn_ratelimited(m->dev,
224 "No services found for channel %s\n", cur_chnl->name);
227 service_id = be16_to_cpu(curr->service_id);
228 tail = vidtv_psi_sdt_service_init(tail,
231 curr->EIT_present_following);
235 desc = vidtv_psi_desc_clone(curr->descriptor);
238 vidtv_psi_desc_assign(&tail->descriptor, desc);
246 cur_chnl = cur_chnl->next;
252 vidtv_psi_sdt_service_destroy(tail);
254 vidtv_psi_sdt_service_destroy(head);
258 static struct vidtv_psi_table_pat_program*
259 vidtv_channel_pat_prog_cat_into_new(struct vidtv_mux *m)
261 /* Concatenate the programs */
262 const struct vidtv_channel *cur_chnl = m->channels;
263 struct vidtv_psi_table_pat_program *curr = NULL;
264 struct vidtv_psi_table_pat_program *head = NULL;
265 struct vidtv_psi_table_pat_program *tail = NULL;
273 curr = cur_chnl->program;
276 dev_warn_ratelimited(m->dev,
277 "No programs found for channel %s\n",
281 serv_id = be16_to_cpu(curr->service_id);
282 pid = vidtv_psi_get_pat_program_pid(curr);
283 tail = vidtv_psi_pat_program_init(tail,
287 vidtv_psi_pat_program_destroy(head);
297 cur_chnl = cur_chnl->next;
304 vidtv_channel_pmt_match_sections(struct vidtv_channel *channels,
305 struct vidtv_psi_table_pmt **sections,
309 * Match channels to their respective PMT sections, then assign the
312 struct vidtv_psi_table_pmt *curr_section = NULL;
313 struct vidtv_channel *cur_chnl = channels;
315 struct vidtv_psi_table_pmt_stream *s = NULL;
316 struct vidtv_psi_table_pmt_stream *head = NULL;
317 struct vidtv_psi_table_pmt_stream *tail = NULL;
319 struct vidtv_psi_desc *desc = NULL;
322 u16 e_pid; /* elementary stream pid */
325 for (j = 0; j < nsections; ++j) {
326 curr_section = sections[j];
331 curr_id = be16_to_cpu(curr_section->header.id);
334 if (curr_id == cur_chnl->program_num) {
335 s = cur_chnl->streams;
337 /* clone the streams for the PMT */
339 e_pid = vidtv_psi_pmt_stream_get_elem_pid(s);
340 tail = vidtv_psi_pmt_stream_init(tail,
347 desc = vidtv_psi_desc_clone(s->descriptor);
348 vidtv_psi_desc_assign(&tail->descriptor, desc);
353 vidtv_psi_pmt_stream_assign(curr_section, head);
358 cur_chnl = cur_chnl->next;
362 static void vidtv_channel_destroy_service_list(struct vidtv_psi_desc_service_list_entry *e)
364 struct vidtv_psi_desc_service_list_entry *tmp;
373 static struct vidtv_psi_desc_service_list_entry
374 *vidtv_channel_build_service_list(struct vidtv_psi_table_sdt_service *s)
376 struct vidtv_psi_desc_service_list_entry *curr_e = NULL;
377 struct vidtv_psi_desc_service_list_entry *head_e = NULL;
378 struct vidtv_psi_desc_service_list_entry *prev_e = NULL;
379 struct vidtv_psi_desc *desc = s->descriptor;
380 struct vidtv_psi_desc_service *s_desc;
384 if (s->descriptor->type != SERVICE_DESCRIPTOR)
387 s_desc = (struct vidtv_psi_desc_service *)desc;
389 curr_e = kzalloc(sizeof(*curr_e), GFP_KERNEL);
391 vidtv_channel_destroy_service_list(head_e);
395 curr_e->service_id = s->service_id;
396 curr_e->service_type = s_desc->service_type;
401 prev_e->next = curr_e;
413 int vidtv_channel_si_init(struct vidtv_mux *m)
415 struct vidtv_psi_table_pat_program *programs = NULL;
416 struct vidtv_psi_table_sdt_service *services = NULL;
417 struct vidtv_psi_desc_service_list_entry *service_list = NULL;
418 struct vidtv_psi_table_eit_event *events = NULL;
420 m->si.pat = vidtv_psi_pat_table_init(m->transport_stream_id);
424 m->si.sdt = vidtv_psi_sdt_table_init(m->transport_stream_id);
428 programs = vidtv_channel_pat_prog_cat_into_new(m);
431 services = vidtv_channel_sdt_serv_cat_into_new(m);
435 events = vidtv_channel_eit_event_cat_into_new(m);
439 /* look for a service descriptor for every service */
440 service_list = vidtv_channel_build_service_list(services);
444 /* use these descriptors to build the NIT */
445 m->si.nit = vidtv_psi_nit_table_init(m->network_id,
446 m->transport_stream_id,
450 goto free_service_list;
452 m->si.eit = vidtv_psi_eit_table_init(m->network_id, m->transport_stream_id);
457 /* assemble all programs and assign to PAT */
458 vidtv_psi_pat_program_assign(m->si.pat, programs);
460 /* assemble all services and assign to SDT */
461 vidtv_psi_sdt_service_assign(m->si.sdt, services);
463 /* assemble all events and assign to EIT */
464 vidtv_psi_eit_event_assign(m->si.eit, events);
466 m->si.pmt_secs = vidtv_psi_pmt_create_sec_for_each_pat_entry(m->si.pat, m->pcr_pid);
470 vidtv_channel_pmt_match_sections(m->channels,
472 m->si.pat->programs);
474 vidtv_channel_destroy_service_list(service_list);
479 vidtv_psi_eit_table_destroy(m->si.eit);
481 vidtv_psi_nit_table_destroy(m->si.nit);
483 vidtv_channel_destroy_service_list(service_list);
485 vidtv_psi_eit_event_destroy(events);
487 vidtv_psi_sdt_service_destroy(services);
489 vidtv_psi_pat_program_destroy(programs);
491 vidtv_psi_sdt_table_destroy(m->si.sdt);
493 vidtv_psi_pat_table_destroy(m->si.pat);
497 void vidtv_channel_si_destroy(struct vidtv_mux *m)
500 u16 num_programs = m->si.pat->programs;
502 vidtv_psi_pat_table_destroy(m->si.pat);
504 for (i = 0; i < num_programs; ++i)
505 vidtv_psi_pmt_table_destroy(m->si.pmt_secs[i]);
507 kfree(m->si.pmt_secs);
508 vidtv_psi_sdt_table_destroy(m->si.sdt);
509 vidtv_psi_nit_table_destroy(m->si.nit);
510 vidtv_psi_eit_table_destroy(m->si.eit);
513 int vidtv_channels_init(struct vidtv_mux *m)
515 /* this is the place to add new 'channels' for vidtv */
516 m->channels = vidtv_channel_s302m_init(NULL, m->transport_stream_id);
524 void vidtv_channels_destroy(struct vidtv_mux *m)
526 struct vidtv_channel *curr = m->channels;
527 struct vidtv_channel *tmp = NULL;
531 vidtv_psi_sdt_service_destroy(curr->service);
532 vidtv_psi_pat_program_destroy(curr->program);
533 vidtv_psi_pmt_stream_destroy(curr->streams);
534 vidtv_channel_encoder_destroy(curr->encoders);
535 vidtv_psi_eit_event_destroy(curr->events);