From owner-freebsd-gnome@FreeBSD.ORG Wed Aug 25 21:46:45 2010 Return-Path: Delivered-To: gnome@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 251091065695; Wed, 25 Aug 2010 21:46:45 +0000 (UTC) (envelope-from nox@jelal.kn-bremen.de) Received: from smtp.kn-bremen.de (gelbbaer.kn-bremen.de [78.46.108.116]) by mx1.freebsd.org (Postfix) with ESMTP id 95B3C8FC13; Wed, 25 Aug 2010 21:46:44 +0000 (UTC) Received: by smtp.kn-bremen.de (Postfix, from userid 10) id 27E971E00076; Wed, 25 Aug 2010 23:46:43 +0200 (CEST) Received: from triton8.kn-bremen.de (noident@localhost [127.0.0.1]) by triton8.kn-bremen.de (8.14.4/8.14.3) with ESMTP id o7PLffaU009221; Wed, 25 Aug 2010 23:41:41 +0200 (CEST) (envelope-from nox@triton8.kn-bremen.de) Received: (from nox@localhost) by triton8.kn-bremen.de (8.14.4/8.14.3/Submit) id o7PLffTi009220; Wed, 25 Aug 2010 23:41:41 +0200 (CEST) (envelope-from nox) From: Juergen Lock Date: Wed, 25 Aug 2010 23:41:41 +0200 To: Joe Marcus Clarke Message-ID: <20100825214141.GA8685@triton8.kn-bremen.de> References: <4C66C4BC.4040504@janh.de> <201008230914.30762.hselasky@freebsd.org> <20100824202118.GA38687@triton8.kn-bremen.de> <201008242304.54247.hselasky@freebsd.org> <4C7435AA.50805@freebsd.org> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <4C7435AA.50805@freebsd.org> User-Agent: Mutt/1.5.20 (2009-06-14) Cc: me@janh.de, kde@freebsd.org, Hans Petter Selasky , Juergen Lock , freebsd-multimedia@freebsd.org, gnome@freebsd.org Subject: Re: kaffeine-1.0 and webcamd based DVB-T? X-BeenThere: freebsd-gnome@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: GNOME for FreeBSD -- porting and maintaining List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 25 Aug 2010 21:46:45 -0000 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 < >> 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 < >> 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 < > > > 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 Index: webcamd.c =================================================================== --- webcamd.c (revision 1621) +++ webcamd.c (working copy) @@ -37,6 +37,11 @@ #include +#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-25 23:11:00.000000000 +0200 +++ webcamd-hal-helper.c 2010-08-25 22:32:04.000000000 +0200 @@ -0,0 +1,303 @@ +/*************************************************************************** + * CVSID: $Id$ + * + * webcamd-hal-helper.c : Notify hal of webcamd cuse4bsd device nodes + * + * 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 + * + * 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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 * +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; +} + +int +main (int argc, char **argv) +{ + int ret = 1; + int fd = -1; + int bus = -1; + int addr = -1; + int intf = -1; + int dvbindex = 0; + char *device_file = NULL; + char *busstr; + char *addrstr; + char *intfstr; + struct video_capability v1cap; + struct v4l2_capability v2cap; + + DBusError error; + DBusConnection *conn; + LibHalContext *hal_ctx; + 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; + } + + char *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); + + 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; +}