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 #define _FILE_OFFSET_BITS 64
20 #define _LARGEFILE_SOURCE 1
21 #define _LARGEFILE64_SOURCE 1
22 
23 #include <libudev.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <locale.h>
27 #include <unistd.h>
28 #include <string.h>
29 
30 #include <config.h>
31 
32 #ifdef HAVE_PTHREAD
33 #  include <pthread.h>
34 #endif
35 
36 #include "dvb-fe-priv.h"
37 #include "dvb-dev-priv.h"
38 
39 #ifdef ENABLE_NLS
40 # include <stdio.h>
41 # include <libintl.h>
42 # define _(string) dgettext(LIBDVBV5_DOMAIN, string)
43 #else
44 # define _(string) string
45 #endif
46 
47 /* taken from glibc unistd.h */
48 #ifndef TEMP_FAILURE_RETRY
49 #define TEMP_FAILURE_RETRY(expression) \
50     ({ long int __result;                                                     \
51        do __result = (long int) (expression);                                 \
52        while (__result == -1L && errno == EINTR);                             \
53        __result; })
54 #endif
55 
56 struct dvb_dev_local_priv {
57 	dvb_dev_change_t notify_dev_change;
58 
59 #ifdef HAVE_PTHREAD
60 	pthread_t dev_change_id;
61 #endif
62 
63 	/* udev control fields */
64 	int udev_fd;
65 	struct udev *udev;
66 	struct udev_monitor *mon;
67 
68 	/* private user data, used by event notifier*/
69 	void *user_priv;
70 };
71 
handle_device_change(struct dvb_device_priv * dvb,struct udev_device * dev,const char * syspath,const char * action)72 static int handle_device_change(struct dvb_device_priv *dvb,
73 				struct udev_device *dev,
74 				const char *syspath,
75 				const char *action)
76 {
77 	struct dvb_dev_local_priv *priv = dvb->priv;
78 	struct dvb_v5_fe_parms_priv *parms = (void *)dvb->d.fe_parms;
79 	struct udev_device *parent = NULL;
80 	struct dvb_dev_list dev_list, *dvb_dev;
81 	enum dvb_dev_change_type type;
82 	const char *bus_type, *p, *sysname;
83 	char *buf;
84 	int i, ret;
85 
86 	/* remove, change, move should all remove the device first */
87 	if (!strcmp(action,"add")) {
88 		type = DVB_DEV_ADD;
89 	} else {
90 		sysname = udev_device_get_sysname(dev);
91 		if (!sysname) {
92 			dvb_logerr(_("udev_device_get_sysname failed"));
93 			return -ENODEV;
94 		}
95 
96 		for (i = 0; i < dvb->d.num_devices; i++) {
97 			if (!strcmp(sysname, dvb->d.devices[i].sysname)) {
98 				memmove(&dvb->d.devices[i],
99 					&dvb->d.devices[i + 1],
100 					sizeof(*dvb->d.devices) * (dvb->d.num_devices - i));
101 				dvb->d.num_devices--;
102 
103 				if (!dvb->d.num_devices) {
104 					free(dvb->d.devices);
105 					dvb->d.devices = NULL;
106 				} else {
107 					p = realloc(dvb->d.devices,
108 						sizeof(*dvb->d.devices) * dvb->d.num_devices);
109 					if (!p) {
110 						dvb_logerr(_("Can't remove a device from the list of DVB devices"));
111 						return -ENODEV;
112 					}
113 				}
114 				break;
115 			}
116 		}
117 
118 		/* Return, if the device was removed */
119 		if (!strcmp(action,"remove")) {
120 			if (priv->notify_dev_change)
121 				priv->notify_dev_change(strdup(sysname),
122 							DVB_DEV_REMOVE, priv->user_priv);
123 			return 0;
124 		}
125 		type = DVB_DEV_CHANGE;
126 	}
127 
128 	/* Fill mandatory fields: path, sysname, dvb_type, bus_type */
129 	dvb_dev = &dev_list;
130 	memset(dvb_dev, 0, sizeof(*dvb_dev));
131 
132 	if (!syspath) {
133 		syspath = udev_device_get_devnode(dev);
134 		if (!syspath) {
135 			dvb_logwarn(_("Can't get device node filename"));
136 			goto err;
137 		}
138 	}
139 	dvb_dev->syspath = strdup(syspath);
140 
141 	p = udev_device_get_devnode(dev);
142 	if (!p || !*p) {
143 		dvb_logwarn(_("Can't get device node filename"));
144 		goto err;
145 	}
146 	dvb_dev->path = strdup(p);
147 
148 	p = udev_device_get_property_value(dev, "DVB_DEVICE_TYPE");
149 	if (!p)
150 		goto err;
151 	for (i = 0; i < dev_type_names_size; i++) {
152 		if (!strcmp(p, dev_type_names[i])) {
153 			dvb_dev->dvb_type = i;
154 			break;
155 		}
156 	}
157 	if (i == dev_type_names_size) {
158 		dvb_logwarn(_("Ignoring device %s"), dvb_dev->path);
159 		goto err;
160 	}
161 
162 	p = udev_device_get_sysname(dev);
163 	if (!p) {
164 		dvb_logwarn(_("Can't get sysname for device %s"), dvb_dev->path);
165 		goto err;
166 	}
167 	dvb_dev->sysname = strdup(p);
168 
169 	parent = udev_device_get_parent(dev);
170 	if (!parent)
171 		goto added;
172 
173 	bus_type = udev_device_get_subsystem(parent);
174 	if (!bus_type) {
175 		dvb_logwarn(_("Can't get bus type for device %s"), dvb_dev->path);
176 		goto added;
177 	}
178 
179 	ret = asprintf(&buf, "%s:%s", bus_type, udev_device_get_sysname(parent));
180 	if (ret < 0) {
181 		dvb_logerr(_("error %d when storing bus address"), errno);
182 		goto err;
183 	}
184 
185 	dvb_dev->bus_addr = buf;
186 
187 	/* Detect dvbloopback and ignore its control interface */
188 	if (!strcmp(dvb_dev->bus_addr, "platform:dvbloopback")) {
189 		char c = dvb_dev->path[strlen(dvb_dev->path) - 1] - '0';
190 		if (c)
191 			goto err;
192 	}
193 
194 	/* Add new element */
195 	dvb->d.num_devices++;
196 	dvb_dev = realloc(dvb->d.devices, sizeof(*dvb->d.devices) * dvb->d.num_devices);
197 	if (!dvb_dev) {
198 		dvb_logerr(_("Not enough memory to store the list of DVB devices"));
199 		goto err;
200 	}
201 
202 	dvb->d.devices = dvb_dev;
203 	dvb->d.devices[dvb->d.num_devices - 1] = dev_list;
204 	dvb_dev = &dvb->d.devices[dvb->d.num_devices - 1];
205 
206 	/* Get optional per-bus fields associated with the device parent */
207 	if (!strcmp(bus_type, "pci")) {
208 		const char *pci_dev, *pci_vend;
209 		char *p;
210 
211 		pci_dev = udev_device_get_sysattr_value(parent, "subsystem_device");
212 		pci_vend = udev_device_get_sysattr_value(parent, "subsystem_vendor");
213 
214 		if (!pci_dev || !pci_vend)
215 			goto added;
216 
217 		p = strstr(pci_dev, "0x");
218 		if (p)
219 			pci_dev = p + 2;
220 
221 		p = strstr(pci_vend, "0x");
222 		if (p)
223 			pci_vend = p + 2;
224 
225 		ret = asprintf(&dvb_dev->bus_id, "%s:%s", pci_dev, pci_vend);
226 	} else if (!strcmp(bus_type, "usb") || !strcmp(bus_type, "usbdevice")) {
227 		const char *vend, *prod;
228 
229 		vend = udev_device_get_sysattr_value(parent, "idVendor");
230 		prod = udev_device_get_sysattr_value(parent, "idProduct");
231 
232 		if (vend && prod)
233 			ret = asprintf(&dvb_dev->bus_id, "%s:%s", vend, prod);
234 
235 		p = udev_device_get_sysattr_value(parent,"manufacturer");
236 		if (p)
237 			dvb_dev->manufacturer = strdup(p);
238 
239 		p = udev_device_get_sysattr_value(parent,"product");
240 		if (p)
241 			dvb_dev->product = strdup(p);
242 
243 		p = udev_device_get_sysattr_value(parent, "serial");
244 		if (p)
245 			dvb_dev->serial = strdup(p);
246 	}
247 added:
248 	if (priv->notify_dev_change)
249 		priv->notify_dev_change(strdup(dvb_dev->sysname), type, priv->user_priv);
250 	dvb_dev_dump_device(_("Found dvb %s device: %s"), parms, dvb_dev);
251 
252 	return 0;
253 
254 err:
255 	free_dvb_dev(dvb_dev);
256 	return -ENODEV;
257 }
258 
259 #ifdef HAVE_PTHREAD
monitor_device_changes(void * privdata)260 static void *monitor_device_changes(void *privdata)
261 {
262 	struct dvb_device_priv *dvb = privdata;
263 	struct dvb_dev_local_priv *priv = dvb->priv;
264 	struct udev_device *dev;
265 
266 	while (1) {
267 		fd_set fds;
268 		struct timeval tv;
269 		int ret;
270 
271 		FD_ZERO(&fds);
272 		FD_SET(priv->udev_fd, &fds);
273 		tv.tv_sec = 1;
274 		tv.tv_usec = 0;
275 
276 		ret = select(priv->udev_fd + 1, &fds, NULL, NULL, &tv);
277 
278 		/* Check if our file descriptor has received data. */
279 		if (ret > 0 && FD_ISSET(priv->udev_fd, &fds)) {
280 			dev = udev_monitor_receive_device(priv->mon);
281 			if (dev) {
282 				const char *action = udev_device_get_action(dev);
283 				handle_device_change(dvb, dev, NULL, action);
284 			}
285 		}
286 	}
287 	return NULL;
288 }
289 #endif
290 
dvb_local_find(struct dvb_device_priv * dvb,dvb_dev_change_t handler,void * user_priv)291 static int dvb_local_find(struct dvb_device_priv *dvb,
292 			  dvb_dev_change_t handler, void *user_priv)
293 {
294 	struct dvb_v5_fe_parms_priv *parms = (void *)dvb->d.fe_parms;
295 	struct dvb_dev_local_priv *priv = dvb->priv;
296 	struct udev_enumerate *enumerate;
297 	struct udev_list_entry *devices, *dev_list_entry;
298 	struct udev_device *dev;
299 
300 	/* Free a previous list of devices */
301 	if (dvb->d.num_devices)
302 		dvb_dev_free_devices(dvb);
303 
304 	/* Create the udev object */
305 	priv->udev = udev_new();
306 	if (!priv->udev) {
307 		dvb_logerr(_("Can't create an udev object\n"));
308 		return -ENOMEM;
309 	}
310 
311 	priv->user_priv = user_priv;
312 	priv->notify_dev_change = handler;
313 	if (priv->notify_dev_change) {
314 #ifndef HAVE_PTHREAD
315 		dvb_logerr("Need to be compiled with pthreads for monitor");
316 		return -EINVAL;
317 #else
318 		/* Set up a monitor to monitor dvb devices */
319 		priv->mon = udev_monitor_new_from_netlink(priv->udev, "udev");
320 		udev_monitor_filter_add_match_subsystem_devtype(priv->mon, "dvb", NULL);
321 		udev_monitor_enable_receiving(priv->mon);
322 		priv->udev_fd = udev_monitor_get_fd(priv->mon);
323 #endif
324 	}
325 
326 	/* Create a list of the devices in the 'dvb' subsystem. */
327 	enumerate = udev_enumerate_new(priv->udev);
328 	udev_enumerate_add_match_subsystem(enumerate, "dvb");
329 	udev_enumerate_scan_devices(enumerate);
330 	devices = udev_enumerate_get_list_entry(enumerate);
331 
332 	udev_list_entry_foreach(dev_list_entry, devices) {
333 		const char *syspath;
334 
335 		syspath = udev_list_entry_get_name(dev_list_entry);
336 
337 		dev = udev_device_new_from_syspath(priv->udev, syspath);
338 		handle_device_change(dvb, dev, syspath, "add");
339 		udev_device_unref(dev);
340 	}
341 
342 	/* Free the enumerator object */
343 	udev_enumerate_unref(enumerate);
344 
345 	/* Begin monitoring udev events */
346 #ifdef HAVE_PTHREAD
347 	if (priv->notify_dev_change) {
348 		int ret;
349 
350 		ret = pthread_create(&priv->dev_change_id, NULL,
351 				     monitor_device_changes, dvb);
352 		if (ret < 0) {
353 			dvb_perror("pthread_create");
354 			return -1;
355 		}
356 	}
357 #endif
358 	if (!priv->notify_dev_change) {
359 		udev_unref(priv->udev);
360 		priv->udev = NULL;
361 	}
362 
363 	return 0;
364 }
365 
dvb_local_stop_monitor(struct dvb_device_priv * dvb)366 static int dvb_local_stop_monitor(struct dvb_device_priv *dvb)
367 {
368 #ifdef HAVE_PTHREAD
369 	struct dvb_dev_local_priv *priv = dvb->priv;
370 
371 	if (priv->notify_dev_change) {
372 		pthread_cancel(priv->dev_change_id);
373 		udev_unref(priv->udev);
374 	}
375 #endif
376 
377 	return 0;
378 }
379 
dvb_local_seek_by_adapter(struct dvb_device_priv * dvb,unsigned int adapter,unsigned int num,enum dvb_dev_type type)380 struct dvb_dev_list *dvb_local_seek_by_adapter(struct dvb_device_priv *dvb,
381 					       unsigned int adapter,
382 					       unsigned int num,
383 					       enum dvb_dev_type type)
384 {
385 	struct dvb_v5_fe_parms_priv *parms = (void *)dvb->d.fe_parms;
386 	int ret, i;
387 	char *p;
388 
389 	if (type > dev_type_names_size){
390 		dvb_logerr(_("Unexpected device type found!"));
391 		return NULL;
392 	}
393 
394 	ret = asprintf(&p, "dvb%d.%s%d", adapter, dev_type_names[type], num);
395 	if (ret < 0) {
396 		dvb_logerr(_("error %d when seeking for device's filename"),
397 			   errno);
398 		return NULL;
399 	}
400 	for (i = 0; i < dvb->d.num_devices; i++) {
401 		if (!strcmp(p, dvb->d.devices[i].sysname)) {
402 			free(p);
403 			dvb_dev_dump_device(_("Selected dvb %s device: %s"),
404 					    parms, &dvb->d.devices[i]);
405 			return &dvb->d.devices[i];
406 		}
407 	}
408 
409 	dvb_logwarn(_("device %s not found"), p);
410 	return NULL;
411 }
412 
dvb_local_get_dev_info(struct dvb_device_priv * dvb,const char * sysname)413 struct dvb_dev_list *dvb_local_get_dev_info(struct dvb_device_priv *dvb,
414 					    const char *sysname)
415 {
416 	struct dvb_v5_fe_parms_priv *parms = (void *)dvb->d.fe_parms;
417 	int i;
418 
419 	if (!sysname) {
420 		dvb_logerr(_("Device not specified"));
421 		return NULL;
422 	}
423 
424 	for (i = 0; i < dvb->d.num_devices; i++) {
425 		if (!strcmp(sysname, dvb->d.devices[i].sysname)) {
426 			return &dvb->d.devices[i];
427 		}
428 	}
429 
430 	dvb_logerr(_("Can't find device %s"), sysname);
431 	return NULL;
432 }
433 
434 static struct dvb_open_descriptor
dvb_local_open(struct dvb_device_priv * dvb,const char * sysname,int flags)435 *dvb_local_open(struct dvb_device_priv *dvb,
436 		const char *sysname, int flags)
437 {
438 	struct dvb_v5_fe_parms_priv *parms = (void *)dvb->d.fe_parms;
439 	struct dvb_dev_list *dev;
440 	struct dvb_open_descriptor *open_dev, *cur;
441 	int ret;
442 
443 	dev = dvb_local_get_dev_info(dvb, sysname);
444 	if (!dev)
445 		return NULL;
446 
447 	open_dev = calloc(1, sizeof(*open_dev));
448 	if (!open_dev) {
449 		dvb_perror("Can't create file descriptor");
450 		return NULL;
451 	}
452 
453 	if (dev->dvb_type == DVB_DEVICE_FRONTEND) {
454 		/*
455 		 * The frontend API was designed for sync frontend access.
456 		 * It is not ready to handle async frontend access.
457 		 * However, dvbloopback is a different beast: it only works
458 		 * if opened with O_NONBLOCK.
459 		 * Also, support for FE_SET_PROPERTY/FE_GET_PROPERTY
460 		 * is broken with dvbloopback and recent Kernels, as it
461 		 * doesn't copy from/to usermemory properly.
462 		 */
463 		if (!strcmp(dev->bus_addr, "platform:dvbloopback")) {
464 			dvb_logwarn(_("Detected dvbloopback"));
465 			flags |= O_NONBLOCK;
466 		} else {
467 			flags &= ~O_NONBLOCK;
468 		}
469 
470 		ret = dvb_fe_open_fname(parms, strdup(dev->path), flags);
471 		if (ret) {
472 			free(open_dev);
473 			return NULL;
474 		}
475 		ret = parms->fd;
476 	} else {
477 		/* We don't need special handling for other DVB device types */
478 		ret = open(dev->path, flags);
479 		if (ret == -1) {
480 			dvb_logerr(_("Can't open %s with flags %d: %d %m"),
481 				   dev->path, flags, errno);
482 			free(open_dev);
483 			return NULL;
484 		}
485 	}
486 
487 	/* Add the fd to the open descriptor's list */
488 	open_dev->fd = ret;
489 	open_dev->dev = dev;
490 	open_dev->dvb = dvb;
491 
492 	cur = &dvb->open_list;
493 	while (cur->next)
494 		cur = cur->next;
495 	cur->next = open_dev;
496 
497 	return open_dev;
498 }
499 
dvb_local_close(struct dvb_open_descriptor * open_dev)500 static int dvb_local_close(struct dvb_open_descriptor *open_dev)
501 {
502 	struct dvb_dev_list *dev = open_dev->dev;
503 	struct dvb_device_priv *dvb = open_dev->dvb;
504 	struct dvb_v5_fe_parms_priv *parms = (void *)dvb->d.fe_parms;
505 	struct dvb_open_descriptor *cur;
506 
507 	if (dev->dvb_type == DVB_DEVICE_FRONTEND)
508 		__dvb_fe_close(parms);
509 	else {
510 		if (dev->dvb_type == DVB_DEVICE_DEMUX)
511 			dvb_dev_dmx_stop(open_dev);
512 
513 		close(open_dev->fd);
514 	}
515 
516 	for (cur = &dvb->open_list; cur->next; cur = cur->next) {
517 		if (cur->next == open_dev) {
518 			cur->next = open_dev->next;
519 			free(open_dev);
520 			return 0;
521 		}
522 	}
523 
524 	/* Should never happen */
525 	dvb_logerr(_("Couldn't free device\n"));
526 
527 	return -ENODEV;
528 }
529 
530 #define MAX_TIME		10	/* 1.0 seconds */
531 
532 #define xioctl(fh, request, arg...) ({					\
533 	int __rc;							\
534 	struct timespec __start, __end;					\
535 									\
536 	clock_gettime(CLOCK_MONOTONIC, &__start);			\
537 	do {								\
538 		__rc = ioctl(fh, request, ##arg);			\
539 		if (__rc != -1)						\
540 			break;						\
541 		if ((errno != EINTR) && (errno != EAGAIN))		\
542 			break;						\
543 		clock_gettime(CLOCK_MONOTONIC, &__end);			\
544 		if (__end.tv_sec * 10 + __end.tv_nsec / 100000000 >	\
545 		    __start.tv_sec * 10 + __start.tv_nsec / 100000000 +	\
546 		    MAX_TIME)						\
547 			break;						\
548 	} while (1);							\
549 									\
550 	__rc;								\
551 })
552 
dvb_local_dmx_stop(struct dvb_open_descriptor * open_dev)553 static int dvb_local_dmx_stop(struct dvb_open_descriptor *open_dev)
554 {
555 	struct dvb_dev_list *dev = open_dev->dev;
556 	struct dvb_device_priv *dvb = open_dev->dvb;
557 	struct dvb_v5_fe_parms_priv *parms = (void *)dvb->d.fe_parms;
558 	int ret, fd = open_dev->fd;
559 
560 	if (dev->dvb_type != DVB_DEVICE_DEMUX)
561 		return -EINVAL;
562 
563 	ret = xioctl(fd, DMX_STOP);
564 	if (ret == -1) {
565 		dvb_perror(_("DMX_STOP failed"));
566 		return -errno;
567 	}
568 
569 	return 0;
570 }
571 
dvb_local_set_bufsize(struct dvb_open_descriptor * open_dev,int buffersize)572 static int dvb_local_set_bufsize(struct dvb_open_descriptor *open_dev,
573 			int buffersize)
574 {
575 	struct dvb_dev_list *dev = open_dev->dev;
576 	struct dvb_device_priv *dvb = open_dev->dvb;
577 	struct dvb_v5_fe_parms_priv *parms = (void *)dvb->d.fe_parms;
578 	int fd = open_dev->fd;
579 
580 	if (dev->dvb_type != DVB_DEVICE_DEMUX && dev->dvb_type != DVB_DEVICE_DVR)
581 		return -EINVAL;
582 
583 	if (xioctl(fd, DMX_SET_BUFFER_SIZE, buffersize) == -1) {
584 		dvb_perror(_("DMX_SET_BUFFER_SIZE failed"));
585 		return -errno;
586 	}
587 
588 	return 0;
589 }
590 
dvb_local_read(struct dvb_open_descriptor * open_dev,void * buf,size_t count)591 static ssize_t dvb_local_read(struct dvb_open_descriptor *open_dev,
592 		     void *buf, size_t count)
593 {
594 	struct dvb_dev_list *dev = open_dev->dev;
595 	struct dvb_device_priv *dvb = open_dev->dvb;
596 	struct dvb_v5_fe_parms_priv *parms = (void *)dvb->d.fe_parms;
597 	int fd = open_dev->fd;
598 	ssize_t ret;
599 
600 	if (dev->dvb_type != DVB_DEVICE_DEMUX && dev->dvb_type != DVB_DEVICE_DVR) {
601 		dvb_logerr("Trying to read from an invalid device type on fd #%d", fd);
602 		return -EINVAL;
603 	}
604 
605 	/*
606 	 * As we opened dvbloopback on non-blocking mode, we need to
607 	 * check if read is ready, in order to emulate blocking mode
608 	 */
609 	if (!strcmp(dev->bus_addr, "platform:dvbloopback")) {
610 		fd_set rset;
611 		fd_set eset;
612 
613 		FD_ZERO(&rset);
614 		FD_SET(fd, &rset);
615 		FD_ZERO(&eset);
616 		FD_SET(fd, &eset);
617 		ret = TEMP_FAILURE_RETRY(select(FD_SETSIZE,
618 						&rset, NULL, &eset, NULL));
619 		if (ret == -1) {
620 			if (errno != EOVERFLOW)
621 				dvb_perror("read()");
622 			return -errno;
623 		}
624 	}
625 
626 	ret = TEMP_FAILURE_RETRY(read(fd, buf, count));
627 	if (ret == -1) {
628 		if (errno != EOVERFLOW && errno != EAGAIN)
629 			dvb_perror("read()");
630 		return -errno;
631 	}
632 
633 	return ret;
634 }
635 
dvb_local_dmx_set_pesfilter(struct dvb_open_descriptor * open_dev,int pid,dmx_pes_type_t type,dmx_output_t output,int bufsize)636 static int dvb_local_dmx_set_pesfilter(struct dvb_open_descriptor *open_dev,
637 			      int pid, dmx_pes_type_t type,
638 			      dmx_output_t output, int bufsize)
639 {
640 	struct dvb_dev_list *dev = open_dev->dev;
641 	struct dvb_device_priv *dvb = open_dev->dvb;
642 	struct dvb_v5_fe_parms_priv *parms = (void *)dvb->d.fe_parms;
643 	struct dmx_pes_filter_params pesfilter;
644 	int fd = open_dev->fd;
645 
646 	if (dev->dvb_type != DVB_DEVICE_DEMUX)
647 		return -EINVAL;
648 
649 	/* Failing here is not fatal, so no need to handle error condition */
650 	if (bufsize)
651 		dvb_dev_set_bufsize(open_dev, bufsize);
652 
653 	memset(&pesfilter, 0, sizeof(pesfilter));
654 
655 	pesfilter.pid = pid;
656 	pesfilter.input = DMX_IN_FRONTEND;
657 	pesfilter.output = output;
658 	pesfilter.pes_type = type;
659 	pesfilter.flags = DMX_IMMEDIATE_START;
660 
661 	if (xioctl(fd, DMX_SET_PES_FILTER, &pesfilter) == -1) {
662 		dvb_logerr(_("DMX_SET_PES_FILTER failed (PID = 0x%04x): %d %m"),
663 			   pid, errno);
664 		return -errno;
665 	}
666 
667 	return 0;
668 }
669 
dvb_local_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)670 static int dvb_local_dmx_set_section_filter(struct dvb_open_descriptor *open_dev,
671 				   int pid, unsigned filtsize,
672 				   unsigned char *filter,
673 				   unsigned char *mask,
674 				   unsigned char *mode,
675 				   unsigned int flags)
676 {
677 	struct dvb_dev_list *dev = open_dev->dev;
678 	struct dvb_device_priv *dvb = open_dev->dvb;
679 	struct dvb_v5_fe_parms_priv *parms = (void *)dvb->d.fe_parms;
680 	struct dmx_sct_filter_params sctfilter;
681 	int fd = open_dev->fd;
682 
683 	if (dev->dvb_type != DVB_DEVICE_DEMUX)
684 		return -EINVAL;
685 
686 	if (filtsize > DMX_FILTER_SIZE)
687 		filtsize = DMX_FILTER_SIZE;
688 
689 	memset(&sctfilter, 0, sizeof(sctfilter));
690 
691 	sctfilter.pid = pid;
692 
693 	if (filter)
694 		memcpy(sctfilter.filter.filter, filter, filtsize);
695 	if (mask)
696 		memcpy(sctfilter.filter.mask, mask, filtsize);
697 	if (mode)
698 		memcpy(sctfilter.filter.mode, mode, filtsize);
699 
700 	sctfilter.flags = flags;
701 
702 	if (xioctl(fd, DMX_SET_FILTER, &sctfilter) == -1) {
703 		dvb_logerr(_("DMX_SET_FILTER failed (PID = 0x%04x): %d %m"),
704 			pid, errno);
705 		return -errno;
706 	}
707 
708 	return 0;
709 }
710 
dvb_local_dmx_get_pmt_pid(struct dvb_open_descriptor * open_dev,int sid)711 static int dvb_local_dmx_get_pmt_pid(struct dvb_open_descriptor *open_dev, int sid)
712 {
713 	struct dvb_dev_list *dev = open_dev->dev;
714 	struct dvb_device_priv *dvb = open_dev->dvb;
715 	struct dvb_v5_fe_parms_priv *parms = (void *)dvb->d.fe_parms;
716 	struct dmx_sct_filter_params f;
717 	unsigned char buft[4096];
718 	unsigned char *buf = buft;
719 	int fd = open_dev->fd;
720 	int count;
721 	int pmt_pid = 0;
722 	int patread = 0;
723 	int section_length;
724 
725 	if (dev->dvb_type != DVB_DEVICE_DEMUX)
726 		return -EINVAL;
727 
728 	memset(&f, 0, sizeof(f));
729 	f.pid = 0;
730 	f.filter.filter[0] = 0x00;
731 	f.filter.mask[0] = 0xff;
732 	f.timeout = 0;
733 	f.flags = DMX_IMMEDIATE_START | DMX_CHECK_CRC;
734 
735 	if (xioctl(fd, DMX_SET_FILTER, &f) == -1) {
736 		dvb_perror("ioctl DMX_SET_FILTER failed");
737 		return -errno;
738 	}
739 
740 	while (!patread){
741 		count = TEMP_FAILURE_RETRY(read(fd, buf, sizeof(buft)));
742 		if (count < 0 && errno == EOVERFLOW)
743 			count = TEMP_FAILURE_RETRY(read(fd, buf, sizeof(buft)));
744 		if (count < 0) {
745 		dvb_perror("read_sections: read error");
746 		return -errno;
747 		}
748 
749 		section_length = ((buf[1] & 0x0f) << 8) | buf[2];
750 		if (count != section_length + 3)
751 			continue;
752 
753 		buf += 8;
754 		section_length -= 8;
755 
756 		patread = 1; /* assumes one section contains the whole pat */
757 		while (section_length > 0) {
758 		int service_id = (buf[0] << 8) | buf[1];
759 		if (service_id == sid) {
760 			pmt_pid = ((buf[2] & 0x1f) << 8) | buf[3];
761 			section_length = 0;
762 		}
763 		buf += 4;
764 		section_length -= 4;
765 		}
766 	}
767 
768 	return pmt_pid;
769 }
770 
dvb_local_scan(struct dvb_open_descriptor * open_dev,struct dvb_entry * entry,check_frontend_t * check_frontend,void * args,unsigned other_nit,unsigned timeout_multiply)771 static struct dvb_v5_descriptors *dvb_local_scan(struct dvb_open_descriptor *open_dev,
772 					struct dvb_entry *entry,
773 					check_frontend_t *check_frontend,
774 					void *args,
775 					unsigned other_nit,
776 					unsigned timeout_multiply)
777 {
778 	struct dvb_dev_list *dev = open_dev->dev;
779 	struct dvb_device_priv *dvb = open_dev->dvb;
780 	struct dvb_v5_fe_parms_priv *parms = (void *)dvb->d.fe_parms;
781 	struct dvb_v5_descriptors *desc;
782 	int fd = open_dev->fd;
783 
784 	if (dev->dvb_type != DVB_DEVICE_DEMUX) {
785 		dvb_logerr(_("dvb_dev_scan: expecting a demux descriptor"));
786 		return NULL;
787 	}
788 
789 	desc = dvb_scan_transponder(dvb->d.fe_parms, entry, fd, check_frontend,
790 				    args, other_nit, timeout_multiply);
791 
792 	return desc;
793 }
794 
795 /* Frontend functions that can be overriden */
796 
dvb_local_fe_set_sys(struct dvb_v5_fe_parms * p,fe_delivery_system_t sys)797 int dvb_local_fe_set_sys(struct dvb_v5_fe_parms *p, fe_delivery_system_t sys)
798 {
799 	return __dvb_set_sys(p, sys);
800 }
801 
dvb_local_fe_get_parms(struct dvb_v5_fe_parms * p)802 int dvb_local_fe_get_parms(struct dvb_v5_fe_parms *p)
803 {
804 	return __dvb_fe_get_parms(p);
805 }
806 
dvb_local_fe_set_parms(struct dvb_v5_fe_parms * p)807 int dvb_local_fe_set_parms(struct dvb_v5_fe_parms *p)
808 {
809 	return __dvb_fe_set_parms(p);
810 }
811 
dvb_local_fe_get_stats(struct dvb_v5_fe_parms * p)812 int dvb_local_fe_get_stats(struct dvb_v5_fe_parms *p)
813 {
814 	return __dvb_fe_get_stats(p);
815 }
816 
817 
dvb_dev_local_free(struct dvb_device_priv * dvb)818 static void dvb_dev_local_free(struct dvb_device_priv *dvb)
819 {
820 	struct dvb_dev_local_priv *priv = dvb->priv;
821 
822 	dvb_local_stop_monitor(dvb);
823 
824 	free(priv);
825 }
826 
dvb_local_get_fd(struct dvb_open_descriptor * open_dev)827 static int dvb_local_get_fd(struct dvb_open_descriptor *open_dev)
828 {
829     return open_dev->fd;
830 }
831 
832 /* Initialize for local usage */
dvb_dev_local_init(struct dvb_device_priv * dvb)833 void dvb_dev_local_init(struct dvb_device_priv *dvb)
834 {
835 	struct dvb_dev_ops *ops = &dvb->ops;
836 
837 	dvb->priv = calloc(1, sizeof(struct dvb_dev_local_priv));
838 
839 	ops->find = dvb_local_find;
840 	ops->seek_by_adapter = dvb_local_seek_by_adapter;
841 	ops->get_dev_info = dvb_local_get_dev_info;
842 	ops->stop_monitor = dvb_local_stop_monitor;
843 	ops->open = dvb_local_open;
844 	ops->close = dvb_local_close;
845 	ops->get_fd = dvb_local_get_fd;
846 
847 	ops->dmx_stop = dvb_local_dmx_stop;
848 	ops->set_bufsize = dvb_local_set_bufsize;
849 	ops->read = dvb_local_read;
850 	ops->dmx_set_pesfilter = dvb_local_dmx_set_pesfilter;
851 	ops->dmx_set_section_filter = dvb_local_dmx_set_section_filter;
852 	ops->dmx_get_pmt_pid = dvb_local_dmx_get_pmt_pid;
853 
854 	ops->scan = dvb_local_scan;
855 
856 	ops->fe_set_sys = dvb_local_fe_set_sys;
857 	ops->fe_get_parms = dvb_local_fe_get_parms;
858 	ops->fe_set_parms = dvb_local_fe_set_parms;
859 	ops->fe_get_stats = dvb_local_fe_get_stats;
860 
861 	ops->free = dvb_dev_local_free;
862 }
863