[kde-freebsd] kaffeine-1.0 and webcamd based DVB-T?
Juergen Lock
nox at jelal.kn-bremen.de
Thu Aug 26 20:35:43 CEST 2010
On Wed, Aug 25, 2010 at 11:50:05PM +0200, Hans Petter Selasky wrote:
> On Wednesday 25 August 2010 23:41:41 Juergen Lock wrote:
> > On Tue, Aug 24, 2010 at 05:12:10PM -0400, Joe Marcus Clarke wrote:
> > > On 8/24/10 5:04 PM, Hans Petter Selasky wrote:
> > > > On Tuesday 24 August 2010 22:21:18 Juergen Lock wrote:
> > > >> #! /bin/sh
> > > >> # add PCTV 452e Sat HDTV Pro USB to hal as /dev/dvb/adapter0
> > > >> hal-device --add usb_device_2304_21f_noserial_dvb_0 <<EOF
> > > >> dvb.device = '/dev/dvb/adapter0/demux0' (string)
> > > >> info.capabilities = {'dvb'} (string list)
> > > >> info.category = 'dvb' (string)
> > > >> info.parent =
> > > >> '/org/freedesktop/Hal/devices/usb_device_2304_21f_noserial' (string)
> > > >> info.product = 'DVB Device' (string)
> > > >> info.subsystem = 'dvb' (string)
> > > >> EOF
> > > >> hal-device --add usb_device_2304_21f_noserial_dvb_1 <<EOF
> > > >> dvb.device = '/dev/dvb/adapter0/dvr0' (string)
> > > >> info.capabilities = {'dvb'} (string list)
> > > >> info.category = 'dvb' (string)
> > > >> info.parent =
> > > >> '/org/freedesktop/Hal/devices/usb_device_2304_21f_noserial' (string)
> > > >> info.product = 'DVB Device' (string)
> > > >> info.subsystem = 'dvb' (string)
> > > >> EOF
> > > >> hal-device --add usb_device_2304_21f_noserial_dvb_2 <<EOF
> > > >
> > > > Hi,
> > > >
> > > > Could you have changed this into "execve()" calls (man execve) and add
> > > > these to webcamd.c whenever cuse_dev_create() is called? Also for
> > > > /dev/videoX entries. Then we don't need to patch HAL?
> > >
> > > Yeah, if webcamd can notify hal that new dvb and v4l devices are
> > > available (and what those devices' capabilities are) then we can remove
> > > the patches from hal.
> >
> > Ok I now made that an extra process (so it can open() /dev/videoX
> > normally and also that way webcamd itself doesn't have to link
> > libhal and possible problems with fork() and threads are avoided),
> > webcamd then just feeds it the device nodes on stdin.
> >
> > Untested with v4l devices since I don't have one here, and
> > I also built the helper manually for now and put it into PATH.
> > And the code can still be cleaned up...
> >
> > helper built as:
> >
> > cc -o webcamd-hal-helper -Wall webcamd-hal-helper.c $(pkg-config --cflags
> > hal) $(pkg-config --libs hal) -I/usr/local/include
> >
> > Patch also at:
> >
> > http://people.freebsd.org/~nox/tmp/webcamd-hal.patch
> >
> > HTH, :)
> > Juergen
>
> Looks good.
>
> Could you also register an atexit() function, that cleans up the HAL registry
> when webcamd exits?
Ok, done. (Tho that already happened automagically when unplugging
the device because the /dev/dvb/adapterX/* are registered as childs
of the usb device's hal entry...)
Patch also at:
http://people.freebsd.org/~nox/tmp/webcamd-hal.patch
Index: webcamd.c
===================================================================
--- webcamd.c (revision 1621)
+++ webcamd.c (working copy)
@@ -37,6 +37,11 @@
#include <cuse4bsd.h>
+#ifndef HALHELPER
+/* Helper process that feeds webcamd cuse4bsd device nodes into hal */
+#define HALHELPER "webcamd-hal-helper"
+#endif
+
static cuse_open_t v4b_open;
static cuse_close_t v4b_close;
static cuse_read_t v4b_read;
@@ -76,6 +81,9 @@
static int do_fork = 0;
static int do_realtime = 1;
static struct pidfh *local_pid = NULL;
+#ifdef HALHELPER
+static FILE *fp_halhelper = NULL;
+#endif
char global_fw_prefix[128] = {"/boot/modules"};
@@ -309,6 +317,13 @@
printf("Creating /dev/");
printf(devnames[n / F_V4B_SUBDEV_MAX], temp);
printf("\n");
+#ifdef HALHELPER
+ if (fp_halhelper) {
+ fprintf(fp_halhelper, "/dev/");
+ fprintf(fp_halhelper, devnames[n / F_V4B_SUBDEV_MAX], temp);
+ fprintf(fp_halhelper, "\n");
+ }
+#endif
ndev++;
}
@@ -354,6 +369,10 @@
pidfile_remove(local_pid);
local_pid = NULL;
}
+#ifdef HALHELPER
+ if (fp_halhelper)
+ pclose(fp_halhelper);
+#endif
}
int
@@ -375,6 +394,24 @@
pidfile_write(local_pid);
}
+#ifdef HALHELPER
+ snprintf(buf, sizeof(buf), "%d", bus);
+ setenv("HAL_PROP_USB_BUS_NUMBER", buf, 1);
+ snprintf(buf, sizeof(buf), "%d", addr);
+ setenv("HAL_PROP_USB_PORT_NUMBER", buf, 1);
+ snprintf(buf, sizeof(buf), "%d", 0);
+ setenv("HAL_PROP_USB_INTERFACE_NUMBER", buf, 1);
+
+ if ((fp_halhelper = popen(HALHELPER, "w")) == NULL) {
+ /* XXX */
+ return (EEXIST);
+ }
+ /* Use line buffering */
+ setvbuf(fp_halhelper, (char *)NULL, _IOLBF, 0);
+ /* Keep going if helper exits (e.g. because hal is not running...) */
+ signal(SIGPIPE, SIG_IGN);
+#endif
+
printf("Attached ugen%d.%d[%d] to cuse unit %d\n",
bus, addr, index, u_videodev);
--- /dev/null 2010-08-26 20:22:01.000000000 +0200
+++ webcamd-hal-helper.c 2010-08-26 20:00:07.000000000 +0200
@@ -0,0 +1,348 @@
+/***************************************************************************
+ * CVSID: $Id$
+ *
+ * webcamd-hal-helper.c : Notify hal of webcamd cuse4bsd device nodes
+ * (yes this is a little ugly and could use some cleanup but it works
+ * and I'm lazy :)
+ * Hacked together by : Juergen Lock <nox at FreeBSD.org>
+ *
+ * Takes env vars HAL_PROP_USB_BUS_NUMBER, HAL_PROP_USB_PORT_NUMBER,
+ * and HAL_PROP_USB_INTERFACE_NUMBER to identify the usb device in
+ * question, reads names of v4l/dvb device nodes to add to hal on
+ * stdin, and accepts -n as arg in which case it doesn't clean up
+ * (remove new device nodes from hal) on eof/exit/signal.
+ *
+ * Build as:
+ * cc -o webcamd-hal-helper -Wall webcamd-hal-helper.c $(pkg-config --cflags hal) $(pkg-config --libs hal) -I/usr/local/include
+ *
+ * Uses code from...
+ *
+ * probe-video4linux.c : Probe video4linux devices
+ * Adapted for FreeBSD by : Joe Marcus Clarke <marcus at FreeBSD.org>
+ *
+ * Copyright (C) 2007 Nokia Corporation
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ **************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/user.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <linux/videodev.h>
+#include <linux/videodev2.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "hal/libhal.h"
+
+#define DEBUG
+
+#ifdef DEBUG
+#define h_info printf
+#else
+#define h_info(...) /* */
+#endif
+
+typedef struct {
+ char *udi;
+ char *real_udi;
+} new_dev_t;
+
+static char *hal_udi = NULL;
+static int dvbindex = 0;
+static LibHalContext *hal_ctx = NULL;
+
+static char *
+find_usb_udi (LibHalContext *ctx, int bus, int addr)
+{
+ int i, num_devices;
+
+ char **u_devs = libhal_manager_find_device_string_match
+ (ctx, "info.bus", "usb_device", &num_devices, NULL);
+
+ if (!u_devs || !num_devices)
+ return NULL;
+
+ for (i = 0; i < num_devices; ++i) {
+ if (libhal_device_get_property_int(ctx, u_devs[i],
+ "usb_device.bus_number", NULL) == bus &&
+ libhal_device_get_property_int(ctx, u_devs[i],
+ "usb_device.port_number", NULL) == addr)
+ return u_devs[i];
+ }
+ return NULL;
+}
+
+static void
+cleanup ()
+{
+ int i;
+
+ if (!hal_udi || !dvbindex)
+ return;
+ for (i = 0; i < dvbindex; ++i) {
+ char *dvbudi;
+
+ if (asprintf(&dvbudi, "%s_dvb_%d", hal_udi, i) == -1) {
+ perror("asprintf");
+ break;
+ }
+ h_info ("Removing %s\n", dvbudi);
+ libhal_remove_device(hal_ctx, dvbudi, NULL);
+ free(dvbudi);
+ }
+ dvbindex = 0;
+}
+
+static void
+termsig (int unused)
+{
+ cleanup();
+ exit(0);
+}
+
+int
+main (int argc, char **argv)
+{
+ int ret = 1;
+ int fd = -1;
+ int bus = -1;
+ int addr = -1;
+ int intf = -1;
+ char *device_file = NULL;
+ char *busstr;
+ char *addrstr;
+ char *intfstr;
+ struct video_capability v1cap;
+ struct v4l2_capability v2cap;
+
+ DBusError error;
+ DBusConnection *conn;
+ LibHalChangeSet *cset;
+
+ busstr = getenv ("HAL_PROP_USB_BUS_NUMBER");
+ if (! busstr)
+ goto out;
+ addrstr = getenv ("HAL_PROP_USB_PORT_NUMBER");
+ if (! addrstr)
+ goto out;
+ intfstr = getenv ("HAL_PROP_USB_INTERFACE_NUMBER");
+ if (! intfstr)
+ goto out;
+
+ bus = atoi (busstr);
+ addr = atoi (addrstr);
+ intf = atoi (intfstr);
+
+ if (intf != 0)
+ goto out;
+
+ dbus_error_init(&error);
+ if (!(conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error))) {
+ fprintf(stderr, "error: dbus_bus_get: %s: %s\n", error.name, error.message);
+ LIBHAL_FREE_DBUS_ERROR (&error);
+ return 2;
+ }
+
+ if (!(hal_ctx = libhal_ctx_new())) return 3;
+ if (!libhal_ctx_set_dbus_connection(hal_ctx, conn)) return 4;
+ if (!libhal_ctx_init(hal_ctx, &error)) {
+ if (dbus_error_is_set(&error)) {
+ fprintf (stderr, "error: libhal_ctx_init: %s: %s\n", error.name, error.message);
+ dbus_error_free (&error);
+ }
+ fprintf (stderr, "Could not initialise connection to hald.\n"
+ "Normally this means the HAL daemon (hald) is not running or not ready.\n");
+ return 5;
+ }
+
+ hal_udi = find_usb_udi (hal_ctx, bus, addr);
+ if (hal_udi == NULL) {
+ fprintf(stderr, "Device not found in hal: usb bus %d, address %d\n",
+ bus, addr);
+ goto out;
+ }
+
+ char line[0x1000];
+
+ /* give a meaningful process title for ps(1) */
+ setproctitle("%s (bus: %i, addr: %i)", hal_udi, bus, addr);
+
+ if (argc < 2 || strcmp(argv[1], "-n")) {
+ atexit(&cleanup);
+ signal(SIGTERM, &termsig);
+ signal(SIGINT, &termsig);
+ }
+
+ while (42) {
+ size_t len;
+
+ device_file = fgets(line, sizeof line, stdin);
+ if (device_file == NULL || !(len = strlen(device_file)) ||
+ device_file[len - 1] != '\n')
+ break;
+ device_file[len - 1] = '\0';
+
+ if (!strncmp(device_file, "/dev/video", sizeof "/dev/video" - 1)) {
+ cset = libhal_device_new_changeset (hal_udi);
+
+ h_info ("Doing probe-video4linux-hal for %s (udi=%s)\n", device_file, hal_udi);
+
+ fd = open (device_file, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "Cannot open %s: %s\n", device_file, strerror (errno));
+ goto out;
+ }
+
+ if (ioctl (fd, VIDIOC_QUERYCAP, &v2cap) == 0) {
+ libhal_changeset_set_property_string (cset,
+ "video4linux.device", device_file);
+ libhal_changeset_set_property_string (cset,
+ "info.category", "video4linux");
+ libhal_changeset_set_property_string (cset,
+ "video4linux.version", "2");
+
+ libhal_changeset_set_property_string (cset,
+ "info.product", (const char *)v2cap.card);
+
+ libhal_device_add_capability (hal_ctx, hal_udi, "video4linux", NULL);
+ if ((v2cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) > 0) {
+ libhal_device_add_capability (hal_ctx, hal_udi, "video4linux.video_capture", NULL);
+ } if ((v2cap.capabilities & V4L2_CAP_VIDEO_OUTPUT) > 0) {
+ libhal_device_add_capability (hal_ctx, hal_udi, "video4linux.video_output", NULL);
+ } if ((v2cap.capabilities & V4L2_CAP_VIDEO_OVERLAY) > 0) {
+ libhal_device_add_capability (hal_ctx, hal_udi, "video4linux.video_overlay", NULL);
+ } if ((v2cap.capabilities & V4L2_CAP_AUDIO) > 0) {
+ libhal_device_add_capability (hal_ctx, hal_udi, "video4linux.audio", NULL);
+ } if ((v2cap.capabilities & V4L2_CAP_TUNER) > 0) {
+ libhal_device_add_capability (hal_ctx, hal_udi, "video4linux.tuner", NULL);
+ } if ((v2cap.capabilities & V4L2_CAP_RADIO) > 0) {
+ libhal_device_add_capability (hal_ctx, hal_udi, "video4linux.radio", NULL);
+ }
+ } else {
+ h_info (("ioctl VIDIOC_QUERYCAP failed\n"));
+
+ if (ioctl (fd, VIDIOCGCAP, &v1cap) == 0) {
+ libhal_changeset_set_property_string (cset,
+ "video4linux.device", device_file);
+ libhal_changeset_set_property_string (cset,
+ "info.category", "video4linux");
+ libhal_changeset_set_property_string (cset,
+ "video4linux.version", "1");
+
+ libhal_changeset_set_property_string (cset,
+ "info.product", v1cap.name);
+
+ libhal_device_add_capability (hal_ctx, hal_udi, "video4linux", NULL);
+ if ((v1cap.type & VID_TYPE_CAPTURE) > 0) {
+ libhal_device_add_capability (hal_ctx, hal_udi, "video4linux.video_capture", NULL);
+ } if ((v1cap.type & VID_TYPE_OVERLAY) > 0) {
+ libhal_device_add_capability (hal_ctx, hal_udi, "video4linux.video_overlay", NULL);
+ } if (v1cap.audios > 0) {
+ libhal_device_add_capability (hal_ctx, hal_udi, "video4linux.audio", NULL);
+ } if ((v1cap.type & VID_TYPE_TUNER) > 0) {
+ libhal_device_add_capability (hal_ctx, hal_udi, "video4linux.tuner", NULL);
+ }
+ } else {
+ h_info (("ioctl VIDIOCGCAP failed; not a v4l device\n"));
+ }
+ }
+
+ libhal_device_commit_changeset (hal_ctx, cset, NULL);
+ libhal_device_free_changeset (cset);
+
+ close (fd);
+ } else if (!strncmp(device_file, "/dev/dvb/adapter", sizeof "/dev/dvb/adapter" - 1)) {
+ char *dvbudi;
+ new_dev_t new_dev;
+
+ if (asprintf(&dvbudi, "%s_dvb_%d", hal_udi, dvbindex++) == -1) {
+ perror("asprintf");
+ goto out;
+ }
+ new_dev.udi = strdup(dvbudi);
+ int dev_exists = libhal_device_exists(hal_ctx, dvbudi, NULL);
+
+ if (dev_exists) {
+ new_dev.real_udi = strdup(new_dev.udi);
+ } else {
+ new_dev.real_udi = libhal_new_device(hal_ctx, &error);
+
+ if (!new_dev.real_udi) {
+ fprintf(stderr, "%s: %s\n", error.name, error.message);
+ LIBHAL_FREE_DBUS_ERROR (&error);
+ free(new_dev.real_udi);
+
+ ret = 22;
+ goto out;
+ }
+
+ //printf("tmp udi: %s\n", new_dev.real_udi);
+ }
+
+ cset = libhal_device_new_changeset (new_dev.real_udi);
+
+ h_info ("Doing add-dvb-hal for %s (udi=%s)\n", device_file, new_dev.udi);
+ libhal_changeset_set_property_string (cset,
+ "dvb.device", device_file);
+ libhal_changeset_set_property_string (cset,
+ "info.category", "dvb");
+ libhal_changeset_set_property_string (cset,
+ "info.parent", hal_udi);
+ libhal_changeset_set_property_string (cset,
+ "info.product", "DVB Device");
+ libhal_changeset_set_property_string (cset,
+ "info.subsystem", "dvb");
+ libhal_device_add_capability (hal_ctx, new_dev.real_udi, "dvb", NULL);
+
+ libhal_device_commit_changeset (hal_ctx, cset, NULL);
+ libhal_device_free_changeset (cset);
+
+ if (!dev_exists &&
+ !libhal_device_commit_to_gdl(hal_ctx, new_dev.real_udi, new_dev.udi, &error)) {
+ fprintf(stderr, "%s: %s\n", error.name, error.message);
+ LIBHAL_FREE_DBUS_ERROR (&error);
+ free(new_dev.real_udi);
+
+ ret = 23;
+ goto out;
+ }
+ } else {
+ printf("Unhandled device %s\n", device_file);
+ }
+ }
+
+ ret = 0;
+
+out:
+ if (fd >= 0)
+ close (fd);
+
+ return ret;
+}
More information about the kde-freebsd
mailing list