1 /*
2  * Copyright (c) 2016 - Mauro Carvalho Chehab
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation version 2.1 of the License.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16  * Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
17  */
18 
19 #include <libudev.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <locale.h>
23 #include <unistd.h>
24 #include <string.h>
25 
26 #include <config.h>
27 
28 #include "dvb-fe-priv.h"
29 #include "dvb-dev-priv.h"
30 
31 #ifdef ENABLE_NLS
32 # include <stdio.h>
33 # include <libintl.h>
34 # define _(string) dgettext(LIBDVBV5_DOMAIN, string)
35 #else
36 # define _(string) string
37 #endif
38 
39 const char * const dev_type_names[] = {
40         "frontend", "demux", "dvr", "net", "ca", "sec", "video", "audio"
41 };
42 
43 const unsigned int
44 dev_type_names_size = sizeof(dev_type_names)/sizeof(*dev_type_names);
45 
free_dvb_dev(struct dvb_dev_list * dvb_dev)46 void free_dvb_dev(struct dvb_dev_list *dvb_dev)
47 {
48 	if (dvb_dev->path)
49 		free(dvb_dev->path);
50 	if (dvb_dev->syspath)
51 		free(dvb_dev->syspath);
52 	if (dvb_dev->sysname)
53 		free(dvb_dev->sysname);
54 	if (dvb_dev->bus_addr)
55 		free(dvb_dev->bus_addr);
56 	if (dvb_dev->bus_id)
57 		free(dvb_dev->bus_id);
58 	if (dvb_dev->manufacturer)
59 		free(dvb_dev->manufacturer);
60 	if (dvb_dev->product)
61 		free(dvb_dev->product);
62 	if (dvb_dev->serial)
63 		free(dvb_dev->serial);
64 }
65 
dvb_dev_alloc(void)66 struct dvb_device *dvb_dev_alloc(void)
67 {
68 	struct dvb_device_priv *dvb;
69 	struct dvb_v5_fe_parms_priv *parms;
70 
71 	dvb = calloc(1, sizeof(struct dvb_device_priv));
72 	if (!dvb)
73 		return NULL;
74 
75 	dvb->d.fe_parms = dvb_fe_dummy();
76 	if (!dvb->d.fe_parms) {
77 		dvb_dev_free(&dvb->d);
78 		return NULL;
79 	}
80 	parms = (void *)dvb->d.fe_parms;
81 	parms->dvb = dvb;
82 
83 	/* Initialize it to use the local DVB devices */
84 	dvb_dev_local_init(dvb);
85 
86 	return &dvb->d;
87 }
88 
dvb_dev_free_devices(struct dvb_device_priv * dvb)89 void dvb_dev_free_devices(struct dvb_device_priv *dvb)
90 {
91 	int i;
92 
93 	for (i = 0; i < dvb->d.num_devices; i++)
94 		free_dvb_dev(&dvb->d.devices[i]);
95 	free(dvb->d.devices);
96 
97 	dvb->d.devices = NULL;
98 	dvb->d.num_devices = 0;
99 }
100 
dvb_dev_free(struct dvb_device * d)101 void dvb_dev_free(struct dvb_device *d)
102 {
103 	struct dvb_device_priv *dvb = (void *)d;
104 	struct dvb_open_descriptor *cur, *next;
105 	struct dvb_dev_ops *ops = &dvb->ops;
106 
107 	/* Close all devices */
108 	cur = dvb->open_list.next;
109 	while (cur) {
110 		next = cur->next;
111 		dvb_dev_close(cur);
112 		cur = next;
113 	}
114 
115 	/* Call an implementation-specific free method, if defined */
116 	if (ops->free)
117 		ops->free(dvb);
118 
119 	dvb_fe_close(dvb->d.fe_parms);
120 
121 	dvb_dev_free_devices(dvb);
122 
123 	free(dvb);
124 }
125 
dvb_dev_dump_device(char * msg,struct dvb_v5_fe_parms_priv * parms,struct dvb_dev_list * dev)126 void dvb_dev_dump_device(char *msg,
127 			struct dvb_v5_fe_parms_priv *parms,
128 			struct dvb_dev_list *dev)
129 {
130 	if (parms->p.verbose < 2)
131 		return;
132 
133 	dvb_log(msg, dev_type_names[dev->dvb_type], dev->sysname);
134 
135 	if (dev->path)
136 		dvb_log(_("  path: %s"), dev->path);
137 	if (dev->syspath)
138 		dvb_log(_("  sysfs path: %s"), dev->syspath);
139 	if (dev->bus_addr)
140 		dvb_log(_("  bus addr: %s"), dev->bus_addr);
141 	if (dev->bus_id)
142 		dvb_log(_("  bus ID: %s"), dev->bus_id);
143 	if (dev->manufacturer)
144 		dvb_log(_("  manufacturer: %s"), dev->manufacturer);
145 	if (dev->product)
146 		dvb_log(_("  product: %s"), dev->product);
147 	if (dev->serial)
148 		dvb_log(_("  serial: %s"), dev->serial);
149 }
150 
dvb_dev_seek_by_adapter(struct dvb_device * d,unsigned int adapter,unsigned int num,enum dvb_dev_type type)151 struct dvb_dev_list *dvb_dev_seek_by_adapter(struct dvb_device *d,
152 					     unsigned int adapter,
153 					     unsigned int num,
154 					     enum dvb_dev_type type)
155 {
156 	struct dvb_device_priv *dvb = (void *)d;
157 	struct dvb_dev_ops *ops = &dvb->ops;
158 
159 	if (!ops->seek_by_adapter)
160 		return NULL;
161 
162 	return ops->seek_by_adapter(dvb, adapter, num, type);
163 }
164 
dvb_dev_set_logpriv(struct dvb_device * dvb,unsigned verbose,dvb_logfunc_priv logfunc_priv,void * logpriv)165 void dvb_dev_set_logpriv(struct dvb_device *dvb, unsigned verbose,
166 		     dvb_logfunc_priv logfunc_priv, void *logpriv)
167 {
168 	struct dvb_v5_fe_parms_priv *parms = (void *)dvb->fe_parms;
169 
170 	/* FIXME: how to get remote logs and set verbosity? */
171 	parms->p.verbose = verbose;
172 	parms->logpriv = logpriv;
173 
174 	if (logfunc_priv != NULL)
175 			parms->logfunc_priv = logfunc_priv;
176 }
177 
dvb_dev_set_log(struct dvb_device * dvb,unsigned verbose,dvb_logfunc logfunc)178 void dvb_dev_set_log(struct dvb_device *dvb, unsigned verbose,
179 		     dvb_logfunc logfunc)
180 {
181 	struct dvb_v5_fe_parms_priv *parms = (void *)dvb->fe_parms;
182 
183 	/* FIXME: how to get remote logs and set verbosity? */
184 	parms->p.verbose = verbose;
185 
186 	if (logfunc != NULL)
187 			parms->p.logfunc = logfunc;
188 }
189 
dvb_dev_find(struct dvb_device * d,dvb_dev_change_t handler,void * user_priv)190 int dvb_dev_find(struct dvb_device *d, dvb_dev_change_t handler, void *user_priv)
191 {
192 	struct dvb_device_priv *dvb = (void *)d;
193 	struct dvb_dev_ops *ops = &dvb->ops;
194 
195 	if (!ops->find)
196 		return -1;
197 
198 	return ops->find(dvb, handler, user_priv);
199 }
200 
dvb_dev_stop_monitor(struct dvb_device * d)201 void dvb_dev_stop_monitor(struct dvb_device *d)
202 {
203 	struct dvb_device_priv *dvb = (void *)d;
204 	struct dvb_dev_ops *ops = &dvb->ops;
205 
206 	if (ops->stop_monitor)
207 		ops->stop_monitor(dvb);
208 }
209 
dvb_get_dev_info(struct dvb_device * d,const char * sysname)210 struct dvb_dev_list *dvb_get_dev_info(struct dvb_device *d,
211 				      const char *sysname)
212 {
213 	struct dvb_device_priv *dvb = (void *)d;
214 	struct dvb_dev_ops *ops = &dvb->ops;
215 
216 	if (!ops->get_dev_info)
217 		return NULL;
218 
219 	return ops->get_dev_info(dvb, sysname);
220 }
221 
dvb_dev_open(struct dvb_device * d,const char * sysname,int flags)222 struct dvb_open_descriptor *dvb_dev_open(struct dvb_device *d,
223 					 const char *sysname, int flags)
224 {
225 	struct dvb_device_priv *dvb = (void *)d;
226 	struct dvb_dev_ops *ops = &dvb->ops;
227 
228 	if (!ops->open)
229 		return NULL;
230 
231 	return ops->open(dvb, sysname, flags);
232 }
233 
dvb_dev_get_fd(struct dvb_open_descriptor * open_dev)234 int dvb_dev_get_fd(struct dvb_open_descriptor *open_dev)
235 {
236 	struct dvb_device_priv *dvb = open_dev->dvb;
237 	struct dvb_dev_ops *ops = &dvb->ops;
238 
239 	if (!ops->get_fd)
240 		return -1;
241 
242 	return ops->get_fd(open_dev);
243 }
244 
dvb_dev_close(struct dvb_open_descriptor * open_dev)245 void dvb_dev_close(struct dvb_open_descriptor *open_dev)
246 {
247 	struct dvb_device_priv *dvb = open_dev->dvb;
248 	struct dvb_dev_ops *ops = &dvb->ops;
249 
250 	if (ops->close)
251 		ops->close(open_dev);
252 }
253 
dvb_dev_dmx_stop(struct dvb_open_descriptor * open_dev)254 void dvb_dev_dmx_stop(struct dvb_open_descriptor *open_dev)
255 {
256 	struct dvb_device_priv *dvb = open_dev->dvb;
257 	struct dvb_dev_ops *ops = &dvb->ops;
258 
259 	if (ops->dmx_stop)
260 		ops->dmx_stop(open_dev);
261 }
262 
dvb_dev_set_bufsize(struct dvb_open_descriptor * open_dev,int buffersize)263 int dvb_dev_set_bufsize(struct dvb_open_descriptor *open_dev,
264 			int buffersize)
265 {
266 	struct dvb_device_priv *dvb = open_dev->dvb;
267 	struct dvb_dev_ops *ops = &dvb->ops;
268 
269 	if (!ops->set_bufsize)
270 		return -1;
271 
272 	return ops->set_bufsize(open_dev, buffersize);
273 }
274 
dvb_dev_read(struct dvb_open_descriptor * open_dev,void * buf,size_t count)275 ssize_t dvb_dev_read(struct dvb_open_descriptor *open_dev,
276 		     void *buf, size_t count)
277 {
278 	struct dvb_device_priv *dvb = open_dev->dvb;
279 	struct dvb_dev_ops *ops = &dvb->ops;
280 
281 	if (!ops->read)
282 		return -1;
283 
284 	return ops->read(open_dev, buf, count);
285 }
286 
dvb_dev_dmx_set_pesfilter(struct dvb_open_descriptor * open_dev,int pid,dmx_pes_type_t type,dmx_output_t output,int bufsize)287 int dvb_dev_dmx_set_pesfilter(struct dvb_open_descriptor *open_dev,
288 			      int pid, dmx_pes_type_t type,
289 			      dmx_output_t output, int bufsize)
290 {
291 	struct dvb_device_priv *dvb = open_dev->dvb;
292 	struct dvb_dev_ops *ops = &dvb->ops;
293 
294 	if (!ops->dmx_set_pesfilter)
295 		return -1;
296 
297 	return ops->dmx_set_pesfilter(open_dev, pid, type, output, bufsize);
298 }
299 
dvb_dev_dmx_set_section_filter(struct dvb_open_descriptor * open_dev,int pid,unsigned filtsize,unsigned char * filter,unsigned char * mask,unsigned char * mode,unsigned int flags)300 int dvb_dev_dmx_set_section_filter(struct dvb_open_descriptor *open_dev,
301 				   int pid, unsigned filtsize,
302 				   unsigned char *filter,
303 				   unsigned char *mask,
304 				   unsigned char *mode,
305 				   unsigned int flags)
306 {
307 	struct dvb_device_priv *dvb = open_dev->dvb;
308 	struct dvb_dev_ops *ops = &dvb->ops;
309 
310 	if (!ops->dmx_set_section_filter)
311 		return -1;
312 
313 	return ops->dmx_set_section_filter(open_dev, pid, filtsize, filter,
314 					   mask, mode, flags);
315 }
316 
dvb_dev_dmx_get_pmt_pid(struct dvb_open_descriptor * open_dev,int sid)317 int dvb_dev_dmx_get_pmt_pid(struct dvb_open_descriptor *open_dev, int sid)
318 {
319 	struct dvb_device_priv *dvb = open_dev->dvb;
320 	struct dvb_dev_ops *ops = &dvb->ops;
321 
322 	if (!ops->dmx_get_pmt_pid)
323 		return -1;
324 
325 	return ops->dmx_get_pmt_pid(open_dev, sid);
326 }
327 
dvb_dev_scan(struct dvb_open_descriptor * open_dev,struct dvb_entry * entry,check_frontend_t * check_frontend,void * args,unsigned other_nit,unsigned timeout_multiply)328 struct dvb_v5_descriptors *dvb_dev_scan(struct dvb_open_descriptor *open_dev,
329 					struct dvb_entry *entry,
330 					check_frontend_t *check_frontend,
331 					void *args,
332 					unsigned other_nit,
333 					unsigned timeout_multiply)
334 {
335 	struct dvb_device_priv *dvb = open_dev->dvb;
336 	struct dvb_dev_ops *ops = &dvb->ops;
337 
338 	if (!ops->scan)
339 		return NULL;
340 
341 	return ops->scan(open_dev, entry, check_frontend, args, other_nit,
342 			 timeout_multiply);
343 }
344 
345 /* Frontend functions that can be overriden */
346 
dvb_set_sys(struct dvb_v5_fe_parms * p,fe_delivery_system_t sys)347 int dvb_set_sys(struct dvb_v5_fe_parms *p, fe_delivery_system_t sys)
348 {
349 	struct dvb_v5_fe_parms_priv *parms = (void *)p;
350 	struct dvb_device_priv *dvb = parms->dvb;
351 
352 	if (!dvb || !dvb->ops.fe_set_sys)
353 		return __dvb_set_sys(p, sys);
354 
355 	return dvb->ops.fe_set_sys(p, sys);
356 }
357 
dvb_fe_get_parms(struct dvb_v5_fe_parms * p)358 int dvb_fe_get_parms(struct dvb_v5_fe_parms *p)
359 {
360 	struct dvb_v5_fe_parms_priv *parms = (void *)p;
361 	struct dvb_device_priv *dvb = parms->dvb;
362 
363 	if (!dvb || !dvb->ops.fe_get_parms)
364 		return __dvb_fe_get_parms(p);
365 
366 	return dvb->ops.fe_get_parms(p);
367 }
368 
dvb_fe_set_parms(struct dvb_v5_fe_parms * p)369 int dvb_fe_set_parms(struct dvb_v5_fe_parms *p)
370 {
371 	struct dvb_v5_fe_parms_priv *parms = (void *)p;
372 	struct dvb_device_priv *dvb = parms->dvb;
373 
374 	if (!dvb || !dvb->ops.fe_set_parms)
375 		return __dvb_fe_set_parms(p);
376 
377 	return dvb->ops.fe_set_parms(p);
378 }
379 
dvb_fe_get_stats(struct dvb_v5_fe_parms * p)380 int dvb_fe_get_stats(struct dvb_v5_fe_parms *p)
381 {
382 	struct dvb_v5_fe_parms_priv *parms = (void *)p;
383 	struct dvb_device_priv *dvb = parms->dvb;
384 
385 	if (!dvb || !dvb->ops.fe_get_stats)
386 		return __dvb_fe_get_stats(p);
387 
388 	return dvb->ops.fe_get_stats(p);
389 }
390