xref: /linux/drivers/media/test-drivers/vidtv/vidtv_channel.c (revision cdd38c5f1ce4398ec58fec95904b75824daab7b5)
1f90cf607SDaniel W. S. Almeida // SPDX-License-Identifier: GPL-2.0
2f90cf607SDaniel W. S. Almeida /*
3f90cf607SDaniel W. S. Almeida  * Vidtv serves as a reference DVB driver and helps validate the existing APIs
4f90cf607SDaniel W. S. Almeida  * in the media subsystem. It can also aid developers working on userspace
5f90cf607SDaniel W. S. Almeida  * applications.
6f90cf607SDaniel W. S. Almeida  *
7f90cf607SDaniel W. S. Almeida  * This file contains the code for a 'channel' abstraction.
8f90cf607SDaniel W. S. Almeida  *
9f90cf607SDaniel W. S. Almeida  * When vidtv boots, it will create some hardcoded channels.
10f90cf607SDaniel W. S. Almeida  * Their services will be concatenated to populate the SDT.
11f90cf607SDaniel W. S. Almeida  * Their programs will be concatenated to populate the PAT
127a7899f6SDaniel W. S. Almeida  * Their events will be concatenated to populate the EIT
13f90cf607SDaniel W. S. Almeida  * For each program in the PAT, a PMT section will be created
14f90cf607SDaniel W. S. Almeida  * The PMT section for a channel will be assigned its streams.
15f90cf607SDaniel W. S. Almeida  * Every stream will have its corresponding encoder polled to produce TS packets
16f90cf607SDaniel W. S. Almeida  * These packets may be interleaved by the mux and then delivered to the bridge
17f90cf607SDaniel W. S. Almeida  *
18f90cf607SDaniel W. S. Almeida  *
19f90cf607SDaniel W. S. Almeida  * Copyright (C) 2020 Daniel W. S. Almeida
20f90cf607SDaniel W. S. Almeida  */
21f90cf607SDaniel W. S. Almeida 
229cfb4d36SMauro Carvalho Chehab #include <linux/dev_printk.h>
23f90cf607SDaniel W. S. Almeida #include <linux/ratelimit.h>
248922e393SMauro Carvalho Chehab #include <linux/slab.h>
258922e393SMauro Carvalho Chehab #include <linux/types.h>
26f90cf607SDaniel W. S. Almeida 
27f90cf607SDaniel W. S. Almeida #include "vidtv_channel.h"
288922e393SMauro Carvalho Chehab #include "vidtv_common.h"
29f90cf607SDaniel W. S. Almeida #include "vidtv_encoder.h"
30f90cf607SDaniel W. S. Almeida #include "vidtv_mux.h"
318922e393SMauro Carvalho Chehab #include "vidtv_psi.h"
32f90cf607SDaniel W. S. Almeida #include "vidtv_s302m.h"
33f90cf607SDaniel W. S. Almeida 
vidtv_channel_encoder_destroy(struct vidtv_encoder * e)34f90cf607SDaniel W. S. Almeida static void vidtv_channel_encoder_destroy(struct vidtv_encoder *e)
35f90cf607SDaniel W. S. Almeida {
36f90cf607SDaniel W. S. Almeida 	struct vidtv_encoder *tmp = NULL;
37a8bd461cSMauro Carvalho Chehab 	struct vidtv_encoder *curr = e;
38f90cf607SDaniel W. S. Almeida 
39f90cf607SDaniel W. S. Almeida 	while (curr) {
40f90cf607SDaniel W. S. Almeida 		/* forward the call to the derived type */
41f90cf607SDaniel W. S. Almeida 		tmp = curr;
42f90cf607SDaniel W. S. Almeida 		curr = curr->next;
43f90cf607SDaniel W. S. Almeida 		tmp->destroy(tmp);
44f90cf607SDaniel W. S. Almeida 	}
45f90cf607SDaniel W. S. Almeida }
46f90cf607SDaniel W. S. Almeida 
472f217729SMauro Carvalho Chehab #define ENCODING_ISO8859_15 "\x0b"
48039b7caeSMauro Carvalho Chehab #define TS_NIT_PID	0x10
492f217729SMauro Carvalho Chehab 
50f90cf607SDaniel W. S. Almeida /*
51f90cf607SDaniel W. S. Almeida  * init an audio only channel with a s302m encoder
52f90cf607SDaniel W. S. Almeida  */
53a8bd461cSMauro Carvalho Chehab struct vidtv_channel
vidtv_channel_s302m_init(struct vidtv_channel * head,u16 transport_stream_id)54a8bd461cSMauro Carvalho Chehab *vidtv_channel_s302m_init(struct vidtv_channel *head, u16 transport_stream_id)
55a8bd461cSMauro Carvalho Chehab {
56a8bd461cSMauro Carvalho Chehab 	const __be32 s302m_fid              = cpu_to_be32(VIDTV_S302M_FORMAT_IDENTIFIER);
57b9e09e06SMauro Carvalho Chehab 	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";
58b9e09e06SMauro Carvalho Chehab 	char *event_name = ENCODING_ISO8859_15 "Ludwig van Beethoven: F\xfcr Elise";
59a8bd461cSMauro Carvalho Chehab 	struct vidtv_s302m_encoder_init_args encoder_args = {};
60a8bd461cSMauro Carvalho Chehab 	char *iso_language_code = ENCODING_ISO8859_15 "eng";
61a8bd461cSMauro Carvalho Chehab 	char *provider = ENCODING_ISO8859_15 "LinuxTV.org";
62a8bd461cSMauro Carvalho Chehab 	char *name = ENCODING_ISO8859_15 "Beethoven";
63a8bd461cSMauro Carvalho Chehab 	const u16 s302m_es_pid              = 0x111; /* packet id for the ES */
64a8bd461cSMauro Carvalho Chehab 	const u16 s302m_program_pid         = 0x101; /* packet id for PMT*/
65f90cf607SDaniel W. S. Almeida 	const u16 s302m_service_id          = 0x880;
66f90cf607SDaniel W. S. Almeida 	const u16 s302m_program_num         = 0x880;
677a7899f6SDaniel W. S. Almeida 	const u16 s302m_beethoven_event_id  = 1;
683be80379SMauro Carvalho Chehab 	struct vidtv_channel *s302m;
69f90cf607SDaniel W. S. Almeida 
703be80379SMauro Carvalho Chehab 	s302m = kzalloc(sizeof(*s302m), GFP_KERNEL);
713be80379SMauro Carvalho Chehab 	if (!s302m)
723be80379SMauro Carvalho Chehab 		return NULL;
733be80379SMauro Carvalho Chehab 
74f90cf607SDaniel W. S. Almeida 	s302m->name = kstrdup(name, GFP_KERNEL);
753be80379SMauro Carvalho Chehab 	if (!s302m->name)
763be80379SMauro Carvalho Chehab 		goto free_s302m;
77f90cf607SDaniel W. S. Almeida 
787a7899f6SDaniel W. S. Almeida 	s302m->service = vidtv_psi_sdt_service_init(NULL, s302m_service_id, false, true);
793be80379SMauro Carvalho Chehab 	if (!s302m->service)
803be80379SMauro Carvalho Chehab 		goto free_name;
81f90cf607SDaniel W. S. Almeida 
82f90cf607SDaniel W. S. Almeida 	s302m->service->descriptor = (struct vidtv_psi_desc *)
83f90cf607SDaniel W. S. Almeida 				     vidtv_psi_service_desc_init(NULL,
8411f4933fSMauro Carvalho Chehab 								 DIGITAL_RADIO_SOUND_SERVICE,
85f90cf607SDaniel W. S. Almeida 								 name,
862f217729SMauro Carvalho Chehab 								 provider);
873be80379SMauro Carvalho Chehab 	if (!s302m->service->descriptor)
883be80379SMauro Carvalho Chehab 		goto free_service;
89f90cf607SDaniel W. S. Almeida 
90f90cf607SDaniel W. S. Almeida 	s302m->transport_stream_id = transport_stream_id;
91f90cf607SDaniel W. S. Almeida 
92f90cf607SDaniel W. S. Almeida 	s302m->program = vidtv_psi_pat_program_init(NULL,
93f90cf607SDaniel W. S. Almeida 						    s302m_service_id,
94f90cf607SDaniel W. S. Almeida 						    s302m_program_pid);
953be80379SMauro Carvalho Chehab 	if (!s302m->program)
963be80379SMauro Carvalho Chehab 		goto free_service;
97f90cf607SDaniel W. S. Almeida 
98f90cf607SDaniel W. S. Almeida 	s302m->program_num = s302m_program_num;
99f90cf607SDaniel W. S. Almeida 
100f90cf607SDaniel W. S. Almeida 	s302m->streams = vidtv_psi_pmt_stream_init(NULL,
101f90cf607SDaniel W. S. Almeida 						   STREAM_PRIVATE_DATA,
102f90cf607SDaniel W. S. Almeida 						   s302m_es_pid);
1033be80379SMauro Carvalho Chehab 	if (!s302m->streams)
1043be80379SMauro Carvalho Chehab 		goto free_program;
105f90cf607SDaniel W. S. Almeida 
106f90cf607SDaniel W. S. Almeida 	s302m->streams->descriptor = (struct vidtv_psi_desc *)
107f90cf607SDaniel W. S. Almeida 				     vidtv_psi_registration_desc_init(NULL,
108f90cf607SDaniel W. S. Almeida 								      s302m_fid,
109f90cf607SDaniel W. S. Almeida 								      NULL,
110f90cf607SDaniel W. S. Almeida 								      0);
1113be80379SMauro Carvalho Chehab 	if (!s302m->streams->descriptor)
1123be80379SMauro Carvalho Chehab 		goto free_streams;
1133be80379SMauro Carvalho Chehab 
114f90cf607SDaniel W. S. Almeida 	encoder_args.es_pid = s302m_es_pid;
115f90cf607SDaniel W. S. Almeida 
116f90cf607SDaniel W. S. Almeida 	s302m->encoders = vidtv_s302m_encoder_init(encoder_args);
1173be80379SMauro Carvalho Chehab 	if (!s302m->encoders)
1183be80379SMauro Carvalho Chehab 		goto free_streams;
119f90cf607SDaniel W. S. Almeida 
1207a7899f6SDaniel W. S. Almeida 	s302m->events = vidtv_psi_eit_event_init(NULL, s302m_beethoven_event_id);
1213be80379SMauro Carvalho Chehab 	if (!s302m->events)
1223be80379SMauro Carvalho Chehab 		goto free_encoders;
1237a7899f6SDaniel W. S. Almeida 	s302m->events->descriptor = (struct vidtv_psi_desc *)
1247a7899f6SDaniel W. S. Almeida 				    vidtv_psi_short_event_desc_init(NULL,
1257a7899f6SDaniel W. S. Almeida 								    iso_language_code,
1267a7899f6SDaniel W. S. Almeida 								    event_name,
1277a7899f6SDaniel W. S. Almeida 								    event_text);
1283be80379SMauro Carvalho Chehab 	if (!s302m->events->descriptor)
1293be80379SMauro Carvalho Chehab 		goto free_events;
1307a7899f6SDaniel W. S. Almeida 
131f90cf607SDaniel W. S. Almeida 	if (head) {
132f90cf607SDaniel W. S. Almeida 		while (head->next)
133f90cf607SDaniel W. S. Almeida 			head = head->next;
134f90cf607SDaniel W. S. Almeida 
135f90cf607SDaniel W. S. Almeida 		head->next = s302m;
136f90cf607SDaniel W. S. Almeida 	}
137f90cf607SDaniel W. S. Almeida 
138f90cf607SDaniel W. S. Almeida 	return s302m;
1393be80379SMauro Carvalho Chehab 
1403be80379SMauro Carvalho Chehab free_events:
1413be80379SMauro Carvalho Chehab 	vidtv_psi_eit_event_destroy(s302m->events);
1423be80379SMauro Carvalho Chehab free_encoders:
1433be80379SMauro Carvalho Chehab 	vidtv_s302m_encoder_destroy(s302m->encoders);
1443be80379SMauro Carvalho Chehab free_streams:
1453be80379SMauro Carvalho Chehab 	vidtv_psi_pmt_stream_destroy(s302m->streams);
1463be80379SMauro Carvalho Chehab free_program:
1473be80379SMauro Carvalho Chehab 	vidtv_psi_pat_program_destroy(s302m->program);
1483be80379SMauro Carvalho Chehab free_service:
1493be80379SMauro Carvalho Chehab 	vidtv_psi_sdt_service_destroy(s302m->service);
1503be80379SMauro Carvalho Chehab free_name:
1513be80379SMauro Carvalho Chehab 	kfree(s302m->name);
1523be80379SMauro Carvalho Chehab free_s302m:
1533be80379SMauro Carvalho Chehab 	kfree(s302m);
1543be80379SMauro Carvalho Chehab 
1553be80379SMauro Carvalho Chehab 	return NULL;
156f90cf607SDaniel W. S. Almeida }
157f90cf607SDaniel W. S. Almeida 
1587a7899f6SDaniel W. S. Almeida static struct vidtv_psi_table_eit_event
vidtv_channel_eit_event_cat_into_new(struct vidtv_mux * m)1597a7899f6SDaniel W. S. Almeida *vidtv_channel_eit_event_cat_into_new(struct vidtv_mux *m)
1607a7899f6SDaniel W. S. Almeida {
1617a7899f6SDaniel W. S. Almeida 	/* Concatenate the events */
1627a7899f6SDaniel W. S. Almeida 	const struct vidtv_channel *cur_chnl = m->channels;
1637a7899f6SDaniel W. S. Almeida 	struct vidtv_psi_table_eit_event *curr = NULL;
1647a7899f6SDaniel W. S. Almeida 	struct vidtv_psi_table_eit_event *head = NULL;
1657a7899f6SDaniel W. S. Almeida 	struct vidtv_psi_table_eit_event *tail = NULL;
1667a7899f6SDaniel W. S. Almeida 	struct vidtv_psi_desc *desc = NULL;
1677a7899f6SDaniel W. S. Almeida 	u16 event_id;
1687a7899f6SDaniel W. S. Almeida 
1697a7899f6SDaniel W. S. Almeida 	if (!cur_chnl)
1707a7899f6SDaniel W. S. Almeida 		return NULL;
1717a7899f6SDaniel W. S. Almeida 
1727a7899f6SDaniel W. S. Almeida 	while (cur_chnl) {
1737a7899f6SDaniel W. S. Almeida 		curr = cur_chnl->events;
1747a7899f6SDaniel W. S. Almeida 
1757a7899f6SDaniel W. S. Almeida 		if (!curr)
1767a7899f6SDaniel W. S. Almeida 			dev_warn_ratelimited(m->dev,
177a8bd461cSMauro Carvalho Chehab 					     "No events found for channel %s\n",
178a8bd461cSMauro Carvalho Chehab 					     cur_chnl->name);
1797a7899f6SDaniel W. S. Almeida 
1807a7899f6SDaniel W. S. Almeida 		while (curr) {
1817a7899f6SDaniel W. S. Almeida 			event_id = be16_to_cpu(curr->event_id);
1827a7899f6SDaniel W. S. Almeida 			tail = vidtv_psi_eit_event_init(tail, event_id);
1833be80379SMauro Carvalho Chehab 			if (!tail) {
1843be80379SMauro Carvalho Chehab 				vidtv_psi_eit_event_destroy(head);
1853be80379SMauro Carvalho Chehab 				return NULL;
1863be80379SMauro Carvalho Chehab 			}
1877a7899f6SDaniel W. S. Almeida 
1887a7899f6SDaniel W. S. Almeida 			desc = vidtv_psi_desc_clone(curr->descriptor);
1897a7899f6SDaniel W. S. Almeida 			vidtv_psi_desc_assign(&tail->descriptor, desc);
1907a7899f6SDaniel W. S. Almeida 
1917a7899f6SDaniel W. S. Almeida 			if (!head)
1927a7899f6SDaniel W. S. Almeida 				head = tail;
1937a7899f6SDaniel W. S. Almeida 
1947a7899f6SDaniel W. S. Almeida 			curr = curr->next;
1957a7899f6SDaniel W. S. Almeida 		}
1967a7899f6SDaniel W. S. Almeida 
1977a7899f6SDaniel W. S. Almeida 		cur_chnl = cur_chnl->next;
1987a7899f6SDaniel W. S. Almeida 	}
1997a7899f6SDaniel W. S. Almeida 
2007a7899f6SDaniel W. S. Almeida 	return head;
2017a7899f6SDaniel W. S. Almeida }
2027a7899f6SDaniel W. S. Almeida 
203f90cf607SDaniel W. S. Almeida static struct vidtv_psi_table_sdt_service
vidtv_channel_sdt_serv_cat_into_new(struct vidtv_mux * m)2049cfb4d36SMauro Carvalho Chehab *vidtv_channel_sdt_serv_cat_into_new(struct vidtv_mux *m)
205f90cf607SDaniel W. S. Almeida {
206f90cf607SDaniel W. S. Almeida 	/* Concatenate the services */
2079cfb4d36SMauro Carvalho Chehab 	const struct vidtv_channel *cur_chnl = m->channels;
208f90cf607SDaniel W. S. Almeida 
209f90cf607SDaniel W. S. Almeida 	struct vidtv_psi_table_sdt_service *curr = NULL;
210f90cf607SDaniel W. S. Almeida 	struct vidtv_psi_table_sdt_service *head = NULL;
211f90cf607SDaniel W. S. Almeida 	struct vidtv_psi_table_sdt_service *tail = NULL;
212f90cf607SDaniel W. S. Almeida 
213f90cf607SDaniel W. S. Almeida 	struct vidtv_psi_desc *desc = NULL;
214f90cf607SDaniel W. S. Almeida 	u16 service_id;
215f90cf607SDaniel W. S. Almeida 
216f90cf607SDaniel W. S. Almeida 	if (!cur_chnl)
217f90cf607SDaniel W. S. Almeida 		return NULL;
218f90cf607SDaniel W. S. Almeida 
219f90cf607SDaniel W. S. Almeida 	while (cur_chnl) {
220f90cf607SDaniel W. S. Almeida 		curr = cur_chnl->service;
221f90cf607SDaniel W. S. Almeida 
222f90cf607SDaniel W. S. Almeida 		if (!curr)
2239cfb4d36SMauro Carvalho Chehab 			dev_warn_ratelimited(m->dev,
224a8bd461cSMauro Carvalho Chehab 					     "No services found for channel %s\n",
225a8bd461cSMauro Carvalho Chehab 					     cur_chnl->name);
226f90cf607SDaniel W. S. Almeida 
227f90cf607SDaniel W. S. Almeida 		while (curr) {
228f90cf607SDaniel W. S. Almeida 			service_id = be16_to_cpu(curr->service_id);
2297a7899f6SDaniel W. S. Almeida 			tail = vidtv_psi_sdt_service_init(tail,
2307a7899f6SDaniel W. S. Almeida 							  service_id,
2317a7899f6SDaniel W. S. Almeida 							  curr->EIT_schedule,
2327a7899f6SDaniel W. S. Almeida 							  curr->EIT_present_following);
2333be80379SMauro Carvalho Chehab 			if (!tail)
2343be80379SMauro Carvalho Chehab 				goto free;
235f90cf607SDaniel W. S. Almeida 
236f90cf607SDaniel W. S. Almeida 			desc = vidtv_psi_desc_clone(curr->descriptor);
2373be80379SMauro Carvalho Chehab 			if (!desc)
2383be80379SMauro Carvalho Chehab 				goto free_tail;
239f90cf607SDaniel W. S. Almeida 			vidtv_psi_desc_assign(&tail->descriptor, desc);
240f90cf607SDaniel W. S. Almeida 
241f90cf607SDaniel W. S. Almeida 			if (!head)
242f90cf607SDaniel W. S. Almeida 				head = tail;
243f90cf607SDaniel W. S. Almeida 
244f90cf607SDaniel W. S. Almeida 			curr = curr->next;
245f90cf607SDaniel W. S. Almeida 		}
246f90cf607SDaniel W. S. Almeida 
247f90cf607SDaniel W. S. Almeida 		cur_chnl = cur_chnl->next;
248f90cf607SDaniel W. S. Almeida 	}
249f90cf607SDaniel W. S. Almeida 
250f90cf607SDaniel W. S. Almeida 	return head;
2513be80379SMauro Carvalho Chehab 
2523be80379SMauro Carvalho Chehab free_tail:
2533be80379SMauro Carvalho Chehab 	vidtv_psi_sdt_service_destroy(tail);
2543be80379SMauro Carvalho Chehab free:
2553be80379SMauro Carvalho Chehab 	vidtv_psi_sdt_service_destroy(head);
2563be80379SMauro Carvalho Chehab 	return NULL;
257f90cf607SDaniel W. S. Almeida }
258f90cf607SDaniel W. S. Almeida 
259f90cf607SDaniel W. S. Almeida static struct vidtv_psi_table_pat_program*
vidtv_channel_pat_prog_cat_into_new(struct vidtv_mux * m)2609cfb4d36SMauro Carvalho Chehab vidtv_channel_pat_prog_cat_into_new(struct vidtv_mux *m)
261f90cf607SDaniel W. S. Almeida {
262f90cf607SDaniel W. S. Almeida 	/* Concatenate the programs */
2639cfb4d36SMauro Carvalho Chehab 	const struct vidtv_channel *cur_chnl = m->channels;
264f90cf607SDaniel W. S. Almeida 	struct vidtv_psi_table_pat_program *curr = NULL;
265f90cf607SDaniel W. S. Almeida 	struct vidtv_psi_table_pat_program *head = NULL;
266f90cf607SDaniel W. S. Almeida 	struct vidtv_psi_table_pat_program *tail = NULL;
267f90cf607SDaniel W. S. Almeida 	u16 serv_id;
268f90cf607SDaniel W. S. Almeida 	u16 pid;
269f90cf607SDaniel W. S. Almeida 
270f90cf607SDaniel W. S. Almeida 	if (!cur_chnl)
271f90cf607SDaniel W. S. Almeida 		return NULL;
272f90cf607SDaniel W. S. Almeida 
273f90cf607SDaniel W. S. Almeida 	while (cur_chnl) {
274f90cf607SDaniel W. S. Almeida 		curr = cur_chnl->program;
275f90cf607SDaniel W. S. Almeida 
276f90cf607SDaniel W. S. Almeida 		if (!curr)
2779cfb4d36SMauro Carvalho Chehab 			dev_warn_ratelimited(m->dev,
2789cfb4d36SMauro Carvalho Chehab 					     "No programs found for channel %s\n",
2799cfb4d36SMauro Carvalho Chehab 					     cur_chnl->name);
280f90cf607SDaniel W. S. Almeida 
281f90cf607SDaniel W. S. Almeida 		while (curr) {
282f90cf607SDaniel W. S. Almeida 			serv_id = be16_to_cpu(curr->service_id);
283f90cf607SDaniel W. S. Almeida 			pid = vidtv_psi_get_pat_program_pid(curr);
284f90cf607SDaniel W. S. Almeida 			tail = vidtv_psi_pat_program_init(tail,
285f90cf607SDaniel W. S. Almeida 							  serv_id,
286f90cf607SDaniel W. S. Almeida 							  pid);
2873be80379SMauro Carvalho Chehab 			if (!tail) {
2883be80379SMauro Carvalho Chehab 				vidtv_psi_pat_program_destroy(head);
2893be80379SMauro Carvalho Chehab 				return NULL;
2903be80379SMauro Carvalho Chehab 			}
291f90cf607SDaniel W. S. Almeida 
292f90cf607SDaniel W. S. Almeida 			if (!head)
293f90cf607SDaniel W. S. Almeida 				head = tail;
294f90cf607SDaniel W. S. Almeida 
295f90cf607SDaniel W. S. Almeida 			curr = curr->next;
296f90cf607SDaniel W. S. Almeida 		}
297f90cf607SDaniel W. S. Almeida 
298f90cf607SDaniel W. S. Almeida 		cur_chnl = cur_chnl->next;
299f90cf607SDaniel W. S. Almeida 	}
300039b7caeSMauro Carvalho Chehab 	/* Add the NIT table */
301039b7caeSMauro Carvalho Chehab 	vidtv_psi_pat_program_init(tail, 0, TS_NIT_PID);
302f90cf607SDaniel W. S. Almeida 
303f90cf607SDaniel W. S. Almeida 	return head;
304f90cf607SDaniel W. S. Almeida }
305f90cf607SDaniel W. S. Almeida 
306a8bd461cSMauro Carvalho Chehab /*
307a8bd461cSMauro Carvalho Chehab  * Match channels to their respective PMT sections, then assign the
308a8bd461cSMauro Carvalho Chehab  * streams
309a8bd461cSMauro Carvalho Chehab  */
310f90cf607SDaniel W. S. Almeida static void
vidtv_channel_pmt_match_sections(struct vidtv_channel * channels,struct vidtv_psi_table_pmt ** sections,u32 nsections)311f90cf607SDaniel W. S. Almeida vidtv_channel_pmt_match_sections(struct vidtv_channel *channels,
312f90cf607SDaniel W. S. Almeida 				 struct vidtv_psi_table_pmt **sections,
313f90cf607SDaniel W. S. Almeida 				 u32 nsections)
314f90cf607SDaniel W. S. Almeida {
315f90cf607SDaniel W. S. Almeida 	struct vidtv_psi_table_pmt *curr_section = NULL;
316f90cf607SDaniel W. S. Almeida 	struct vidtv_psi_table_pmt_stream *head = NULL;
317f90cf607SDaniel W. S. Almeida 	struct vidtv_psi_table_pmt_stream *tail = NULL;
318a8bd461cSMauro Carvalho Chehab 	struct vidtv_psi_table_pmt_stream *s = NULL;
319a8bd461cSMauro Carvalho Chehab 	struct vidtv_channel *cur_chnl = channels;
320f90cf607SDaniel W. S. Almeida 	struct vidtv_psi_desc *desc = NULL;
321f90cf607SDaniel W. S. Almeida 	u16 e_pid; /* elementary stream pid */
322a8bd461cSMauro Carvalho Chehab 	u16 curr_id;
323a8bd461cSMauro Carvalho Chehab 	u32 j;
324f90cf607SDaniel W. S. Almeida 
325f90cf607SDaniel W. S. Almeida 	while (cur_chnl) {
326f90cf607SDaniel W. S. Almeida 		for (j = 0; j < nsections; ++j) {
327f90cf607SDaniel W. S. Almeida 			curr_section = sections[j];
328f90cf607SDaniel W. S. Almeida 
329f90cf607SDaniel W. S. Almeida 			if (!curr_section)
330f90cf607SDaniel W. S. Almeida 				continue;
331f90cf607SDaniel W. S. Almeida 
332f90cf607SDaniel W. S. Almeida 			curr_id = be16_to_cpu(curr_section->header.id);
333f90cf607SDaniel W. S. Almeida 
334f90cf607SDaniel W. S. Almeida 			/* we got a match */
335f90cf607SDaniel W. S. Almeida 			if (curr_id == cur_chnl->program_num) {
336f90cf607SDaniel W. S. Almeida 				s = cur_chnl->streams;
337f90cf607SDaniel W. S. Almeida 
338f90cf607SDaniel W. S. Almeida 				/* clone the streams for the PMT */
339f90cf607SDaniel W. S. Almeida 				while (s) {
340f90cf607SDaniel W. S. Almeida 					e_pid = vidtv_psi_pmt_stream_get_elem_pid(s);
341f90cf607SDaniel W. S. Almeida 					tail = vidtv_psi_pmt_stream_init(tail,
342f90cf607SDaniel W. S. Almeida 									 s->type,
343f90cf607SDaniel W. S. Almeida 									 e_pid);
344f90cf607SDaniel W. S. Almeida 
345f90cf607SDaniel W. S. Almeida 					if (!head)
346f90cf607SDaniel W. S. Almeida 						head = tail;
347f90cf607SDaniel W. S. Almeida 
348f90cf607SDaniel W. S. Almeida 					desc = vidtv_psi_desc_clone(s->descriptor);
349a8bd461cSMauro Carvalho Chehab 					vidtv_psi_desc_assign(&tail->descriptor,
350a8bd461cSMauro Carvalho Chehab 							      desc);
351f90cf607SDaniel W. S. Almeida 
352f90cf607SDaniel W. S. Almeida 					s = s->next;
353f90cf607SDaniel W. S. Almeida 				}
354f90cf607SDaniel W. S. Almeida 
355f90cf607SDaniel W. S. Almeida 				vidtv_psi_pmt_stream_assign(curr_section, head);
356f90cf607SDaniel W. S. Almeida 				break;
357f90cf607SDaniel W. S. Almeida 			}
358f90cf607SDaniel W. S. Almeida 		}
359f90cf607SDaniel W. S. Almeida 
360f90cf607SDaniel W. S. Almeida 		cur_chnl = cur_chnl->next;
361f90cf607SDaniel W. S. Almeida 	}
362f90cf607SDaniel W. S. Almeida }
363f90cf607SDaniel W. S. Almeida 
364a8bd461cSMauro Carvalho Chehab static void
vidtv_channel_destroy_service_list(struct vidtv_psi_desc_service_list_entry * e)365a8bd461cSMauro Carvalho Chehab vidtv_channel_destroy_service_list(struct vidtv_psi_desc_service_list_entry *e)
3663be80379SMauro Carvalho Chehab {
3673be80379SMauro Carvalho Chehab 	struct vidtv_psi_desc_service_list_entry *tmp;
3683be80379SMauro Carvalho Chehab 
3693be80379SMauro Carvalho Chehab 	while (e) {
3703be80379SMauro Carvalho Chehab 		tmp = e;
3713be80379SMauro Carvalho Chehab 		e = e->next;
3723be80379SMauro Carvalho Chehab 		kfree(tmp);
3733be80379SMauro Carvalho Chehab 	}
3743be80379SMauro Carvalho Chehab }
3753be80379SMauro Carvalho Chehab 
376c2f78f0cSDaniel W. S. Almeida static struct vidtv_psi_desc_service_list_entry
vidtv_channel_build_service_list(struct vidtv_psi_table_sdt_service * s)377c2f78f0cSDaniel W. S. Almeida *vidtv_channel_build_service_list(struct vidtv_psi_table_sdt_service *s)
378c2f78f0cSDaniel W. S. Almeida {
379c2f78f0cSDaniel W. S. Almeida 	struct vidtv_psi_desc_service_list_entry *curr_e = NULL;
380c2f78f0cSDaniel W. S. Almeida 	struct vidtv_psi_desc_service_list_entry *head_e = NULL;
381c2f78f0cSDaniel W. S. Almeida 	struct vidtv_psi_desc_service_list_entry *prev_e = NULL;
382c2f78f0cSDaniel W. S. Almeida 	struct vidtv_psi_desc *desc = s->descriptor;
383c2f78f0cSDaniel W. S. Almeida 	struct vidtv_psi_desc_service *s_desc;
384c2f78f0cSDaniel W. S. Almeida 
385c2f78f0cSDaniel W. S. Almeida 	while (s) {
386c2f78f0cSDaniel W. S. Almeida 		while (desc) {
387c2f78f0cSDaniel W. S. Almeida 			if (s->descriptor->type != SERVICE_DESCRIPTOR)
388c2f78f0cSDaniel W. S. Almeida 				goto next_desc;
389c2f78f0cSDaniel W. S. Almeida 
390c2f78f0cSDaniel W. S. Almeida 			s_desc = (struct vidtv_psi_desc_service *)desc;
391c2f78f0cSDaniel W. S. Almeida 
392c2f78f0cSDaniel W. S. Almeida 			curr_e = kzalloc(sizeof(*curr_e), GFP_KERNEL);
3933be80379SMauro Carvalho Chehab 			if (!curr_e) {
3943be80379SMauro Carvalho Chehab 				vidtv_channel_destroy_service_list(head_e);
3953be80379SMauro Carvalho Chehab 				return NULL;
3963be80379SMauro Carvalho Chehab 			}
3973be80379SMauro Carvalho Chehab 
398c2f78f0cSDaniel W. S. Almeida 			curr_e->service_id = s->service_id;
399c2f78f0cSDaniel W. S. Almeida 			curr_e->service_type = s_desc->service_type;
400c2f78f0cSDaniel W. S. Almeida 
401c2f78f0cSDaniel W. S. Almeida 			if (!head_e)
402c2f78f0cSDaniel W. S. Almeida 				head_e = curr_e;
403c2f78f0cSDaniel W. S. Almeida 			if (prev_e)
404c2f78f0cSDaniel W. S. Almeida 				prev_e->next = curr_e;
405c2f78f0cSDaniel W. S. Almeida 
406c2f78f0cSDaniel W. S. Almeida 			prev_e = curr_e;
407c2f78f0cSDaniel W. S. Almeida 
408c2f78f0cSDaniel W. S. Almeida next_desc:
409c2f78f0cSDaniel W. S. Almeida 			desc = desc->next;
410c2f78f0cSDaniel W. S. Almeida 		}
411c2f78f0cSDaniel W. S. Almeida 		s = s->next;
412c2f78f0cSDaniel W. S. Almeida 	}
413c2f78f0cSDaniel W. S. Almeida 	return head_e;
414c2f78f0cSDaniel W. S. Almeida }
415c2f78f0cSDaniel W. S. Almeida 
vidtv_channel_si_init(struct vidtv_mux * m)4163be80379SMauro Carvalho Chehab int vidtv_channel_si_init(struct vidtv_mux *m)
417f90cf607SDaniel W. S. Almeida {
418a8bd461cSMauro Carvalho Chehab 	struct vidtv_psi_desc_service_list_entry *service_list = NULL;
419f90cf607SDaniel W. S. Almeida 	struct vidtv_psi_table_pat_program *programs = NULL;
420f90cf607SDaniel W. S. Almeida 	struct vidtv_psi_table_sdt_service *services = NULL;
4217a7899f6SDaniel W. S. Almeida 	struct vidtv_psi_table_eit_event *events = NULL;
422f90cf607SDaniel W. S. Almeida 
423f90cf607SDaniel W. S. Almeida 	m->si.pat = vidtv_psi_pat_table_init(m->transport_stream_id);
4243be80379SMauro Carvalho Chehab 	if (!m->si.pat)
4253be80379SMauro Carvalho Chehab 		return -ENOMEM;
426f90cf607SDaniel W. S. Almeida 
427bfa4aaebSMauro Carvalho Chehab 	m->si.sdt = vidtv_psi_sdt_table_init(m->network_id,
428bfa4aaebSMauro Carvalho Chehab 					     m->transport_stream_id);
4293be80379SMauro Carvalho Chehab 	if (!m->si.sdt)
4303be80379SMauro Carvalho Chehab 		goto free_pat;
431f90cf607SDaniel W. S. Almeida 
4329cfb4d36SMauro Carvalho Chehab 	programs = vidtv_channel_pat_prog_cat_into_new(m);
4333be80379SMauro Carvalho Chehab 	if (!programs)
4343be80379SMauro Carvalho Chehab 		goto free_sdt;
4359cfb4d36SMauro Carvalho Chehab 	services = vidtv_channel_sdt_serv_cat_into_new(m);
4363be80379SMauro Carvalho Chehab 	if (!services)
4373be80379SMauro Carvalho Chehab 		goto free_programs;
438f90cf607SDaniel W. S. Almeida 
4397a7899f6SDaniel W. S. Almeida 	events = vidtv_channel_eit_event_cat_into_new(m);
4403be80379SMauro Carvalho Chehab 	if (!events)
4413be80379SMauro Carvalho Chehab 		goto free_services;
4427a7899f6SDaniel W. S. Almeida 
443c2f78f0cSDaniel W. S. Almeida 	/* look for a service descriptor for every service */
444c2f78f0cSDaniel W. S. Almeida 	service_list = vidtv_channel_build_service_list(services);
4453be80379SMauro Carvalho Chehab 	if (!service_list)
4463be80379SMauro Carvalho Chehab 		goto free_events;
447c2f78f0cSDaniel W. S. Almeida 
448c2f78f0cSDaniel W. S. Almeida 	/* use these descriptors to build the NIT */
449c2f78f0cSDaniel W. S. Almeida 	m->si.nit = vidtv_psi_nit_table_init(m->network_id,
450c2f78f0cSDaniel W. S. Almeida 					     m->transport_stream_id,
451c2f78f0cSDaniel W. S. Almeida 					     m->network_name,
452c2f78f0cSDaniel W. S. Almeida 					     service_list);
4533be80379SMauro Carvalho Chehab 	if (!m->si.nit)
4543be80379SMauro Carvalho Chehab 		goto free_service_list;
455c2f78f0cSDaniel W. S. Almeida 
456a8bd461cSMauro Carvalho Chehab 	m->si.eit = vidtv_psi_eit_table_init(m->network_id,
45791a8a240SMauro Carvalho Chehab 					     m->transport_stream_id,
45891a8a240SMauro Carvalho Chehab 					     programs->service_id);
4593be80379SMauro Carvalho Chehab 	if (!m->si.eit)
4603be80379SMauro Carvalho Chehab 		goto free_nit;
4613be80379SMauro Carvalho Chehab 
462f90cf607SDaniel W. S. Almeida 	/* assemble all programs and assign to PAT */
463f90cf607SDaniel W. S. Almeida 	vidtv_psi_pat_program_assign(m->si.pat, programs);
464f90cf607SDaniel W. S. Almeida 
465f90cf607SDaniel W. S. Almeida 	/* assemble all services and assign to SDT */
466f90cf607SDaniel W. S. Almeida 	vidtv_psi_sdt_service_assign(m->si.sdt, services);
467f90cf607SDaniel W. S. Almeida 
4687a7899f6SDaniel W. S. Almeida 	/* assemble all events and assign to EIT */
4697a7899f6SDaniel W. S. Almeida 	vidtv_psi_eit_event_assign(m->si.eit, events);
4707a7899f6SDaniel W. S. Almeida 
471a8bd461cSMauro Carvalho Chehab 	m->si.pmt_secs = vidtv_psi_pmt_create_sec_for_each_pat_entry(m->si.pat,
472a8bd461cSMauro Carvalho Chehab 								     m->pcr_pid);
4733be80379SMauro Carvalho Chehab 	if (!m->si.pmt_secs)
4743be80379SMauro Carvalho Chehab 		goto free_eit;
475f90cf607SDaniel W. S. Almeida 
476f90cf607SDaniel W. S. Almeida 	vidtv_channel_pmt_match_sections(m->channels,
477f90cf607SDaniel W. S. Almeida 					 m->si.pmt_secs,
478039b7caeSMauro Carvalho Chehab 					 m->si.pat->num_pmt);
479c2f78f0cSDaniel W. S. Almeida 
480c2f78f0cSDaniel W. S. Almeida 	vidtv_channel_destroy_service_list(service_list);
4813be80379SMauro Carvalho Chehab 
4823be80379SMauro Carvalho Chehab 	return 0;
4833be80379SMauro Carvalho Chehab 
4843be80379SMauro Carvalho Chehab free_eit:
4853be80379SMauro Carvalho Chehab 	vidtv_psi_eit_table_destroy(m->si.eit);
4863be80379SMauro Carvalho Chehab free_nit:
4873be80379SMauro Carvalho Chehab 	vidtv_psi_nit_table_destroy(m->si.nit);
4883be80379SMauro Carvalho Chehab free_service_list:
4893be80379SMauro Carvalho Chehab 	vidtv_channel_destroy_service_list(service_list);
4903be80379SMauro Carvalho Chehab free_events:
4913be80379SMauro Carvalho Chehab 	vidtv_psi_eit_event_destroy(events);
4923be80379SMauro Carvalho Chehab free_services:
4933be80379SMauro Carvalho Chehab 	vidtv_psi_sdt_service_destroy(services);
4943be80379SMauro Carvalho Chehab free_programs:
4953be80379SMauro Carvalho Chehab 	vidtv_psi_pat_program_destroy(programs);
4963be80379SMauro Carvalho Chehab free_sdt:
4973be80379SMauro Carvalho Chehab 	vidtv_psi_sdt_table_destroy(m->si.sdt);
4983be80379SMauro Carvalho Chehab free_pat:
4993be80379SMauro Carvalho Chehab 	vidtv_psi_pat_table_destroy(m->si.pat);
5003be80379SMauro Carvalho Chehab 	return 0;
501f90cf607SDaniel W. S. Almeida }
502f90cf607SDaniel W. S. Almeida 
vidtv_channel_si_destroy(struct vidtv_mux * m)503f90cf607SDaniel W. S. Almeida void vidtv_channel_si_destroy(struct vidtv_mux *m)
504f90cf607SDaniel W. S. Almeida {
505a8bd461cSMauro Carvalho Chehab 	u32 i;
506f90cf607SDaniel W. S. Almeida 
507039b7caeSMauro Carvalho Chehab 	for (i = 0; i < m->si.pat->num_pmt; ++i)
508f90cf607SDaniel W. S. Almeida 		vidtv_psi_pmt_table_destroy(m->si.pmt_secs[i]);
509f90cf607SDaniel W. S. Almeida 
510*3c0dde35SColin Ian King 	vidtv_psi_pat_table_destroy(m->si.pat);
511*3c0dde35SColin Ian King 
512f90cf607SDaniel W. S. Almeida 	kfree(m->si.pmt_secs);
513f90cf607SDaniel W. S. Almeida 	vidtv_psi_sdt_table_destroy(m->si.sdt);
514c2f78f0cSDaniel W. S. Almeida 	vidtv_psi_nit_table_destroy(m->si.nit);
5157a7899f6SDaniel W. S. Almeida 	vidtv_psi_eit_table_destroy(m->si.eit);
516f90cf607SDaniel W. S. Almeida }
517f90cf607SDaniel W. S. Almeida 
vidtv_channels_init(struct vidtv_mux * m)5183be80379SMauro Carvalho Chehab int vidtv_channels_init(struct vidtv_mux *m)
519f90cf607SDaniel W. S. Almeida {
520f90cf607SDaniel W. S. Almeida 	/* this is the place to add new 'channels' for vidtv */
521f90cf607SDaniel W. S. Almeida 	m->channels = vidtv_channel_s302m_init(NULL, m->transport_stream_id);
5223be80379SMauro Carvalho Chehab 
5233be80379SMauro Carvalho Chehab 	if (!m->channels)
5243be80379SMauro Carvalho Chehab 		return -ENOMEM;
5253be80379SMauro Carvalho Chehab 
5263be80379SMauro Carvalho Chehab 	return 0;
527f90cf607SDaniel W. S. Almeida }
528f90cf607SDaniel W. S. Almeida 
vidtv_channels_destroy(struct vidtv_mux * m)529f90cf607SDaniel W. S. Almeida void vidtv_channels_destroy(struct vidtv_mux *m)
530f90cf607SDaniel W. S. Almeida {
531f90cf607SDaniel W. S. Almeida 	struct vidtv_channel *curr = m->channels;
532f90cf607SDaniel W. S. Almeida 	struct vidtv_channel *tmp = NULL;
533f90cf607SDaniel W. S. Almeida 
534f90cf607SDaniel W. S. Almeida 	while (curr) {
535f90cf607SDaniel W. S. Almeida 		kfree(curr->name);
536f90cf607SDaniel W. S. Almeida 		vidtv_psi_sdt_service_destroy(curr->service);
537f90cf607SDaniel W. S. Almeida 		vidtv_psi_pat_program_destroy(curr->program);
538f90cf607SDaniel W. S. Almeida 		vidtv_psi_pmt_stream_destroy(curr->streams);
539f90cf607SDaniel W. S. Almeida 		vidtv_channel_encoder_destroy(curr->encoders);
5407a7899f6SDaniel W. S. Almeida 		vidtv_psi_eit_event_destroy(curr->events);
541f90cf607SDaniel W. S. Almeida 
542f90cf607SDaniel W. S. Almeida 		tmp = curr;
543f90cf607SDaniel W. S. Almeida 		curr = curr->next;
544f90cf607SDaniel W. S. Almeida 		kfree(tmp);
545f90cf607SDaniel W. S. Almeida 	}
546f90cf607SDaniel W. S. Almeida }
547