hal: Branch 'master'
David Zeuthen
david at kemper.freedesktop.org
Wed Feb 28 12:24:02 PST 2007
hald/linux/device.c | 30 ++
hald/linux/probing/Makefile.am | 4
hald/linux/probing/probe-ieee1394-unit.c | 390 +++++++++++++++++++++++++++++++
3 files changed, 419 insertions(+), 5 deletions(-)
New commits:
diff-tree a3f79521a8e02968711e930b7a8deabda1e8e9bd (from 3a9fbfeab22e073a7c3aa87ec89684cc271c3722)
Author: David Zeuthen <davidz at redhat.com>
Date: Wed Feb 28 15:23:47 2007 -0500
probe firewire AVC devices
This code was mostly written by Kristian Hogsberg <krh at redhat.com>
diff --git a/hald/linux/device.c b/hald/linux/device.c
index b3811f6..aab6f4f 100644
--- a/hald/linux/device.c
+++ b/hald/linux/device.c
@@ -2487,6 +2487,26 @@ out:
return d;
}
+static const gchar *
+firewire_get_prober (HalDevice *d)
+{
+ const char *prober = NULL;
+
+ /* run prober only for AVC devices */
+ if (hal_device_has_capability (d, "ieee1394_unit.avc")) {
+ prober = "hald-probe-ieee1394-unit";
+ }
+
+ return prober;
+}
+
+static gboolean
+firewire_post_probing (HalDevice *d)
+{
+ return TRUE;
+}
+
+
static gboolean
firewire_compute_udi (HalDevice *d)
{
@@ -3186,10 +3206,12 @@ static DevHandler dev_handler_ieee1394 =
/* krh's new firewire stack */
static DevHandler dev_handler_firewire = {
- .subsystem = "firewire",
- .add = firewire_add,
- .compute_udi = firewire_compute_udi,
- .remove = dev_remove
+ .subsystem = "firewire",
+ .add = firewire_add,
+ .get_prober = firewire_get_prober,
+ .post_probing = firewire_post_probing,
+ .compute_udi = firewire_compute_udi,
+ .remove = dev_remove
};
static DevHandler dev_handler_xen = {
diff --git a/hald/linux/probing/Makefile.am b/hald/linux/probing/Makefile.am
index 5b2d3c2..6919e64 100644
--- a/hald/linux/probing/Makefile.am
+++ b/hald/linux/probing/Makefile.am
@@ -10,7 +10,7 @@ INCLUDES = \
if HALD_COMPILE_LINUX
libexec_PROGRAMS = hald-probe-input hald-probe-hiddev hald-probe-storage hald-probe-volume hald-probe-printer \
- hald-probe-pc-floppy hald-probe-smbios hald-probe-serial
+ hald-probe-pc-floppy hald-probe-smbios hald-probe-serial hald-probe-ieee1394-unit
endif
hald_probe_smbios_SOURCES = probe-smbios.c ../../logger.c
@@ -37,3 +37,5 @@ hald_probe_pc_floppy_SOURCES = probe-pc-
hald_probe_volume_SOURCES = probe-volume.c linux_dvd_rw_utils.c ../../logger.c
hald_probe_volume_LDADD = $(top_builddir)/libhal/libhal.la $(top_builddir)/partutil/libpartutil.la @GLIB_LIBS@ @VOLUME_ID_LIBS@
+hald_probe_ieee1394_unit_SOURCES = probe-ieee1394-unit.c ../../logger.c
+hald_probe_ieee1394_unit_LDADD = $(top_builddir)/libhal/libhal.la
diff --git a/hald/linux/probing/probe-ieee1394-unit.c b/hald/linux/probing/probe-ieee1394-unit.c
new file mode 100644
index 0000000..ea64814
--- /dev/null
+++ b/hald/linux/probing/probe-ieee1394-unit.c
@@ -0,0 +1,390 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
+ ***************************************************************************
+ * CVSID: $Id$
+ *
+ * probe-ieee1394-unit.c : Probe for Firewire unit types
+ *
+ * Copyright (C) 2007 David Zeuthen, <david at redhat.com>
+ * Copyright (C) 2007 Kristian Hogsberg, <krh at redhat.com>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <sys/mman.h>
+#include <asm/types.h>
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+
+#include "../../logger.h"
+#include "libhal/libhal.h"
+
+/* Defines and structs copied from fw-device-cdev.h */
+
+#define TCODE_WRITE_BLOCK_REQUEST 1
+#define RCODE_COMPLETE 0x0
+#define RCODE_TYPE_ERROR 0x6
+
+#define FW_CDEV_EVENT_BUS_RESET 0x00
+#define FW_CDEV_EVENT_RESPONSE 0x01
+#define FW_CDEV_EVENT_REQUEST 0x02
+#define FW_CDEV_EVENT_ISO_INTERRUPT 0x03
+
+struct fw_cdev_event_response {
+ __u32 type;
+ __u32 rcode;
+ __u64 closure;
+ __u32 length;
+ __u32 data[0];
+};
+
+struct fw_cdev_event_request {
+ __u32 type;
+ __u32 tcode;
+ __u64 offset;
+ __u64 closure;
+ __u32 serial;
+ __u32 length;
+ __u32 data[0];
+};
+
+#define FW_CDEV_IOC_SEND_REQUEST _IO('#', 0x01)
+#define FW_CDEV_IOC_ALLOCATE _IO('#', 0x02)
+#define FW_CDEV_IOC_SEND_RESPONSE _IO('#', 0x03)
+
+struct fw_cdev_send_request {
+ __u32 tcode;
+ __u32 length;
+ __u64 offset;
+ __u64 closure;
+ __u64 data;
+};
+
+struct fw_cdev_send_response {
+ __u32 rcode;
+ __u32 length;
+ __u64 data;
+ __u32 serial;
+};
+
+struct fw_cdev_allocate {
+ __u64 offset;
+ __u64 closure;
+ __u32 length;
+};
+
+/* end of code from fw-device-cdev.h */
+
+
+#define ARRAY_LENGTH(a) (sizeof(a)/sizeof((a)[0]))
+
+#define ptr_to_u64(p) ((__u64)(unsigned long)(p))
+#define u64_to_ptr(p) ((void *)(unsigned long)(p))
+
+#define CSR_FCP_COMMAND 0xfffff0000b00ull
+#define CSR_FCP_RESPONSE 0xfffff0000d00ull
+
+struct avc_frame {
+ unsigned int ctype : 4;
+ unsigned int cts : 4;
+ unsigned int subunit_id : 3;
+ unsigned int subunit_type : 5;
+ unsigned int opcode : 8;
+ unsigned int operand0 : 8;
+};
+
+enum {
+ CTS_AVC
+ /* Nevermind the rest. */
+};
+
+enum {
+ AVC_COMMAND_CONTROL,
+ AVC_COMMAND_STATUS,
+ AVC_COMMAND_SPECIFIC_INQUIRY,
+ AVC_COMMAND_NOTIFY,
+ AVC_COMMAND_GENERAL_INQUIRY,
+ AVC_RESPONSE_NOT_IMPLEMENTED = 0x08,
+ AVC_RESPONSE_ACCEPTED,
+ AVC_RESPONSE_REJECTED,
+ AVC_RESPONSE_IN_TRANSITION,
+ AVC_RESPONSE_STABLE,
+ AVC_RESPONSE_CHANGED,
+ AVC_RESPONSE_INTERIM = 0x0f
+};
+
+enum {
+ AVC_SUBUNIT_MONITOR,
+ AVC_SUBUNIT_AUDIO,
+ AVC_SUBUNIT_PRINTER,
+ AVC_SUBUNIT_DISC,
+ AVC_SUBUNIT_TAPE_RECORDER_PLAYER,
+ AVC_SUBUNIT_TUNER,
+ AVC_SUBUNIT_CA,
+ AVC_SUBUNIT_CAMERA,
+ AVC_SUBUNIT_PANEL = 0x09,
+ AVC_SUBUNIT_BULLETIN_BOARD,
+ AVC_SUBUNIT_CAMERA_STORAGE,
+ AVC_SUBUNIT_VENDOR_UNIQUE = 0x1c,
+ AVC_SUBUNIT_ALL,
+ AVC_SUBUNIT_EXTENDED,
+ AVC_SUBUNIT_UNIT
+};
+
+static const char * const unit_names[] = {
+ "monitor",
+ "audio",
+ "printer",
+ "disc",
+ "tape_recorder_player",
+ "tuner",
+ "ca",
+ "camera",
+ NULL, /* unused */
+ "panel",
+ "bulletin_board",
+ "camera_storage",
+};
+
+enum {
+ AVC_OPCODE_UNIT_INFO = 0x30,
+};
+
+enum {
+ AVC_SUBUNIT_ID_UNIT = 0x07,
+};
+
+static const char *udi = NULL;
+static LibHalContext *ctx = NULL;
+
+
+static void
+send_response (int fd, __u32 serial, int rcode, void *data, size_t length)
+{
+ struct fw_cdev_send_response response;
+
+ response.length = length;
+ response.serial = serial;
+ response.rcode = rcode;
+ response.data = ptr_to_u64(data);
+
+ if (ioctl (fd, FW_CDEV_IOC_SEND_RESPONSE, &response) < 0) {
+ HAL_ERROR (("failed to send response: %s", strerror (errno)));
+ return;
+ }
+}
+
+static int
+handle_request (int fd, struct fw_cdev_event_request *request)
+{
+ struct {
+ struct avc_frame frame;
+ unsigned char operands[8];
+ } *response;
+ unsigned int unit_type;
+ char capname[256];
+
+ if (request->tcode != TCODE_WRITE_BLOCK_REQUEST ||
+ request->offset != CSR_FCP_RESPONSE) {
+ send_response (fd, request->serial, RCODE_TYPE_ERROR, NULL, 0);
+ HAL_ERROR (("AVC response to wrong address"));
+ return -1;
+ }
+
+ send_response (fd, request->serial, RCODE_COMPLETE, NULL, 0);
+
+ response = (void *) request->data;
+ if (response->frame.cts != CTS_AVC) {
+ HAL_ERROR (("not an fcp response"));
+ return -1;
+ }
+
+ if (response->frame.ctype == AVC_RESPONSE_INTERIM) {
+ HAL_ERROR (("got interim"));
+ /* Returning -1 here will make get_unit_info() go back into
+ * poll() and wait for up to 200ms. */
+ return -1;
+ }
+
+ unit_type = response->operands[0] >> 3;
+ if (unit_type > ARRAY_LENGTH(unit_names) || unit_names[unit_type] == NULL) {
+ HAL_ERROR (("unknown unit type"));
+ return -1;
+ }
+
+ snprintf (capname, sizeof (capname), "ieee1394_unit.avc.%s", unit_names[unit_type]);
+ libhal_device_add_capability (ctx, udi, capname, NULL);
+
+ return 0;
+}
+
+/* We wait 200ms for the AV/C response and the IEEE1394 response. */
+#define AVC_TIMEOUT 200
+
+static int
+get_unit_info (int fd)
+{
+ struct {
+ struct avc_frame frame;
+ unsigned char operands[8];
+ } payload;
+ struct fw_cdev_send_request request;
+ union {
+ struct fw_cdev_event_response response;
+ struct fw_cdev_event_request request;
+ __u8 buffer[64];
+ } u;
+ struct pollfd fds[1];
+
+ request.tcode = TCODE_WRITE_BLOCK_REQUEST;
+ request.offset = CSR_FCP_COMMAND;
+ request.length = 8;
+ request.data = ptr_to_u64(&payload);
+
+ payload.frame.cts = CTS_AVC;
+ payload.frame.ctype = AVC_COMMAND_STATUS;
+ payload.frame.subunit_type = AVC_SUBUNIT_UNIT;
+ payload.frame.subunit_id = AVC_SUBUNIT_ID_UNIT;
+ payload.frame.opcode = AVC_OPCODE_UNIT_INFO;
+ payload.frame.operand0 = 0xff;
+ payload.operands[0] = 0xff;
+ payload.operands[1] = 0xff;
+ payload.operands[2] = 0xff;
+ payload.operands[3] = 0xff;
+
+ if (ioctl (fd, FW_CDEV_IOC_SEND_REQUEST, &request) < 0) {
+ HAL_ERROR (("failed to write request: %s", strerror (errno)));
+ return -1;
+ }
+
+ fds[0].fd = fd;
+ fds[1].events = POLLIN;
+
+ while (TRUE) {
+ if (poll (fds, 1, AVC_TIMEOUT) < 0) {
+ HAL_ERROR (("poll error: %s", strerror (errno)));
+ return -1;
+ }
+
+ if (fds[0].revents == 0) {
+ HAL_ERROR (("timeout"));
+ return -1;
+ }
+
+ if (read (fd, &u, sizeof u) < 0) {
+ HAL_ERROR (("read failed: %s", strerror (errno)));
+ return -1;
+ }
+
+ switch (u.response.type) {
+ case FW_CDEV_EVENT_RESPONSE:
+ if (u.response.rcode != RCODE_COMPLETE) {
+ /* The device didn't appreciate us sending an AV/C
+ * command, maybe it doesn't speak AV/C afterall...*/
+ HAL_ERROR (("not AVC device?"));
+ return -1;
+ }
+ break;
+ case FW_CDEV_EVENT_REQUEST:
+ if (handle_request(fd, &u.request) == 0)
+ return 0;
+
+ /* Maybe we got AVC_RESPONSE_INTERIM, so wait a little longer. */
+ break;
+
+ case FW_CDEV_EVENT_BUS_RESET:
+ HAL_ERROR (("bus reset"));
+ return -1;
+
+ default:
+ HAL_ERROR (("unexpected event, shouldn't happen"));
+ return -1;
+ }
+ }
+}
+
+int main (int argc, char *argv[])
+{
+ int i;
+ int fd;
+ int ret;
+ struct fw_cdev_allocate request;
+ const char *device_file;
+ const char *ieee1394_udi;
+ DBusError error;
+
+ /* assume failure */
+ ret = 1;
+
+ setup_logger ();
+
+ udi = getenv ("UDI");
+ if (udi == NULL)
+ goto out;
+
+ ieee1394_udi = getenv ("HAL_PROP_IEEE1394_UNIT_ORIGINATING_DEVICE");
+ if (ieee1394_udi == NULL)
+ goto out;
+
+ dbus_error_init (&error);
+ if ((ctx = libhal_ctx_init_direct (&error)) == NULL)
+ goto out;
+
+ device_file = libhal_device_get_property_string (ctx, ieee1394_udi, "ieee1394.device", &error);
+ if (device_file == NULL)
+ goto out;
+
+ HAL_INFO (("Investigating '%s'", device_file));
+
+ fd = open (device_file, O_RDWR);
+ if (fd < 0) {
+ HAL_ERROR (("failed to open %s: %d", device_file, strerror (errno)));
+ goto out;
+ }
+
+ request.offset = CSR_FCP_RESPONSE;
+ request.length = 0x200;
+ request.closure = (__u64) NULL;
+ if (ioctl (fd, FW_CDEV_IOC_ALLOCATE, &request) < 0) {
+ HAL_ERROR (("failed to allocate fcp response area: %s", device_file, strerror (errno)));
+ goto out;
+ }
+
+ /* Retry the command three times. */
+ for (i = 0; i < 3; i++) {
+ if (get_unit_info(fd) == 0)
+ break;
+ poll (NULL, 0, 500); /* take a 500ms nap */
+ }
+
+ close(fd);
+
+ ret = 0;
+
+out:
+ return ret;
+}
More information about the hal-commit
mailing list