From ab95aadd08ff3617f2433fd80618b1cc4536cae8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Mon, 19 Mar 2007 23:25:30 +0000 Subject: [PATCH] - Add support for new stack (juju). --- .cvsignore | 1 + libraw1394-juju.patch | 1877 +++++++++++++++++++++++++++++++++++++++++ libraw1394.spec | 4 + sources | 1 - 4 files changed, 1882 insertions(+), 1 deletion(-) create mode 100644 libraw1394-juju.patch diff --git a/.cvsignore b/.cvsignore index e72d9ae..5de9d16 100644 --- a/.cvsignore +++ b/.cvsignore @@ -1,2 +1,3 @@ libraw1394-1.2.0.tar.gz libraw1394-1.2.1.tar.gz +fw-device-cdev.h diff --git a/libraw1394-juju.patch b/libraw1394-juju.patch new file mode 100644 index 0000000..c04f781 --- /dev/null +++ b/libraw1394-juju.patch @@ -0,0 +1,1877 @@ +Index: tools/testlibraw.c +=================================================================== +--- tools/testlibraw.c (revision 171) ++++ tools/testlibraw.c (working copy) +@@ -1,4 +1,5 @@ +-/* ++/* -*- c-basic-offset: 8 -*- ++ * + * libraw1394 - library for raw access to the 1394 bus with the Linux subsystem. + * + * Copyright (C) 1999,2000 Andreas Bombe +@@ -13,12 +14,13 @@ + #include + #include + #include ++#include + + #include "../src/raw1394.h" + #include "../src/csr.h" + + +-#define TESTADDR (CSR_REGISTER_BASE + CSR_CYCLE_TIME) ++#define TESTADDR (CSR_REGISTER_BASE + CSR_CONFIG_ROM) + + const char not_compatible[] = "\ + This libraw1394 does not work with your version of Linux. You need a different\n\ +@@ -45,12 +47,18 @@ + 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,7 +70,48 @@ + 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) + { + raw1394handle_t handle; +@@ -73,7 +122,6 @@ + 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,18 +198,9 @@ + } + } + +- 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); + printf("get_config_rom returned %d, romsize %d, rom_version %d\n",retval,rom_size,rom_version); +@@ -176,16 +215,19 @@ + 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"); +Index: tools/Makefile.am +=================================================================== +--- tools/Makefile.am (revision 171) ++++ tools/Makefile.am (working copy) +@@ -2,4 +2,4 @@ + + # testlibraw + bin_PROGRAMS = testlibraw sendiso dumpiso +-LDADD = ../src/libraw1394.la ++LDADD = ../$(LIB_SUBDIR)/libraw1394.la +Index: configure.ac +=================================================================== +--- configure.ac (revision 171) ++++ configure.ac (working copy) +@@ -24,13 +24,35 @@ + AC_SUBST(lt_revision) + AC_SUBST(lt_age) + ++AC_ARG_WITH(juju-dir,[ --with-juju-dir= Path to juju include files]) ++if ! test -z "$with_juju_dir" ; then ++ JUJU_DIR="$with_juju_dir" ++ LIB_SUBDIR=juju ++ AC_SUBST(JUJU_DIR) ++else ++ LIB_SUBDIR=src ++fi ++AC_SUBST(LIB_SUBDIR) + ++AC_ARG_WITH(fw-device-prefix, ++ [ --with-fw-device-prefix= Prefix of firewire device file names (default "fw").], ++ [FW_DEVICE_PREFIX="\"$withval\""], [FW_DEVICE_PREFIX="\"fw\""]) ++AC_ARG_WITH(fw-device-dir, ++ [ --with-fw-device-dir= Directory to watch for firewire device files (default "/dev").], ++ [FW_DEVICE_DIR="\"$withval\""], [FW_DEVICE_DIR="\"/dev\""]) ++ ++AC_DEFINE_UNQUOTED(FW_DEVICE_PREFIX, $FW_DEVICE_PREFIX, ++ [Prefix of firewire device file names.]) ++AC_DEFINE_UNQUOTED(FW_DEVICE_DIR, $FW_DEVICE_DIR, ++ [Directory to watch for firewire device files.]) ++ + #CFLAGS=${CFLAGS:-"-Wall"} + AC_OUTPUT([ + Makefile + libraw1394.pc + libraw1394.spec + src/Makefile ++juju/Makefile + tools/Makefile + doc/Makefile + doc/testlibraw.1 +Index: Makefile.am +=================================================================== +--- Makefile.am (revision 171) ++++ Makefile.am (working copy) +@@ -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 +Index: juju/raw1394-iso.c +=================================================================== +--- juju/raw1394-iso.c (revision 0) ++++ juju/raw1394-iso.c (revision 0) +@@ -0,0 +1,197 @@ ++/* -*- c-basic-offset: 8 -*- ++ * ++ * raw1394-iso.c -- Emulation of the raw1394 rawiso API on the juju stack ++ * ++ * Copyright (C) 2007 Kristian Hoegsberg ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software Foundation, ++ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ */ ++ ++#include ++#include ++ ++#include "juju.h" ++ ++int raw1394_iso_xmit_init(raw1394handle_t handle, ++ raw1394_iso_xmit_handler_t handler, ++ unsigned int buf_packets, ++ unsigned int max_packet_size, ++ unsigned char channel, ++ enum raw1394_iso_speed speed, ++ int irq_interval) ++{ ++ struct fw_cdev_create_iso_context create; ++ ++ handle->iso.buffer = ++ mmap(NULL, buf_packets * max_packet_size, ++ PROT_READ | PROT_WRITE, MAP_SHARED, handle->local_fd, 0); ++ ++ if (handle->iso.buffer == MAP_FAILED) ++ return -1; ++ ++ create.type = FW_CDEV_ISO_CONTEXT_TRANSMIT; ++ create.channel = channel; ++ create.speed = speed; ++ ++ handle->iso.type = FW_CDEV_ISO_CONTEXT_TRANSMIT; ++ handle->iso.irq_interval = irq_interval; ++ handle->iso.xmit_handler = handler; ++ ++ return ioctl(handle->local_fd, ++ FW_CDEV_IOC_CREATE_ISO_CONTEXT, &create); ++} ++ ++int raw1394_iso_recv_init(raw1394handle_t handle, ++ raw1394_iso_recv_handler_t handler, ++ unsigned int buf_packets, ++ unsigned int max_packet_size, ++ unsigned char channel, ++ enum raw1394_iso_dma_recv_mode mode, ++ int irq_interval) ++{ ++ struct fw_cdev_create_iso_context create; ++ ++ /* FIXME: Do we need this? When would you ever want this...? */ ++ if (mode == RAW1394_DMA_PACKET_PER_BUFFER) ++ return -1; ++ ++ handle->iso.buffer = ++ mmap(NULL, buf_packets * max_packet_size, ++ PROT_READ, MAP_SHARED, handle->local_fd, 0); ++ ++ if (handle->iso.buffer == MAP_FAILED) ++ return -1; ++ ++ create.type = FW_CDEV_ISO_CONTEXT_TRANSMIT; ++ create.channel = channel; ++ create.speed = 0; ++ create.header_size = 0; /* Never strip any headers. */ ++ ++ handle->iso.type = FW_CDEV_ISO_CONTEXT_TRANSMIT; ++ handle->iso.irq_interval = irq_interval; ++ handle->iso.recv_handler = handler; ++ ++ return ioctl(handle->local_fd, ++ FW_CDEV_IOC_CREATE_ISO_CONTEXT, &create); ++} ++ ++int raw1394_iso_multichannel_recv_init(raw1394handle_t handle, ++ raw1394_iso_recv_handler_t handler, ++ unsigned int buf_packets, ++ unsigned int max_packet_size, ++ int irq_interval) ++{ ++ /* FIXME: gah */ ++ return -1; ++} ++ ++int raw1394_iso_recv_listen_channel(raw1394handle_t handle, ++ unsigned char channel) ++{ ++ /* FIXME: multichannel */ ++ return -1; ++} ++ ++int raw1394_iso_recv_unlisten_channel(raw1394handle_t handle, ++ unsigned char channel) ++{ ++ /* FIXME: multichannel */ ++ return -1; ++} ++ ++int raw1394_iso_recv_set_channel_mask(raw1394handle_t handle, u_int64_t mask) ++{ ++ /* FIXME: multichannel */ ++ return -1; ++} ++ ++int raw1394_iso_xmit_start(raw1394handle_t handle, int start_on_cycle, ++ int prebuffer_packets) ++{ ++ struct fw_cdev_start_iso start_iso; ++ ++ handle->iso.start_cycle = start_on_cycle; ++ if (prebuffer_packets == -1) ++ handle->iso.prebuffer = 64; ++ else ++ handle->iso.prebuffer = prebuffer_packets; ++ ++ if (handle->iso.buffered_packet_count < handle->iso.prebuffer) ++ return 0; ++ ++ start_iso.cycle = handle->iso.start_cycle; ++ ++ return ioctl(handle->local_fd, FW_CDEV_IOC_START_ISO, &start_iso); ++} ++ ++int raw1394_iso_recv_start(raw1394handle_t handle, int start_on_cycle, ++ int tag_mask, int sync) ++{ ++ struct fw_cdev_start_iso start_iso; ++ ++ start_iso.cycle = start_on_cycle; ++ start_iso.tags = ++ tag_mask == -1 ? FW_CDEV_ISO_CONTEXT_MATCH_ALL_TAGS : tag_mask; ++ /* sync is documented as 'not used' */ ++ start_iso.sync = 0; ++ ++ return ioctl(handle->local_fd, FW_CDEV_IOC_START_ISO, &start_iso); ++} ++ ++int raw1394_iso_xmit_write(raw1394handle_t handle, unsigned char *data, ++ unsigned int len, unsigned char tag, ++ unsigned char sy) ++{ ++ struct fw_cdev_iso_packet packet; ++ ++ packet.payload_length = len; ++ packet.interrupt = handle->iso.packet_phase == 0; ++ packet.skip = 0; ++ packet.tag = tag; ++ packet.sy = sy; ++ packet.header_length = 0; ++ ++ handle->iso.packet_phase++; ++ if (handle->iso.packet_phase == handle->iso.irq_interval) ++ handle->iso.packet_phase = 0; ++ ++ /* FIXME: circular buffer goo. */ ++ ++ memcpy(handle->iso.head, data, len); ++ handle->iso.head += len; ++ ++ return -1; ++} ++ ++int raw1394_iso_xmit_sync(raw1394handle_t handle) ++{ ++ /* FIXME: queue a skip packet and wait for that interrupt. */ ++} ++ ++int raw1394_iso_recv_flush(raw1394handle_t handle) ++{ ++ /* FIXME: huh, we'll need kernel support here... */ ++} ++ ++void raw1394_iso_stop(raw1394handle_t handle) ++{ ++ ioctl(handle->local_fd, FW_CDEV_IOC_STOP_ISO); ++} ++ ++void raw1394_iso_shutdown(raw1394handle_t handle) ++{ ++ /* Maybe we should just open a new fd for the local device and ++ * close that here... */ ++} +Index: juju/juju.h +=================================================================== +--- juju/juju.h (revision 0) ++++ juju/juju.h (revision 0) +@@ -0,0 +1,107 @@ ++/* -*- c-basic-offset: 8 -*- ++ * ++ * juju.h -- Internal header file for raw1394 emulation ++ * ++ * Copyright (C) 2007 Kristian Hoegsberg ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software Foundation, ++ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ */ ++ ++#ifndef __juju_h ++#define __juju_h ++ ++#include ++#include ++#include "../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)) ++ ++#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) ++ ++#define BUFFER_SIZE (16 * 1024) ++ ++#define MAX_PORTS 16 ++ ++struct port { ++ char device_file[32]; ++ char *name; ++ int node_count; ++ int card; ++}; ++ ++#define MAX_DEVICES 63 ++#define INOTIFY_INDEX 64 ++#define PIPE_INDEX 65 ++ ++struct device { ++ int fd; ++ int node_id; ++ int generation; ++ char filename[16]; ++}; ++ ++struct closure { ++ void *data; ++ size_t length; ++ unsigned long tag; ++ struct raw1394_reqhandle reqhandle; ++}; ++ ++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; ++ ++ int epoll_fd; ++ int inotify_fd; ++ int inotify_watch; ++ int pipe_fds[2]; ++ ++ struct device devices[MAX_DEVICES]; ++ int nodes[MAX_DEVICES]; ++ int local_fd; ++ ++ struct fw_cdev_event_bus_reset reset; ++ ++ struct { ++ int type; ++ int irq_interval; ++ int prebuffer; ++ int start_cycle; ++ int buffered_packet_count; ++ int packet_phase; ++ enum raw1394_iso_dma_recv_mode recv_mode; ++ raw1394_iso_xmit_handler_t xmit_handler; ++ raw1394_iso_recv_handler_t recv_handler; ++ unsigned char *buffer, *head, *tail; ++ } iso; ++ ++ char buffer[BUFFER_SIZE]; ++}; ++ ++#endif +Index: juju/Makefile.am +=================================================================== +--- juju/Makefile.am (revision 0) ++++ juju/Makefile.am (revision 0) +@@ -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 +Index: juju/raw1394.c +=================================================================== +--- juju/raw1394.c (revision 0) ++++ juju/raw1394.c (revision 0) +@@ -0,0 +1,1336 @@ ++/* -*- 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 "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; ++ ++ 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; ++ size_t size; ++ ++ 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) ++{ ++ quadlet_t value; ++ ++ if (read(handle->pipe_fds[0], &value, sizeof value) < 0) ++ return -1; ++ ++ return value; ++} ++ ++static int ++handle_new_device(raw1394handle_t handle) ++{ ++ 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); ++ ep.events = EPOLLIN; ++ ep.data.u32 = i; ++ if (epoll_ctl(handle->epoll_fd, EPOLL_CTL_ADD, fd, &ep) < 0) { ++ close(fd); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int ++handle_lost_device(raw1394handle_t handle, int i) ++{ ++ int phy_id; ++ ++ /* The device got unplugged, get rid of it. The fd is ++ * automatically dropped from the epoll context when we close it. */ ++ ++ close(handle->devices[i].fd); ++ phy_id = handle->devices[i].node_id & 0x3f; ++ if (handle->nodes[phy_id] == i) ++ handle->nodes[phy_id] = -1; ++ handle->devices[i].node_id = -1; ++ ++ return 0; ++} ++ ++struct address_closure { ++ int (*callback)(raw1394handle_t handle, struct address_closure *ac, ++ struct fw_cdev_event_request *request, int i); ++}; ++ ++static int ++handle_fcp_request(raw1394handle_t handle, struct address_closure *ac, ++ struct fw_cdev_event_request *request, int i) ++{ ++ struct fw_cdev_send_response response; ++ int is_response; ++ ++ response.serial = request->serial; ++ response.rcode = RCODE_COMPLETE; ++ response.length = 0; ++ response.data = 0; ++ ++ if (handle->fcp_handler == NULL) ++ response.rcode = RCODE_ADDRESS_ERROR; ++ ++ if (request->tcode >= TCODE_WRITE_RESPONSE) ++ response.rcode = RCODE_CONFLICT_ERROR; ++ ++ if (ioctl(handle->devices[i].fd, ++ FW_CDEV_IOC_SEND_RESPONSE, &response) < 0) ++ return -1; ++ ++ if (response.rcode != RCODE_COMPLETE) ++ return 0; ++ ++ is_response = request->offset >= CSR_REGISTER_BASE + CSR_FCP_RESPONSE; ++ ++ 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, int i) ++{ ++ union { ++ struct fw_cdev_event_bus_reset bus_reset; ++ struct fw_cdev_event_response response; ++ struct fw_cdev_event_request request; ++ struct fw_cdev_event_iso_interrupt interrupt; ++ } *u; ++ struct address_closure *ac; ++ struct closure *closure; ++ raw1394_errcode_t errcode; ++ int fd, last, len, phy_id; ++ ++ len = read(handle->devices[i].fd, ++ handle->buffer, sizeof handle->buffer); ++ if (len < 0) ++ return -1; ++ ++ u = (void *) handle->buffer; ++ switch (u->response.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: ++ closure = u64_to_ptr(u->response.closure); ++ ++ if (closure->data != NULL) ++ memcpy(closure->data, ++ u->response.data, closure->length); ++ ++ errcode = juju_to_raw1394_errcode(u->response.rcode); ++ ++ return handle->tag_handler(handle, closure->tag, errcode); ++ ++ case FW_CDEV_EVENT_REQUEST: ++ ac = u64_to_ptr(u->request.closure); ++ return ac->callback(handle, ac, &u->request, i); ++ ++ case FW_CDEV_EVENT_ISO_INTERRUPT: ++ return 0; ++ } ++} ++ ++int raw1394_loop_iterate(raw1394handle_t handle) ++{ ++ int i, last, count, retval = 0; ++ ++ 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++) { ++ if (ep[i].data.u32 == PIPE_INDEX) ++ retval = handle_echo_pipe(handle); ++ else if (ep[i].data.u32 == INOTIFY_INDEX) ++ retval = handle_new_device(handle); ++ else if (ep[i].events & EPOLLHUP) ++ retval = handle_lost_device(handle, ep[i].data.u32); ++ else if (ep[i].events & EPOLLIN) ++ retval = handle_device_event(handle, ep[i].data.u32); ++ } ++ ++ /* 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->notify_bus_reset = RAW1394_NOTIFY_ON; ++ handle->bus_reset_handler = default_bus_reset_handler; ++ ++ 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; ++ ++ ep.events = EPOLLIN; ++ ep.data.u32 = PIPE_INDEX; ++ if (epoll_ctl(handle->epoll_fd, EPOLL_CTL_ADD, ++ handle->pipe_fds[0], &ep) < 0) ++ goto out_inotify; ++ ++ ep.events = EPOLLIN; ++ ep.data.u32 = INOTIFY_INDEX; ++ 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); ++ ++ ep.events = EPOLLIN; ++ ep.data.u32 = i; ++ 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; ++ } ++ ++ i++; ++ } ++ ++ return 0; ++} ++ ++int raw1394_reset_bus(raw1394handle_t handle) ++{ ++ 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; ++ 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; ++ struct raw1394_arm_request_response *arm_req_resp; ++ arm_options_t type; ++ size_t in_length; ++ int offset; ++ ++ offset = request->offset - allocation->offset; ++ response.serial = request->serial; ++ ++ switch (request->tcode) { ++ case TCODE_WRITE_QUADLET_REQUEST: ++ case TCODE_WRITE_BLOCK_REQUEST: ++ printf("got write request, offset=0x%012llx, length=%d\n", ++ request->offset, request->length); ++ ++ type = RAW1394_ARM_WRITE; ++ in_length = request->length; ++ response.rcode = RCODE_COMPLETE; ++ response.length = 0; ++ response.data = 0; ++ break; ++ ++ case TCODE_READ_QUADLET_REQUEST: ++ case TCODE_READ_BLOCK_REQUEST: ++ printf("got read request, offset=0x%012llx, length=%d\n", ++ request->offset, request->length); ++ ++ type = RAW1394_ARM_READ; ++ in_length = 0; ++ response.rcode = RCODE_COMPLETE; ++ response.length = request->length; ++ response.data = ptr_to_u64(allocation->data + offset); ++ break; ++ ++ case TCODE_LOCK_REQUEST: ++ type = RAW1394_ARM_LOCK; ++ in_length = request->length; ++ response.length = 4; ++ break; ++ ++ default: ++ 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); ++ ++ 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; ++ ++ allocation = malloc(sizeof *allocation + length); ++ if (allocation == NULL) ++ return -1; ++ ++ allocation->closure.callback = handle_arm_request; ++ allocation->buffer = initial_value; ++ allocation->tag = arm_tag; ++ allocation->access_rights = access_rights; ++ allocation->notification_options = notification_options; ++ allocation->client_transactions = client_transactions; ++ allocation->offset = start; ++ allocation->length = length; ++ if (initial_value != NULL) ++ memcpy(allocation->data, initial_value, length); ++ ++ request.offset = start; ++ request.length = length; ++ request.closure = ptr_to_u64(&allocation->closure); ++ ++ retval = ioctl(handle->local_fd, FW_CDEV_IOC_ALLOCATE, &request); ++ if (retval < 0) { ++ free(allocation); ++ return -1; ++ } ++ ++ allocation->next = handle->allocations; ++ handle->allocations = allocation; ++ ++ return 0; ++} ++ ++static struct allocation * ++lookup_allocation(raw1394handle_t handle, nodeaddr_t start, int delete) ++{ ++ struct allocation *a, **prev; ++ ++ prev = &handle->allocations; ++ for (a = handle->allocations; a != NULL; a = a->next) { ++ if (a->offset <= start && start < a->offset + a->length) ++ break; ++ prev = &a->next; ++ } ++ ++ if (a != NULL && delete) ++ *prev = a->next; ++ ++ return a; ++} ++ ++int ++raw1394_arm_unregister(raw1394handle_t handle, nodeaddr_t start) ++{ ++ struct fw_cdev_deallocate request; ++ struct allocation *allocation; ++ ++ allocation = lookup_allocation(handle, start, 1); ++ if (allocation == NULL) { ++ errno = EINVAL; ++ return -1; ++ } ++ ++ free(allocation); ++ ++ request.offset = start; ++ ++ return ioctl(handle->local_fd, FW_CDEV_IOC_DEALLOCATE, &request); ++} ++ ++int ++raw1394_arm_set_buf(raw1394handle_t handle, nodeaddr_t start, ++ size_t length, void *buf) ++{ ++ struct allocation *allocation; ++ ++ allocation = lookup_allocation(handle, start, 0); ++ if (allocation == NULL) { ++ errno = ENOENT; ++ return -1; ++ } ++ ++ memcpy(allocation->data + allocation->offset - start, buf, length); ++ ++ return 0; ++} ++ ++int ++raw1394_arm_get_buf(raw1394handle_t handle, nodeaddr_t start, ++ size_t length, void *buf) ++{ ++ struct allocation *allocation; ++ ++ allocation = lookup_allocation(handle, start, 0); ++ if (allocation == NULL) { ++ errno = ENOENT; ++ return -1; ++ } ++ ++ memcpy(buf, allocation->data + allocation->offset - start, length); ++ ++ return 0; ++} ++ ++int ++raw1394_echo_request(raw1394handle_t handle, quadlet_t data) ++{ ++ return write(handle->pipe_fds[1], &data, sizeof data); ++} ++ ++int raw1394_wake_up(raw1394handle_t handle) ++{ ++ return raw1394_echo_request(handle, 0); ++} ++ ++int raw1394_phy_packet_write (raw1394handle_t handle, quadlet_t data) ++{ ++} ++ ++int ++raw1394_start_phy_packet_write(raw1394handle_t handle, ++ quadlet_t data, unsigned long tag) ++{ ++} ++ ++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 closure *closure; ++ int i, fd; ++ ++ 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; ++} ++ ++static int ++send_request_sync(raw1394handle_t handle, int tcode, ++ nodeid_t node, nodeaddr_t addr, ++ size_t length, void *in, void *out) ++{ ++ struct raw1394_reqhandle reqhandle; ++ struct sync_data sd = { 0, 0 }; ++ int err; ++ ++ reqhandle.callback = sync_callback; ++ reqhandle.data = &sd; ++ ++ err = send_request(handle, tcode, node, addr, ++ length, in, out, (unsigned long) &reqhandle); ++ ++ while (!sd.done) { ++ if (err < 0) ++ return err; ++ err = raw1394_loop_iterate(handle); ++ } ++ ++ handle->err = sd.err; ++ errno = raw1394_errcode_to_errno(sd.err); ++ ++ return (errno ? -1 : 0); ++} ++ ++int ++raw1394_read(raw1394handle_t handle, nodeid_t node, nodeaddr_t addr, ++ size_t length, quadlet_t *buffer) ++{ ++ int tcode; ++ ++ if (length == 4) ++ tcode = TCODE_READ_QUADLET_REQUEST; ++ else ++ tcode = TCODE_READ_BLOCK_REQUEST; ++ ++ return send_request_sync(handle, tcode, ++ node, addr, length, NULL, buffer); ++} ++ ++int ++raw1394_write(raw1394handle_t handle, nodeid_t node, nodeaddr_t addr, ++ size_t length, quadlet_t *data) ++{ ++ int tcode; ++ ++ if (length == 4) ++ tcode = TCODE_WRITE_QUADLET_REQUEST; ++ else ++ tcode = TCODE_WRITE_BLOCK_REQUEST; ++ ++ return send_request_sync(handle, tcode, ++ node, addr, length, data, NULL); ++} ++ ++int ++raw1394_lock(raw1394handle_t handle, nodeid_t node, nodeaddr_t addr, ++ unsigned int extcode, quadlet_t data, quadlet_t arg, ++ quadlet_t *result) ++{ ++ quadlet_t buffer[2]; ++ size_t length; ++ ++ length = setup_lock(extcode, data, arg, buffer); ++ if (length < 0) ++ return length; ++ ++ return send_request_sync(handle, 16 + extcode, node, addr, ++ length, buffer, result); ++} ++ ++int ++raw1394_lock64(raw1394handle_t handle, nodeid_t node, nodeaddr_t addr, ++ unsigned int extcode, octlet_t data, octlet_t arg, ++ octlet_t *result) ++{ ++ octlet_t buffer[2]; ++ size_t length; ++ ++ length = setup_lock64(extcode, data, arg, buffer); ++ if (length < 0) ++ return length; ++ ++ return send_request_sync(handle, 16 + extcode, node, addr, ++ length, buffer, result); ++} ++ ++int ++raw1394_async_stream(raw1394handle_t handle, unsigned int channel, ++ unsigned int tag, unsigned int sy, unsigned int speed, ++ size_t length, quadlet_t *data) ++{ ++ /* FIXME: implement this? */ ++ return -1; ++} ++ ++int ++raw1394_async_send(raw1394handle_t handle, ++ size_t length, size_t header_length, ++ unsigned int expect_response, ++ quadlet_t *data) ++{ ++ /* FIXME: implement this? */ ++ return -1; ++} ++ ++int ++raw1394_start_fcp_listen(raw1394handle_t handle) ++{ ++ struct fw_cdev_allocate request; ++ struct address_closure *closure; ++ ++ closure = malloc(sizeof *closure); ++ if (closure == NULL) ++ return -1; ++ ++ closure->callback = handle_fcp_request; ++ ++ request.offset = CSR_REGISTER_BASE + CSR_FCP_COMMAND; ++ request.length = CSR_FCP_END - CSR_FCP_COMMAND; ++ request.closure = ptr_to_u64(closure); ++ if (ioctl(handle->local_fd, FW_CDEV_IOC_ALLOCATE, &request) < 0) ++ return -1; ++ ++ return 0; ++} ++ ++int ++raw1394_stop_fcp_listen(raw1394handle_t handle) ++{ ++ struct fw_cdev_deallocate request; ++ ++ request.offset = CSR_REGISTER_BASE + CSR_FCP_COMMAND; ++ ++ return ioctl(handle->local_fd, FW_CDEV_IOC_DEALLOCATE, &request); ++} ++ ++const char * ++raw1394_get_libversion(void) ++{ ++ return VERSION " (Juju)"; ++} ++ ++int ++raw1394_update_config_rom(raw1394handle_t handle, const quadlet_t *new_rom, ++ size_t size, unsigned char rom_version) ++{ ++ return -1; ++} ++ ++int ++raw1394_get_config_rom(raw1394handle_t handle, quadlet_t *buffer, ++ size_t buffersize, size_t *rom_size, ++ unsigned char *rom_version) ++{ ++ struct fw_cdev_get_info get_info; ++ int err; ++ ++ get_info.version = FW_CDEV_VERSION; ++ get_info.rom = ptr_to_u64(buffer); ++ get_info.rom_length = buffersize; ++ get_info.bus_reset = 0; ++ ++ err = ioctl(handle->local_fd, FW_CDEV_IOC_GET_INFO, &get_info); ++ if (err) ++ return err; ++ ++ *rom_size = get_info.rom_length; ++ *rom_version = 0; ++ ++ return 0; ++} ++ ++int ++raw1394_bandwidth_modify (raw1394handle_t handle, unsigned int bandwidth, ++ enum raw1394_modify_mode mode) ++{ ++ /* FIXME: copy and audit the libraw1394 version */ ++} ++ ++int ++raw1394_channel_modify (raw1394handle_t handle, unsigned int channel, ++ enum raw1394_modify_mode mode) ++{ ++ /* FIXME: copy and audit the libraw1394 version */ ++} diff --git a/libraw1394.spec b/libraw1394.spec index 8fe099a..4cf008f 100644 --- a/libraw1394.spec +++ b/libraw1394.spec @@ -30,6 +30,10 @@ Development libraries needed to build applications against libraw1394. %patch0 -p0 -b .juju %build + +test -e %{_builddir}/fw-device-cdev.h || \ + cp %{_sourcedir}/fw-device-cdev.h %{_builddir} + aclocal autoconf automake diff --git a/sources b/sources index 790bc15..09a25fe 100644 --- a/sources +++ b/sources @@ -1,2 +1 @@ e6210ff05b7f4ec0401ad3d11f493e1a libraw1394-1.2.1.tar.gz -1be31713ca1e4d3387310fd96274ebb4 fw-device-cdev.h