aboutsummaryrefslogtreecommitdiffstats
path: root/lib/libdvbv5/dvb-dev-local.c
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@s-opensource.com>2016-07-28 12:40:41 (GMT)
committerMauro Carvalho Chehab <mchehab@s-opensource.com>2016-07-28 12:40:41 (GMT)
commit1534816d0f3ee8d6c6b771dd9d72afa9d83000a7 (patch)
tree5959ae0fd9d234c041dcba60df8f4d0e27044d7f /lib/libdvbv5/dvb-dev-local.c
parent7785594dd82b4fa04585928e5b825a0df73a2774 (diff)
libdvbv5: rename dvb-dev.c to dvb-dev-local.c
As we'll be implementing support for remote devices, let's first rename the implementation of the local DVB access routines to dvb-dev-local.c. Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
Diffstat (limited to 'lib/libdvbv5/dvb-dev-local.c')
-rw-r--r--lib/libdvbv5/dvb-dev-local.c783
1 files changed, 783 insertions, 0 deletions
diff --git a/lib/libdvbv5/dvb-dev-local.c b/lib/libdvbv5/dvb-dev-local.c
new file mode 100644
index 0000000..789f008
--- /dev/null
+++ b/lib/libdvbv5/dvb-dev-local.c
@@ -0,0 +1,783 @@
+/*
+ * Copyright (c) 2016 - Mauro Carvalho Chehab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation version 2.1 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ */
+
+#include <libudev.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <config.h>
+
+#include "dvb-fe-priv.h"
+#include <libdvbv5/dvb-dev.h>
+
+#ifdef ENABLE_NLS
+# include "gettext.h"
+# include <libintl.h>
+# define _(string) dgettext(LIBDVBV5_DOMAIN, string)
+#else
+# define _(string) string
+#endif
+
+struct dvb_device_priv;
+
+struct dvb_open_descriptor {
+ int fd;
+ struct dvb_dev_list *dev;
+ struct dvb_device_priv *dvb;
+ struct dvb_open_descriptor *next;
+};
+
+struct dvb_device_priv {
+ struct dvb_device d;
+
+ volatile int monitor;
+
+ /* udev control fields */
+ struct udev *udev;
+ struct udev_monitor *mon;
+
+ struct dvb_open_descriptor open_list;
+};
+
+static void free_dvb_dev(struct dvb_dev_list *dvb_dev)
+{
+ if (dvb_dev->path)
+ free (dvb_dev->path);
+ if (dvb_dev->syspath)
+ free (dvb_dev->syspath);
+ if (dvb_dev->sysname)
+ free(dvb_dev->sysname);
+ if (dvb_dev->bus_addr)
+ free(dvb_dev->bus_addr);
+ if (dvb_dev->manufacturer)
+ free(dvb_dev->manufacturer);
+ if (dvb_dev->product)
+ free(dvb_dev->product);
+ if (dvb_dev->serial)
+ free(dvb_dev->serial);
+}
+
+struct dvb_device *dvb_dev_alloc(void)
+{
+ struct dvb_device *dvb;
+
+ dvb = calloc(1, sizeof(struct dvb_device_priv));
+ if (!dvb)
+ return NULL;
+
+ dvb->fe_parms = dvb_fe_dummy();
+ if (!dvb->fe_parms) {
+ dvb_dev_free(dvb);
+ return NULL;
+ }
+
+ return dvb;
+}
+
+static void dvb_dev_free_devices(struct dvb_device_priv *dvb)
+{
+ int i;
+
+ for (i = 0; i < dvb->d.num_devices; i++)
+ free_dvb_dev(&dvb->d.devices[i]);
+ free(dvb->d.devices);
+
+ dvb->d.devices = NULL;
+ dvb->d.num_devices = 0;
+}
+
+void dvb_dev_free(struct dvb_device *d)
+{
+ struct dvb_device_priv *dvb = (void *)d;
+ struct dvb_open_descriptor *cur, *next;
+ struct dvb_v5_fe_parms_priv *parms = (void *)dvb->d.fe_parms;
+
+ /* Close all devices */
+ cur = dvb->open_list.next;
+ while (cur) {
+ next = cur->next;
+ dvb_dev_close(cur);
+ cur = next;
+ }
+
+ dvb_dev_free_devices(dvb);
+
+ /* Wait for dvb_dev_find() to stop */
+ while (dvb->udev) {
+ dvb->monitor = 0;
+ usleep(1000);
+ }
+ __dvb_fe_close(parms);
+ free(dvb);
+}
+
+static const char * const dev_type_names[] = {
+ "frontend", "demux", "dvr", "net", "ca", "sec"
+};
+
+static void dump_device(char *msg,
+ struct dvb_v5_fe_parms_priv *parms,
+ struct dvb_dev_list *dev)
+{
+ if (parms->p.verbose < 2)
+ return;
+
+ dvb_log(msg, dev_type_names[dev->dvb_type], dev->sysname);
+
+ if (dev->path)
+ dvb_log(_(" path: %s"), dev->path);
+ if (dev->syspath)
+ dvb_log(_(" sysfs path: %s"), dev->syspath);
+ if (dev->bus_addr)
+ dvb_log(_(" bus addr: %s"), dev->bus_addr);
+ if (dev->bus_id)
+ dvb_log(_(" bus ID: %s"), dev->bus_id);
+ if (dev->manufacturer)
+ dvb_log(_(" manufacturer: %s"), dev->manufacturer);
+ if (dev->product)
+ dvb_log(_(" product: %s"), dev->product);
+ if (dev->serial)
+ dvb_log(_(" serial: %s"), dev->serial);
+}
+
+struct dvb_dev_list *dvb_dev_seek_by_sysname(struct dvb_device *d,
+ unsigned int adapter,
+ unsigned int num,
+ enum dvb_dev_type type)
+{
+ struct dvb_device_priv *dvb = (void *)d;
+ struct dvb_v5_fe_parms_priv *parms = (void *)dvb->d.fe_parms;
+ int ret, i;
+ char *p;
+
+ if (type > sizeof(dev_type_names)/sizeof(*dev_type_names)){
+ dvb_logerr(_("Unexpected device type found!"));
+ return NULL;
+ }
+
+ ret = asprintf(&p, "dvb%d.%s%d", adapter, dev_type_names[type], num);
+ if (ret < 0) {
+ dvb_logerr(_("error %d when seeking for device's filename"), errno);
+ return NULL;
+ }
+ for (i = 0; i < dvb->d.num_devices; i++) {
+ if (!strcmp(p, dvb->d.devices[i].sysname)) {
+ free(p);
+ dump_device(_("Selected dvb %s device: %s"), parms,
+ &dvb->d.devices[i]);
+ return &dvb->d.devices[i];
+ }
+ }
+
+ dvb_logwarn(_("device %s not found"), p);
+ return NULL;
+}
+
+static int handle_device_change(struct dvb_device_priv *dvb,
+ struct udev_device *dev,
+ const char *syspath,
+ const char *action)
+{
+ struct dvb_v5_fe_parms_priv *parms = (void *)dvb->d.fe_parms;
+ struct udev_device *parent = NULL;
+ struct dvb_dev_list dev_list, *dvb_dev;
+ const char *bus_type, *p;
+ char *buf;
+ int i, ret, len;
+
+ /* remove, change, move should all remove the device first */
+ if (strcmp(action,"add")) {
+ p = udev_device_get_sysname(dev);
+ if (!p) {
+ dvb_logerr(_("udev_device_get_sysname failed"));
+ return -1;
+ }
+
+ for (i = 0; i < dvb->d.num_devices; i++) {
+ if (!strcmp(p, dvb->d.devices[i].sysname)) {
+ memmove(&dvb->d.devices[i],
+ &dvb->d.devices[i + 1],
+ sizeof(*dvb->d.devices) * (dvb->d.num_devices - i));
+ dvb->d.num_devices--;
+
+ p = realloc(dvb->d.devices,
+ sizeof(*dvb->d.devices) * dvb->d.num_devices);
+ if (!p) {
+ dvb_logerr(_("Can't remove a device from the list of DVB devices"));
+ return -2;
+ }
+ break;
+ }
+ }
+
+ /* Return, if the device was removed */
+ if (!strcmp(action,"remove"))
+ return 0;
+ }
+
+ /* Fill mandatory fields: path, sysname, dvb_type, bus_type */
+ dvb_dev = &dev_list;
+ memset(dvb_dev, 0, sizeof(*dvb_dev));
+
+ if (!syspath) {
+ syspath = udev_device_get_devnode(dev);
+ if (!syspath) {
+ dvb_logwarn(_("Can't get device node filename"));
+ goto err;
+ }
+ }
+ dvb_dev->syspath = strdup(syspath);
+
+ p = udev_device_get_devnode(dev);
+ if (!p) {
+ dvb_logwarn(_("Can't get device node filename"));
+ goto err;
+ }
+ dvb_dev->path = strdup(p);
+
+ p = udev_device_get_property_value(dev, "DVB_DEVICE_TYPE");
+ if (!p)
+ goto err;
+ len = sizeof(dev_type_names)/sizeof(*dev_type_names);
+ for (i = 0; i < len; i++) {
+ if (!strcmp(p, dev_type_names[i])) {
+ dvb_dev->dvb_type = i;
+ break;
+ }
+ }
+ if (i == len) {
+ dvb_logwarn(_("Ignoring device %s"), dvb_dev->path);
+ goto err;
+ }
+
+ p = udev_device_get_sysname(dev);
+ if (!p) {
+ dvb_logwarn(_("Can't get sysname for device %s"), dvb_dev->path);
+ goto err;
+ }
+ dvb_dev->sysname = strdup(p);
+
+ parent = udev_device_get_parent(dev);
+ if (!parent)
+ goto added;
+
+ bus_type = udev_device_get_subsystem(parent);
+ if (!bus_type) {
+ dvb_logwarn(_("Can't get bus type for device %s"), dvb_dev->path);
+ goto added;
+ }
+
+ ret = asprintf(&buf, "%s:%s", bus_type, udev_device_get_sysname(parent));
+ if (ret < 0) {
+ dvb_logerr(_("error %d when storing bus address"), errno);
+ goto err;
+ }
+
+ dvb_dev->bus_addr = buf;
+
+ /* Add new element */
+ dvb->d.num_devices++;
+ dvb_dev = realloc(dvb->d.devices, sizeof(*dvb->d.devices) * dvb->d.num_devices);
+ if (!dvb_dev) {
+ dvb_logerr(_("Not enough memory to store the list of DVB devices"));
+ goto err;
+ }
+
+ dvb->d.devices = dvb_dev;
+ dvb->d.devices[dvb->d.num_devices - 1] = dev_list;
+ dvb_dev = &dvb->d.devices[dvb->d.num_devices - 1];
+
+ /* Get optional per-bus fields associated with the device parent */
+ if (!strcmp(bus_type, "pci")) {
+ const char *pci_dev, *pci_vend;
+ char *p;
+
+ pci_dev = udev_device_get_sysattr_value(parent, "subsystem_device");
+ pci_vend = udev_device_get_sysattr_value(parent, "subsystem_vendor");
+
+ if (!pci_dev || !pci_vend)
+ goto added;
+
+ p = strstr(pci_dev, "0x");
+ if (p)
+ pci_dev = p + 2;
+
+ p = strstr(pci_vend, "0x");
+ if (p)
+ pci_vend = p + 2;
+
+ ret = asprintf(&dvb_dev->bus_id, "%s:%s", pci_dev, pci_vend);
+ } else if (!strcmp(bus_type, "usb") || !strcmp(bus_type, "usbdevice")) {
+ const char *vend, *prod;
+
+ vend = udev_device_get_sysattr_value(parent, "idVendor");
+ prod = udev_device_get_sysattr_value(parent, "idProduct");
+
+ if (vend && prod)
+ ret = asprintf(&dvb_dev->bus_id, "%s:%s", vend, prod);
+
+ p = udev_device_get_sysattr_value(parent,"manufacturer");
+ if (p)
+ dvb_dev->manufacturer = strdup(p);
+
+ p = udev_device_get_sysattr_value(parent,"product");
+ if (p)
+ dvb_dev->product = strdup(p);
+
+ p = udev_device_get_sysattr_value(parent, "serial");
+ if (p)
+ dvb_dev->serial = strdup(p);
+ }
+added:
+ dump_device(_("Found dvb %s device: %s"), parms, dvb_dev);
+
+ return 0;
+
+err:
+ free_dvb_dev(dvb_dev);
+ return -1;
+}
+
+int dvb_dev_find(struct dvb_device *d, int enable_monitor)
+{
+ struct dvb_device_priv *dvb = (void *)d;
+ struct dvb_v5_fe_parms_priv *parms = (void *)dvb->d.fe_parms;
+ struct udev_enumerate *enumerate;
+ struct udev_list_entry *devices, *dev_list_entry;
+ struct udev_device *dev;
+ int fd = -1;
+
+ /* Free a previous list of devices */
+ if (dvb->d.num_devices)
+ dvb_dev_free_devices(dvb);
+
+ /* Create the udev object */
+ dvb->udev = udev_new();
+ if (!dvb->udev) {
+ dvb_logerr(_("Can't create an udev object\n"));
+ return -1;
+ }
+
+ dvb->monitor = enable_monitor;
+ if (dvb->monitor) {
+ /* Set up a monitor to monitor dvb devices */
+ dvb->mon = udev_monitor_new_from_netlink(dvb->udev, "udev");
+ udev_monitor_filter_add_match_subsystem_devtype(dvb->mon, "dvb", NULL);
+ udev_monitor_enable_receiving(dvb->mon);
+ fd = udev_monitor_get_fd(dvb->mon);
+ }
+
+ /* Create a list of the devices in the 'dvb' subsystem. */
+ enumerate = udev_enumerate_new(dvb->udev);
+ udev_enumerate_add_match_subsystem(enumerate, "dvb");
+ udev_enumerate_scan_devices(enumerate);
+ devices = udev_enumerate_get_list_entry(enumerate);
+
+ udev_list_entry_foreach(dev_list_entry, devices) {
+ const char *path;
+
+ path = udev_list_entry_get_name(dev_list_entry);
+ dev = udev_device_new_from_syspath(dvb->udev, path);
+
+ handle_device_change(dvb, dev, path, "add");
+ udev_device_unref(dev);
+ }
+
+ /* Free the enumerator object */
+ udev_enumerate_unref(enumerate);
+
+ /* Begin monitoring udev events */
+ while (dvb->monitor) {
+ fd_set fds;
+ struct timeval tv;
+ int ret;
+
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+
+ ret = select(fd + 1, &fds, NULL, NULL, &tv);
+
+ /* Check if our file descriptor has received data. */
+ if (ret > 0 && FD_ISSET(fd, &fds)) {
+ dev = udev_monitor_receive_device(dvb->mon);
+ if (dev) {
+ const char *action = udev_device_get_action(dev);
+ handle_device_change(dvb, dev, NULL, action);
+ }
+ }
+ }
+ udev_unref(dvb->udev);
+ dvb->udev = NULL;
+
+ return 0;
+}
+
+void dvb_dev_stop_monitor(struct dvb_device *d)
+{
+ struct dvb_device_priv *dvb = (void *)d;
+
+ dvb->monitor = 0;
+}
+
+void dvb_dev_set_log(struct dvb_device *dvb, unsigned verbose,
+ dvb_logfunc logfunc)
+{
+ struct dvb_v5_fe_parms_priv *parms = (void *)dvb->fe_parms;
+
+ parms->p.verbose = verbose;
+
+ if (logfunc != NULL)
+ parms->p.logfunc = logfunc;
+}
+
+struct dvb_open_descriptor *dvb_dev_open(struct dvb_device *d,
+ char *sysname, int flags)
+{
+ struct dvb_device_priv *dvb = (void *)d;
+ struct dvb_v5_fe_parms_priv *parms = (void *)d->fe_parms;
+ struct dvb_dev_list *dev = NULL;
+ struct dvb_open_descriptor *open_dev, *cur;
+ int ret, i;
+
+ open_dev = calloc(1, sizeof(*open_dev));
+ if (!open_dev) {
+ dvb_perror("Can't create file descriptor");
+ return NULL;
+ }
+
+ if (!sysname) {
+ dvb_logerr(_("Device not specified"));
+ free(open_dev);
+ return NULL;
+ }
+
+ for (i = 0; i < dvb->d.num_devices; i++) {
+ if (!strcmp(sysname, dvb->d.devices[i].sysname)) {
+ dev = &dvb->d.devices[i];
+ break;
+ }
+ }
+ if (!dev) {
+ dvb_logerr(_("Can't find device %s"), sysname);
+ free(open_dev);
+ return NULL;
+ }
+
+ if (dev->dvb_type == DVB_DEVICE_FRONTEND) {
+ /*
+ * The frontend API was designed for sync frontend access.
+ * It is not ready to handle async frontend access.
+ */
+ flags &= ~O_NONBLOCK;
+
+ ret = dvb_fe_open_fname(parms, dev->path, flags);
+ if (ret) {
+ free(open_dev);
+ return NULL;
+ }
+ ret = parms->fd;
+ } else {
+ /* We don't need special handling for other DVB device types */
+ ret = open(dev->path, flags);
+ if (ret == -1) {
+ dvb_logerr(_("Can't open %s with flags %d: %d %m"),
+ dev->path, flags, errno);
+ free(open_dev);
+ return NULL;
+ }
+ }
+
+ /* Add the fd to the open descriptor's list */
+ open_dev->fd = ret;
+ open_dev->dev = dev;
+ open_dev->dvb = dvb;
+
+ cur = &dvb->open_list;
+ while (cur->next)
+ cur = cur->next;
+ cur->next = open_dev;
+
+ return open_dev;
+}
+
+void dvb_dev_close(struct dvb_open_descriptor *open_dev)
+{
+ struct dvb_dev_list *dev = open_dev->dev;
+ struct dvb_device_priv *dvb = open_dev->dvb;
+ struct dvb_v5_fe_parms_priv *parms = (void *)dvb->d.fe_parms;
+ struct dvb_open_descriptor *cur;
+
+ if (dev->dvb_type == DVB_DEVICE_FRONTEND)
+ __dvb_fe_close(parms);
+ else {
+ if (dev->dvb_type == DVB_DEVICE_DEMUX)
+ dvb_dev_dmx_stop(open_dev);
+
+ close(open_dev->fd);
+ }
+
+ for (cur = &dvb->open_list; cur->next; cur = cur->next) {
+ if (cur->next == open_dev) {
+ cur->next = open_dev->next;
+ free(open_dev);
+ return;
+ }
+ }
+
+ /* Should never happen */
+ dvb_logerr(_("Couldn't free device\n"));
+}
+
+#define MAX_TIME 10 /* 1.0 seconds */
+
+#define xioctl(fh, request, arg...) ({ \
+ int __rc; \
+ struct timespec __start, __end; \
+ \
+ clock_gettime(CLOCK_MONOTONIC, &__start); \
+ do { \
+ __rc = ioctl(fh, request, ##arg); \
+ if (__rc != -1) \
+ break; \
+ if ((errno != EINTR) && (errno != EAGAIN)) \
+ break; \
+ clock_gettime(CLOCK_MONOTONIC, &__end); \
+ if (__end.tv_sec * 10 + __end.tv_nsec / 100000000 > \
+ __start.tv_sec * 10 + __start.tv_nsec / 100000000 + \
+ MAX_TIME) \
+ break; \
+ } while (1); \
+ \
+ __rc; \
+})
+
+void dvb_dev_dmx_stop(struct dvb_open_descriptor *open_dev)
+{
+ struct dvb_dev_list *dev = open_dev->dev;
+ struct dvb_device_priv *dvb = open_dev->dvb;
+ struct dvb_v5_fe_parms_priv *parms = (void *)dvb->d.fe_parms;
+ int ret, fd = open_dev->fd;
+
+ if (dev->dvb_type != DVB_DEVICE_DEMUX)
+ return;
+
+ ret = xioctl(fd, DMX_STOP);
+ if (ret == -1)
+ dvb_perror(_("DMX_STOP failed"));
+}
+
+int dvb_dev_set_bufsize(struct dvb_open_descriptor *open_dev,
+ int buffersize)
+{
+ struct dvb_dev_list *dev = open_dev->dev;
+ struct dvb_device_priv *dvb = open_dev->dvb;
+ struct dvb_v5_fe_parms_priv *parms = (void *)dvb->d.fe_parms;
+ int fd = open_dev->fd;
+
+ if (dev->dvb_type != DVB_DEVICE_DEMUX && dev->dvb_type != DVB_DEVICE_DVR)
+ return -1;
+
+ if (xioctl(fd, DMX_SET_BUFFER_SIZE, buffersize) == -1) {
+ dvb_perror(_("DMX_SET_BUFFER_SIZE failed"));
+ return -1;
+ }
+
+ return 0;
+}
+
+ssize_t dvb_dev_read(struct dvb_open_descriptor *open_dev,
+ void *buf, size_t count)
+{
+ struct dvb_dev_list *dev = open_dev->dev;
+ struct dvb_device_priv *dvb = open_dev->dvb;
+ struct dvb_v5_fe_parms_priv *parms = (void *)dvb->d.fe_parms;
+ int fd = open_dev->fd;
+ ssize_t ret;
+
+ if (dev->dvb_type != DVB_DEVICE_DEMUX && dev->dvb_type != DVB_DEVICE_DVR)
+ return -1;
+
+ ret = read(fd, buf, count);
+ if (ret == -1)
+ dvb_perror("read()");
+
+ return ret;
+}
+
+int dvb_dev_dmx_set_pesfilter(struct dvb_open_descriptor *open_dev,
+ int pid, dmx_pes_type_t type,
+ dmx_output_t output, int bufsize)
+{
+ struct dvb_dev_list *dev = open_dev->dev;
+ struct dvb_device_priv *dvb = open_dev->dvb;
+ struct dvb_v5_fe_parms_priv *parms = (void *)dvb->d.fe_parms;
+ struct dmx_pes_filter_params pesfilter;
+ int fd = open_dev->fd;
+
+ if (dev->dvb_type != DVB_DEVICE_DEMUX)
+ return -1;
+
+ /* Failing here is not fatal, so no need to handle error condition */
+ if (bufsize)
+ dvb_dev_set_bufsize(open_dev, bufsize);
+
+ memset(&pesfilter, 0, sizeof(pesfilter));
+
+ pesfilter.pid = pid;
+ pesfilter.input = DMX_IN_FRONTEND;
+ pesfilter.output = output;
+ pesfilter.pes_type = type;
+ pesfilter.flags = DMX_IMMEDIATE_START;
+
+ if (xioctl(fd, DMX_SET_PES_FILTER, &pesfilter) == -1) {
+ dvb_logerr(_("DMX_SET_PES_FILTER failed (PID = 0x%04x): %d %m"),
+ pid, errno);
+ return -1;
+ }
+
+ return 0;
+}
+
+int 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)
+{
+ struct dvb_dev_list *dev = open_dev->dev;
+ struct dvb_device_priv *dvb = open_dev->dvb;
+ struct dvb_v5_fe_parms_priv *parms = (void *)dvb->d.fe_parms;
+ struct dmx_sct_filter_params sctfilter;
+ int fd = open_dev->fd;
+
+ if (dev->dvb_type != DVB_DEVICE_DEMUX)
+ return -1;
+
+ if (filtsize > DMX_FILTER_SIZE)
+ filtsize = DMX_FILTER_SIZE;
+
+ memset(&sctfilter, 0, sizeof(sctfilter));
+
+ sctfilter.pid = pid;
+
+ if (filter)
+ memcpy(sctfilter.filter.filter, filter, filtsize);
+ if (mask)
+ memcpy(sctfilter.filter.mask, mask, filtsize);
+ if (mode)
+ memcpy(sctfilter.filter.mode, mode, filtsize);
+
+ sctfilter.flags = flags;
+
+ if (xioctl(fd, DMX_SET_FILTER, &sctfilter) == -1) {
+ dvb_logerr(_("DMX_SET_FILTER failed (PID = 0x%04x): %d %m"),
+ pid, errno);
+ return -1;
+ }
+
+ return 0;
+}
+
+int dvb_dev_dmx_get_pmt_pid(struct dvb_open_descriptor *open_dev, int sid)
+{
+ struct dvb_dev_list *dev = open_dev->dev;
+ struct dvb_device_priv *dvb = open_dev->dvb;
+ struct dvb_v5_fe_parms_priv *parms = (void *)dvb->d.fe_parms;
+ struct dmx_sct_filter_params f;
+ unsigned char buft[4096];
+ unsigned char *buf = buft;
+ int fd = open_dev->fd;
+ int count;
+ int pmt_pid = 0;
+ int patread = 0;
+ int section_length;
+
+ if (dev->dvb_type != DVB_DEVICE_DEMUX)
+ return -1;
+
+ memset(&f, 0, sizeof(f));
+ f.pid = 0;
+ f.filter.filter[0] = 0x00;
+ f.filter.mask[0] = 0xff;
+ f.timeout = 0;
+ f.flags = DMX_IMMEDIATE_START | DMX_CHECK_CRC;
+
+ if (xioctl(fd, DMX_SET_FILTER, &f) == -1) {
+ dvb_perror("ioctl DMX_SET_FILTER failed");
+ return -1;
+ }
+
+ while (!patread){
+ if (((count = read(fd, buf, sizeof(buft))) < 0) && errno == EOVERFLOW)
+ count = read(fd, buf, sizeof(buft));
+ if (count < 0) {
+ dvb_perror("read_sections: read error");
+ return -1;
+ }
+
+ section_length = ((buf[1] & 0x0f) << 8) | buf[2];
+ if (count != section_length + 3)
+ continue;
+
+ buf += 8;
+ section_length -= 8;
+
+ patread = 1; /* assumes one section contains the whole pat */
+ while (section_length > 0) {
+ int service_id = (buf[0] << 8) | buf[1];
+ if (service_id == sid) {
+ pmt_pid = ((buf[2] & 0x1f) << 8) | buf[3];
+ section_length = 0;
+ }
+ buf += 4;
+ section_length -= 4;
+ }
+ }
+
+ return pmt_pid;
+}
+
+struct dvb_v5_descriptors *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)
+{
+ struct dvb_dev_list *dev = open_dev->dev;
+ struct dvb_device_priv *dvb = open_dev->dvb;
+ struct dvb_v5_fe_parms_priv *parms = (void *)dvb->d.fe_parms;
+ struct dvb_v5_descriptors *desc;
+ int fd = open_dev->fd;
+
+ if (dev->dvb_type != DVB_DEVICE_DEMUX) {
+ dvb_logerr(_("dvb_dev_scan: expecting a demux descriptor"));
+ return NULL;
+ }
+
+ desc = dvb_scan_transponder(dvb->d.fe_parms, entry, fd, check_frontend,
+ args, other_nit, timeout_multiply);
+
+ return desc;
+}

Privacy Policy