Merge tag 'platform-drivers-x86-v5.11-1' of git://git.kernel.org/pub/scm/linux/kernel...
[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 #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 }