diff --git a/Makefile.am b/Makefile.am
index 04ed38a..21df527 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,6 +1,7 @@
# process this file with automake to create a Makefile.in
-SUBDIRS = src tools doc debian
+SUBDIRS = $(LIB_SUBDIR) tools doc debian
+DIST_SUBDIRS = src juju
pkgconfigdir = @libdir@/pkgconfig
pkgconfig_DATA = libraw1394.pc
diff --git a/configure.ac b/configure.ac
index fe23ca8..7e5dd66 100644
--- a/configure.ac
+++ b/configure.ac
@@ -24,6 +24,27 @@ AC_SUBST(lt_major)
AC_SUBST(lt_revision)
AC_SUBST(lt_age)
+AC_ARG_WITH(juju-dir,[ --with-juju-dir=
Path to juju include files])
+if ! test -z "$with_juju_dir" ; then
+ JUJU_DIR="$with_juju_dir"
+ LIB_SUBDIR=juju
+ AC_SUBST(JUJU_DIR)
+else
+ LIB_SUBDIR=src
+fi
+AC_SUBST(LIB_SUBDIR)
+
+AC_ARG_WITH(fw-device-prefix,
+ [ --with-fw-device-prefix= Prefix of firewire device file names (default "fw").],
+ [FW_DEVICE_PREFIX="\"$withval\""], [FW_DEVICE_PREFIX="\"fw\""])
+AC_ARG_WITH(fw-device-dir,
+ [ --with-fw-device-dir= Directory to watch for firewire device files (default "/dev").],
+ [FW_DEVICE_DIR="\"$withval\""], [FW_DEVICE_DIR="\"/dev\""])
+
+AC_DEFINE_UNQUOTED(FW_DEVICE_PREFIX, $FW_DEVICE_PREFIX,
+ [Prefix of firewire device file names.])
+AC_DEFINE_UNQUOTED(FW_DEVICE_DIR, $FW_DEVICE_DIR,
+ [Directory to watch for firewire device files.])
#CFLAGS=${CFLAGS:-"-Wall"}
AC_OUTPUT([
@@ -31,6 +52,7 @@ Makefile
libraw1394.pc
libraw1394.spec
src/Makefile
+juju/Makefile
tools/Makefile
doc/Makefile
doc/testlibraw.1
diff --git a/juju/Makefile.am b/juju/Makefile.am
new file mode 100644
index 0000000..6fd6a5e
--- /dev/null
+++ b/juju/Makefile.am
@@ -0,0 +1,8 @@
+lib_LTLIBRARIES = libraw1394.la
+
+INCLUDES = -I$(JUJU_DIR)
+libraw1394_la_LDFLAGS = -version-info @lt_major@:@lt_revision@:@lt_age@
+
+libraw1394_la_SOURCES = raw1394.c raw1394-iso.c juju.h
+
+pkginclude_HEADERS = ../src/raw1394.h ../src/csr.h ../src/ieee1394.h
diff --git a/juju/juju.h b/juju/juju.h
new file mode 100644
index 0000000..5299cbf
--- /dev/null
+++ b/juju/juju.h
@@ -0,0 +1,139 @@
+/* -*- c-basic-offset: 8 -*-
+ *
+ * juju.h -- Internal header file for raw1394 emulation
+ *
+ * Copyright (C) 2007 Kristian Hoegsberg
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __juju_h
+#define __juju_h
+
+#include
+#include
+#include
+#include "../src/raw1394.h"
+#include "../src/csr.h"
+#include "config.h"
+
+#define ACK_COMPLETE 1
+
+#define ptr_to_u64(p) ((__u64)(unsigned long)(p))
+#define u64_to_ptr(p) ((void *)(unsigned long)(p))
+
+static inline __u32
+be32_to_cpu(__u32 q)
+{
+ union { char c[4]; __u32 q; } u = { { 1, 0, 0, 0 } };
+
+ return u.q == 1 ? bswap_32(q) : q;
+}
+
+static inline __u32
+cpu_to_be32(__u32 q)
+{
+ return be32_to_cpu(q);
+}
+
+#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
+
+#define BUFFER_SIZE (16 * 1024)
+
+#define MAX_PORTS 16
+
+struct epoll_closure {
+ int (*func)(raw1394handle_t handle,
+ struct epoll_closure *closure, __uint32_t events);
+};
+
+struct port {
+ char device_file[32];
+ char *name;
+ int node_count;
+ int card;
+};
+
+#define MAX_DEVICES 63
+#define FILENAME_SIZE 16
+
+struct device {
+ struct epoll_closure closure;
+ int fd;
+ int node_id;
+ int generation;
+ char filename[FILENAME_SIZE];
+};
+
+struct request_closure {
+ void *data;
+ size_t length;
+ unsigned long tag;
+ struct raw1394_reqhandle reqhandle;
+};
+
+struct allocation;
+
+struct raw1394_handle {
+ struct port ports[MAX_PORTS];
+ int port_count;
+ int err;
+ int generation;
+ void *user_data;
+ int notify_bus_reset;
+
+ bus_reset_handler_t bus_reset_handler;
+ tag_handler_t tag_handler;
+ arm_tag_handler_t arm_tag_handler;
+ fcp_handler_t fcp_handler;
+ struct allocation *allocations;
+
+ int epoll_fd;
+ int inotify_fd;
+ int inotify_watch;
+ int pipe_fds[2];
+
+ struct epoll_closure pipe_closure;
+ struct epoll_closure inotify_closure;
+
+ struct device devices[MAX_DEVICES];
+ int nodes[MAX_DEVICES];
+ int local_fd;
+ char local_filename[FILENAME_SIZE];
+
+ struct fw_cdev_event_bus_reset reset;
+
+ struct {
+ struct epoll_closure closure;
+ int fd;
+ int type;
+ int irq_interval;
+ int packet_index;
+ int packet_phase;
+ int buf_packets;
+ int max_packet_size;
+ enum raw1394_iso_dma_recv_mode recv_mode;
+ raw1394_iso_xmit_handler_t xmit_handler;
+ raw1394_iso_recv_handler_t recv_handler;
+ unsigned char *buffer, *head, *tail;
+
+ struct fw_cdev_queue_iso queue_iso;
+ struct fw_cdev_iso_packet *packets;
+ } iso;
+
+ char buffer[BUFFER_SIZE];
+};
+
+#endif
diff --git a/juju/raw1394-iso.c b/juju/raw1394-iso.c
new file mode 100644
index 0000000..6427d39
--- /dev/null
+++ b/juju/raw1394-iso.c
@@ -0,0 +1,385 @@
+/* -*- c-basic-offset: 8 -*-
+ *
+ * raw1394-iso.c -- Emulation of the raw1394 rawiso API on the juju stack
+ *
+ * Copyright (C) 2007 Kristian Hoegsberg
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "juju.h"
+
+static int
+refill_xmit_buffer(raw1394handle_t handle, struct fw_cdev_queue_iso *queue_iso)
+{
+ int i;
+ struct fw_cdev_iso_packet *p = handle->iso.packets;
+ enum raw1394_iso_disposition d;
+ unsigned int len, dropped;
+ unsigned char tag, sy, *data, *buffer;
+ int cycle;
+
+ buffer = handle->iso.buffer +
+ handle->iso.packet_index * handle->iso.max_packet_size;
+ data = buffer;
+
+ for (i = 0; i < handle->iso.irq_interval; i++) {
+ cycle = -1;
+ dropped = 0;
+ d = handle->iso.xmit_handler(handle, data,
+ &len, &tag, &sy, cycle, dropped);
+ /* FIXME: handle the different dispositions. */
+
+ p->payload_length = len;
+ p->interrupt = handle->iso.packet_phase == 0;
+ p->skip = 0;
+ p->tag = tag;
+ p->sy = sy;
+ p->header_length = 0;
+
+ data += handle->iso.max_packet_size;
+ handle->iso.packet_index++;
+ if (handle->iso.packet_index == handle->iso.buf_packets) {
+ handle->iso.packet_index = 0;
+ break;
+ }
+
+ handle->iso.packet_phase++;
+ if (handle->iso.packet_phase == handle->iso.irq_interval)
+ handle->iso.packet_phase = 0;
+
+ }
+
+ queue_iso->packets = ptr_to_u64(handle->iso.packets);
+ queue_iso->size =
+ handle->iso.irq_interval * sizeof handle->iso.packets[0];
+ queue_iso->data = ptr_to_u64(buffer);
+
+ return 0;
+}
+
+static int
+flush_xmit_packets(raw1394handle_t handle, int limit)
+{
+ struct fw_cdev_queue_iso queue_iso;
+ int len;
+
+ while (handle->iso.packet_index + handle->iso.irq_interval <= limit) {
+ if (handle->iso.queue_iso.size == 0)
+ refill_xmit_buffer(handle, &queue_iso);
+ len = ioctl(handle->iso.fd,
+ FW_CDEV_IOC_QUEUE_ISO, &queue_iso);
+ if (len < 0)
+ return -1;
+ if (handle->iso.queue_iso.size > 0)
+ break;
+ }
+
+ return 0;
+}
+
+int raw1394_iso_xmit_start(raw1394handle_t handle, int start_on_cycle,
+ int prebuffer_packets)
+{
+ struct fw_cdev_start_iso start_iso;
+ int retval;
+
+ if (prebuffer_packets == -1)
+ prebuffer_packets = handle->iso.irq_interval;
+
+ flush_xmit_packets(handle, prebuffer_packets);
+
+ start_iso.cycle = start_on_cycle;
+
+ retval = ioctl(handle->iso.fd, FW_CDEV_IOC_START_ISO, &start_iso);
+ if (retval < 0)
+ return retval;
+
+ return flush_xmit_packets(handle, handle->iso.buf_packets);
+}
+
+static int
+handle_recv_packets(raw1394handle_t handle,
+ struct fw_cdev_event_iso_interrupt *interrupt)
+{
+ enum raw1394_iso_disposition d;
+ quadlet_t header, *p, *end;
+ unsigned int len, cycle, dropped;
+ unsigned char channel, tag, sy;
+ unsigned char *data;
+
+ p = interrupt->header;
+ end = (void *) interrupt->header + interrupt->header_length;
+ cycle = interrupt->cycle;
+ data = NULL;
+
+ while (p < end) {
+ header = be32_to_cpu(*p++);
+ len = header >> 8;
+ channel = header >> 8;
+ tag = header >> 8;
+ sy = header >> 8;
+
+ d = handle->iso.recv_handler(handle, data, len, channel,
+ tag, sy, cycle, dropped);
+ cycle++;
+ }
+
+ return 0;
+}
+
+int raw1394_iso_recv_start(raw1394handle_t handle, int start_on_cycle,
+ int tag_mask, int sync)
+{
+ struct fw_cdev_start_iso start_iso;
+
+ start_iso.cycle = start_on_cycle;
+ start_iso.tags =
+ tag_mask == -1 ? FW_CDEV_ISO_CONTEXT_MATCH_ALL_TAGS : tag_mask;
+ /* sync is documented as 'not used' */
+ start_iso.sync = 0;
+
+ return ioctl(handle->iso.fd, FW_CDEV_IOC_START_ISO, &start_iso);
+}
+
+static int handle_iso_event(raw1394handle_t handle,
+ struct epoll_closure *closure, __uint32_t events)
+{
+ struct fw_cdev_event_iso_interrupt *interrupt;
+ int len;
+
+ len = read(handle->iso.fd, handle->buffer, sizeof handle->buffer);
+ if (len < 0)
+ return -1;
+
+ interrupt = (struct fw_cdev_event_iso_interrupt *) handle->buffer;
+ if (interrupt->type != FW_CDEV_EVENT_BUS_RESET)
+ return 0;
+
+ switch (handle->iso.type) {
+ case FW_CDEV_ISO_CONTEXT_TRANSMIT:
+ handle->iso.packet_index -= handle->iso.irq_interval;
+ return flush_xmit_packets(handle, handle->iso.buf_packets);
+ case FW_CDEV_ISO_CONTEXT_RECEIVE:
+ return handle_recv_packets(handle, interrupt);
+ default:
+ /* Doesn't happen. */
+ return -1;
+ }
+}
+
+int raw1394_iso_xmit_write(raw1394handle_t handle, unsigned char *data,
+ unsigned int len, unsigned char tag,
+ unsigned char sy)
+{
+ struct fw_cdev_iso_packet packet;
+
+ packet.payload_length = len;
+ packet.interrupt = handle->iso.packet_phase == 0;
+ packet.skip = 0;
+ packet.tag = tag;
+ packet.sy = sy;
+ packet.header_length = 0;
+
+ handle->iso.packet_phase++;
+ if (handle->iso.packet_phase == handle->iso.irq_interval)
+ handle->iso.packet_phase = 0;
+
+ /* FIXME: circular buffer goo. */
+
+ memcpy(handle->iso.head, data, len);
+ handle->iso.head += len;
+
+ return -1;
+}
+
+int raw1394_iso_xmit_sync(raw1394handle_t handle)
+{
+ /* FIXME: queue a skip packet and wait for that interrupt. */
+
+ return 0;
+}
+
+int raw1394_iso_recv_flush(raw1394handle_t handle)
+{
+ /* FIXME: huh, we'll need kernel support here... */
+
+ return 0;
+}
+
+int raw1394_iso_xmit_init(raw1394handle_t handle,
+ raw1394_iso_xmit_handler_t handler,
+ unsigned int buf_packets,
+ unsigned int max_packet_size,
+ unsigned char channel,
+ enum raw1394_iso_speed speed,
+ int irq_interval)
+{
+ struct fw_cdev_create_iso_context create;
+ struct epoll_event ep;
+ int retval;
+
+ if (handle->iso.fd != -1) {
+ errno = EBUSY;
+ return -1;
+ }
+
+ handle->iso.type = FW_CDEV_ISO_CONTEXT_TRANSMIT;
+ handle->iso.irq_interval = irq_interval;
+ handle->iso.xmit_handler = handler;
+ handle->iso.buf_packets = buf_packets;
+ handle->iso.max_packet_size = max_packet_size;
+ handle->iso.packet_index = 0;
+ handle->iso.packet_phase = 0;
+ handle->iso.queue_iso.size = 0;
+ handle->iso.packets =
+ malloc(irq_interval * sizeof handle->iso.packets[0]);
+ if (handle->iso.packets == NULL)
+ return -1;
+
+ handle->iso.fd = open(handle->local_filename, O_RDWR);
+ if (handle->iso.fd < 0) {
+ free(handle->iso.packets);
+ return -1;
+ }
+
+ handle->iso.closure.func = handle_iso_event;
+ ep.events = EPOLLIN;
+ ep.data.ptr = &handle->iso.closure;
+ if (epoll_ctl(handle->epoll_fd, EPOLL_CTL_ADD,
+ handle->iso.fd, &ep) < 0) {
+ close(handle->iso.fd);
+ free(handle->iso.packets);
+ return -1;
+ }
+
+ create.type = FW_CDEV_ISO_CONTEXT_TRANSMIT;
+ create.channel = channel;
+ create.speed = speed;
+
+ retval = ioctl(handle->iso.fd,
+ FW_CDEV_IOC_CREATE_ISO_CONTEXT, &create);
+ if (retval < 0) {
+ close(handle->iso.fd);
+ free(handle->iso.packets);
+ return retval;
+ }
+
+ handle->iso.buffer =
+ mmap(NULL, buf_packets * max_packet_size,
+ PROT_READ | PROT_WRITE, MAP_SHARED, handle->iso.fd, 0);
+
+ if (handle->iso.buffer == MAP_FAILED) {
+ close(handle->iso.fd);
+ free(handle->iso.packets);
+ return -1;
+ }
+
+ return 0;
+}
+
+int raw1394_iso_recv_init(raw1394handle_t handle,
+ raw1394_iso_recv_handler_t handler,
+ unsigned int buf_packets,
+ unsigned int max_packet_size,
+ unsigned char channel,
+ enum raw1394_iso_dma_recv_mode mode,
+ int irq_interval)
+{
+ struct fw_cdev_create_iso_context create;
+
+ if (handle->iso.fd != -1) {
+ errno = EBUSY;
+ return -1;
+ }
+
+ /* FIXME: Do we need this? When would you ever want this...? */
+ if (mode == RAW1394_DMA_PACKET_PER_BUFFER)
+ return -1;
+
+ handle->iso.buffer =
+ mmap(NULL, buf_packets * max_packet_size,
+ PROT_READ, MAP_SHARED, handle->iso.fd, 0);
+
+ if (handle->iso.buffer == MAP_FAILED)
+ return -1;
+
+ create.type = FW_CDEV_ISO_CONTEXT_RECEIVE;
+ create.channel = channel;
+ create.speed = 0;
+ create.header_size = 0; /* Never strip any headers. */
+
+ handle->iso.type = FW_CDEV_ISO_CONTEXT_RECEIVE;
+ handle->iso.irq_interval = irq_interval;
+ handle->iso.recv_handler = handler;
+
+ return ioctl(handle->iso.fd,
+ FW_CDEV_IOC_CREATE_ISO_CONTEXT, &create);
+}
+
+int raw1394_iso_multichannel_recv_init(raw1394handle_t handle,
+ raw1394_iso_recv_handler_t handler,
+ unsigned int buf_packets,
+ unsigned int max_packet_size,
+ int irq_interval)
+{
+ /* FIXME: gah */
+ errno = ENOSYS;
+ return -1;
+}
+
+int raw1394_iso_recv_listen_channel(raw1394handle_t handle,
+ unsigned char channel)
+{
+ /* FIXME: multichannel */
+ errno = ENOSYS;
+ return -1;
+}
+
+int raw1394_iso_recv_unlisten_channel(raw1394handle_t handle,
+ unsigned char channel)
+{
+ /* FIXME: multichannel */
+ errno = ENOSYS;
+ return -1;
+}
+
+int raw1394_iso_recv_set_channel_mask(raw1394handle_t handle, u_int64_t mask)
+{
+ /* FIXME: multichannel */
+ errno = ENOSYS;
+ return -1;
+}
+
+void raw1394_iso_stop(raw1394handle_t handle)
+{
+ ioctl(handle->iso.fd, FW_CDEV_IOC_STOP_ISO);
+}
+
+void raw1394_iso_shutdown(raw1394handle_t handle)
+{
+ munmap(handle->iso.buffer,
+ handle->iso.buf_packets * handle->iso.max_packet_size);
+ close(handle->iso.fd);
+ free(handle->iso.packets);
+}
diff --git a/juju/raw1394.c b/juju/raw1394.c
new file mode 100644
index 0000000..6bfd7e1
--- /dev/null
+++ b/juju/raw1394.c
@@ -0,0 +1,1437 @@
+/* -*- c-basic-offset: 8 -*-
+ *
+ * raw1394.c -- Emulation of the raw1394 API on the juju stack
+ *
+ * Copyright (C) 2007 Kristian Hoegsberg
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "juju.h"
+
+raw1394_errcode_t
+raw1394_get_errcode(raw1394handle_t handle)
+{
+ return handle->err;
+}
+
+int
+raw1394_errcode_to_errno(raw1394_errcode_t errcode)
+{
+ switch (errcode) {
+
+ case -RCODE_SEND_ERROR:
+ case -RCODE_CANCELLED:
+ case -RCODE_BUSY:
+ case -RCODE_GENERATION:
+ case -RCODE_NO_ACK:
+ return EAGAIN;
+
+ case raw1394_make_errcode(ACK_COMPLETE, RCODE_COMPLETE):
+ return 0;
+ case raw1394_make_errcode(ACK_COMPLETE, RCODE_CONFLICT_ERROR):
+ return EAGAIN;
+ case raw1394_make_errcode(ACK_COMPLETE, RCODE_DATA_ERROR):
+ return EREMOTEIO;
+ case raw1394_make_errcode(ACK_COMPLETE, RCODE_TYPE_ERROR):
+ return EPERM;
+ case raw1394_make_errcode(ACK_COMPLETE, RCODE_ADDRESS_ERROR):
+ return EINVAL;
+ default:
+ return EINVAL;
+ }
+}
+
+static int
+juju_to_raw1394_errcode(int rcode)
+{
+ /* Best effort matching juju extended rcodes to raw1394 err
+ * code. Since the raw1394 errcode decoding are macros we try
+ * to convert the juju rcodes to something that looks enough
+ * like the raw1394 errcodes that we retain ABI compatibility.
+ *
+ * Juju rcodes less than 0x10 are standard ieee1394 rcodes,
+ * which we map to a raw1394 errcode by or'ing in an
+ * ACK_COMPLETE ack code in the upper 16 bits. Errors
+ * internal to raw1394 are negative values, but juju encodes
+ * these errors as rcodes greater than or equal to 0x10. In
+ * this case, we just the negated value, which will look like
+ * an raw1394 internal error code. */
+
+ if (rcode < 0x10)
+ return raw1394_make_errcode(ACK_COMPLETE, rcode);
+ else
+ return -rcode;
+}
+
+static int
+default_tag_handler(raw1394handle_t handle,
+ unsigned long tag, raw1394_errcode_t err)
+{
+ struct raw1394_reqhandle *rh = (struct raw1394_reqhandle *) tag;
+
+ if (rh != NULL)
+ return rh->callback(handle, rh->data, err);
+
+ return -1;
+}
+
+static int
+default_arm_tag_handler(raw1394handle_t handle, unsigned long arm_tag,
+ byte_t type, unsigned int length, void *data)
+{
+ struct raw1394_arm_reqhandle *rh;
+
+ if (arm_tag == 0)
+ return -1;
+
+ rh = (struct raw1394_arm_reqhandle *) arm_tag;
+
+ return rh->arm_callback(handle, data, length, rh->pcontext, type);
+}
+
+static int
+default_bus_reset_handler(struct raw1394_handle *handle, unsigned int gen)
+{
+ raw1394_update_generation(handle, gen);
+
+ return 0;
+}
+
+static int
+scan_devices(raw1394handle_t handle)
+{
+ DIR *dir;
+ struct dirent *de;
+ char filename[32];
+ struct fw_cdev_get_info get_info;
+ struct fw_cdev_event_bus_reset reset;
+ int fd, err, i;
+ struct port *ports;
+
+ ports = handle->ports;
+ memset(ports, 0, sizeof handle->ports);
+ dir = opendir(FW_DEVICE_DIR);
+ if (dir == NULL)
+ return -1;
+
+ i = 0;
+ while (1) {
+ de = readdir(dir);
+ if (de == NULL)
+ break;
+
+ if (strncmp(de->d_name,
+ FW_DEVICE_PREFIX, strlen(FW_DEVICE_PREFIX)) != 0)
+ continue;
+
+ snprintf(filename, sizeof filename, FW_DEVICE_DIR "/%s", de->d_name);
+
+ fd = open(filename, O_RDWR);
+ if (fd < 0)
+ continue;
+ get_info.version = FW_CDEV_VERSION;
+ get_info.rom = 0;
+ get_info.rom_length = 0;
+ get_info.bus_reset = ptr_to_u64(&reset);
+ err = ioctl(fd, FW_CDEV_IOC_GET_INFO, &get_info);
+ close(fd);
+
+ if (err < 0)
+ continue;
+
+ if (i < MAX_PORTS && reset.node_id == reset.local_node_id) {
+ strncpy(ports[i].device_file, filename,
+ sizeof ports[i].device_file);
+ ports[i].node_count = (reset.root_node_id & 0x3f) + 1;
+ ports[i].card = get_info.card;
+ i++;
+ }
+ }
+ closedir(dir);
+
+ handle->port_count = i;
+
+ return 0;
+}
+
+static int
+handle_echo_pipe(raw1394handle_t handle,
+ struct epoll_closure *ec, __uint32_t events)
+{
+ quadlet_t value;
+
+ if (read(handle->pipe_fds[0], &value, sizeof value) < 0)
+ return -1;
+
+ return value;
+}
+
+static int
+handle_lost_device(raw1394handle_t handle, int i)
+{
+ int phy_id;
+
+ /* The device got unplugged, get rid of it. The fd is
+ * automatically dropped from the epoll context when we close it. */
+
+ close(handle->devices[i].fd);
+ phy_id = handle->devices[i].node_id & 0x3f;
+ if (handle->nodes[phy_id] == i)
+ handle->nodes[phy_id] = -1;
+ handle->devices[i].node_id = -1;
+
+ return 0;
+}
+
+struct address_closure {
+ int (*callback)(raw1394handle_t handle, struct address_closure *ac,
+ struct fw_cdev_event_request *request, int i);
+};
+
+static int
+handle_fcp_request(raw1394handle_t handle, struct address_closure *ac,
+ struct fw_cdev_event_request *request, int i)
+{
+ struct fw_cdev_send_response response;
+ int is_response;
+
+ response.serial = request->serial;
+ response.rcode = RCODE_COMPLETE;
+ response.length = 0;
+ response.data = 0;
+
+ if (handle->fcp_handler == NULL)
+ response.rcode = RCODE_ADDRESS_ERROR;
+
+ if (request->tcode >= TCODE_WRITE_RESPONSE)
+ response.rcode = RCODE_CONFLICT_ERROR;
+
+ if (ioctl(handle->devices[i].fd,
+ FW_CDEV_IOC_SEND_RESPONSE, &response) < 0)
+ return -1;
+
+ if (response.rcode != RCODE_COMPLETE)
+ return 0;
+
+ is_response = request->offset >= CSR_REGISTER_BASE + CSR_FCP_RESPONSE;
+
+ return handle->fcp_handler(handle,
+ handle->devices[i].node_id,
+ is_response,
+ request->length,
+ (unsigned char *) request->data);
+}
+
+static int
+handle_device_event(raw1394handle_t handle,
+ struct epoll_closure *ec, __uint32_t events)
+{
+ union fw_cdev_event *u;
+ struct device *device = (struct device *) ec;
+ struct address_closure *ac;
+ struct request_closure *rc;
+ raw1394_errcode_t errcode;
+ int len, phy_id;
+ int i;
+
+ i = device - handle->devices;
+ if (events == EPOLLHUP)
+ return handle_lost_device(handle, i);
+
+ len = read(handle->devices[i].fd,
+ handle->buffer, sizeof handle->buffer);
+ if (len < 0)
+ return -1;
+
+ u = (void *) handle->buffer;
+ switch (u->common.type) {
+ case FW_CDEV_EVENT_BUS_RESET:
+ /* Clear old entry, unless it's been overwritten. */
+ phy_id = handle->devices[i].node_id & 0x3f;
+ if (handle->nodes[phy_id] == i)
+ handle->nodes[phy_id] = -1;
+ handle->nodes[u->bus_reset.node_id & 0x3f] = i;
+ handle->devices[i].node_id = u->bus_reset.node_id;
+ handle->devices[i].generation = u->bus_reset.generation;
+
+ if (u->bus_reset.node_id != u->bus_reset.local_node_id)
+ return 0;
+
+ memcpy(&handle->reset, &u->bus_reset, sizeof handle->reset);
+ return handle->bus_reset_handler(handle,
+ u->bus_reset.generation);
+
+ case FW_CDEV_EVENT_RESPONSE:
+ rc = u64_to_ptr(u->response.closure);
+
+ if (rc->data != NULL)
+ memcpy(rc->data, u->response.data, rc->length);
+
+ errcode = juju_to_raw1394_errcode(u->response.rcode);
+
+ return handle->tag_handler(handle, rc->tag, errcode);
+
+ case FW_CDEV_EVENT_REQUEST:
+ ac = u64_to_ptr(u->request.closure);
+ return ac->callback(handle, ac, &u->request, i);
+
+ default:
+ case FW_CDEV_EVENT_ISO_INTERRUPT:
+ /* Never happens. */
+ return -1;
+ }
+}
+
+static int
+handle_inotify(raw1394handle_t handle, struct epoll_closure *ec,
+ __uint32_t events)
+{
+ struct inotify_event *event;
+ char filename[32];
+ struct fw_cdev_get_info info;
+ struct fw_cdev_event_bus_reset reset;
+ struct epoll_event ep;
+ int i, len, fd, phy_id;
+
+ event = (struct inotify_event *) handle->buffer;
+ len = read(handle->inotify_fd, event, BUFFER_SIZE);
+ if (!(event->mask & IN_CREATE))
+ return -1;
+ if (strncmp(event->name,
+ FW_DEVICE_PREFIX, strlen(FW_DEVICE_PREFIX)) != 0)
+ return 0;
+ snprintf(filename, sizeof filename, FW_DEVICE_DIR "/%s", event->name);
+ fd = open(filename, O_RDWR);
+ if (fd < 0) {
+ switch (errno) {
+ case ENOENT:
+ /* Huh, it disappeared before we could
+ * open it. */
+ return 0;
+ case EACCES:
+ /* We don't have permission to talk to
+ * this device, maybe it's a storage
+ * device. */
+ return 0;
+ default:
+ /* Anything else is bad news. */
+ return -1;
+ }
+ }
+
+ info.version = FW_CDEV_VERSION;
+ info.rom = 0;
+ info.rom_length = 0;
+ info.bus_reset = ptr_to_u64(&reset);
+ if (ioctl(fd, FW_CDEV_IOC_GET_INFO, &info) < 0) {
+ close(fd);
+ return -1;
+ }
+
+ for (i = 0; i < MAX_DEVICES; i++)
+ if (handle->devices[i].node_id == -1)
+ break;
+ if (i == MAX_DEVICES) {
+ close(fd);
+ return -1;
+ }
+
+ phy_id = reset.node_id & 0x3f;
+ handle->nodes[phy_id] = i;
+ handle->devices[i].node_id = reset.node_id;
+ handle->devices[i].generation = reset.generation;
+ handle->devices[i].fd = fd;
+ strncpy(handle->devices[i].filename, filename,
+ sizeof handle->devices[i].filename);
+ handle->devices[i].closure.func = handle_device_event;
+ ep.events = EPOLLIN;
+ ep.data.ptr = &handle->devices[i].closure;
+ if (epoll_ctl(handle->epoll_fd, EPOLL_CTL_ADD, fd, &ep) < 0) {
+ close(fd);
+ return -1;
+ }
+
+ return 0;
+}
+
+int raw1394_loop_iterate(raw1394handle_t handle)
+{
+ int i, count, retval = 0;
+ struct epoll_closure *closure;
+ struct epoll_event ep[32];
+
+ count = epoll_wait(handle->epoll_fd, ep, ARRAY_LENGTH(ep), -1);
+ if (count < 0)
+ return -1;
+
+ for (i = 0; i < count; i++) {
+ closure = ep[i].data.ptr;
+ retval = closure->func(handle, closure, ep[i].events);
+ }
+
+ /* It looks like we have to add this work-around to get epoll
+ * to recompute the POLLIN status of the epoll_fd. */
+ epoll_wait(handle->epoll_fd, ep, ARRAY_LENGTH(ep), 0);
+
+ return retval;
+}
+
+raw1394handle_t raw1394_new_handle(void)
+{
+ raw1394handle_t handle;
+ struct epoll_event ep;
+ int i;
+
+ handle = malloc(sizeof *handle);
+
+ handle->tag_handler = default_tag_handler;
+ handle->arm_tag_handler = default_arm_tag_handler;
+ handle->allocations = NULL;
+
+ handle->notify_bus_reset = RAW1394_NOTIFY_ON;
+ handle->bus_reset_handler = default_bus_reset_handler;
+
+ handle->iso.fd = -1;
+
+ handle->epoll_fd = epoll_create(16);
+ if (handle->epoll_fd < 0)
+ goto out_handle;
+
+ if (pipe(handle->pipe_fds) < 0)
+ goto out_epoll;
+
+ handle->inotify_fd = inotify_init();
+ if (handle->inotify_fd < 0)
+ goto out_pipe;
+
+ handle->inotify_watch =
+ inotify_add_watch(handle->inotify_fd, FW_DEVICE_DIR, IN_CREATE);
+ if (handle->inotify_watch < 0)
+ goto out_inotify;
+
+ handle->pipe_closure.func = handle_echo_pipe;
+ ep.events = EPOLLIN;
+ ep.data.ptr = &handle->pipe_closure;
+ if (epoll_ctl(handle->epoll_fd, EPOLL_CTL_ADD,
+ handle->pipe_fds[0], &ep) < 0)
+ goto out_inotify;
+
+ handle->inotify_closure.func = handle_inotify;
+ ep.events = EPOLLIN;
+ ep.data.ptr = &handle->inotify_closure;
+ if (epoll_ctl(handle->epoll_fd, EPOLL_CTL_ADD,
+ handle->inotify_fd, &ep) < 0)
+ goto out_inotify;
+
+ for (i = 0; i < MAX_DEVICES; i++) {
+ handle->nodes[i] = -1;
+ handle->devices[i].node_id = -1;
+ }
+
+ scan_devices(handle);
+
+ return handle;
+
+ out_inotify:
+ close(handle->inotify_fd);
+ out_pipe:
+ close(handle->pipe_fds[0]);
+ close(handle->pipe_fds[1]);
+ out_epoll:
+ close(handle->epoll_fd);
+ out_handle:
+ free(handle);
+ return NULL;
+}
+
+void raw1394_destroy_handle(raw1394handle_t handle)
+{
+ int i;
+
+ close(handle->inotify_fd);
+ close(handle->pipe_fds[0]);
+ close(handle->pipe_fds[1]);
+
+ for (i = 0; i < MAX_DEVICES; i++) {
+ if (handle->devices[i].node_id == -1)
+ continue;
+
+ close(handle->devices[i].fd);
+ }
+
+ close(handle->epoll_fd);
+
+ free(handle);
+
+ return;
+}
+
+raw1394handle_t raw1394_new_handle_on_port(int port)
+{
+ raw1394handle_t handle;
+
+ handle = raw1394_new_handle();
+ if (handle == NULL)
+ return NULL;
+
+ if (raw1394_set_port(handle, port) < 0)
+ return NULL;
+
+ return handle;
+}
+
+int raw1394_busreset_notify (raw1394handle_t handle, int off_on_switch)
+{
+ handle->notify_bus_reset = off_on_switch;
+
+ return 0;
+}
+
+int raw1394_get_fd(raw1394handle_t handle)
+{
+ return handle->epoll_fd;
+}
+
+void raw1394_set_userdata(raw1394handle_t handle, void *data)
+{
+ handle->user_data = data;
+}
+
+void *raw1394_get_userdata(raw1394handle_t handle)
+{
+ return handle->user_data;
+}
+
+nodeid_t raw1394_get_local_id(raw1394handle_t handle)
+{
+ return handle->reset.local_node_id;
+}
+
+nodeid_t raw1394_get_irm_id(raw1394handle_t handle)
+{
+ return handle->reset.irm_node_id;
+}
+
+int raw1394_get_nodecount(raw1394handle_t handle)
+{
+ return (handle->reset.root_node_id & 0x3f) + 1;
+}
+
+int raw1394_get_port_info(raw1394handle_t handle,
+ struct raw1394_portinfo *pinf,
+ int maxports)
+{
+ int i;
+
+ if (maxports >= handle->port_count)
+ maxports = handle->port_count;
+
+ for (i = 0; i < maxports; i++) {
+ pinf[i].nodes = handle->ports[i].node_count;
+ strncpy(pinf[i].name, handle->ports[i].device_file,
+ sizeof pinf[i].name);
+ }
+
+ return handle->port_count;
+}
+
+int raw1394_set_port(raw1394handle_t handle, int port)
+{
+ struct fw_cdev_get_info get_info;
+ struct fw_cdev_event_bus_reset reset;
+ struct epoll_event ep;
+ struct dirent *de;
+ char filename[32];
+ DIR *dir;
+ int i, fd, phy_id;
+
+ if (port >= handle->port_count) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ dir = opendir("/dev");
+ if (dir == NULL)
+ return -1;
+
+ for (i = 0; i < MAX_DEVICES; ) {
+ de = readdir(dir);
+ if (de == NULL)
+ break;
+
+ if (strncmp(de->d_name, "fw", 2) != 0)
+ continue;
+
+ snprintf(filename, sizeof filename, "/dev/%s", de->d_name);
+
+ fd = open(filename, O_RDWR);
+ if (fd < 0)
+ continue;
+
+ get_info.version = FW_CDEV_VERSION;
+ get_info.rom = 0;
+ get_info.rom_length = 0;
+ get_info.bus_reset = ptr_to_u64(&reset);
+ if (ioctl(fd, FW_CDEV_IOC_GET_INFO, &get_info) < 0) {
+ close(fd);
+ continue;
+ }
+
+ if (get_info.card != handle->ports[port].card) {
+ close(fd);
+ continue;
+ }
+
+ phy_id = reset.node_id & 0x3f;
+ handle->nodes[phy_id] = i;
+ handle->devices[i].node_id = reset.node_id;
+ handle->devices[i].generation = reset.generation;
+ handle->devices[i].fd = fd;
+ strncpy(handle->devices[i].filename, filename,
+ sizeof handle->devices[i].filename);
+
+ handle->devices[i].closure.func = handle_device_event;
+ ep.events = EPOLLIN;
+ ep.data.ptr = &handle->devices[i].closure;
+ if (epoll_ctl(handle->epoll_fd, EPOLL_CTL_ADD, fd, &ep) < 0) {
+ close(fd);
+ return -1;
+ }
+
+ handle->generation = reset.generation;
+ if (reset.node_id == reset.local_node_id) {
+ memcpy(&handle->reset, &reset, sizeof handle->reset);
+ handle->local_fd = fd;
+ strncpy(handle->local_filename, filename,
+ sizeof handle->local_filename);
+ }
+
+ i++;
+ }
+
+ return 0;
+}
+
+int raw1394_reset_bus(raw1394handle_t handle)
+{
+ return raw1394_reset_bus_new(handle, RAW1394_LONG_RESET);
+}
+
+int raw1394_reset_bus_new(raw1394handle_t handle, int type)
+{
+ struct fw_cdev_initiate_bus_reset initiate;
+
+ switch (type) {
+ case RAW1394_LONG_RESET:
+ initiate.type = FW_CDEV_LONG_RESET;
+ break;
+ case RAW1394_SHORT_RESET:
+ initiate.type = FW_CDEV_SHORT_RESET;
+ break;
+ }
+
+ return ioctl(handle->local_fd,
+ FW_CDEV_IOC_INITIATE_BUS_RESET, &initiate);
+}
+
+bus_reset_handler_t raw1394_set_bus_reset_handler(raw1394handle_t handle,
+ bus_reset_handler_t new_h)
+{
+ bus_reset_handler_t old_h = handle->bus_reset_handler;
+
+ handle->bus_reset_handler = new_h;
+
+ return old_h;
+}
+
+unsigned int raw1394_get_generation(raw1394handle_t handle)
+{
+ return handle->generation;
+}
+
+void raw1394_update_generation(raw1394handle_t handle, unsigned int generation)
+{
+ handle->generation = generation;
+}
+
+tag_handler_t
+raw1394_set_tag_handler(raw1394handle_t handle, tag_handler_t new_h)
+{
+ tag_handler_t old_h = handle->tag_handler;
+
+ handle->tag_handler = new_h;
+
+ return old_h;
+}
+
+arm_tag_handler_t
+raw1394_set_arm_tag_handler(raw1394handle_t handle, arm_tag_handler_t new_h)
+{
+ arm_tag_handler_t old_h = handle->arm_tag_handler;
+
+ handle->arm_tag_handler = new_h;
+
+ return old_h;
+}
+
+fcp_handler_t
+raw1394_set_fcp_handler(raw1394handle_t handle, fcp_handler_t new_h)
+{
+ fcp_handler_t old_h = handle->fcp_handler;
+
+ handle->fcp_handler = new_h;
+
+ return old_h;
+}
+
+struct request_response_block {
+ struct raw1394_arm_request_response request_response;
+ struct raw1394_arm_request request;
+ struct raw1394_arm_response response;
+ unsigned char data[0];
+};
+
+struct allocation {
+ struct address_closure closure;
+ struct allocation *next;
+ byte_t *buffer;
+ octlet_t tag;
+ arm_options_t access_rights;
+ arm_options_t notification_options;
+ arm_options_t client_transactions;
+ nodeaddr_t offset;
+ size_t length;
+ unsigned char data[0];
+};
+
+static int
+handle_arm_request(raw1394handle_t handle, struct address_closure *ac,
+ struct fw_cdev_event_request *request, int i)
+{
+ struct allocation *allocation = (struct allocation *) ac;
+ struct request_response_block *rrb;
+ struct fw_cdev_send_response response;
+ arm_options_t type;
+ size_t in_length;
+ int offset;
+
+ offset = request->offset - allocation->offset;
+ response.serial = request->serial;
+
+ switch (request->tcode) {
+ case TCODE_WRITE_QUADLET_REQUEST:
+ case TCODE_WRITE_BLOCK_REQUEST:
+ printf("got write request, offset=0x%012llx, length=%d\n",
+ request->offset, request->length);
+
+ type = RAW1394_ARM_WRITE;
+ in_length = request->length;
+ response.rcode = RCODE_COMPLETE;
+ response.length = 0;
+ response.data = 0;
+ break;
+
+ case TCODE_READ_QUADLET_REQUEST:
+ case TCODE_READ_BLOCK_REQUEST:
+ printf("got read request, offset=0x%012llx, length=%d\n",
+ request->offset, request->length);
+
+ type = RAW1394_ARM_READ;
+ in_length = 0;
+ response.rcode = RCODE_COMPLETE;
+ response.length = request->length;
+ response.data = ptr_to_u64(allocation->data + offset);
+ break;
+
+ case TCODE_LOCK_REQUEST:
+ type = RAW1394_ARM_LOCK;
+ in_length = request->length;
+ response.length = 4;
+ break;
+
+ default:
+ in_length = 0;
+ type = 0;
+ break;
+ }
+
+ if (!(allocation->access_rights & type)) {
+ response.rcode = RCODE_TYPE_ERROR;
+ response.length = 0;
+ response.data = 0;
+ if (ioctl(handle->devices[i].fd,
+ FW_CDEV_IOC_SEND_RESPONSE, &response) < 0)
+ return -1;
+ } else if (!(allocation->client_transactions & type)) {
+ if (type == RAW1394_ARM_WRITE)
+ memcpy(allocation->data + offset,
+ request->data, request->length);
+ else if (type == RAW1394_ARM_LOCK)
+ /* FIXME: do lock ops here */;
+
+ if (ioctl(handle->devices[i].fd,
+ FW_CDEV_IOC_SEND_RESPONSE, &response) < 0)
+ return -1;
+ }
+
+ if (!(allocation->notification_options & type))
+ return 0;
+
+ rrb = malloc(sizeof *rrb + in_length + response.length);
+
+ rrb->request_response.request = &rrb->request;
+ rrb->request_response.response = &rrb->response;
+
+ rrb->request.destination_nodeid = handle->reset.local_node_id;
+ rrb->request.source_nodeid = handle->devices[i].node_id;
+ rrb->request.destination_offset = request->offset;
+ rrb->request.tlabel = 0;
+ if (request->tcode < 0x10) {
+ rrb->request.tcode = request->tcode;
+ rrb->request.extended_transaction_code = 0;
+ } else {
+ rrb->request.tcode = TCODE_LOCK_REQUEST;
+ rrb->request.extended_transaction_code = request->tcode - 0x10;
+ }
+ rrb->request.generation = handle->reset.generation;
+ rrb->request.buffer_length = in_length;
+ memcpy(rrb->request.buffer, request->data, in_length);
+
+ rrb->response.response_code = response.rcode;
+ rrb->response.buffer_length = response.length;
+ memcpy(rrb->response.buffer,
+ allocation->data + offset, response.length);
+
+ return handle->arm_tag_handler(handle, allocation->tag, type,
+ request->length,
+ &rrb->request_response);
+}
+
+int
+raw1394_arm_register(raw1394handle_t handle, nodeaddr_t start,
+ size_t length, byte_t *initial_value,
+ octlet_t arm_tag, arm_options_t access_rights,
+ arm_options_t notification_options,
+ arm_options_t client_transactions)
+{
+ struct fw_cdev_allocate request;
+ struct allocation *allocation;
+ int retval;
+
+ allocation = malloc(sizeof *allocation + length);
+ if (allocation == NULL)
+ return -1;
+
+ allocation->closure.callback = handle_arm_request;
+ allocation->buffer = initial_value;
+ allocation->tag = arm_tag;
+ allocation->access_rights = access_rights;
+ allocation->notification_options = notification_options;
+ allocation->client_transactions = client_transactions;
+ allocation->offset = start;
+ allocation->length = length;
+ if (initial_value != NULL)
+ memcpy(allocation->data, initial_value, length);
+
+ request.offset = start;
+ request.length = length;
+ request.closure = ptr_to_u64(&allocation->closure);
+
+ retval = ioctl(handle->local_fd, FW_CDEV_IOC_ALLOCATE, &request);
+ if (retval < 0) {
+ free(allocation);
+ return -1;
+ }
+
+ allocation->next = handle->allocations;
+ handle->allocations = allocation;
+
+ return 0;
+}
+
+static struct allocation *
+lookup_allocation(raw1394handle_t handle, nodeaddr_t start, int delete)
+{
+ struct allocation *a, **prev;
+
+ prev = &handle->allocations;
+ for (a = handle->allocations; a != NULL; a = a->next) {
+ if (a->offset <= start && start < a->offset + a->length)
+ break;
+ prev = &a->next;
+ }
+
+ if (a != NULL && delete)
+ *prev = a->next;
+
+ return a;
+}
+
+int
+raw1394_arm_unregister(raw1394handle_t handle, nodeaddr_t start)
+{
+ struct fw_cdev_deallocate request;
+ struct allocation *allocation;
+
+ allocation = lookup_allocation(handle, start, 1);
+ if (allocation == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ free(allocation);
+
+ request.offset = start;
+
+ return ioctl(handle->local_fd, FW_CDEV_IOC_DEALLOCATE, &request);
+}
+
+int
+raw1394_arm_set_buf(raw1394handle_t handle, nodeaddr_t start,
+ size_t length, void *buf)
+{
+ struct allocation *allocation;
+
+ allocation = lookup_allocation(handle, start, 0);
+ if (allocation == NULL) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ memcpy(allocation->data + allocation->offset - start, buf, length);
+
+ return 0;
+}
+
+int
+raw1394_arm_get_buf(raw1394handle_t handle, nodeaddr_t start,
+ size_t length, void *buf)
+{
+ struct allocation *allocation;
+
+ allocation = lookup_allocation(handle, start, 0);
+ if (allocation == NULL) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ memcpy(buf, allocation->data + allocation->offset - start, length);
+
+ return 0;
+}
+
+int
+raw1394_echo_request(raw1394handle_t handle, quadlet_t data)
+{
+ return write(handle->pipe_fds[1], &data, sizeof data);
+}
+
+int raw1394_wake_up(raw1394handle_t handle)
+{
+ return raw1394_echo_request(handle, 0);
+}
+
+int raw1394_phy_packet_write (raw1394handle_t handle, quadlet_t data)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int
+raw1394_start_phy_packet_write(raw1394handle_t handle,
+ quadlet_t data, unsigned long tag)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static int
+send_request(raw1394handle_t handle, int tcode,
+ nodeid_t node, nodeaddr_t addr,
+ size_t length, void *in, void *out, unsigned long tag)
+{
+ struct fw_cdev_send_request *request;
+ struct request_closure *closure;
+ int i;
+
+ if (node > handle->reset.root_node_id) {
+ handle->err = -RCODE_NO_ACK;
+ errno = raw1394_errcode_to_errno(handle->err);
+ return -1;
+ }
+
+ i = handle->nodes[node & 0x3f];
+ if (i == -1) {
+ handle->err = -RCODE_NO_ACK;
+ errno = raw1394_errcode_to_errno(handle->err);
+ return -1;
+ }
+
+ if (handle->generation != handle->devices[i].generation) {
+ handle->err = -RCODE_GENERATION;
+ errno = raw1394_errcode_to_errno(handle->err);
+ return -1;
+ }
+
+ closure = malloc(sizeof *closure);
+ if (closure == NULL) {
+ handle->err = -RCODE_SEND_ERROR;
+ errno = raw1394_errcode_to_errno(handle->err);
+ return -1;
+ }
+
+ closure->data = out;
+ closure->length = length;
+ closure->tag = tag;
+
+ request = (struct fw_cdev_send_request *) handle->buffer;
+ request->tcode = tcode;
+ request->generation = handle->generation;
+ request->offset = addr;
+ request->length = length;
+ request->closure = ptr_to_u64(closure);
+ request->data = ptr_to_u64(in);
+
+ return ioctl(handle->devices[i].fd, FW_CDEV_IOC_SEND_REQUEST, request);
+}
+
+int
+raw1394_start_read(raw1394handle_t handle, nodeid_t node, nodeaddr_t addr,
+ size_t length, quadlet_t *buffer, unsigned long tag)
+{
+ int tcode;
+
+ if (length == 4)
+ tcode = TCODE_READ_QUADLET_REQUEST;
+ else
+ tcode = TCODE_READ_BLOCK_REQUEST;
+
+ return send_request(handle, tcode,
+ node, addr, length, NULL, buffer, tag);
+}
+
+int
+raw1394_start_write(raw1394handle_t handle, nodeid_t node, nodeaddr_t addr,
+ size_t length, quadlet_t *data, unsigned long tag)
+{
+ int tcode;
+
+ if (length == 4)
+ tcode = TCODE_WRITE_QUADLET_REQUEST;
+ else
+ tcode = TCODE_WRITE_BLOCK_REQUEST;
+
+ return send_request(handle, tcode,
+ node, addr, length, data, NULL, tag);
+}
+
+static int
+setup_lock(int extcode, quadlet_t data, quadlet_t arg, quadlet_t *buffer)
+{
+ switch (extcode) {
+ case RAW1394_EXTCODE_FETCH_ADD:
+ case RAW1394_EXTCODE_LITTLE_ADD:
+ buffer[0] = data;
+ return sizeof buffer[0];
+
+ case RAW1394_EXTCODE_MASK_SWAP:
+ case RAW1394_EXTCODE_COMPARE_SWAP:
+ case RAW1394_EXTCODE_BOUNDED_ADD:
+ case RAW1394_EXTCODE_WRAP_ADD:
+ buffer[0] = arg;
+ buffer[1] = data;
+ return sizeof buffer;
+
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+}
+
+static int
+setup_lock64(int extcode, octlet_t data, octlet_t arg, octlet_t *buffer)
+{
+ switch (extcode) {
+ case RAW1394_EXTCODE_FETCH_ADD:
+ case RAW1394_EXTCODE_LITTLE_ADD:
+ buffer[0] = data;
+ return sizeof buffer[0];
+
+ case RAW1394_EXTCODE_MASK_SWAP:
+ case RAW1394_EXTCODE_COMPARE_SWAP:
+ case RAW1394_EXTCODE_BOUNDED_ADD:
+ case RAW1394_EXTCODE_WRAP_ADD:
+ buffer[0] = arg;
+ buffer[1] = data;
+ return sizeof buffer;
+
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+}
+
+int
+raw1394_start_lock(raw1394handle_t handle, nodeid_t node, nodeaddr_t addr,
+ unsigned int extcode, quadlet_t data, quadlet_t arg,
+ quadlet_t *result, unsigned long tag)
+{
+ quadlet_t buffer[2];
+ int length;
+
+ length = setup_lock(extcode, data, arg, buffer);
+ if (length < 0)
+ return length;
+
+ return send_request(handle, 16 + extcode,
+ node, addr, length, buffer, result, tag);
+}
+
+int
+raw1394_start_lock64(raw1394handle_t handle, nodeid_t node, nodeaddr_t addr,
+ unsigned int extcode, octlet_t data, octlet_t arg,
+ octlet_t *result, unsigned long tag)
+{
+ octlet_t buffer[2];
+ int length;
+
+ length = setup_lock64(extcode, data, arg, buffer);
+ if (length < 0)
+ return length;
+
+ return send_request(handle, 16 + extcode,
+ node, addr, length, buffer, result, tag);
+}
+
+int
+raw1394_start_async_stream(raw1394handle_t handle, unsigned int channel,
+ unsigned int tag, unsigned int sy,
+ unsigned int speed, size_t length, quadlet_t *data,
+ unsigned long rawtag)
+{
+ /* FIXME: implement this? */
+ return -1;
+}
+
+
+int
+raw1394_start_async_send(raw1394handle_t handle,
+ size_t length, size_t header_length,
+ unsigned int expect_response,
+ quadlet_t *data, unsigned long rawtag)
+{
+ /* FIXME: implement this? */
+ return -1;
+}
+
+struct sync_data {
+ raw1394_errcode_t err;
+ int done;
+};
+
+static int
+sync_callback(raw1394handle_t handle, void *data, raw1394_errcode_t err)
+{
+ struct sync_data *sd = data;
+
+ sd->err = err;
+ sd->done = 1;
+
+ return 0;
+}
+
+static int
+send_request_sync(raw1394handle_t handle, int tcode,
+ nodeid_t node, nodeaddr_t addr,
+ size_t length, void *in, void *out)
+{
+ struct raw1394_reqhandle reqhandle;
+ struct sync_data sd = { 0, 0 };
+ int err;
+
+ reqhandle.callback = sync_callback;
+ reqhandle.data = &sd;
+
+ err = send_request(handle, tcode, node, addr,
+ length, in, out, (unsigned long) &reqhandle);
+
+ while (!sd.done) {
+ if (err < 0)
+ return err;
+ err = raw1394_loop_iterate(handle);
+ }
+
+ handle->err = sd.err;
+ errno = raw1394_errcode_to_errno(sd.err);
+
+ return (errno ? -1 : 0);
+}
+
+int
+raw1394_read(raw1394handle_t handle, nodeid_t node, nodeaddr_t addr,
+ size_t length, quadlet_t *buffer)
+{
+ int tcode;
+
+ if (length == 4)
+ tcode = TCODE_READ_QUADLET_REQUEST;
+ else
+ tcode = TCODE_READ_BLOCK_REQUEST;
+
+ return send_request_sync(handle, tcode,
+ node, addr, length, NULL, buffer);
+}
+
+int
+raw1394_write(raw1394handle_t handle, nodeid_t node, nodeaddr_t addr,
+ size_t length, quadlet_t *data)
+{
+ int tcode;
+
+ if (length == 4)
+ tcode = TCODE_WRITE_QUADLET_REQUEST;
+ else
+ tcode = TCODE_WRITE_BLOCK_REQUEST;
+
+ return send_request_sync(handle, tcode,
+ node, addr, length, data, NULL);
+}
+
+int
+raw1394_lock(raw1394handle_t handle, nodeid_t node, nodeaddr_t addr,
+ unsigned int extcode, quadlet_t data, quadlet_t arg,
+ quadlet_t *result)
+{
+ quadlet_t buffer[2];
+ size_t length;
+
+ length = setup_lock(extcode, data, arg, buffer);
+ if (length < 0)
+ return length;
+
+ return send_request_sync(handle, 16 + extcode, node, addr,
+ length, buffer, result);
+}
+
+int
+raw1394_lock64(raw1394handle_t handle, nodeid_t node, nodeaddr_t addr,
+ unsigned int extcode, octlet_t data, octlet_t arg,
+ octlet_t *result)
+{
+ octlet_t buffer[2];
+ size_t length;
+
+ length = setup_lock64(extcode, data, arg, buffer);
+ if (length < 0)
+ return length;
+
+ return send_request_sync(handle, 16 + extcode, node, addr,
+ length, buffer, result);
+}
+
+int
+raw1394_async_stream(raw1394handle_t handle, unsigned int channel,
+ unsigned int tag, unsigned int sy, unsigned int speed,
+ size_t length, quadlet_t *data)
+{
+ /* FIXME: implement this? */
+ return -1;
+}
+
+int
+raw1394_async_send(raw1394handle_t handle,
+ size_t length, size_t header_length,
+ unsigned int expect_response,
+ quadlet_t *data)
+{
+ /* FIXME: implement this? */
+ return -1;
+}
+
+int
+raw1394_start_fcp_listen(raw1394handle_t handle)
+{
+ struct fw_cdev_allocate request;
+ struct address_closure *closure;
+
+ closure = malloc(sizeof *closure);
+ if (closure == NULL)
+ return -1;
+
+ closure->callback = handle_fcp_request;
+
+ request.offset = CSR_REGISTER_BASE + CSR_FCP_COMMAND;
+ request.length = CSR_FCP_END - CSR_FCP_COMMAND;
+ request.closure = ptr_to_u64(closure);
+ if (ioctl(handle->local_fd, FW_CDEV_IOC_ALLOCATE, &request) < 0)
+ return -1;
+
+ return 0;
+}
+
+int
+raw1394_stop_fcp_listen(raw1394handle_t handle)
+{
+ struct fw_cdev_deallocate request;
+
+ request.offset = CSR_REGISTER_BASE + CSR_FCP_COMMAND;
+
+ return ioctl(handle->local_fd, FW_CDEV_IOC_DEALLOCATE, &request);
+}
+
+const char *
+raw1394_get_libversion(void)
+{
+ return VERSION " (Juju)";
+}
+
+int
+raw1394_update_config_rom(raw1394handle_t handle, const quadlet_t *new_rom,
+ size_t size, unsigned char rom_version)
+{
+ return -1;
+}
+
+int
+raw1394_get_config_rom(raw1394handle_t handle, quadlet_t *buffer,
+ size_t buffersize, size_t *rom_size,
+ unsigned char *rom_version)
+{
+ struct fw_cdev_get_info get_info;
+ int err;
+
+ get_info.version = FW_CDEV_VERSION;
+ get_info.rom = ptr_to_u64(buffer);
+ get_info.rom_length = buffersize;
+ get_info.bus_reset = 0;
+
+ err = ioctl(handle->local_fd, FW_CDEV_IOC_GET_INFO, &get_info);
+ if (err)
+ return err;
+
+ *rom_size = get_info.rom_length;
+ *rom_version = 0;
+
+ return 0;
+}
+
+#define MAXIMUM_BANDWIDTH 4915
+
+int
+raw1394_bandwidth_modify (raw1394handle_t handle,
+ unsigned int bandwidth,
+ enum raw1394_modify_mode mode)
+{
+ quadlet_t buffer, compare, swap;
+ nodeaddr_t addr;
+ int result;
+
+ if (bandwidth == 0)
+ return 0;
+
+ addr = CSR_REGISTER_BASE + CSR_BANDWIDTH_AVAILABLE;
+ /* Read current bandwidth usage from IRM. */
+ result = raw1394_read (handle, raw1394_get_irm_id (handle), addr,
+ sizeof buffer, &buffer);
+ if (result < 0)
+ return -1;
+
+ compare = ntohl (buffer);
+ switch (mode) {
+ case RAW1394_MODIFY_ALLOC:
+ swap = compare - bandwidth;
+ if (swap < 0)
+ return -1;
+ break;
+
+ case RAW1394_MODIFY_FREE:
+ swap = compare + bandwidth;
+ if (swap > MAXIMUM_BANDWIDTH)
+ swap = MAXIMUM_BANDWIDTH;
+ break;
+
+ default:
+ return -1;
+ }
+
+ result = raw1394_lock(handle, raw1394_get_irm_id (handle), addr,
+ RAW1394_EXTCODE_COMPARE_SWAP,
+ htonl(swap), htonl(compare), &buffer);
+ if (result < 0 || ntohl(buffer) != compare)
+ return -1;
+
+ return 0;
+}
+
+int
+raw1394_channel_modify (raw1394handle_t handle,
+ unsigned int channel,
+ enum raw1394_modify_mode mode)
+{
+ quadlet_t buffer, compare, swap, bit;
+ nodeaddr_t addr;
+ int result;
+
+ if (channel >= 64)
+ return -1;
+ addr = CSR_REGISTER_BASE +
+ CSR_CHANNELS_AVAILABLE_HI + 4 * (channel / 32);
+ /* Read currently available channels from IRM. */
+ result = raw1394_read(handle, raw1394_get_irm_id (handle), addr,
+ sizeof buffer, &buffer);
+ if (result < 0)
+ return -1;
+
+ /* IEEE numbers bits from MSB (0) to LSB (31). */
+ bit = 1 << (31 - (channel & 31));
+ compare = ntohl(buffer);
+ switch (mode) {
+ case RAW1394_MODIFY_ALLOC:
+ if ((compare & bit) == 0)
+ return -1;
+ swap = buffer & ~bit;
+ break;
+
+ case RAW1394_MODIFY_FREE:
+ if ((buffer & bit) != 0)
+ return -1;
+ swap = buffer | bit;
+ break;
+
+ default:
+ return -1;
+ }
+
+ result = raw1394_lock (handle, raw1394_get_irm_id (handle), addr,
+ RAW1394_EXTCODE_COMPARE_SWAP,
+ htonl(swap), htonl(compare), &buffer);
+
+ if (result < 0 || ntohl(buffer) != compare)
+ return -1;
+
+ return 0;
+}
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 29b250e..5be1b6f 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -2,4 +2,4 @@ MAINTAINERCLEANFILES = Makefile.in
# testlibraw
bin_PROGRAMS = testlibraw sendiso dumpiso
-LDADD = ../src/libraw1394.la
+LDADD = ../$(LIB_SUBDIR)/libraw1394.la
diff --git a/tools/testlibraw.c b/tools/testlibraw.c
index 5f73bd9..2f02a6d 100644
--- a/tools/testlibraw.c
+++ b/tools/testlibraw.c
@@ -1,4 +1,5 @@
-/*
+/* -*- c-basic-offset: 8 -*-
+ *
* libraw1394 - library for raw access to the 1394 bus with the Linux subsystem.
*
* Copyright (C) 1999,2000 Andreas Bombe
@@ -13,12 +14,13 @@
#include
#include
#include
+#include
#include "../src/raw1394.h"
#include "../src/csr.h"
-#define TESTADDR (CSR_REGISTER_BASE + CSR_CYCLE_TIME)
+#define TESTADDR (CSR_REGISTER_BASE + CSR_CONFIG_ROM)
const char not_compatible[] = "\
This libraw1394 does not work with your version of Linux. You need a different\n\
@@ -45,12 +47,18 @@ int my_tag_handler(raw1394handle_t handle, unsigned long tag,
return 0;
}
+static const unsigned char fcp_data[] =
+ { 0x1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
+
int my_fcp_handler(raw1394handle_t handle, nodeid_t nodeid, int response,
size_t length, unsigned char *data)
{
printf("got fcp %s from node %d of %d bytes:",
(response ? "response" : "command"), nodeid & 0x3f, length);
+ if (memcmp(fcp_data, data, sizeof fcp_data) != 0)
+ printf("ERROR: fcp payload not correct\n");
+
while (length) {
printf(" %02x", *data);
data++;
@@ -62,6 +70,47 @@ int my_fcp_handler(raw1394handle_t handle, nodeid_t nodeid, int response,
return 0;
}
+static void
+test_fcp(raw1394handle_t handle)
+{
+ printf("\ntesting FCP monitoring on local node\n");
+ raw1394_set_fcp_handler(handle, my_fcp_handler);
+ raw1394_start_fcp_listen(handle);
+ raw1394_write(handle, raw1394_get_local_id(handle),
+ CSR_REGISTER_BASE + CSR_FCP_COMMAND, sizeof(fcp_data),
+ (quadlet_t *)fcp_data);
+ raw1394_write(handle, raw1394_get_local_id(handle),
+ CSR_REGISTER_BASE + CSR_FCP_RESPONSE, sizeof(fcp_data),
+ (quadlet_t *)fcp_data);
+}
+
+static void
+read_topology_map(raw1394handle_t handle)
+{
+ quadlet_t map[70];
+ nodeid_t local_id;
+ int node_count, self_id_count, i, retval;
+
+ local_id = raw1394_get_local_id(handle) | 0xffc0;
+
+ retval = raw1394_read(handle, local_id,
+ CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP, 12, &map[0]);
+ if (retval < 0)
+ perror("topology map: raw1394_read failed with error");
+
+ self_id_count = ntohl(map[2]) & 0xffff;
+ node_count = ntohl(map[2]) >> 16;
+ retval = raw1394_read(handle, local_id,
+ CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP + 12,
+ self_id_count * sizeof map[0], &map[3]);
+ if (retval < 0)
+ perror("topology map: raw1394_read failed with error");
+
+ printf("topology map: %d nodes, %d self ids, generation %d\n",
+ node_count, self_id_count, ntohl(map[1]));
+ for (i = 0; i < self_id_count; i++)
+ printf(" 0x%08x\n", ntohl(map[3 + i]));
+}
int main(int argc, char **argv)
{
@@ -73,7 +122,6 @@ int main(int argc, char **argv)
int retval;
struct pollfd pfd;
- unsigned char fcp_test[] = { 0x1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
quadlet_t rom[0x100];
size_t rom_size;
unsigned char rom_version;
@@ -150,17 +198,8 @@ int main(int argc, char **argv)
}
}
- printf("\ntesting FCP monitoring on local node\n");
- raw1394_set_fcp_handler(handle, my_fcp_handler);
- raw1394_start_fcp_listen(handle);
- raw1394_write(handle, raw1394_get_local_id(handle),
- CSR_REGISTER_BASE + CSR_FCP_COMMAND, sizeof(fcp_test),
- (quadlet_t *)fcp_test);
- raw1394_write(handle, raw1394_get_local_id(handle),
- CSR_REGISTER_BASE + CSR_FCP_RESPONSE, sizeof(fcp_test),
- (quadlet_t *)fcp_test);
-
-
+ test_fcp(handle);
+ read_topology_map(handle);
printf("testing config rom stuff\n");
retval=raw1394_get_config_rom(handle, rom, 0x100, &rom_size, &rom_version);
@@ -176,16 +215,19 @@ int main(int argc, char **argv)
retval=raw1394_update_config_rom(handle, rom, rom_size, rom_version);
printf("update_config_rom returned %d\n",retval);
+ printf("\nposting 0xdeadbeef as an echo request\n");
+ raw1394_echo_request(handle, 0xdeadbeef);
-
- printf("\npolling for leftover messages\n");
+ printf("polling for leftover messages\n");
pfd.fd = raw1394_get_fd(handle);
pfd.events = POLLIN;
pfd.revents = 0;
while (1) {
retval = poll(&pfd, 1, 10);
if (retval < 1) break;
- raw1394_loop_iterate(handle);
+ retval = raw1394_loop_iterate(handle);
+ if (retval != 0)
+ printf("raw1394_loop_iterate() returned 0x%08x\n", retval);
}
if (retval < 0) perror("poll failed");