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