diff --git a/.cvsignore b/.cvsignore
index 5de9d16..ad0dec6 100644
--- a/.cvsignore
+++ b/.cvsignore
@@ -1,3 +1,4 @@
libraw1394-1.2.0.tar.gz
libraw1394-1.2.1.tar.gz
fw-device-cdev.h
+libraw1394-1.3.0.tar.gz
diff --git a/libraw1394-juju.patch b/libraw1394-juju.patch
index 47a5613..fe2d80b 100644
--- a/libraw1394-juju.patch
+++ b/libraw1394-juju.patch
@@ -1,49 +1,36 @@
-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)
+diff -Naurp libraw1394-1.3.0.orig/configure.ac libraw1394-1.3.0/configure.ac
+--- libraw1394-1.3.0.orig/configure.ac 2007-05-30 01:32:37.000000000 -0400
++++ libraw1394-1.3.0/configure.ac 2007-10-18 22:21:34.000000000 -0400
+@@ -24,6 +24,28 @@ 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)
++ JUJU_DIR="$with_juju_dir"
++ LIB_SUBDIR=juju
++ AC_SUBST(JUJU_DIR)
+else
-+ LIB_SUBDIR=src
++ 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\""])
++ [ --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\""])
++ [ --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.])
++ [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
++ [Directory to watch for firewire device files.])
++
+ dnl Check to see if valgrind is available
+ AC_ARG_WITH(valgrind, AC_HELP_STRING([--with-valgrind],[compile with valgrind support]))
+ if test x$with_valgrind = xyes ; then
+@@ -36,6 +58,7 @@ Makefile
libraw1394.pc
libraw1394.spec
src/Makefile
@@ -51,25 +38,9 @@ index fe23ca8..7e5dd66 100644
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..c7a2ebd
---- /dev/null
-+++ b/juju/juju.h
+diff -Naurp libraw1394-1.3.0.orig/juju/juju.h libraw1394-1.3.0/juju/juju.h
+--- libraw1394-1.3.0.orig/juju/juju.h 1969-12-31 19:00:00.000000000 -0500
++++ libraw1394-1.3.0/juju/juju.h 2007-10-18 22:18:46.000000000 -0400
@@ -0,0 +1,143 @@
+/* -*- c-basic-offset: 8 -*-
+ *
@@ -214,15 +185,25 @@ index 0000000..c7a2ebd
+};
+
+#endif
-diff --git a/juju/raw1394-iso.c b/juju/raw1394-iso.c
-new file mode 100644
-index 0000000..5e18dab
---- /dev/null
-+++ b/juju/raw1394-iso.c
-@@ -0,0 +1,522 @@
+diff -Naurp libraw1394-1.3.0.orig/juju/Makefile.am libraw1394-1.3.0/juju/Makefile.am
+--- libraw1394-1.3.0.orig/juju/Makefile.am 1969-12-31 19:00:00.000000000 -0500
++++ libraw1394-1.3.0/juju/Makefile.am 2007-10-18 22:18:46.000000000 -0400
+@@ -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 -Naurp libraw1394-1.3.0.orig/juju/raw1394.c libraw1394-1.3.0/juju/raw1394.c
+--- libraw1394-1.3.0.orig/juju/raw1394.c 1969-12-31 19:00:00.000000000 -0500
++++ libraw1394-1.3.0/juju/raw1394.c 2007-10-18 22:18:46.000000000 -0400
+@@ -0,0 +1,1441 @@
+/* -*- c-basic-offset: 8 -*-
+ *
-+ * raw1394-iso.c -- Emulation of the raw1394 rawiso API on the juju stack
++ * raw1394.c -- Emulation of the raw1394 API on the juju stack
+ *
+ * Copyright (C) 2007 Kristian Hoegsberg
+ *
@@ -241,1968 +222,1976 @@ index 0000000..5e18dab
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
++#include
+#include
-+#include
-+#include
-+#include
-+#include
+#include
-+#include
++#include
+#include
++#include
++#include
++#include
++#include
++#include
++#include /* for ntohl and htonl */
+
+#include "juju.h"
+
-+static int
-+queue_packet(raw1394handle_t handle,
-+ unsigned int length, unsigned int header_length,
-+ unsigned char tag, unsigned char sy)
++raw1394_errcode_t
++raw1394_get_errcode(raw1394handle_t handle)
+{
-+ struct fw_cdev_queue_iso queue_iso;
-+ struct fw_cdev_iso_packet *p;
-+ int err;
-+
-+ p = &handle->iso.packets[handle->iso.packet_index];
-+ p->payload_length = length;
-+ p->interrupt =
-+ handle->iso.packet_phase == handle->iso.irq_interval - 1;
-+ p->skip = 0;
-+ p->tag = tag;
-+ p->sy = sy;
-+ p->header_length = header_length;
-+
-+ handle->iso.head += length;
-+ handle->iso.packet_count++;
-+ handle->iso.packet_phase++;
-+ handle->iso.packet_index++;
-+
-+ if (handle->iso.packet_phase == handle->iso.irq_interval)
-+ handle->iso.packet_phase = 0;
++ return handle->err;
++}
+
-+ if (handle->iso.head + handle->iso.max_packet_size > handle->iso.buffer_end)
-+ handle->iso.head = handle->iso.buffer;
++int
++raw1394_errcode_to_errno(raw1394_errcode_t errcode)
++{
++ switch (errcode) {
+
-+ /* Queue the packets in the kernel if we filled up the packets
-+ * array or wrapped the payload buffer. */
-+ if (handle->iso.packet_index == handle->iso.irq_interval ||
-+ handle->iso.head == handle->iso.buffer) {
-+ queue_iso.packets = ptr_to_u64(handle->iso.packets);
-+ queue_iso.size = handle->iso.packet_index * sizeof handle->iso.packets[0];
-+ queue_iso.data = ptr_to_u64(handle->iso.first_payload);
-+ queue_iso.handle = 0;
-+ handle->iso.packet_index = 0;
-+ handle->iso.first_payload = handle->iso.head;
++ case -RCODE_SEND_ERROR:
++ case -RCODE_CANCELLED:
++ case -RCODE_BUSY:
++ case -RCODE_GENERATION:
++ case -RCODE_NO_ACK:
++ return EAGAIN;
+
-+ err = ioctl(handle->iso.fd, FW_CDEV_IOC_QUEUE_ISO, &queue_iso);
-+ if (err < 0)
-+ return -1;
++ 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
-+queue_xmit_packets(raw1394handle_t handle, int limit)
++juju_to_raw1394_errcode(int rcode)
+{
-+ enum raw1394_iso_disposition d;
-+ unsigned char tag, sy;
-+ int len, cycle, dropped;
-+
-+ if (handle->iso.xmit_handler == NULL)
-+ return 0;
-+
-+ while (handle->iso.packet_count < limit) {
-+
-+ d = handle->iso.xmit_handler(handle, handle->iso.head,
-+ &len, &tag, &sy, cycle, dropped);
-+
-+ switch (d) {
-+ case RAW1394_ISO_OK:
-+ queue_packet(handle, len, 0, tag, sy);
-+ break;
-+ case RAW1394_ISO_DEFER:
-+ case RAW1394_ISO_AGAIN:
-+ default:
-+ return 0;
-+ case RAW1394_ISO_ERROR:
-+ return -1;
-+ case RAW1394_ISO_STOP:
-+ raw1394_iso_stop(handle);
-+ return 0;
-+ }
-+ }
++ /* 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. */
+
-+ return 0;
++ if (rcode < 0x10)
++ return raw1394_make_errcode(ACK_COMPLETE, rcode);
++ else
++ return -rcode;
+}
+
-+int raw1394_iso_xmit_start(raw1394handle_t handle, int start_on_cycle,
-+ int prebuffer_packets)
++static int
++default_tag_handler(raw1394handle_t handle,
++ unsigned long tag, raw1394_errcode_t err)
+{
-+ struct fw_cdev_start_iso start_iso;
-+ int retval;
++ struct raw1394_reqhandle *rh = (struct raw1394_reqhandle *) tag;
+
-+ if (prebuffer_packets == -1)
-+ prebuffer_packets = handle->iso.irq_interval;
++ if (rh != NULL)
++ return rh->callback(handle, rh->data, err);
+
-+ handle->iso.prebuffer = prebuffer_packets;
-+ handle->iso.start_on_cycle = start_on_cycle;
++ return -1;
++}
+
-+ queue_xmit_packets(handle, prebuffer_packets);
++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 (handle->iso.prebuffer <= handle->iso.packet_count) {
-+ start_iso.cycle = start_on_cycle;
-+ start_iso.handle = 0;
++ if (arm_tag == 0)
++ return -1;
+
-+ retval = ioctl(handle->iso.fd,
-+ FW_CDEV_IOC_START_ISO, &start_iso);
-+ if (retval < 0)
-+ return retval;
-+ }
++ rh = (struct raw1394_arm_reqhandle *) arm_tag;
+
-+ return queue_xmit_packets(handle, handle->iso.buf_packets);
++ return rh->arm_callback(handle, data, length, rh->pcontext, type);
+}
+
+static int
-+queue_recv_packets(raw1394handle_t handle)
++default_bus_reset_handler(struct raw1394_handle *handle, unsigned int gen)
+{
-+ while (handle->iso.packet_count <= handle->iso.buf_packets)
-+ queue_packet(handle, handle->iso.max_packet_size, 4, 0, 0);
++ raw1394_update_generation(handle, gen);
+
+ return 0;
+}
-+
-+static enum raw1394_iso_disposition
-+flush_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;
+
-+ p = interrupt->header;
-+ end = (void *) interrupt->header + interrupt->header_length;
-+ cycle = interrupt->cycle;
-+ dropped = 0;
-+ d = RAW1394_ISO_OK;
++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;
+
-+ while (p < end) {
-+ header = be32_to_cpu(*p++);
-+ len = header >> 16;
-+ tag = (header >> 14) & 0x3;
-+ channel = (header >> 8) & 0x3f;
-+ sy = header & 0x0f;
++ ports = handle->ports;
++ memset(ports, 0, sizeof handle->ports);
++ dir = opendir(FW_DEVICE_DIR);
++ if (dir == NULL)
++ return -1;
+
-+ d = handle->iso.recv_handler(handle, handle->iso.tail, len,
-+ channel, tag, sy, cycle, dropped);
-+ if (d != RAW1394_ISO_OK)
-+ /* FIXME: we need to save the headers so we
-+ * can restart this loop. */
++ i = 0;
++ while (1) {
++ de = readdir(dir);
++ if (de == NULL)
+ break;
-+ cycle++;
+
-+ handle->iso.tail += handle->iso.max_packet_size;
-+ handle->iso.packet_count--;
++ if (strncmp(de->d_name,
++ FW_DEVICE_PREFIX, strlen(FW_DEVICE_PREFIX)) != 0)
++ continue;
+
-+ if (handle->iso.tail + handle->iso.max_packet_size > handle->iso.buffer_end)
-+ handle->iso.tail = handle->iso.buffer;
-+ }
++ snprintf(filename, sizeof filename, FW_DEVICE_DIR "/%s", de->d_name);
+
-+ switch (d) {
-+ case RAW1394_ISO_OK:
-+ case RAW1394_ISO_DEFER:
-+ default:
-+ break;
-+
-+ case RAW1394_ISO_ERROR:
-+ return -1;
++ 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);
+
-+ case RAW1394_ISO_STOP:
-+ raw1394_iso_stop(handle);
-+ return 0;
++ 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);
+
-+ queue_recv_packets(handle);
++ handle->port_count = i;
+
+ return 0;
+}
+
-+int raw1394_iso_recv_start(raw1394handle_t handle, int start_on_cycle,
-+ int tag_mask, int sync)
++static int
++handle_echo_pipe(raw1394handle_t handle,
++ struct epoll_closure *ec, __uint32_t events)
+{
-+ struct fw_cdev_start_iso start_iso;
-+
-+ queue_recv_packets(handle);
++ quadlet_t value;
+
-+ 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;
-+ start_iso.handle = 0;
++ if (read(handle->pipe_fds[0], &value, sizeof value) < 0)
++ return -1;
+
-+ return ioctl(handle->iso.fd, FW_CDEV_IOC_START_ISO, &start_iso);
++ return value;
+}
+
-+static int handle_iso_event(raw1394handle_t handle,
-+ struct epoll_closure *closure, __uint32_t events)
++static int
++handle_lost_device(raw1394handle_t handle, int i)
+{
-+ struct fw_cdev_event_iso_interrupt *interrupt;
-+ int len;
++ int phy_id;
+
-+ len = read(handle->iso.fd, handle->buffer, sizeof handle->buffer);
-+ if (len < 0)
-+ return -1;
++ /* The device got unplugged, get rid of it. The fd is
++ * automatically dropped from the epoll context when we close it. */
+
-+ interrupt = (struct fw_cdev_event_iso_interrupt *) handle->buffer;
-+ if (interrupt->type != FW_CDEV_EVENT_ISO_INTERRUPT)
-+ return 0;
++ 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;
+
-+ switch (handle->iso.type) {
-+ case FW_CDEV_ISO_CONTEXT_TRANSMIT:
-+ handle->iso.packet_count -= handle->iso.irq_interval;
-+ return queue_xmit_packets(handle, handle->iso.buf_packets);
-+ case FW_CDEV_ISO_CONTEXT_RECEIVE:
-+ return flush_recv_packets(handle, interrupt);
-+ default:
-+ /* Doesn't happen. */
-+ return -1;
-+ }
++ return 0;
+}
+
-+int raw1394_iso_xmit_write(raw1394handle_t handle, unsigned char *data,
-+ unsigned int len, unsigned char tag,
-+ unsigned char sy)
++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_queue_iso queue_iso;
-+ struct fw_cdev_start_iso start_iso;
-+ struct fw_cdev_iso_packet *p;
++ struct fw_cdev_send_response response;
++ int is_response;
+
-+ if (len > handle->iso.max_packet_size) {
-+ errno = EINVAL;
-+ return -1;
-+ }
++ response.handle = request->handle;
++ response.rcode = RCODE_COMPLETE;
++ response.length = 0;
++ response.data = 0;
+
-+ /* Block until we have space for another packet. */
-+ while (handle->iso.packet_count + handle->iso.irq_interval >
-+ handle->iso.buf_packets)
-+ raw1394_loop_iterate(handle);
-+
-+ memcpy(handle->iso.head, data, len);
-+ if (queue_packet(handle, len, 0, tag, sy) < 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;
+
-+ /* Start the streaming if it's not already running and if
-+ * we've buffered up enough packets. */
-+ if (handle->iso.prebuffer > 0 &&
-+ handle->iso.packet_count >= handle->iso.prebuffer) {
-+ /* Set this to 0 to indicate that we're running. */
-+ handle->iso.prebuffer = 0;
-+ start_iso.cycle = handle->iso.start_on_cycle;
-+ start_iso.handle = 0;
++ if (response.rcode != RCODE_COMPLETE)
++ return 0;
+
-+ len = ioctl(handle->iso.fd,
-+ FW_CDEV_IOC_START_ISO, &start_iso);
-+ if (len < 0)
-+ return len;
-+ }
++ is_response = request->offset >= CSR_REGISTER_BASE + CSR_FCP_RESPONSE;
+
-+ return 0;
++ return handle->fcp_handler(handle,
++ handle->devices[i].node_id,
++ is_response,
++ request->length,
++ (unsigned char *) request->data);
+}
+
-+int raw1394_iso_xmit_sync(raw1394handle_t handle)
++static int
++handle_device_event(raw1394handle_t handle,
++ struct epoll_closure *ec, __uint32_t events)
+{
-+ struct fw_cdev_iso_packet skip;
-+ struct fw_cdev_queue_iso queue_iso;
-+ int len;
-+
-+ skip.payload_length = 0;
-+ skip.interrupt = 1;
-+ skip.skip = 1;
-+ skip.tag = 0;
-+ skip.sy = 0;
-+ skip.header_length = 0;
++ 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;
+
-+ queue_iso.packets = ptr_to_u64(&skip);
-+ queue_iso.size = sizeof skip;
-+ queue_iso.data = 0;
-+ queue_iso.handle = 0;
++ i = device - handle->devices;
++ if (events == EPOLLHUP)
++ return handle_lost_device(handle, i);
+
-+ len = ioctl(handle->iso.fd, FW_CDEV_IOC_QUEUE_ISO, &queue_iso);
++ len = read(handle->devices[i].fd,
++ handle->buffer, sizeof handle->buffer);
+ if (len < 0)
+ return -1;
+
-+ /* Now that we've queued the skip packet, we'll get an
-+ * interrupt when the transmit buffer is flushed, so all we do
-+ * here is wait. */
-+ while (handle->iso.packet_count > 0)
-+ raw1394_loop_iterate(handle);
++ 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;
+
-+ /* The iso mainloop thinks that interrutps indicate another
-+ * irq_interval number of packets was sent, so the skip
-+ * interrupt makes it go out of whack. We just reset it. */
-+ handle->iso.head = handle->iso.buffer;
-+ handle->iso.tail = handle->iso.buffer;
-+ handle->iso.first_payload = handle->iso.buffer;
-+ handle->iso.packet_phase = 0;
-+ handle->iso.packet_count = 0;
++ if (u->bus_reset.node_id != u->bus_reset.local_node_id)
++ return 0;
+
-+ return 0;
-+}
++ memcpy(&handle->reset, &u->bus_reset, sizeof handle->reset);
++ return handle->bus_reset_handler(handle,
++ u->bus_reset.generation);
+
-+int raw1394_iso_recv_flush(raw1394handle_t handle)
-+{
-+ /* FIXME: huh, we'll need kernel support here... */
++ case FW_CDEV_EVENT_RESPONSE:
++ rc = u64_to_ptr(u->response.closure);
+
-+ return 0;
-+}
++ if (rc->data != NULL)
++ memcpy(rc->data, u->response.data, rc->length);
+
-+static unsigned int
-+round_to_power_of_two(unsigned int value)
-+{
-+ unsigned int pot;
++ errcode = juju_to_raw1394_errcode(u->response.rcode);
+
-+ pot = 1;
-+ while (pot < value)
-+ pot <<= 1;
++ return handle->tag_handler(handle, rc->tag, errcode);
+
-+ return pot;
++ 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
-+iso_init(raw1394handle_t handle, int type,
-+ raw1394_iso_xmit_handler_t xmit_handler,
-+ raw1394_iso_recv_handler_t recv_handler,
-+ unsigned int buf_packets,
-+ unsigned int max_packet_size,
-+ unsigned char channel,
-+ enum raw1394_iso_speed speed,
-+ int irq_interval)
++handle_inotify(raw1394handle_t handle, struct epoll_closure *ec,
++ __uint32_t events)
+{
-+ struct fw_cdev_create_iso_context create;
++ 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 retval, prot;
++ int i, len, fd, phy_id;
+
-+ if (handle->iso.fd != -1) {
-+ errno = EBUSY;
-+ return -1;
-+ }
-+
-+ switch (type) {
-+ case FW_CDEV_ISO_CONTEXT_TRANSMIT:
-+ prot = PROT_READ | PROT_WRITE;
-+ break;
-+ case FW_CDEV_ISO_CONTEXT_RECEIVE:
-+ prot = PROT_READ;
-+ break;
-+ default:
-+ errno = EINVAL;
++ 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;
++ }
+ }
+
-+ handle->iso.type = type;
-+ if (irq_interval < 0)
-+ handle->iso.irq_interval = 256;
-+ else
-+ handle->iso.irq_interval = irq_interval;
-+ handle->iso.xmit_handler = xmit_handler;
-+ handle->iso.recv_handler = recv_handler;
-+ handle->iso.buf_packets = buf_packets;
-+ handle->iso.max_packet_size = round_to_power_of_two(max_packet_size);
-+ handle->iso.packet_phase = 0;
-+ handle->iso.packet_count = 0;
-+ handle->iso.packets =
-+ malloc(handle->iso.irq_interval * sizeof handle->iso.packets[0]);
-+ if (handle->iso.packets == NULL)
++ 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;
++ }
+
-+ handle->iso.fd = open(handle->local_filename, O_RDWR);
-+ if (handle->iso.fd < 0) {
-+ free(handle->iso.packets);
++ for (i = 0; i < MAX_DEVICES; i++)
++ if (handle->devices[i].node_id == -1)
++ break;
++ if (i == MAX_DEVICES) {
++ close(fd);
+ return -1;
+ }
+
-+ handle->iso.closure.func = handle_iso_event;
++ 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->iso.closure;
-+ if (epoll_ctl(handle->epoll_fd, EPOLL_CTL_ADD,
-+ handle->iso.fd, &ep) < 0) {
-+ close(handle->iso.fd);
-+ free(handle->iso.packets);
++ ep.data.ptr = &handle->devices[i].closure;
++ if (epoll_ctl(handle->epoll_fd, EPOLL_CTL_ADD, fd, &ep) < 0) {
++ close(fd);
+ return -1;
+ }
+
-+ create.type = type;
-+ create.channel = channel;
-+ create.speed = speed;
-+ create.header_size = 4;
-+
-+ 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;
-+ }
++ return 0;
++}
+
-+ handle->iso.buffer =
-+ mmap(NULL, buf_packets * max_packet_size,
-+ prot, MAP_SHARED, handle->iso.fd, 0);
++int raw1394_loop_iterate(raw1394handle_t handle)
++{
++ int i, count, retval = 0;
++ struct epoll_closure *closure;
++ struct epoll_event ep[32];
+
-+ if (handle->iso.buffer == MAP_FAILED) {
-+ close(handle->iso.fd);
-+ free(handle->iso.packets);
++ 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);
+ }
+
-+ handle->iso.buffer_end = handle->iso.buffer +
-+ buf_packets * max_packet_size;
-+ handle->iso.head = handle->iso.buffer;
-+ handle->iso.tail = handle->iso.buffer;
-+ handle->iso.first_payload = handle->iso.buffer;
++ /* 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 0;
++ return retval;
+}
+
-+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)
++raw1394handle_t raw1394_new_handle(void)
+{
-+ return iso_init(handle, FW_CDEV_ISO_CONTEXT_TRANSMIT,
-+ handler, NULL, buf_packets, max_packet_size,
-+ channel, speed, irq_interval);
++ 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;
+}
+
-+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)
++void raw1394_destroy_handle(raw1394handle_t handle)
+{
-+ return iso_init(handle, FW_CDEV_ISO_CONTEXT_RECEIVE,
-+ NULL, handler, buf_packets, max_packet_size,
-+ channel, 0, irq_interval);
++ 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;
+}
+
-+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)
++raw1394handle_t raw1394_new_handle_on_port(int port)
+{
-+ /* FIXME: gah */
-+ errno = ENOSYS;
-+ return -1;
++ 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_iso_recv_listen_channel(raw1394handle_t handle,
-+ unsigned char channel)
++int raw1394_busreset_notify (raw1394handle_t handle, int off_on_switch)
+{
-+ /* FIXME: multichannel */
-+ errno = ENOSYS;
-+ return -1;
++ handle->notify_bus_reset = off_on_switch;
++
++ return 0;
+}
+
-+int raw1394_iso_recv_unlisten_channel(raw1394handle_t handle,
-+ unsigned char channel)
++int raw1394_get_fd(raw1394handle_t handle)
+{
-+ /* FIXME: multichannel */
-+ errno = ENOSYS;
-+ return -1;
++ return handle->epoll_fd;
+}
+
-+int raw1394_iso_recv_set_channel_mask(raw1394handle_t handle, u_int64_t mask)
++void raw1394_set_userdata(raw1394handle_t handle, void *data)
+{
-+ /* FIXME: multichannel */
-+ errno = ENOSYS;
-+ return -1;
-+}
-+
-+void raw1394_iso_stop(raw1394handle_t handle)
-+{
-+ struct fw_cdev_stop_iso stop_iso;
-+
-+ stop_iso.handle = 0;
-+ ioctl(handle->iso.fd, FW_CDEV_IOC_STOP_ISO);
-+
-+ handle->iso.head = handle->iso.buffer;
-+ handle->iso.tail = handle->iso.buffer;
-+ handle->iso.first_payload = handle->iso.buffer;
-+ handle->iso.packet_phase = 0;
-+ handle->iso.packet_count = 0;
-+}
-+
-+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);
++ handle->user_data = data;
+}
-diff --git a/juju/raw1394.c b/juju/raw1394.c
-new file mode 100644
-index 0000000..7f73b3b
---- /dev/null
-+++ b/juju/raw1394.c
-@@ -0,0 +1,1441 @@
-+/* -*- 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 /* for ntohl and htonl */
-+
-+#include "juju.h"
+
-+raw1394_errcode_t
-+raw1394_get_errcode(raw1394handle_t handle)
++void *raw1394_get_userdata(raw1394handle_t handle)
+{
-+ return handle->err;
++ return handle->user_data;
+}
+
-+int
-+raw1394_errcode_to_errno(raw1394_errcode_t errcode)
++nodeid_t raw1394_get_local_id(raw1394handle_t handle)
+{
-+ 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;
-+ }
++ return handle->reset.local_node_id;
+}
+
-+static int
-+juju_to_raw1394_errcode(int rcode)
++nodeid_t raw1394_get_irm_id(raw1394handle_t handle)
+{
-+ /* 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;
++ return handle->reset.irm_node_id;
+}
+
-+static int
-+default_tag_handler(raw1394handle_t handle,
-+ unsigned long tag, raw1394_errcode_t err)
++int raw1394_get_nodecount(raw1394handle_t handle)
+{
-+ struct raw1394_reqhandle *rh = (struct raw1394_reqhandle *) tag;
-+
-+ if (rh != NULL)
-+ return rh->callback(handle, rh->data, err);
-+
-+ return -1;
++ return (handle->reset.root_node_id & 0x3f) + 1;
+}
+
-+static int
-+default_arm_tag_handler(raw1394handle_t handle, unsigned long arm_tag,
-+ byte_t type, unsigned int length, void *data)
++int raw1394_get_port_info(raw1394handle_t handle,
++ struct raw1394_portinfo *pinf,
++ int maxports)
+{
-+ struct raw1394_arm_reqhandle *rh;
-+
-+ if (arm_tag == 0)
-+ return -1;
-+
-+ rh = (struct raw1394_arm_reqhandle *) arm_tag;
++ int i;
+
-+ return rh->arm_callback(handle, data, length, rh->pcontext, type);
-+}
++ if (maxports >= handle->port_count)
++ maxports = handle->port_count;
+
-+static int
-+default_bus_reset_handler(struct raw1394_handle *handle, unsigned int gen)
-+{
-+ raw1394_update_generation(handle, gen);
++ 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 0;
++ return handle->port_count;
+}
+
-+static int
-+scan_devices(raw1394handle_t handle)
++int raw1394_set_port(raw1394handle_t handle, int port)
+{
-+ 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;
++ struct epoll_event ep;
++ struct dirent *de;
++ char filename[32];
++ DIR *dir;
++ int i, fd, phy_id;
+
-+ ports = handle->ports;
-+ memset(ports, 0, sizeof handle->ports);
-+ dir = opendir(FW_DEVICE_DIR);
++ if (port >= handle->port_count) {
++ errno = EINVAL;
++ return -1;
++ }
++
++ dir = opendir("/dev");
+ if (dir == NULL)
+ return -1;
+
-+ i = 0;
-+ while (1) {
++ for (i = 0; i < MAX_DEVICES; ) {
+ de = readdir(dir);
+ if (de == NULL)
+ break;
+
-+ if (strncmp(de->d_name,
-+ FW_DEVICE_PREFIX, strlen(FW_DEVICE_PREFIX)) != 0)
++ if (strncmp(de->d_name, "fw", 2) != 0)
+ continue;
+
-+ snprintf(filename, sizeof filename, FW_DEVICE_DIR "/%s", de->d_name);
++ 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);
-+ err = ioctl(fd, FW_CDEV_IOC_GET_INFO, &get_info);
-+ close(fd);
++ if (ioctl(fd, FW_CDEV_IOC_GET_INFO, &get_info) < 0) {
++ close(fd);
++ continue;
++ }
+
-+ if (err < 0)
++ if (get_info.card != handle->ports[port].card) {
++ close(fd);
+ 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++;
++ 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;
+ }
-+ }
-+ closedir(dir);
+
-+ handle->port_count = i;
++ 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;
+}
+
-+static int
-+handle_echo_pipe(raw1394handle_t handle,
-+ struct epoll_closure *ec, __uint32_t events)
++int raw1394_reset_bus(raw1394handle_t handle)
+{
-+ quadlet_t value;
++ return raw1394_reset_bus_new(handle, RAW1394_LONG_RESET);
++}
+
-+ if (read(handle->pipe_fds[0], &value, sizeof value) < 0)
-+ return -1;
++int raw1394_reset_bus_new(raw1394handle_t handle, int type)
++{
++ struct fw_cdev_initiate_bus_reset initiate;
+
-+ return value;
++ 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);
+}
+
-+static int
-+handle_lost_device(raw1394handle_t handle, int i)
++bus_reset_handler_t raw1394_set_bus_reset_handler(raw1394handle_t handle,
++ bus_reset_handler_t new_h)
+{
-+ int phy_id;
++ bus_reset_handler_t old_h = handle->bus_reset_handler;
+
-+ /* 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;
++ handle->bus_reset_handler = new_h;
+
-+ return 0;
++ return old_h;
+}
+
-+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)
++unsigned int raw1394_get_generation(raw1394handle_t handle)
+{
-+ struct fw_cdev_send_response response;
-+ int is_response;
++ return handle->generation;
++}
+
-+ response.handle = request->handle;
-+ response.rcode = RCODE_COMPLETE;
-+ response.length = 0;
-+ response.data = 0;
++void raw1394_update_generation(raw1394handle_t handle, unsigned int generation)
++{
++ handle->generation = generation;
++}
+
-+ if (handle->fcp_handler == NULL)
-+ response.rcode = RCODE_ADDRESS_ERROR;
++tag_handler_t
++raw1394_set_tag_handler(raw1394handle_t handle, tag_handler_t new_h)
++{
++ tag_handler_t old_h = handle->tag_handler;
+
-+ if (request->tcode >= TCODE_WRITE_RESPONSE)
-+ response.rcode = RCODE_CONFLICT_ERROR;
++ handle->tag_handler = new_h;
+
-+ if (ioctl(handle->devices[i].fd,
-+ FW_CDEV_IOC_SEND_RESPONSE, &response) < 0)
-+ return -1;
++ return old_h;
++}
+
-+ if (response.rcode != RCODE_COMPLETE)
-+ return 0;
++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;
+
-+ is_response = request->offset >= CSR_REGISTER_BASE + CSR_FCP_RESPONSE;
++ handle->arm_tag_handler = new_h;
+
-+ return handle->fcp_handler(handle,
-+ handle->devices[i].node_id,
-+ is_response,
-+ request->length,
-+ (unsigned char *) request->data);
++ return old_h;
+}
+
-+static int
-+handle_device_event(raw1394handle_t handle,
-+ struct epoll_closure *ec, __uint32_t events)
++fcp_handler_t
++raw1394_set_fcp_handler(raw1394handle_t handle, fcp_handler_t new_h)
+{
-+ 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;
++ fcp_handler_t old_h = handle->fcp_handler;
+
-+ i = device - handle->devices;
-+ if (events == EPOLLHUP)
-+ return handle_lost_device(handle, i);
++ handle->fcp_handler = new_h;
+
-+ len = read(handle->devices[i].fd,
-+ handle->buffer, sizeof handle->buffer);
-+ if (len < 0)
-+ return -1;
++ return old_h;
++}
+
-+ 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;
++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];
++};
+
-+ if (u->bus_reset.node_id != u->bus_reset.local_node_id)
-+ return 0;
++struct allocation {
++ struct address_closure closure;
++ struct allocation *next;
++ __u32 handle;
++ 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];
++};
+
-+ memcpy(&handle->reset, &u->bus_reset, sizeof handle->reset);
-+ return handle->bus_reset_handler(handle,
-+ u->bus_reset.generation);
++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;
+
-+ case FW_CDEV_EVENT_RESPONSE:
-+ rc = u64_to_ptr(u->response.closure);
++ offset = request->offset - allocation->offset;
++ response.handle = request->handle;
+
-+ if (rc->data != NULL)
-+ memcpy(rc->data, u->response.data, rc->length);
++ 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);
+
-+ errcode = juju_to_raw1394_errcode(u->response.rcode);
++ type = RAW1394_ARM_WRITE;
++ in_length = request->length;
++ response.rcode = RCODE_COMPLETE;
++ response.length = 0;
++ response.data = 0;
++ break;
+
-+ return handle->tag_handler(handle, rc->tag, errcode);
++ case TCODE_READ_QUADLET_REQUEST:
++ case TCODE_READ_BLOCK_REQUEST:
++ printf("got read request, offset=0x%012llx, length=%d\n",
++ request->offset, request->length);
+
-+ case FW_CDEV_EVENT_REQUEST:
-+ ac = u64_to_ptr(u->request.closure);
-+ return ac->callback(handle, ac, &u->request, i);
++ 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:
-+ case FW_CDEV_EVENT_ISO_INTERRUPT:
-+ /* Never happens. */
-+ return -1;
++ in_length = 0;
++ type = 0;
++ break;
+ }
-+}
-+
-+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. */
++ 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 */;
+
-+ 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;
++ if (ioctl(handle->devices[i].fd,
++ FW_CDEV_IOC_SEND_RESPONSE, &response) < 0)
++ 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;
-+ }
++ if (!(allocation->notification_options & type))
++ return 0;
+
-+ 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;
-+ }
++ rrb = malloc(sizeof *rrb + in_length + response.length);
+
-+ return 0;
-+}
++ rrb->request_response.request = &rrb->request;
++ rrb->request_response.response = &rrb->response;
+
-+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);
++ 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);
+
-+ /* 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);
++ rrb->response.response_code = response.rcode;
++ rrb->response.buffer_length = response.length;
++ memcpy(rrb->response.buffer,
++ allocation->data + offset, response.length);
+
-+ return retval;
++ return handle->arm_tag_handler(handle, allocation->tag, type,
++ request->length,
++ &rrb->request_response);
+}
+
-+raw1394handle_t raw1394_new_handle(void)
++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)
+{
-+ 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;
++ struct fw_cdev_allocate request;
++ struct allocation *allocation;
++ int retval;
+
-+ handle->iso.fd = -1;
++ allocation = malloc(sizeof *allocation + length);
++ if (allocation == NULL)
++ return -1;
+
-+ handle->epoll_fd = epoll_create(16);
-+ if (handle->epoll_fd < 0)
-+ goto out_handle;
++ 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);
+
-+ if (pipe(handle->pipe_fds) < 0)
-+ goto out_epoll;
++ request.offset = start;
++ request.length = length;
++ request.closure = ptr_to_u64(&allocation->closure);
+
-+ handle->inotify_fd = inotify_init();
-+ if (handle->inotify_fd < 0)
-+ goto out_pipe;
++ retval = ioctl(handle->local_fd, FW_CDEV_IOC_ALLOCATE, &request);
++ if (retval < 0) {
++ free(allocation);
++ return -1;
++ }
+
-+ handle->inotify_watch =
-+ inotify_add_watch(handle->inotify_fd, FW_DEVICE_DIR, IN_CREATE);
-+ if (handle->inotify_watch < 0)
-+ goto out_inotify;
++ allocation->handle = request.handle;
++ allocation->next = handle->allocations;
++ handle->allocations = allocation;
+
-+ 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;
++ return 0;
++}
+
-+ 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;
++static struct allocation *
++lookup_allocation(raw1394handle_t handle, nodeaddr_t start, int delete)
++{
++ struct allocation *a, **prev;
+
-+ for (i = 0; i < MAX_DEVICES; i++) {
-+ handle->nodes[i] = -1;
-+ handle->devices[i].node_id = -1;
++ 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;
+ }
+
-+ scan_devices(handle);
-+
-+ return handle;
++ if (a != NULL && delete)
++ *prev = a->next;
+
-+ 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;
++ return a;
+}
+
-+void raw1394_destroy_handle(raw1394handle_t handle)
++int
++raw1394_arm_unregister(raw1394handle_t handle, nodeaddr_t start)
+{
-+ 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;
++ struct fw_cdev_deallocate request;
++ struct allocation *allocation;
+
-+ close(handle->devices[i].fd);
++ allocation = lookup_allocation(handle, start, 1);
++ if (allocation == NULL) {
++ errno = EINVAL;
++ return -1;
+ }
+
-+ close(handle->epoll_fd);
-+
-+ free(handle);
++ request.handle = allocation->handle;
++ free(allocation);
+
-+ return;
++ return ioctl(handle->local_fd, FW_CDEV_IOC_DEALLOCATE, &request);
+}
+
-+raw1394handle_t raw1394_new_handle_on_port(int port)
++int
++raw1394_arm_set_buf(raw1394handle_t handle, nodeaddr_t start,
++ size_t length, void *buf)
+{
-+ raw1394handle_t handle;
++ struct allocation *allocation;
+
-+ handle = raw1394_new_handle();
-+ if (handle == NULL)
-+ return NULL;
++ allocation = lookup_allocation(handle, start, 0);
++ if (allocation == NULL) {
++ errno = ENOENT;
++ return -1;
++ }
+
-+ if (raw1394_set_port(handle, port) < 0)
-+ return NULL;
++ memcpy(allocation->data + allocation->offset - start, buf, length);
+
-+ return handle;
++ return 0;
+}
+
-+int raw1394_busreset_notify (raw1394handle_t handle, int off_on_switch)
++int
++raw1394_arm_get_buf(raw1394handle_t handle, nodeaddr_t start,
++ size_t length, void *buf)
+{
-+ handle->notify_bus_reset = off_on_switch;
++ struct allocation *allocation;
+
-+ return 0;
-+}
++ allocation = lookup_allocation(handle, start, 0);
++ if (allocation == NULL) {
++ errno = ENOENT;
++ return -1;
++ }
+
-+int raw1394_get_fd(raw1394handle_t handle)
-+{
-+ return handle->epoll_fd;
-+}
++ memcpy(buf, allocation->data + allocation->offset - start, length);
+
-+void raw1394_set_userdata(raw1394handle_t handle, void *data)
-+{
-+ handle->user_data = data;
++ return 0;
+}
+
-+void *raw1394_get_userdata(raw1394handle_t handle)
++int
++raw1394_echo_request(raw1394handle_t handle, quadlet_t data)
+{
-+ return handle->user_data;
++ return write(handle->pipe_fds[1], &data, sizeof data);
+}
+
-+nodeid_t raw1394_get_local_id(raw1394handle_t handle)
++int raw1394_wake_up(raw1394handle_t handle)
+{
-+ return handle->reset.local_node_id;
++ return raw1394_echo_request(handle, 0);
+}
+
-+nodeid_t raw1394_get_irm_id(raw1394handle_t handle)
++int raw1394_phy_packet_write (raw1394handle_t handle, quadlet_t data)
+{
-+ return handle->reset.irm_node_id;
++ errno = ENOSYS;
++ return -1;
+}
+
-+int raw1394_get_nodecount(raw1394handle_t handle)
++int
++raw1394_start_phy_packet_write(raw1394handle_t handle,
++ quadlet_t data, unsigned long tag)
+{
-+ return (handle->reset.root_node_id & 0x3f) + 1;
++ errno = ENOSYS;
++ return -1;
+}
+
-+int raw1394_get_port_info(raw1394handle_t handle,
-+ struct raw1394_portinfo *pinf,
-+ int maxports)
++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 (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);
++ if (node > handle->reset.root_node_id) {
++ handle->err = -RCODE_NO_ACK;
++ errno = raw1394_errcode_to_errno(handle->err);
++ return -1;
+ }
+
-+ return handle->port_count;
-+}
++ i = handle->nodes[node & 0x3f];
++ if (i == -1) {
++ handle->err = -RCODE_NO_ACK;
++ errno = raw1394_errcode_to_errno(handle->err);
++ return -1;
++ }
+
-+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;
++ if (handle->generation != handle->devices[i].generation) {
++ handle->err = -RCODE_GENERATION;
++ errno = raw1394_errcode_to_errno(handle->err);
+ return -1;
+ }
+
-+ dir = opendir("/dev");
-+ if (dir == NULL)
++ closure = malloc(sizeof *closure);
++ if (closure == NULL) {
++ handle->err = -RCODE_SEND_ERROR;
++ errno = raw1394_errcode_to_errno(handle->err);
+ return -1;
++ }
+
-+ for (i = 0; i < MAX_DEVICES; ) {
-+ de = readdir(dir);
-+ if (de == NULL)
-+ break;
++ closure->data = out;
++ closure->length = length;
++ closure->tag = tag;
+
-+ if (strncmp(de->d_name, "fw", 2) != 0)
-+ continue;
++ 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);
+
-+ snprintf(filename, sizeof filename, "/dev/%s", de->d_name);
++ return ioctl(handle->devices[i].fd, FW_CDEV_IOC_SEND_REQUEST, request);
++}
+
-+ fd = open(filename, O_RDWR);
-+ if (fd < 0)
-+ continue;
++int
++raw1394_start_read(raw1394handle_t handle, nodeid_t node, nodeaddr_t addr,
++ size_t length, quadlet_t *buffer, unsigned long tag)
++{
++ int tcode;
+
-+ 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 (length == 4)
++ tcode = TCODE_READ_QUADLET_REQUEST;
++ else
++ tcode = TCODE_READ_BLOCK_REQUEST;
+
-+ if (get_info.card != handle->ports[port].card) {
-+ close(fd);
-+ continue;
-+ }
++ return send_request(handle, tcode,
++ node, addr, length, NULL, buffer, tag);
++}
+
-+ 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);
++int
++raw1394_start_write(raw1394handle_t handle, nodeid_t node, nodeaddr_t addr,
++ size_t length, quadlet_t *data, unsigned long tag)
++{
++ int tcode;
+
-+ 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;
-+ }
++ if (length == 4)
++ tcode = TCODE_WRITE_QUADLET_REQUEST;
++ else
++ tcode = TCODE_WRITE_BLOCK_REQUEST;
+
-+ 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);
-+ }
++ return send_request(handle, tcode,
++ node, addr, length, data, NULL, tag);
++}
+
-+ i++;
-+ }
++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];
+
-+ return 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 2 * sizeof buffer[0];
++
++ default:
++ errno = EINVAL;
++ return -1;
++ }
+}
+
-+int raw1394_reset_bus(raw1394handle_t handle)
++static int
++setup_lock64(int extcode, octlet_t data, octlet_t arg, octlet_t *buffer)
+{
-+ return raw1394_reset_bus_new(handle, RAW1394_LONG_RESET);
++ 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 2 * sizeof buffer[0];
++
++ default:
++ errno = EINVAL;
++ return -1;
++ }
+}
+
-+int raw1394_reset_bus_new(raw1394handle_t handle, int type)
++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)
+{
-+ struct fw_cdev_initiate_bus_reset initiate;
++ quadlet_t buffer[2];
++ int length;
+
-+ switch (type) {
-+ case RAW1394_LONG_RESET:
-+ initiate.type = FW_CDEV_LONG_RESET;
-+ break;
-+ case RAW1394_SHORT_RESET:
-+ initiate.type = FW_CDEV_SHORT_RESET;
-+ break;
-+ }
++ length = setup_lock(extcode, data, arg, buffer);
++ if (length < 0)
++ return length;
+
-+ return ioctl(handle->local_fd,
-+ FW_CDEV_IOC_INITIATE_BUS_RESET, &initiate);
++ return send_request(handle, 16 + extcode,
++ node, addr, length, buffer, result, tag);
+}
+
-+bus_reset_handler_t raw1394_set_bus_reset_handler(raw1394handle_t handle,
-+ bus_reset_handler_t new_h)
++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)
+{
-+ bus_reset_handler_t old_h = handle->bus_reset_handler;
++ octlet_t buffer[2];
++ int length;
+
-+ handle->bus_reset_handler = new_h;
++ length = setup_lock64(extcode, data, arg, buffer);
++ if (length < 0)
++ return length;
+
-+ return old_h;
++ return send_request(handle, 16 + extcode,
++ node, addr, length, buffer, result, tag);
+}
+
-+unsigned int raw1394_get_generation(raw1394handle_t handle)
++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)
+{
-+ return handle->generation;
++ /* FIXME: implement this? */
++ return -1;
+}
+
-+void raw1394_update_generation(raw1394handle_t handle, unsigned int generation)
++
++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)
+{
-+ handle->generation = generation;
++ /* FIXME: implement this? */
++ return -1;
+}
+
-+tag_handler_t
-+raw1394_set_tag_handler(raw1394handle_t handle, tag_handler_t new_h)
++struct sync_data {
++ raw1394_errcode_t err;
++ int done;
++};
++
++static int
++sync_callback(raw1394handle_t handle, void *data, raw1394_errcode_t err)
+{
-+ tag_handler_t old_h = handle->tag_handler;
++ struct sync_data *sd = data;
+
-+ handle->tag_handler = new_h;
++ sd->err = err;
++ sd->done = 1;
+
-+ return old_h;
++ return 0;
+}
+
-+arm_tag_handler_t
-+raw1394_set_arm_tag_handler(raw1394handle_t handle, arm_tag_handler_t new_h)
++static int
++send_request_sync(raw1394handle_t handle, int tcode,
++ nodeid_t node, nodeaddr_t addr,
++ size_t length, void *in, void *out)
+{
-+ arm_tag_handler_t old_h = handle->arm_tag_handler;
++ struct raw1394_reqhandle reqhandle;
++ struct sync_data sd = { 0, 0 };
++ int err;
+
-+ handle->arm_tag_handler = new_h;
++ reqhandle.callback = sync_callback;
++ reqhandle.data = &sd;
+
-+ return old_h;
-+}
++ err = send_request(handle, tcode, node, addr,
++ length, in, out, (unsigned long) &reqhandle);
+
-+fcp_handler_t
-+raw1394_set_fcp_handler(raw1394handle_t handle, fcp_handler_t new_h)
-+{
-+ fcp_handler_t old_h = handle->fcp_handler;
++ while (!sd.done) {
++ if (err < 0)
++ return err;
++ err = raw1394_loop_iterate(handle);
++ }
+
-+ handle->fcp_handler = new_h;
++ handle->err = sd.err;
++ errno = raw1394_errcode_to_errno(sd.err);
+
-+ return old_h;
++ return (errno ? -1 : 0);
+}
+
-+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;
-+ __u32 handle;
-+ 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)
++int
++raw1394_read(raw1394handle_t handle, nodeid_t node, nodeaddr_t addr,
++ size_t length, quadlet_t *buffer)
+{
-+ 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.handle = request->handle;
-+
-+ 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);
++ int tcode;
+
-+ type = RAW1394_ARM_WRITE;
-+ in_length = request->length;
-+ response.rcode = RCODE_COMPLETE;
-+ response.length = 0;
-+ response.data = 0;
-+ break;
++ if (length == 4)
++ tcode = TCODE_READ_QUADLET_REQUEST;
++ else
++ tcode = TCODE_READ_BLOCK_REQUEST;
+
-+ case TCODE_READ_QUADLET_REQUEST:
-+ case TCODE_READ_BLOCK_REQUEST:
-+ printf("got read request, offset=0x%012llx, length=%d\n",
-+ request->offset, request->length);
++ return send_request_sync(handle, tcode,
++ node, addr, length, NULL, buffer);
++}
+
-+ type = RAW1394_ARM_READ;
-+ in_length = 0;
-+ response.rcode = RCODE_COMPLETE;
-+ response.length = request->length;
-+ response.data = ptr_to_u64(allocation->data + offset);
-+ break;
++int
++raw1394_write(raw1394handle_t handle, nodeid_t node, nodeaddr_t addr,
++ size_t length, quadlet_t *data)
++{
++ int tcode;
+
-+ case TCODE_LOCK_REQUEST:
-+ type = RAW1394_ARM_LOCK;
-+ in_length = request->length;
-+ response.length = 4;
-+ break;
++ if (length == 4)
++ tcode = TCODE_WRITE_QUADLET_REQUEST;
++ else
++ tcode = TCODE_WRITE_BLOCK_REQUEST;
+
-+ default:
-+ in_length = 0;
-+ type = 0;
-+ break;
-+ }
++ return send_request_sync(handle, tcode,
++ node, addr, length, data, NULL);
++}
+
-+ 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 */;
++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;
+
-+ if (ioctl(handle->devices[i].fd,
-+ FW_CDEV_IOC_SEND_RESPONSE, &response) < 0)
-+ return -1;
-+ }
++ length = setup_lock(extcode, data, arg, buffer);
++ if (length < 0)
++ return length;
+
-+ if (!(allocation->notification_options & type))
-+ return 0;
++ return send_request_sync(handle, 16 + extcode, node, addr,
++ length, buffer, result);
++}
+
-+ rrb = malloc(sizeof *rrb + in_length + response.length);
++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;
+
-+ rrb->request_response.request = &rrb->request;
-+ rrb->request_response.response = &rrb->response;
++ length = setup_lock64(extcode, data, arg, buffer);
++ if (length < 0)
++ return length;
+
-+ 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);
++ return send_request_sync(handle, 16 + extcode, node, addr,
++ length, buffer, result);
++}
+
-+ rrb->response.response_code = response.rcode;
-+ rrb->response.buffer_length = response.length;
-+ memcpy(rrb->response.buffer,
-+ allocation->data + offset, response.length);
++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;
++}
+
-+ return handle->arm_tag_handler(handle, allocation->tag, type,
-+ request->length,
-+ &rrb->request_response);
++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_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)
++raw1394_start_fcp_listen(raw1394handle_t handle)
+{
+ struct fw_cdev_allocate request;
-+ struct allocation *allocation;
-+ int retval;
++ struct address_closure *closure;
+
-+ allocation = malloc(sizeof *allocation + length);
-+ if (allocation == NULL)
++ closure = malloc(sizeof *closure);
++ if (closure == 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);
++ closure->callback = handle_fcp_request;
+
-+ retval = ioctl(handle->local_fd, FW_CDEV_IOC_ALLOCATE, &request);
-+ if (retval < 0) {
-+ free(allocation);
++ 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;
-+ }
+
-+ allocation->handle = request.handle;
-+ allocation->next = handle->allocations;
-+ handle->allocations = allocation;
++ handle->fcp_allocation_handle = request.handle;
+
+ 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)
++raw1394_stop_fcp_listen(raw1394handle_t handle)
+{
+ struct fw_cdev_deallocate request;
-+ struct allocation *allocation;
-+
-+ allocation = lookup_allocation(handle, start, 1);
-+ if (allocation == NULL) {
-+ errno = EINVAL;
-+ return -1;
-+ }
+
-+ request.handle = allocation->handle;
-+ free(allocation);
++ request.handle = handle->fcp_allocation_handle;
+
+ 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)
++const char *
++raw1394_get_libversion(void)
+{
-+ 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;
++ return VERSION " (Juju)";
+}
+
+int
-+raw1394_arm_get_buf(raw1394handle_t handle, nodeaddr_t start,
-+ size_t length, void *buf)
++raw1394_update_config_rom(raw1394handle_t handle, const quadlet_t *new_rom,
++ size_t size, unsigned char rom_version)
+{
-+ 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;
++ return -1;
+}
+
+int
-+raw1394_echo_request(raw1394handle_t handle, quadlet_t data)
++raw1394_get_config_rom(raw1394handle_t handle, quadlet_t *buffer,
++ size_t buffersize, size_t *rom_size,
++ unsigned char *rom_version)
+{
-+ return write(handle->pipe_fds[1], &data, sizeof data);
-+}
++ struct fw_cdev_get_info get_info;
++ int err;
+
-+int raw1394_wake_up(raw1394handle_t handle)
-+{
-+ return raw1394_echo_request(handle, 0);
-+}
++ get_info.version = FW_CDEV_VERSION;
++ get_info.rom = ptr_to_u64(buffer);
++ get_info.rom_length = buffersize;
++ get_info.bus_reset = 0;
+
-+int raw1394_phy_packet_write (raw1394handle_t handle, quadlet_t data)
-+{
-+ errno = ENOSYS;
-+ return -1;
++ 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_start_phy_packet_write(raw1394handle_t handle,
-+ quadlet_t data, unsigned long tag)
++raw1394_bandwidth_modify (raw1394handle_t handle,
++ unsigned int bandwidth,
++ enum raw1394_modify_mode mode)
+{
-+ errno = ENOSYS;
-+ return -1;
-+}
++ quadlet_t buffer, compare, swap;
++ nodeaddr_t addr;
++ int result;
+
-+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 (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;
+
-+ if (node > handle->reset.root_node_id) {
-+ handle->err = -RCODE_NO_ACK;
-+ errno = raw1394_errcode_to_errno(handle->err);
-+ return -1;
-+ }
++ compare = ntohl (buffer);
++ switch (mode) {
++ case RAW1394_MODIFY_ALLOC:
++ swap = compare - bandwidth;
++ if (swap < 0)
++ return -1;
++ break;
+
-+ i = handle->nodes[node & 0x3f];
-+ if (i == -1) {
-+ handle->err = -RCODE_NO_ACK;
-+ errno = raw1394_errcode_to_errno(handle->err);
++ case RAW1394_MODIFY_FREE:
++ swap = compare + bandwidth;
++ if (swap > MAXIMUM_BANDWIDTH)
++ swap = MAXIMUM_BANDWIDTH;
++ break;
++
++ default:
+ return -1;
+ }
+
-+ if (handle->generation != handle->devices[i].generation) {
-+ handle->err = -RCODE_GENERATION;
-+ errno = raw1394_errcode_to_errno(handle->err);
++ 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;
++}
+
-+ closure = malloc(sizeof *closure);
-+ if (closure == NULL) {
-+ handle->err = -RCODE_SEND_ERROR;
-+ errno = raw1394_errcode_to_errno(handle->err);
++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;
+
-+ closure->data = out;
-+ closure->length = length;
-+ closure->tag = tag;
++ case RAW1394_MODIFY_FREE:
++ if ((buffer & bit) != 0)
++ return -1;
++ swap = buffer | bit;
++ break;
+
-+ 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);
++ default:
++ return -1;
++ }
++
++ result = raw1394_lock (handle, raw1394_get_irm_id (handle), addr,
++ RAW1394_EXTCODE_COMPARE_SWAP,
++ htonl(swap), htonl(compare), &buffer);
+
-+ return ioctl(handle->devices[i].fd, FW_CDEV_IOC_SEND_REQUEST, request);
++ if (result < 0 || ntohl(buffer) != compare)
++ return -1;
++
++ return 0;
+}
+diff -Naurp libraw1394-1.3.0.orig/juju/raw1394-iso.c libraw1394-1.3.0/juju/raw1394-iso.c
+--- libraw1394-1.3.0.orig/juju/raw1394-iso.c 1969-12-31 19:00:00.000000000 -0500
++++ libraw1394-1.3.0/juju/raw1394-iso.c 2007-10-18 22:18:46.000000000 -0400
+@@ -0,0 +1,522 @@
++/* -*- 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.
++ */
+
-+int
-+raw1394_start_read(raw1394handle_t handle, nodeid_t node, nodeaddr_t addr,
-+ size_t length, quadlet_t *buffer, unsigned long tag)
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++
++#include "juju.h"
++
++static int
++queue_packet(raw1394handle_t handle,
++ unsigned int length, unsigned int header_length,
++ unsigned char tag, unsigned char sy)
+{
-+ int tcode;
++ struct fw_cdev_queue_iso queue_iso;
++ struct fw_cdev_iso_packet *p;
++ int err;
+
-+ if (length == 4)
-+ tcode = TCODE_READ_QUADLET_REQUEST;
-+ else
-+ tcode = TCODE_READ_BLOCK_REQUEST;
++ p = &handle->iso.packets[handle->iso.packet_index];
++ p->payload_length = length;
++ p->interrupt =
++ handle->iso.packet_phase == handle->iso.irq_interval - 1;
++ p->skip = 0;
++ p->tag = tag;
++ p->sy = sy;
++ p->header_length = header_length;
+
-+ return send_request(handle, tcode,
-+ node, addr, length, NULL, buffer, tag);
-+}
++ handle->iso.head += length;
++ handle->iso.packet_count++;
++ handle->iso.packet_phase++;
++ handle->iso.packet_index++;
+
-+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 (handle->iso.packet_phase == handle->iso.irq_interval)
++ handle->iso.packet_phase = 0;
+
-+ if (length == 4)
-+ tcode = TCODE_WRITE_QUADLET_REQUEST;
-+ else
-+ tcode = TCODE_WRITE_BLOCK_REQUEST;
++ if (handle->iso.head + handle->iso.max_packet_size > handle->iso.buffer_end)
++ handle->iso.head = handle->iso.buffer;
+
-+ return send_request(handle, tcode,
-+ node, addr, length, data, NULL, tag);
++ /* Queue the packets in the kernel if we filled up the packets
++ * array or wrapped the payload buffer. */
++ if (handle->iso.packet_index == handle->iso.irq_interval ||
++ handle->iso.head == handle->iso.buffer) {
++ queue_iso.packets = ptr_to_u64(handle->iso.packets);
++ queue_iso.size = handle->iso.packet_index * sizeof handle->iso.packets[0];
++ queue_iso.data = ptr_to_u64(handle->iso.first_payload);
++ queue_iso.handle = 0;
++ handle->iso.packet_index = 0;
++ handle->iso.first_payload = handle->iso.head;
++
++ err = ioctl(handle->iso.fd, FW_CDEV_IOC_QUEUE_ISO, &queue_iso);
++ if (err < 0)
++ return -1;
++ }
+}
+
+static int
-+setup_lock(int extcode, quadlet_t data, quadlet_t arg, quadlet_t *buffer)
++queue_xmit_packets(raw1394handle_t handle, int limit)
+{
-+ switch (extcode) {
-+ case RAW1394_EXTCODE_FETCH_ADD:
-+ case RAW1394_EXTCODE_LITTLE_ADD:
-+ buffer[0] = data;
-+ return sizeof buffer[0];
++ enum raw1394_iso_disposition d;
++ unsigned char tag, sy;
++ int len, cycle, dropped;
+
-+ 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 2 * sizeof buffer[0];
++ if (handle->iso.xmit_handler == NULL)
++ return 0;
+
-+ default:
-+ errno = EINVAL;
-+ return -1;
++ while (handle->iso.packet_count < limit) {
++
++ d = handle->iso.xmit_handler(handle, handle->iso.head,
++ &len, &tag, &sy, cycle, dropped);
++
++ switch (d) {
++ case RAW1394_ISO_OK:
++ queue_packet(handle, len, 0, tag, sy);
++ break;
++ case RAW1394_ISO_DEFER:
++ case RAW1394_ISO_AGAIN:
++ default:
++ return 0;
++ case RAW1394_ISO_ERROR:
++ return -1;
++ case RAW1394_ISO_STOP:
++ raw1394_iso_stop(handle);
++ return 0;
++ }
+ }
++
++ return 0;
+}
+
-+static int
-+setup_lock64(int extcode, octlet_t data, octlet_t arg, octlet_t *buffer)
++int raw1394_iso_xmit_start(raw1394handle_t handle, int start_on_cycle,
++ int prebuffer_packets)
+{
-+ switch (extcode) {
-+ case RAW1394_EXTCODE_FETCH_ADD:
-+ case RAW1394_EXTCODE_LITTLE_ADD:
-+ buffer[0] = data;
-+ return sizeof buffer[0];
++ struct fw_cdev_start_iso start_iso;
++ int retval;
+
-+ 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 2 * sizeof buffer[0];
++ if (prebuffer_packets == -1)
++ prebuffer_packets = handle->iso.irq_interval;
+
-+ default:
-+ errno = EINVAL;
-+ return -1;
++ handle->iso.prebuffer = prebuffer_packets;
++ handle->iso.start_on_cycle = start_on_cycle;
++
++ queue_xmit_packets(handle, prebuffer_packets);
++
++ if (handle->iso.prebuffer <= handle->iso.packet_count) {
++ start_iso.cycle = start_on_cycle;
++ start_iso.handle = 0;
++
++ retval = ioctl(handle->iso.fd,
++ FW_CDEV_IOC_START_ISO, &start_iso);
++ if (retval < 0)
++ return retval;
+ }
++
++ return queue_xmit_packets(handle, handle->iso.buf_packets);
+}
+
-+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)
++static int
++queue_recv_packets(raw1394handle_t handle)
+{
-+ quadlet_t buffer[2];
-+ int length;
-+
-+ length = setup_lock(extcode, data, arg, buffer);
-+ if (length < 0)
-+ return length;
++ while (handle->iso.packet_count <= handle->iso.buf_packets)
++ queue_packet(handle, handle->iso.max_packet_size, 4, 0, 0);
+
-+ return send_request(handle, 16 + extcode,
-+ node, addr, length, buffer, result, tag);
++ return 0;
+}
-+
-+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)
++
++static enum raw1394_iso_disposition
++flush_recv_packets(raw1394handle_t handle,
++ struct fw_cdev_event_iso_interrupt *interrupt)
+{
-+ octlet_t buffer[2];
-+ int length;
++ enum raw1394_iso_disposition d;
++ quadlet_t header, *p, *end;
++ unsigned int len, cycle, dropped;
++ unsigned char channel, tag, sy;
++
++ p = interrupt->header;
++ end = (void *) interrupt->header + interrupt->header_length;
++ cycle = interrupt->cycle;
++ dropped = 0;
++ d = RAW1394_ISO_OK;
++
++ while (p < end) {
++ header = be32_to_cpu(*p++);
++ len = header >> 16;
++ tag = (header >> 14) & 0x3;
++ channel = (header >> 8) & 0x3f;
++ sy = header & 0x0f;
++
++ d = handle->iso.recv_handler(handle, handle->iso.tail, len,
++ channel, tag, sy, cycle, dropped);
++ if (d != RAW1394_ISO_OK)
++ /* FIXME: we need to save the headers so we
++ * can restart this loop. */
++ break;
++ cycle++;
++
++ handle->iso.tail += handle->iso.max_packet_size;
++ handle->iso.packet_count--;
++
++ if (handle->iso.tail + handle->iso.max_packet_size > handle->iso.buffer_end)
++ handle->iso.tail = handle->iso.buffer;
++ }
++
++ switch (d) {
++ case RAW1394_ISO_OK:
++ case RAW1394_ISO_DEFER:
++ default:
++ break;
++
++ case RAW1394_ISO_ERROR:
++ return -1;
+
-+ length = setup_lock64(extcode, data, arg, buffer);
-+ if (length < 0)
-+ return length;
++ case RAW1394_ISO_STOP:
++ raw1394_iso_stop(handle);
++ return 0;
++ }
+
-+ return send_request(handle, 16 + extcode,
-+ node, addr, length, buffer, result, tag);
++ queue_recv_packets(handle);
++
++ return 0;
+}
+
-+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)
++int raw1394_iso_recv_start(raw1394handle_t handle, int start_on_cycle,
++ int tag_mask, int sync)
+{
-+ /* FIXME: implement this? */
-+ return -1;
-+}
++ struct fw_cdev_start_iso start_iso;
+
++ queue_recv_packets(handle);
+
-+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;
-+}
++ 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;
++ start_iso.handle = 0;
+
-+struct sync_data {
-+ raw1394_errcode_t err;
-+ int done;
-+};
++ return ioctl(handle->iso.fd, FW_CDEV_IOC_START_ISO, &start_iso);
++}
+
-+static int
-+sync_callback(raw1394handle_t handle, void *data, raw1394_errcode_t err)
++static int handle_iso_event(raw1394handle_t handle,
++ struct epoll_closure *closure, __uint32_t events)
+{
-+ struct sync_data *sd = data;
++ struct fw_cdev_event_iso_interrupt *interrupt;
++ int len;
+
-+ sd->err = err;
-+ sd->done = 1;
++ len = read(handle->iso.fd, handle->buffer, sizeof handle->buffer);
++ if (len < 0)
++ return -1;
+
-+ return 0;
++ interrupt = (struct fw_cdev_event_iso_interrupt *) handle->buffer;
++ if (interrupt->type != FW_CDEV_EVENT_ISO_INTERRUPT)
++ return 0;
++
++ switch (handle->iso.type) {
++ case FW_CDEV_ISO_CONTEXT_TRANSMIT:
++ handle->iso.packet_count -= handle->iso.irq_interval;
++ return queue_xmit_packets(handle, handle->iso.buf_packets);
++ case FW_CDEV_ISO_CONTEXT_RECEIVE:
++ return flush_recv_packets(handle, interrupt);
++ default:
++ /* Doesn't happen. */
++ return -1;
++ }
+}
+
-+static int
-+send_request_sync(raw1394handle_t handle, int tcode,
-+ nodeid_t node, nodeaddr_t addr,
-+ size_t length, void *in, void *out)
++int raw1394_iso_xmit_write(raw1394handle_t handle, unsigned char *data,
++ unsigned int len, unsigned char tag,
++ unsigned char sy)
+{
-+ struct raw1394_reqhandle reqhandle;
-+ struct sync_data sd = { 0, 0 };
-+ int err;
++ struct fw_cdev_queue_iso queue_iso;
++ struct fw_cdev_start_iso start_iso;
++ struct fw_cdev_iso_packet *p;
+
-+ reqhandle.callback = sync_callback;
-+ reqhandle.data = &sd;
++ if (len > handle->iso.max_packet_size) {
++ errno = EINVAL;
++ return -1;
++ }
+
-+ err = send_request(handle, tcode, node, addr,
-+ length, in, out, (unsigned long) &reqhandle);
++ /* Block until we have space for another packet. */
++ while (handle->iso.packet_count + handle->iso.irq_interval >
++ handle->iso.buf_packets)
++ raw1394_loop_iterate(handle);
++
++ memcpy(handle->iso.head, data, len);
++ if (queue_packet(handle, len, 0, tag, sy) < 0)
++ return -1;
+
-+ while (!sd.done) {
-+ if (err < 0)
-+ return err;
-+ err = raw1394_loop_iterate(handle);
-+ }
++ /* Start the streaming if it's not already running and if
++ * we've buffered up enough packets. */
++ if (handle->iso.prebuffer > 0 &&
++ handle->iso.packet_count >= handle->iso.prebuffer) {
++ /* Set this to 0 to indicate that we're running. */
++ handle->iso.prebuffer = 0;
++ start_iso.cycle = handle->iso.start_on_cycle;
++ start_iso.handle = 0;
+
-+ handle->err = sd.err;
-+ errno = raw1394_errcode_to_errno(sd.err);
++ len = ioctl(handle->iso.fd,
++ FW_CDEV_IOC_START_ISO, &start_iso);
++ if (len < 0)
++ return len;
++ }
+
-+ return (errno ? -1 : 0);
++ return 0;
+}
+
-+int
-+raw1394_read(raw1394handle_t handle, nodeid_t node, nodeaddr_t addr,
-+ size_t length, quadlet_t *buffer)
++int raw1394_iso_xmit_sync(raw1394handle_t handle)
+{
-+ int tcode;
++ struct fw_cdev_iso_packet skip;
++ struct fw_cdev_queue_iso queue_iso;
++ int len;
+
-+ if (length == 4)
-+ tcode = TCODE_READ_QUADLET_REQUEST;
-+ else
-+ tcode = TCODE_READ_BLOCK_REQUEST;
++ skip.payload_length = 0;
++ skip.interrupt = 1;
++ skip.skip = 1;
++ skip.tag = 0;
++ skip.sy = 0;
++ skip.header_length = 0;
+
-+ return send_request_sync(handle, tcode,
-+ node, addr, length, NULL, buffer);
++ queue_iso.packets = ptr_to_u64(&skip);
++ queue_iso.size = sizeof skip;
++ queue_iso.data = 0;
++ queue_iso.handle = 0;
++
++ len = ioctl(handle->iso.fd, FW_CDEV_IOC_QUEUE_ISO, &queue_iso);
++ if (len < 0)
++ return -1;
++
++ /* Now that we've queued the skip packet, we'll get an
++ * interrupt when the transmit buffer is flushed, so all we do
++ * here is wait. */
++ while (handle->iso.packet_count > 0)
++ raw1394_loop_iterate(handle);
++
++ /* The iso mainloop thinks that interrutps indicate another
++ * irq_interval number of packets was sent, so the skip
++ * interrupt makes it go out of whack. We just reset it. */
++ handle->iso.head = handle->iso.buffer;
++ handle->iso.tail = handle->iso.buffer;
++ handle->iso.first_payload = handle->iso.buffer;
++ handle->iso.packet_phase = 0;
++ handle->iso.packet_count = 0;
++
++ return 0;
+}
+
-+int
-+raw1394_write(raw1394handle_t handle, nodeid_t node, nodeaddr_t addr,
-+ size_t length, quadlet_t *data)
++int raw1394_iso_recv_flush(raw1394handle_t handle)
+{
-+ int tcode;
-+
-+ if (length == 4)
-+ tcode = TCODE_WRITE_QUADLET_REQUEST;
-+ else
-+ tcode = TCODE_WRITE_BLOCK_REQUEST;
++ /* FIXME: huh, we'll need kernel support here... */
+
-+ return send_request_sync(handle, tcode,
-+ node, addr, length, data, NULL);
++ return 0;
+}
+
-+int
-+raw1394_lock(raw1394handle_t handle, nodeid_t node, nodeaddr_t addr,
-+ unsigned int extcode, quadlet_t data, quadlet_t arg,
-+ quadlet_t *result)
++static unsigned int
++round_to_power_of_two(unsigned int value)
+{
-+ quadlet_t buffer[2];
-+ size_t length;
++ unsigned int pot;
+
-+ length = setup_lock(extcode, data, arg, buffer);
-+ if (length < 0)
-+ return length;
++ pot = 1;
++ while (pot < value)
++ pot <<= 1;
+
-+ return send_request_sync(handle, 16 + extcode, node, addr,
-+ length, buffer, result);
++ return pot;
+}
+
-+int
-+raw1394_lock64(raw1394handle_t handle, nodeid_t node, nodeaddr_t addr,
-+ unsigned int extcode, octlet_t data, octlet_t arg,
-+ octlet_t *result)
++static int
++iso_init(raw1394handle_t handle, int type,
++ raw1394_iso_xmit_handler_t xmit_handler,
++ raw1394_iso_recv_handler_t recv_handler,
++ unsigned int buf_packets,
++ unsigned int max_packet_size,
++ unsigned char channel,
++ enum raw1394_iso_speed speed,
++ int irq_interval)
+{
-+ octlet_t buffer[2];
-+ size_t length;
++ struct fw_cdev_create_iso_context create;
++ struct epoll_event ep;
++ int retval, prot;
+
-+ length = setup_lock64(extcode, data, arg, buffer);
-+ if (length < 0)
-+ return length;
++ if (handle->iso.fd != -1) {
++ errno = EBUSY;
++ return -1;
++ }
+
-+ return send_request_sync(handle, 16 + extcode, node, addr,
-+ length, buffer, result);
-+}
++ switch (type) {
++ case FW_CDEV_ISO_CONTEXT_TRANSMIT:
++ prot = PROT_READ | PROT_WRITE;
++ break;
++ case FW_CDEV_ISO_CONTEXT_RECEIVE:
++ prot = PROT_READ;
++ break;
++ default:
++ errno = EINVAL;
++ return -1;
++ }
++
++ handle->iso.type = type;
++ if (irq_interval < 0)
++ handle->iso.irq_interval = 256;
++ else
++ handle->iso.irq_interval = irq_interval;
++ handle->iso.xmit_handler = xmit_handler;
++ handle->iso.recv_handler = recv_handler;
++ handle->iso.buf_packets = buf_packets;
++ handle->iso.max_packet_size = round_to_power_of_two(max_packet_size);
++ handle->iso.packet_phase = 0;
++ handle->iso.packet_count = 0;
++ handle->iso.packets =
++ malloc(handle->iso.irq_interval * sizeof handle->iso.packets[0]);
++ if (handle->iso.packets == NULL)
++ return -1;
+
-+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;
-+}
++ handle->iso.fd = open(handle->local_filename, O_RDWR);
++ if (handle->iso.fd < 0) {
++ free(handle->iso.packets);
++ 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;
-+}
++ 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;
++ }
+
-+int
-+raw1394_start_fcp_listen(raw1394handle_t handle)
-+{
-+ struct fw_cdev_allocate request;
-+ struct address_closure *closure;
++ create.type = type;
++ create.channel = channel;
++ create.speed = speed;
++ create.header_size = 4;
+
-+ closure = malloc(sizeof *closure);
-+ if (closure == NULL)
-+ return -1;
++ 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;
++ }
+
-+ closure->callback = handle_fcp_request;
++ handle->iso.buffer =
++ mmap(NULL, buf_packets * max_packet_size,
++ prot, MAP_SHARED, handle->iso.fd, 0);
+
-+ 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)
++ if (handle->iso.buffer == MAP_FAILED) {
++ close(handle->iso.fd);
++ free(handle->iso.packets);
+ return -1;
++ }
+
-+ handle->fcp_allocation_handle = request.handle;
++ handle->iso.buffer_end = handle->iso.buffer +
++ buf_packets * max_packet_size;
++ handle->iso.head = handle->iso.buffer;
++ handle->iso.tail = handle->iso.buffer;
++ handle->iso.first_payload = handle->iso.buffer;
+
+ return 0;
+}
+
-+int
-+raw1394_stop_fcp_listen(raw1394handle_t handle)
++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_deallocate request;
-+
-+ request.handle = handle->fcp_allocation_handle;
-+
-+ return ioctl(handle->local_fd, FW_CDEV_IOC_DEALLOCATE, &request);
++ return iso_init(handle, FW_CDEV_ISO_CONTEXT_TRANSMIT,
++ handler, NULL, buf_packets, max_packet_size,
++ channel, speed, irq_interval);
+}
+
-+const char *
-+raw1394_get_libversion(void)
++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)
+{
-+ return VERSION " (Juju)";
++ return iso_init(handle, FW_CDEV_ISO_CONTEXT_RECEIVE,
++ NULL, handler, buf_packets, max_packet_size,
++ channel, 0, irq_interval);
+}
+
-+int
-+raw1394_update_config_rom(raw1394handle_t handle, const quadlet_t *new_rom,
-+ size_t size, unsigned char rom_version)
++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_get_config_rom(raw1394handle_t handle, quadlet_t *buffer,
-+ size_t buffersize, size_t *rom_size,
-+ unsigned char *rom_version)
++int raw1394_iso_recv_listen_channel(raw1394handle_t handle,
++ unsigned char channel)
+{
-+ 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;
++ /* FIXME: multichannel */
++ errno = ENOSYS;
++ return -1;
+}
+
-+#define MAXIMUM_BANDWIDTH 4915
-+
-+int
-+raw1394_bandwidth_modify (raw1394handle_t handle,
-+ unsigned int bandwidth,
-+ enum raw1394_modify_mode mode)
++int raw1394_iso_recv_unlisten_channel(raw1394handle_t handle,
++ unsigned char channel)
+{
-+ 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;
-+ }
++ /* FIXME: multichannel */
++ errno = ENOSYS;
++ 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_iso_recv_set_channel_mask(raw1394handle_t handle, u_int64_t mask)
++{
++ /* FIXME: multichannel */
++ errno = ENOSYS;
++ return -1;
+}
+
-+int
-+raw1394_channel_modify (raw1394handle_t handle,
-+ unsigned int channel,
-+ enum raw1394_modify_mode mode)
++void raw1394_iso_stop(raw1394handle_t handle)
+{
-+ 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;
++ struct fw_cdev_stop_iso stop_iso;
+
-+ case RAW1394_MODIFY_FREE:
-+ if ((buffer & bit) != 0)
-+ return -1;
-+ swap = buffer | bit;
-+ break;
++ stop_iso.handle = 0;
++ ioctl(handle->iso.fd, FW_CDEV_IOC_STOP_ISO);
+
-+ default:
-+ return -1;
-+ }
-+
-+ result = raw1394_lock (handle, raw1394_get_irm_id (handle), addr,
-+ RAW1394_EXTCODE_COMPARE_SWAP,
-+ htonl(swap), htonl(compare), &buffer);
++ handle->iso.head = handle->iso.buffer;
++ handle->iso.tail = handle->iso.buffer;
++ handle->iso.first_payload = handle->iso.buffer;
++ handle->iso.packet_phase = 0;
++ handle->iso.packet_count = 0;
++}
+
-+ if (result < 0 || ntohl(buffer) != compare)
-+ return -1;
-+
-+ return 0;
++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/tools/Makefile.am b/tools/Makefile.am
-index 29b250e..5be1b6f 100644
---- a/tools/Makefile.am
-+++ b/tools/Makefile.am
+diff -Naurp libraw1394-1.3.0.orig/Makefile.am libraw1394-1.3.0/Makefile.am
+--- libraw1394-1.3.0.orig/Makefile.am 2004-11-05 19:26:44.000000000 -0500
++++ libraw1394-1.3.0/Makefile.am 2007-10-18 22:18:46.000000000 -0400
+@@ -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 -Naurp libraw1394-1.3.0.orig/tools/Makefile.am libraw1394-1.3.0/tools/Makefile.am
+--- libraw1394-1.3.0.orig/tools/Makefile.am 2004-11-05 19:26:44.000000000 -0500
++++ libraw1394-1.3.0/tools/Makefile.am 2007-10-18 22:18:46.000000000 -0400
@@ -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
+diff -Naurp libraw1394-1.3.0.orig/tools/testlibraw.c libraw1394-1.3.0/tools/testlibraw.c
+--- libraw1394-1.3.0.orig/tools/testlibraw.c 2004-01-31 15:26:03.000000000 -0500
++++ libraw1394-1.3.0/tools/testlibraw.c 2007-10-18 22:18:46.000000000 -0400
@@ -1,4 +1,5 @@
-/*
+/* -*- c-basic-offset: 8 -*-
@@ -2225,7 +2214,7 @@ index 5f73bd9..2f02a6d 100644
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,
+@@ -45,12 +47,18 @@ int my_tag_handler(raw1394handle_t handl
return 0;
}
@@ -2244,7 +2233,7 @@ index 5f73bd9..2f02a6d 100644
while (length) {
printf(" %02x", *data);
data++;
-@@ -62,6 +70,47 @@ int my_fcp_handler(raw1394handle_t handle, nodeid_t nodeid, int response,
+@@ -62,6 +70,47 @@ int my_fcp_handler(raw1394handle_t handl
return 0;
}
diff --git a/libraw1394-underquoted.patch b/libraw1394-underquoted.patch
deleted file mode 100644
index a1e677d..0000000
--- a/libraw1394-underquoted.patch
+++ /dev/null
@@ -1,47 +0,0 @@
---- libraw1394-0.10.1/libraw1394.m4.underquoted 2004-07-15 12:59:11.467143881 +0100
-+++ libraw1394-0.10.1/libraw1394.m4 2004-07-15 12:59:57.705291918 +0100
-@@ -3,7 +3,7 @@
- dnl This just unconditionally sets the options. It should offer an option for
- dnl explicitly giving the path to libraw1394 on the configure command line.
- dnl
--AC_DEFUN(AC_LIB_RAW1394_FLAGS, [
-+AC_DEFUN([AC_LIB_RAW1394_FLAGS], [
- LIBRAW1394_CPPFLAGS=""
- LIBRAW1394_CFLAGS=""
- LIBRAW1394_LIBS="-lraw1394"
-@@ -16,7 +16,7 @@
- dnl
- dnl AC_LIB_RAW1394_HEADERS([ACTION_IF_FOUND[,ACTION_IF_NOT_FOUND]])
- dnl
--AC_DEFUN(AC_LIB_RAW1394_HEADERS, [
-+AC_DEFUN([AC_LIB_RAW1394_HEADERS], [
- AC_REQUIRE([AC_LIB_RAW1394_FLAGS])
-
- ac_libraw1394_save_cppflags=$CPPFLAGS
-@@ -38,7 +38,7 @@
- dnl
- dnl AC_LIB_RAW1394_LIBVERSION(MINIMUMVERSION[,ACTION_IF_FOUND[,ACTION_IF_NOT_FOUND]])
- dnl
--AC_DEFUN(AC_LIB_RAW1394_LIBVERSION, [
-+AC_DEFUN([AC_LIB_RAW1394_LIBVERSION], [
- AC_REQUIRE([AC_PROG_CC])
- AC_REQUIRE([AC_LIB_RAW1394_FLAGS])
-
-@@ -72,7 +72,7 @@
- dnl
- dnl AC_LIB_RAW1394_RUNTEST(MINIMUMVERSION[,ACTION_IF_FOUND
- dnl [,ACTION_IF_NOT_FOUND[,ACTION_IF_CROSS_COMPILING]]])
--AC_DEFUN(AC_LIB_RAW1394_RUNTEST, [
-+AC_DEFUN([AC_LIB_RAW1394_RUNTEST], [
- ac_libraw1394_save_cppflags=$CPPFLAGS
- ac_libraw1394_save_cflags=$CFLAGS
- ac_libraw1394_save_libs=$LIBS
-@@ -135,7 +135,7 @@
- dnl Versions before 0.9 can't be checked, so this will always fail if the
- dnl installed libraw1394 is older than 0.9 as if the library weren't found.
- dnl
--AC_DEFUN(AC_LIB_RAW1394, [
-+AC_DEFUN([AC_LIB_RAW1394], [
-
- AC_LIB_RAW1394_FLAGS
- AC_LIB_RAW1394_HEADERS(ac_libraw1394_found=yes, ac_libraw1394_found=no)
diff --git a/libraw1394.spec b/libraw1394.spec
index ed7b49a..c12b991 100644
--- a/libraw1394.spec
+++ b/libraw1394.spec
@@ -1,7 +1,7 @@
Summary: Library providing low-level IEEE-1394 access
Name: libraw1394
-Version: 1.2.1
-Release: 10%{?dist}
+Version: 1.3.0
+Release: 1%{?dist}
License: LGPL
Group: System Environment/Libraries
Source: http://www.linux1394.org/dl/libraw1394-%{version}.tar.gz
@@ -77,6 +77,9 @@ rm -rf $RPM_BUILD_ROOT
%changelog
+* Thu Oct 18 2007 Jarod Wilson - 1.3.0-1
+- libraw1394 v1.3.0
+
* Wed Aug 29 2007 Fedora Release Engineering - 1.2.1-10
- Rebuild for selinux ppc32 issue.
diff --git a/sources b/sources
index 09a25fe..23e349f 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-e6210ff05b7f4ec0401ad3d11f493e1a libraw1394-1.2.1.tar.gz
+c5d9ab62bd25dba96af010b3471e816a libraw1394-1.3.0.tar.gz