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