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
*tmp
= NULL
;
37 struct vidtv_encoder
*curr
= e
;
40 /* forward the call to the derived type */
47 #define ENCODING_ISO8859_15 "\x0b"
48 #define TS_NIT_PID 0x10
51 * init an audio only channel with a s302m encoder
54 *vidtv_channel_s302m_init(struct vidtv_channel
*head
, u16 transport_stream_id
)
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
;
70 s302m
= kzalloc(sizeof(*s302m
), GFP_KERNEL
);
74 s302m
->name
= kstrdup(name
, GFP_KERNEL
);
78 s302m
->service
= vidtv_psi_sdt_service_init(NULL
, s302m_service_id
, false, true);
82 s302m
->service
->descriptor
= (struct vidtv_psi_desc
*)
83 vidtv_psi_service_desc_init(NULL
,
84 DIGITAL_RADIO_SOUND_SERVICE
,
87 if (!s302m
->service
->descriptor
)
90 s302m
->transport_stream_id
= transport_stream_id
;
92 s302m
->program
= vidtv_psi_pat_program_init(NULL
,
98 s302m
->program_num
= s302m_program_num
;
100 s302m
->streams
= vidtv_psi_pmt_stream_init(NULL
,
106 s302m
->streams
->descriptor
= (struct vidtv_psi_desc
*)
107 vidtv_psi_registration_desc_init(NULL
,
111 if (!s302m
->streams
->descriptor
)
114 encoder_args
.es_pid
= s302m_es_pid
;
116 s302m
->encoders
= vidtv_s302m_encoder_init(encoder_args
);
117 if (!s302m
->encoders
)
120 s302m
->events
= vidtv_psi_eit_event_init(NULL
, s302m_beethoven_event_id
);
123 s302m
->events
->descriptor
= (struct vidtv_psi_desc
*)
124 vidtv_psi_short_event_desc_init(NULL
,
128 if (!s302m
->events
->descriptor
)
141 vidtv_psi_eit_event_destroy(s302m
->events
);
143 vidtv_s302m_encoder_destroy(s302m
->encoders
);
145 vidtv_psi_pmt_stream_destroy(s302m
->streams
);
147 vidtv_psi_pat_program_destroy(s302m
->program
);
149 vidtv_psi_sdt_service_destroy(s302m
->service
);
158 static struct vidtv_psi_table_eit_event
159 *vidtv_channel_eit_event_cat_into_new(struct vidtv_mux
*m
)
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
;
173 curr
= cur_chnl
->events
;
176 dev_warn_ratelimited(m
->dev
,
177 "No events found for channel %s\n",
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",
228 service_id
= be16_to_cpu(curr
->service_id
);
229 tail
= vidtv_psi_sdt_service_init(tail
,
232 curr
->EIT_present_following
);
236 desc
= vidtv_psi_desc_clone(curr
->descriptor
);
239 vidtv_psi_desc_assign(&tail
->descriptor
, desc
);
247 cur_chnl
= cur_chnl
->next
;
253 vidtv_psi_sdt_service_destroy(tail
);
255 vidtv_psi_sdt_service_destroy(head
);
259 static struct vidtv_psi_table_pat_program
*
260 vidtv_channel_pat_prog_cat_into_new(struct vidtv_mux
*m
)
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
;
274 curr
= cur_chnl
->program
;
277 dev_warn_ratelimited(m
->dev
,
278 "No programs found for channel %s\n",
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
,
288 vidtv_psi_pat_program_destroy(head
);
298 cur_chnl
= cur_chnl
->next
;
300 /* Add the NIT table */
301 vidtv_psi_pat_program_init(tail
, 0, TS_NIT_PID
);
307 * Match channels to their respective PMT sections, then assign the
311 vidtv_channel_pmt_match_sections(struct vidtv_channel
*channels
,
312 struct vidtv_psi_table_pmt
**sections
,
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 */
326 for (j
= 0; j
< nsections
; ++j
) {
327 curr_section
= sections
[j
];
332 curr_id
= be16_to_cpu(curr_section
->header
.id
);
335 if (curr_id
== cur_chnl
->program_num
) {
336 s
= cur_chnl
->streams
;
338 /* clone the streams for the PMT */
340 e_pid
= vidtv_psi_pmt_stream_get_elem_pid(s
);
341 tail
= vidtv_psi_pmt_stream_init(tail
,
348 desc
= vidtv_psi_desc_clone(s
->descriptor
);
349 vidtv_psi_desc_assign(&tail
->descriptor
,
355 vidtv_psi_pmt_stream_assign(curr_section
, head
);
360 cur_chnl
= cur_chnl
->next
;
365 vidtv_channel_destroy_service_list(struct vidtv_psi_desc_service_list_entry
*e
)
367 struct vidtv_psi_desc_service_list_entry
*tmp
;
376 static struct vidtv_psi_desc_service_list_entry
377 *vidtv_channel_build_service_list(struct vidtv_psi_table_sdt_service
*s
)
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
;
387 if (s
->descriptor
->type
!= SERVICE_DESCRIPTOR
)
390 s_desc
= (struct vidtv_psi_desc_service
*)desc
;
392 curr_e
= kzalloc(sizeof(*curr_e
), GFP_KERNEL
);
394 vidtv_channel_destroy_service_list(head_e
);
398 curr_e
->service_id
= s
->service_id
;
399 curr_e
->service_type
= s_desc
->service_type
;
404 prev_e
->next
= curr_e
;
416 int vidtv_channel_si_init(struct vidtv_mux
*m
)
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
;
423 m
->si
.pat
= vidtv_psi_pat_table_init(m
->transport_stream_id
);
427 m
->si
.sdt
= vidtv_psi_sdt_table_init(m
->network_id
,
428 m
->transport_stream_id
);
432 programs
= vidtv_channel_pat_prog_cat_into_new(m
);
435 services
= vidtv_channel_sdt_serv_cat_into_new(m
);
439 events
= vidtv_channel_eit_event_cat_into_new(m
);
443 /* look for a service descriptor for every service */
444 service_list
= vidtv_channel_build_service_list(services
);
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
,
454 goto free_service_list
;
456 m
->si
.eit
= vidtv_psi_eit_table_init(m
->network_id
,
457 m
->transport_stream_id
,
458 programs
->service_id
);
462 /* assemble all programs and assign to PAT */
463 vidtv_psi_pat_program_assign(m
->si
.pat
, programs
);
465 /* assemble all services and assign to SDT */
466 vidtv_psi_sdt_service_assign(m
->si
.sdt
, services
);
468 /* assemble all events and assign to EIT */
469 vidtv_psi_eit_event_assign(m
->si
.eit
, events
);
471 m
->si
.pmt_secs
= vidtv_psi_pmt_create_sec_for_each_pat_entry(m
->si
.pat
,
476 vidtv_channel_pmt_match_sections(m
->channels
,
480 vidtv_channel_destroy_service_list(service_list
);
485 vidtv_psi_eit_table_destroy(m
->si
.eit
);
487 vidtv_psi_nit_table_destroy(m
->si
.nit
);
489 vidtv_channel_destroy_service_list(service_list
);
491 vidtv_psi_eit_event_destroy(events
);
493 vidtv_psi_sdt_service_destroy(services
);
495 vidtv_psi_pat_program_destroy(programs
);
497 vidtv_psi_sdt_table_destroy(m
->si
.sdt
);
499 vidtv_psi_pat_table_destroy(m
->si
.pat
);
503 void vidtv_channel_si_destroy(struct vidtv_mux
*m
)
507 for (i
= 0; i
< m
->si
.pat
->num_pmt
; ++i
)
508 vidtv_psi_pmt_table_destroy(m
->si
.pmt_secs
[i
]);
510 vidtv_psi_pat_table_destroy(m
->si
.pat
);
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
);
518 int vidtv_channels_init(struct vidtv_mux
*m
)
520 /* this is the place to add new 'channels' for vidtv */
521 m
->channels
= vidtv_channel_s302m_init(NULL
, m
->transport_stream_id
);
529 void vidtv_channels_destroy(struct vidtv_mux
*m
)
531 struct vidtv_channel
*curr
= m
->channels
;
532 struct vidtv_channel
*tmp
= NULL
;
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
);