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