From 5659d28c2de4a3b7ca1b9a77d847478303475996 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Mon, 26 Mar 2007 16:49:12 -0400 Subject: [PATCH 01/16] Add the juju support work so far. --- Makefile.am | 3 +- configure.ac | 22 + juju/Makefile.am | 8 + juju/juju.h | 139 +++++ juju/raw1394-iso.c | 385 ++++++++++++ juju/raw1394.c | 1437 ++++++++++++++++++++++++++++++++++++++++++++ tools/Makefile.am | 2 +- tools/testlibraw.c | 76 ++- 8 files changed, 2053 insertions(+), 19 deletions(-) create mode 100644 juju/Makefile.am create mode 100644 juju/juju.h create mode 100644 juju/raw1394-iso.c create mode 100644 juju/raw1394.c diff --git a/Makefile.am b/Makefile.am index 04ed38a..21df527 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,7 @@ # process this file with automake to create a Makefile.in -SUBDIRS = src tools doc debian +SUBDIRS = $(LIB_SUBDIR) tools doc debian +DIST_SUBDIRS = src juju pkgconfigdir = @libdir@/pkgconfig pkgconfig_DATA = libraw1394.pc diff --git a/configure.ac b/configure.ac index fe23ca8..7e5dd66 100644 --- a/configure.ac +++ b/configure.ac @@ -24,6 +24,27 @@ AC_SUBST(lt_major) AC_SUBST(lt_revision) AC_SUBST(lt_age) +AC_ARG_WITH(juju-dir,[ --with-juju-dir= Path to juju include files]) +if ! test -z "$with_juju_dir" ; then + JUJU_DIR="$with_juju_dir" + LIB_SUBDIR=juju + AC_SUBST(JUJU_DIR) +else + LIB_SUBDIR=src +fi +AC_SUBST(LIB_SUBDIR) + +AC_ARG_WITH(fw-device-prefix, + [ --with-fw-device-prefix= Prefix of firewire device file names (default "fw").], + [FW_DEVICE_PREFIX="\"$withval\""], [FW_DEVICE_PREFIX="\"fw\""]) +AC_ARG_WITH(fw-device-dir, + [ --with-fw-device-dir= Directory to watch for firewire device files (default "/dev").], + [FW_DEVICE_DIR="\"$withval\""], [FW_DEVICE_DIR="\"/dev\""]) + +AC_DEFINE_UNQUOTED(FW_DEVICE_PREFIX, $FW_DEVICE_PREFIX, + [Prefix of firewire device file names.]) +AC_DEFINE_UNQUOTED(FW_DEVICE_DIR, $FW_DEVICE_DIR, + [Directory to watch for firewire device files.]) #CFLAGS=${CFLAGS:-"-Wall"} AC_OUTPUT([ @@ -31,6 +52,7 @@ Makefile libraw1394.pc libraw1394.spec src/Makefile +juju/Makefile tools/Makefile doc/Makefile doc/testlibraw.1 diff --git a/juju/Makefile.am b/juju/Makefile.am new file mode 100644 index 0000000..6fd6a5e --- /dev/null +++ b/juju/Makefile.am @@ -0,0 +1,8 @@ +lib_LTLIBRARIES = libraw1394.la + +INCLUDES = -I$(JUJU_DIR) +libraw1394_la_LDFLAGS = -version-info @lt_major@:@lt_revision@:@lt_age@ + +libraw1394_la_SOURCES = raw1394.c raw1394-iso.c juju.h + +pkginclude_HEADERS = ../src/raw1394.h ../src/csr.h ../src/ieee1394.h diff --git a/juju/juju.h b/juju/juju.h new file mode 100644 index 0000000..5299cbf --- /dev/null +++ b/juju/juju.h @@ -0,0 +1,139 @@ +/* -*- c-basic-offset: 8 -*- + * + * juju.h -- Internal header file for raw1394 emulation + * + * Copyright (C) 2007 Kristian Hoegsberg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __juju_h +#define __juju_h + +#include +#include +#include +#include "../src/raw1394.h" +#include "../src/csr.h" +#include "config.h" + +#define ACK_COMPLETE 1 + +#define ptr_to_u64(p) ((__u64)(unsigned long)(p)) +#define u64_to_ptr(p) ((void *)(unsigned long)(p)) + +static inline __u32 +be32_to_cpu(__u32 q) +{ + union { char c[4]; __u32 q; } u = { { 1, 0, 0, 0 } }; + + return u.q == 1 ? bswap_32(q) : q; +} + +static inline __u32 +cpu_to_be32(__u32 q) +{ + return be32_to_cpu(q); +} + +#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) + +#define BUFFER_SIZE (16 * 1024) + +#define MAX_PORTS 16 + +struct epoll_closure { + int (*func)(raw1394handle_t handle, + struct epoll_closure *closure, __uint32_t events); +}; + +struct port { + char device_file[32]; + char *name; + int node_count; + int card; +}; + +#define MAX_DEVICES 63 +#define FILENAME_SIZE 16 + +struct device { + struct epoll_closure closure; + int fd; + int node_id; + int generation; + char filename[FILENAME_SIZE]; +}; + +struct request_closure { + void *data; + size_t length; + unsigned long tag; + struct raw1394_reqhandle reqhandle; +}; + +struct allocation; + +struct raw1394_handle { + struct port ports[MAX_PORTS]; + int port_count; + int err; + int generation; + void *user_data; + int notify_bus_reset; + + bus_reset_handler_t bus_reset_handler; + tag_handler_t tag_handler; + arm_tag_handler_t arm_tag_handler; + fcp_handler_t fcp_handler; + struct allocation *allocations; + + int epoll_fd; + int inotify_fd; + int inotify_watch; + int pipe_fds[2]; + + struct epoll_closure pipe_closure; + struct epoll_closure inotify_closure; + + struct device devices[MAX_DEVICES]; + int nodes[MAX_DEVICES]; + int local_fd; + char local_filename[FILENAME_SIZE]; + + struct fw_cdev_event_bus_reset reset; + + struct { + struct epoll_closure closure; + int fd; + int type; + int irq_interval; + int packet_index; + int packet_phase; + int buf_packets; + int max_packet_size; + enum raw1394_iso_dma_recv_mode recv_mode; + raw1394_iso_xmit_handler_t xmit_handler; + raw1394_iso_recv_handler_t recv_handler; + unsigned char *buffer, *head, *tail; + + struct fw_cdev_queue_iso queue_iso; + struct fw_cdev_iso_packet *packets; + } iso; + + char buffer[BUFFER_SIZE]; +}; + +#endif diff --git a/juju/raw1394-iso.c b/juju/raw1394-iso.c new file mode 100644 index 0000000..6427d39 --- /dev/null +++ b/juju/raw1394-iso.c @@ -0,0 +1,385 @@ +/* -*- c-basic-offset: 8 -*- + * + * raw1394-iso.c -- Emulation of the raw1394 rawiso API on the juju stack + * + * Copyright (C) 2007 Kristian Hoegsberg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "juju.h" + +static int +refill_xmit_buffer(raw1394handle_t handle, struct fw_cdev_queue_iso *queue_iso) +{ + int i; + struct fw_cdev_iso_packet *p = handle->iso.packets; + enum raw1394_iso_disposition d; + unsigned int len, dropped; + unsigned char tag, sy, *data, *buffer; + int cycle; + + buffer = handle->iso.buffer + + handle->iso.packet_index * handle->iso.max_packet_size; + data = buffer; + + for (i = 0; i < handle->iso.irq_interval; i++) { + cycle = -1; + dropped = 0; + d = handle->iso.xmit_handler(handle, data, + &len, &tag, &sy, cycle, dropped); + /* FIXME: handle the different dispositions. */ + + p->payload_length = len; + p->interrupt = handle->iso.packet_phase == 0; + p->skip = 0; + p->tag = tag; + p->sy = sy; + p->header_length = 0; + + data += handle->iso.max_packet_size; + handle->iso.packet_index++; + if (handle->iso.packet_index == handle->iso.buf_packets) { + handle->iso.packet_index = 0; + break; + } + + handle->iso.packet_phase++; + if (handle->iso.packet_phase == handle->iso.irq_interval) + handle->iso.packet_phase = 0; + + } + + queue_iso->packets = ptr_to_u64(handle->iso.packets); + queue_iso->size = + handle->iso.irq_interval * sizeof handle->iso.packets[0]; + queue_iso->data = ptr_to_u64(buffer); + + return 0; +} + +static int +flush_xmit_packets(raw1394handle_t handle, int limit) +{ + struct fw_cdev_queue_iso queue_iso; + int len; + + while (handle->iso.packet_index + handle->iso.irq_interval <= limit) { + if (handle->iso.queue_iso.size == 0) + refill_xmit_buffer(handle, &queue_iso); + len = ioctl(handle->iso.fd, + FW_CDEV_IOC_QUEUE_ISO, &queue_iso); + if (len < 0) + return -1; + if (handle->iso.queue_iso.size > 0) + break; + } + + return 0; +} + +int raw1394_iso_xmit_start(raw1394handle_t handle, int start_on_cycle, + int prebuffer_packets) +{ + struct fw_cdev_start_iso start_iso; + int retval; + + if (prebuffer_packets == -1) + prebuffer_packets = handle->iso.irq_interval; + + flush_xmit_packets(handle, prebuffer_packets); + + start_iso.cycle = start_on_cycle; + + retval = ioctl(handle->iso.fd, FW_CDEV_IOC_START_ISO, &start_iso); + if (retval < 0) + return retval; + + return flush_xmit_packets(handle, handle->iso.buf_packets); +} + +static int +handle_recv_packets(raw1394handle_t handle, + struct fw_cdev_event_iso_interrupt *interrupt) +{ + enum raw1394_iso_disposition d; + quadlet_t header, *p, *end; + unsigned int len, cycle, dropped; + unsigned char channel, tag, sy; + unsigned char *data; + + p = interrupt->header; + end = (void *) interrupt->header + interrupt->header_length; + cycle = interrupt->cycle; + data = NULL; + + while (p < end) { + header = be32_to_cpu(*p++); + len = header >> 8; + channel = header >> 8; + tag = header >> 8; + sy = header >> 8; + + d = handle->iso.recv_handler(handle, data, len, channel, + tag, sy, cycle, dropped); + cycle++; + } + + return 0; +} + +int raw1394_iso_recv_start(raw1394handle_t handle, int start_on_cycle, + int tag_mask, int sync) +{ + struct fw_cdev_start_iso start_iso; + + start_iso.cycle = start_on_cycle; + start_iso.tags = + tag_mask == -1 ? FW_CDEV_ISO_CONTEXT_MATCH_ALL_TAGS : tag_mask; + /* sync is documented as 'not used' */ + start_iso.sync = 0; + + return ioctl(handle->iso.fd, FW_CDEV_IOC_START_ISO, &start_iso); +} + +static int handle_iso_event(raw1394handle_t handle, + struct epoll_closure *closure, __uint32_t events) +{ + struct fw_cdev_event_iso_interrupt *interrupt; + int len; + + len = read(handle->iso.fd, handle->buffer, sizeof handle->buffer); + if (len < 0) + return -1; + + interrupt = (struct fw_cdev_event_iso_interrupt *) handle->buffer; + if (interrupt->type != FW_CDEV_EVENT_BUS_RESET) + return 0; + + switch (handle->iso.type) { + case FW_CDEV_ISO_CONTEXT_TRANSMIT: + handle->iso.packet_index -= handle->iso.irq_interval; + return flush_xmit_packets(handle, handle->iso.buf_packets); + case FW_CDEV_ISO_CONTEXT_RECEIVE: + return handle_recv_packets(handle, interrupt); + default: + /* Doesn't happen. */ + return -1; + } +} + +int raw1394_iso_xmit_write(raw1394handle_t handle, unsigned char *data, + unsigned int len, unsigned char tag, + unsigned char sy) +{ + struct fw_cdev_iso_packet packet; + + packet.payload_length = len; + packet.interrupt = handle->iso.packet_phase == 0; + packet.skip = 0; + packet.tag = tag; + packet.sy = sy; + packet.header_length = 0; + + handle->iso.packet_phase++; + if (handle->iso.packet_phase == handle->iso.irq_interval) + handle->iso.packet_phase = 0; + + /* FIXME: circular buffer goo. */ + + memcpy(handle->iso.head, data, len); + handle->iso.head += len; + + return -1; +} + +int raw1394_iso_xmit_sync(raw1394handle_t handle) +{ + /* FIXME: queue a skip packet and wait for that interrupt. */ + + return 0; +} + +int raw1394_iso_recv_flush(raw1394handle_t handle) +{ + /* FIXME: huh, we'll need kernel support here... */ + + return 0; +} + +int raw1394_iso_xmit_init(raw1394handle_t handle, + raw1394_iso_xmit_handler_t handler, + unsigned int buf_packets, + unsigned int max_packet_size, + unsigned char channel, + enum raw1394_iso_speed speed, + int irq_interval) +{ + struct fw_cdev_create_iso_context create; + struct epoll_event ep; + int retval; + + if (handle->iso.fd != -1) { + errno = EBUSY; + return -1; + } + + handle->iso.type = FW_CDEV_ISO_CONTEXT_TRANSMIT; + handle->iso.irq_interval = irq_interval; + handle->iso.xmit_handler = handler; + handle->iso.buf_packets = buf_packets; + handle->iso.max_packet_size = max_packet_size; + handle->iso.packet_index = 0; + handle->iso.packet_phase = 0; + handle->iso.queue_iso.size = 0; + handle->iso.packets = + malloc(irq_interval * sizeof handle->iso.packets[0]); + if (handle->iso.packets == NULL) + return -1; + + handle->iso.fd = open(handle->local_filename, O_RDWR); + if (handle->iso.fd < 0) { + free(handle->iso.packets); + return -1; + } + + handle->iso.closure.func = handle_iso_event; + ep.events = EPOLLIN; + ep.data.ptr = &handle->iso.closure; + if (epoll_ctl(handle->epoll_fd, EPOLL_CTL_ADD, + handle->iso.fd, &ep) < 0) { + close(handle->iso.fd); + free(handle->iso.packets); + return -1; + } + + create.type = FW_CDEV_ISO_CONTEXT_TRANSMIT; + create.channel = channel; + create.speed = speed; + + retval = ioctl(handle->iso.fd, + FW_CDEV_IOC_CREATE_ISO_CONTEXT, &create); + if (retval < 0) { + close(handle->iso.fd); + free(handle->iso.packets); + return retval; + } + + handle->iso.buffer = + mmap(NULL, buf_packets * max_packet_size, + PROT_READ | PROT_WRITE, MAP_SHARED, handle->iso.fd, 0); + + if (handle->iso.buffer == MAP_FAILED) { + close(handle->iso.fd); + free(handle->iso.packets); + return -1; + } + + return 0; +} + +int raw1394_iso_recv_init(raw1394handle_t handle, + raw1394_iso_recv_handler_t handler, + unsigned int buf_packets, + unsigned int max_packet_size, + unsigned char channel, + enum raw1394_iso_dma_recv_mode mode, + int irq_interval) +{ + struct fw_cdev_create_iso_context create; + + if (handle->iso.fd != -1) { + errno = EBUSY; + return -1; + } + + /* FIXME: Do we need this? When would you ever want this...? */ + if (mode == RAW1394_DMA_PACKET_PER_BUFFER) + return -1; + + handle->iso.buffer = + mmap(NULL, buf_packets * max_packet_size, + PROT_READ, MAP_SHARED, handle->iso.fd, 0); + + if (handle->iso.buffer == MAP_FAILED) + return -1; + + create.type = FW_CDEV_ISO_CONTEXT_RECEIVE; + create.channel = channel; + create.speed = 0; + create.header_size = 0; /* Never strip any headers. */ + + handle->iso.type = FW_CDEV_ISO_CONTEXT_RECEIVE; + handle->iso.irq_interval = irq_interval; + handle->iso.recv_handler = handler; + + return ioctl(handle->iso.fd, + FW_CDEV_IOC_CREATE_ISO_CONTEXT, &create); +} + +int raw1394_iso_multichannel_recv_init(raw1394handle_t handle, + raw1394_iso_recv_handler_t handler, + unsigned int buf_packets, + unsigned int max_packet_size, + int irq_interval) +{ + /* FIXME: gah */ + errno = ENOSYS; + return -1; +} + +int raw1394_iso_recv_listen_channel(raw1394handle_t handle, + unsigned char channel) +{ + /* FIXME: multichannel */ + errno = ENOSYS; + return -1; +} + +int raw1394_iso_recv_unlisten_channel(raw1394handle_t handle, + unsigned char channel) +{ + /* FIXME: multichannel */ + errno = ENOSYS; + return -1; +} + +int raw1394_iso_recv_set_channel_mask(raw1394handle_t handle, u_int64_t mask) +{ + /* FIXME: multichannel */ + errno = ENOSYS; + return -1; +} + +void raw1394_iso_stop(raw1394handle_t handle) +{ + ioctl(handle->iso.fd, FW_CDEV_IOC_STOP_ISO); +} + +void raw1394_iso_shutdown(raw1394handle_t handle) +{ + munmap(handle->iso.buffer, + handle->iso.buf_packets * handle->iso.max_packet_size); + close(handle->iso.fd); + free(handle->iso.packets); +} diff --git a/juju/raw1394.c b/juju/raw1394.c new file mode 100644 index 0000000..6bfd7e1 --- /dev/null +++ b/juju/raw1394.c @@ -0,0 +1,1437 @@ +/* -*- c-basic-offset: 8 -*- + * + * raw1394.c -- Emulation of the raw1394 API on the juju stack + * + * Copyright (C) 2007 Kristian Hoegsberg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "juju.h" + +raw1394_errcode_t +raw1394_get_errcode(raw1394handle_t handle) +{ + return handle->err; +} + +int +raw1394_errcode_to_errno(raw1394_errcode_t errcode) +{ + switch (errcode) { + + case -RCODE_SEND_ERROR: + case -RCODE_CANCELLED: + case -RCODE_BUSY: + case -RCODE_GENERATION: + case -RCODE_NO_ACK: + return EAGAIN; + + case raw1394_make_errcode(ACK_COMPLETE, RCODE_COMPLETE): + return 0; + case raw1394_make_errcode(ACK_COMPLETE, RCODE_CONFLICT_ERROR): + return EAGAIN; + case raw1394_make_errcode(ACK_COMPLETE, RCODE_DATA_ERROR): + return EREMOTEIO; + case raw1394_make_errcode(ACK_COMPLETE, RCODE_TYPE_ERROR): + return EPERM; + case raw1394_make_errcode(ACK_COMPLETE, RCODE_ADDRESS_ERROR): + return EINVAL; + default: + return EINVAL; + } +} + +static int +juju_to_raw1394_errcode(int rcode) +{ + /* Best effort matching juju extended rcodes to raw1394 err + * code. Since the raw1394 errcode decoding are macros we try + * to convert the juju rcodes to something that looks enough + * like the raw1394 errcodes that we retain ABI compatibility. + * + * Juju rcodes less than 0x10 are standard ieee1394 rcodes, + * which we map to a raw1394 errcode by or'ing in an + * ACK_COMPLETE ack code in the upper 16 bits. Errors + * internal to raw1394 are negative values, but juju encodes + * these errors as rcodes greater than or equal to 0x10. In + * this case, we just the negated value, which will look like + * an raw1394 internal error code. */ + + if (rcode < 0x10) + return raw1394_make_errcode(ACK_COMPLETE, rcode); + else + return -rcode; +} + +static int +default_tag_handler(raw1394handle_t handle, + unsigned long tag, raw1394_errcode_t err) +{ + struct raw1394_reqhandle *rh = (struct raw1394_reqhandle *) tag; + + if (rh != NULL) + return rh->callback(handle, rh->data, err); + + return -1; +} + +static int +default_arm_tag_handler(raw1394handle_t handle, unsigned long arm_tag, + byte_t type, unsigned int length, void *data) +{ + struct raw1394_arm_reqhandle *rh; + + if (arm_tag == 0) + return -1; + + rh = (struct raw1394_arm_reqhandle *) arm_tag; + + return rh->arm_callback(handle, data, length, rh->pcontext, type); +} + +static int +default_bus_reset_handler(struct raw1394_handle *handle, unsigned int gen) +{ + raw1394_update_generation(handle, gen); + + return 0; +} + +static int +scan_devices(raw1394handle_t handle) +{ + DIR *dir; + struct dirent *de; + char filename[32]; + struct fw_cdev_get_info get_info; + struct fw_cdev_event_bus_reset reset; + int fd, err, i; + struct port *ports; + + ports = handle->ports; + memset(ports, 0, sizeof handle->ports); + dir = opendir(FW_DEVICE_DIR); + if (dir == NULL) + return -1; + + i = 0; + while (1) { + de = readdir(dir); + if (de == NULL) + break; + + if (strncmp(de->d_name, + FW_DEVICE_PREFIX, strlen(FW_DEVICE_PREFIX)) != 0) + continue; + + snprintf(filename, sizeof filename, FW_DEVICE_DIR "/%s", de->d_name); + + fd = open(filename, O_RDWR); + if (fd < 0) + continue; + get_info.version = FW_CDEV_VERSION; + get_info.rom = 0; + get_info.rom_length = 0; + get_info.bus_reset = ptr_to_u64(&reset); + err = ioctl(fd, FW_CDEV_IOC_GET_INFO, &get_info); + close(fd); + + if (err < 0) + continue; + + if (i < MAX_PORTS && reset.node_id == reset.local_node_id) { + strncpy(ports[i].device_file, filename, + sizeof ports[i].device_file); + ports[i].node_count = (reset.root_node_id & 0x3f) + 1; + ports[i].card = get_info.card; + i++; + } + } + closedir(dir); + + handle->port_count = i; + + return 0; +} + +static int +handle_echo_pipe(raw1394handle_t handle, + struct epoll_closure *ec, __uint32_t events) +{ + quadlet_t value; + + if (read(handle->pipe_fds[0], &value, sizeof value) < 0) + return -1; + + return value; +} + +static int +handle_lost_device(raw1394handle_t handle, int i) +{ + int phy_id; + + /* The device got unplugged, get rid of it. The fd is + * automatically dropped from the epoll context when we close it. */ + + close(handle->devices[i].fd); + phy_id = handle->devices[i].node_id & 0x3f; + if (handle->nodes[phy_id] == i) + handle->nodes[phy_id] = -1; + handle->devices[i].node_id = -1; + + return 0; +} + +struct address_closure { + int (*callback)(raw1394handle_t handle, struct address_closure *ac, + struct fw_cdev_event_request *request, int i); +}; + +static int +handle_fcp_request(raw1394handle_t handle, struct address_closure *ac, + struct fw_cdev_event_request *request, int i) +{ + struct fw_cdev_send_response response; + int is_response; + + response.serial = request->serial; + response.rcode = RCODE_COMPLETE; + response.length = 0; + response.data = 0; + + if (handle->fcp_handler == NULL) + response.rcode = RCODE_ADDRESS_ERROR; + + if (request->tcode >= TCODE_WRITE_RESPONSE) + response.rcode = RCODE_CONFLICT_ERROR; + + if (ioctl(handle->devices[i].fd, + FW_CDEV_IOC_SEND_RESPONSE, &response) < 0) + return -1; + + if (response.rcode != RCODE_COMPLETE) + return 0; + + is_response = request->offset >= CSR_REGISTER_BASE + CSR_FCP_RESPONSE; + + return handle->fcp_handler(handle, + handle->devices[i].node_id, + is_response, + request->length, + (unsigned char *) request->data); +} + +static int +handle_device_event(raw1394handle_t handle, + struct epoll_closure *ec, __uint32_t events) +{ + union fw_cdev_event *u; + struct device *device = (struct device *) ec; + struct address_closure *ac; + struct request_closure *rc; + raw1394_errcode_t errcode; + int len, phy_id; + int i; + + i = device - handle->devices; + if (events == EPOLLHUP) + return handle_lost_device(handle, i); + + len = read(handle->devices[i].fd, + handle->buffer, sizeof handle->buffer); + if (len < 0) + return -1; + + u = (void *) handle->buffer; + switch (u->common.type) { + case FW_CDEV_EVENT_BUS_RESET: + /* Clear old entry, unless it's been overwritten. */ + phy_id = handle->devices[i].node_id & 0x3f; + if (handle->nodes[phy_id] == i) + handle->nodes[phy_id] = -1; + handle->nodes[u->bus_reset.node_id & 0x3f] = i; + handle->devices[i].node_id = u->bus_reset.node_id; + handle->devices[i].generation = u->bus_reset.generation; + + if (u->bus_reset.node_id != u->bus_reset.local_node_id) + return 0; + + memcpy(&handle->reset, &u->bus_reset, sizeof handle->reset); + return handle->bus_reset_handler(handle, + u->bus_reset.generation); + + case FW_CDEV_EVENT_RESPONSE: + rc = u64_to_ptr(u->response.closure); + + if (rc->data != NULL) + memcpy(rc->data, u->response.data, rc->length); + + errcode = juju_to_raw1394_errcode(u->response.rcode); + + return handle->tag_handler(handle, rc->tag, errcode); + + case FW_CDEV_EVENT_REQUEST: + ac = u64_to_ptr(u->request.closure); + return ac->callback(handle, ac, &u->request, i); + + default: + case FW_CDEV_EVENT_ISO_INTERRUPT: + /* Never happens. */ + return -1; + } +} + +static int +handle_inotify(raw1394handle_t handle, struct epoll_closure *ec, + __uint32_t events) +{ + struct inotify_event *event; + char filename[32]; + struct fw_cdev_get_info info; + struct fw_cdev_event_bus_reset reset; + struct epoll_event ep; + int i, len, fd, phy_id; + + event = (struct inotify_event *) handle->buffer; + len = read(handle->inotify_fd, event, BUFFER_SIZE); + if (!(event->mask & IN_CREATE)) + return -1; + if (strncmp(event->name, + FW_DEVICE_PREFIX, strlen(FW_DEVICE_PREFIX)) != 0) + return 0; + snprintf(filename, sizeof filename, FW_DEVICE_DIR "/%s", event->name); + fd = open(filename, O_RDWR); + if (fd < 0) { + switch (errno) { + case ENOENT: + /* Huh, it disappeared before we could + * open it. */ + return 0; + case EACCES: + /* We don't have permission to talk to + * this device, maybe it's a storage + * device. */ + return 0; + default: + /* Anything else is bad news. */ + return -1; + } + } + + info.version = FW_CDEV_VERSION; + info.rom = 0; + info.rom_length = 0; + info.bus_reset = ptr_to_u64(&reset); + if (ioctl(fd, FW_CDEV_IOC_GET_INFO, &info) < 0) { + close(fd); + return -1; + } + + for (i = 0; i < MAX_DEVICES; i++) + if (handle->devices[i].node_id == -1) + break; + if (i == MAX_DEVICES) { + close(fd); + return -1; + } + + phy_id = reset.node_id & 0x3f; + handle->nodes[phy_id] = i; + handle->devices[i].node_id = reset.node_id; + handle->devices[i].generation = reset.generation; + handle->devices[i].fd = fd; + strncpy(handle->devices[i].filename, filename, + sizeof handle->devices[i].filename); + handle->devices[i].closure.func = handle_device_event; + ep.events = EPOLLIN; + ep.data.ptr = &handle->devices[i].closure; + if (epoll_ctl(handle->epoll_fd, EPOLL_CTL_ADD, fd, &ep) < 0) { + close(fd); + return -1; + } + + return 0; +} + +int raw1394_loop_iterate(raw1394handle_t handle) +{ + int i, count, retval = 0; + struct epoll_closure *closure; + struct epoll_event ep[32]; + + count = epoll_wait(handle->epoll_fd, ep, ARRAY_LENGTH(ep), -1); + if (count < 0) + return -1; + + for (i = 0; i < count; i++) { + closure = ep[i].data.ptr; + retval = closure->func(handle, closure, ep[i].events); + } + + /* It looks like we have to add this work-around to get epoll + * to recompute the POLLIN status of the epoll_fd. */ + epoll_wait(handle->epoll_fd, ep, ARRAY_LENGTH(ep), 0); + + return retval; +} + +raw1394handle_t raw1394_new_handle(void) +{ + raw1394handle_t handle; + struct epoll_event ep; + int i; + + handle = malloc(sizeof *handle); + + handle->tag_handler = default_tag_handler; + handle->arm_tag_handler = default_arm_tag_handler; + handle->allocations = NULL; + + handle->notify_bus_reset = RAW1394_NOTIFY_ON; + handle->bus_reset_handler = default_bus_reset_handler; + + handle->iso.fd = -1; + + handle->epoll_fd = epoll_create(16); + if (handle->epoll_fd < 0) + goto out_handle; + + if (pipe(handle->pipe_fds) < 0) + goto out_epoll; + + handle->inotify_fd = inotify_init(); + if (handle->inotify_fd < 0) + goto out_pipe; + + handle->inotify_watch = + inotify_add_watch(handle->inotify_fd, FW_DEVICE_DIR, IN_CREATE); + if (handle->inotify_watch < 0) + goto out_inotify; + + handle->pipe_closure.func = handle_echo_pipe; + ep.events = EPOLLIN; + ep.data.ptr = &handle->pipe_closure; + if (epoll_ctl(handle->epoll_fd, EPOLL_CTL_ADD, + handle->pipe_fds[0], &ep) < 0) + goto out_inotify; + + handle->inotify_closure.func = handle_inotify; + ep.events = EPOLLIN; + ep.data.ptr = &handle->inotify_closure; + if (epoll_ctl(handle->epoll_fd, EPOLL_CTL_ADD, + handle->inotify_fd, &ep) < 0) + goto out_inotify; + + for (i = 0; i < MAX_DEVICES; i++) { + handle->nodes[i] = -1; + handle->devices[i].node_id = -1; + } + + scan_devices(handle); + + return handle; + + out_inotify: + close(handle->inotify_fd); + out_pipe: + close(handle->pipe_fds[0]); + close(handle->pipe_fds[1]); + out_epoll: + close(handle->epoll_fd); + out_handle: + free(handle); + return NULL; +} + +void raw1394_destroy_handle(raw1394handle_t handle) +{ + int i; + + close(handle->inotify_fd); + close(handle->pipe_fds[0]); + close(handle->pipe_fds[1]); + + for (i = 0; i < MAX_DEVICES; i++) { + if (handle->devices[i].node_id == -1) + continue; + + close(handle->devices[i].fd); + } + + close(handle->epoll_fd); + + free(handle); + + return; +} + +raw1394handle_t raw1394_new_handle_on_port(int port) +{ + raw1394handle_t handle; + + handle = raw1394_new_handle(); + if (handle == NULL) + return NULL; + + if (raw1394_set_port(handle, port) < 0) + return NULL; + + return handle; +} + +int raw1394_busreset_notify (raw1394handle_t handle, int off_on_switch) +{ + handle->notify_bus_reset = off_on_switch; + + return 0; +} + +int raw1394_get_fd(raw1394handle_t handle) +{ + return handle->epoll_fd; +} + +void raw1394_set_userdata(raw1394handle_t handle, void *data) +{ + handle->user_data = data; +} + +void *raw1394_get_userdata(raw1394handle_t handle) +{ + return handle->user_data; +} + +nodeid_t raw1394_get_local_id(raw1394handle_t handle) +{ + return handle->reset.local_node_id; +} + +nodeid_t raw1394_get_irm_id(raw1394handle_t handle) +{ + return handle->reset.irm_node_id; +} + +int raw1394_get_nodecount(raw1394handle_t handle) +{ + return (handle->reset.root_node_id & 0x3f) + 1; +} + +int raw1394_get_port_info(raw1394handle_t handle, + struct raw1394_portinfo *pinf, + int maxports) +{ + int i; + + if (maxports >= handle->port_count) + maxports = handle->port_count; + + for (i = 0; i < maxports; i++) { + pinf[i].nodes = handle->ports[i].node_count; + strncpy(pinf[i].name, handle->ports[i].device_file, + sizeof pinf[i].name); + } + + return handle->port_count; +} + +int raw1394_set_port(raw1394handle_t handle, int port) +{ + struct fw_cdev_get_info get_info; + struct fw_cdev_event_bus_reset reset; + struct epoll_event ep; + struct dirent *de; + char filename[32]; + DIR *dir; + int i, fd, phy_id; + + if (port >= handle->port_count) { + errno = EINVAL; + return -1; + } + + dir = opendir("/dev"); + if (dir == NULL) + return -1; + + for (i = 0; i < MAX_DEVICES; ) { + de = readdir(dir); + if (de == NULL) + break; + + if (strncmp(de->d_name, "fw", 2) != 0) + continue; + + snprintf(filename, sizeof filename, "/dev/%s", de->d_name); + + fd = open(filename, O_RDWR); + if (fd < 0) + continue; + + get_info.version = FW_CDEV_VERSION; + get_info.rom = 0; + get_info.rom_length = 0; + get_info.bus_reset = ptr_to_u64(&reset); + if (ioctl(fd, FW_CDEV_IOC_GET_INFO, &get_info) < 0) { + close(fd); + continue; + } + + if (get_info.card != handle->ports[port].card) { + close(fd); + continue; + } + + phy_id = reset.node_id & 0x3f; + handle->nodes[phy_id] = i; + handle->devices[i].node_id = reset.node_id; + handle->devices[i].generation = reset.generation; + handle->devices[i].fd = fd; + strncpy(handle->devices[i].filename, filename, + sizeof handle->devices[i].filename); + + handle->devices[i].closure.func = handle_device_event; + ep.events = EPOLLIN; + ep.data.ptr = &handle->devices[i].closure; + if (epoll_ctl(handle->epoll_fd, EPOLL_CTL_ADD, fd, &ep) < 0) { + close(fd); + return -1; + } + + handle->generation = reset.generation; + if (reset.node_id == reset.local_node_id) { + memcpy(&handle->reset, &reset, sizeof handle->reset); + handle->local_fd = fd; + strncpy(handle->local_filename, filename, + sizeof handle->local_filename); + } + + i++; + } + + return 0; +} + +int raw1394_reset_bus(raw1394handle_t handle) +{ + return raw1394_reset_bus_new(handle, RAW1394_LONG_RESET); +} + +int raw1394_reset_bus_new(raw1394handle_t handle, int type) +{ + struct fw_cdev_initiate_bus_reset initiate; + + switch (type) { + case RAW1394_LONG_RESET: + initiate.type = FW_CDEV_LONG_RESET; + break; + case RAW1394_SHORT_RESET: + initiate.type = FW_CDEV_SHORT_RESET; + break; + } + + return ioctl(handle->local_fd, + FW_CDEV_IOC_INITIATE_BUS_RESET, &initiate); +} + +bus_reset_handler_t raw1394_set_bus_reset_handler(raw1394handle_t handle, + bus_reset_handler_t new_h) +{ + bus_reset_handler_t old_h = handle->bus_reset_handler; + + handle->bus_reset_handler = new_h; + + return old_h; +} + +unsigned int raw1394_get_generation(raw1394handle_t handle) +{ + return handle->generation; +} + +void raw1394_update_generation(raw1394handle_t handle, unsigned int generation) +{ + handle->generation = generation; +} + +tag_handler_t +raw1394_set_tag_handler(raw1394handle_t handle, tag_handler_t new_h) +{ + tag_handler_t old_h = handle->tag_handler; + + handle->tag_handler = new_h; + + return old_h; +} + +arm_tag_handler_t +raw1394_set_arm_tag_handler(raw1394handle_t handle, arm_tag_handler_t new_h) +{ + arm_tag_handler_t old_h = handle->arm_tag_handler; + + handle->arm_tag_handler = new_h; + + return old_h; +} + +fcp_handler_t +raw1394_set_fcp_handler(raw1394handle_t handle, fcp_handler_t new_h) +{ + fcp_handler_t old_h = handle->fcp_handler; + + handle->fcp_handler = new_h; + + return old_h; +} + +struct request_response_block { + struct raw1394_arm_request_response request_response; + struct raw1394_arm_request request; + struct raw1394_arm_response response; + unsigned char data[0]; +}; + +struct allocation { + struct address_closure closure; + struct allocation *next; + byte_t *buffer; + octlet_t tag; + arm_options_t access_rights; + arm_options_t notification_options; + arm_options_t client_transactions; + nodeaddr_t offset; + size_t length; + unsigned char data[0]; +}; + +static int +handle_arm_request(raw1394handle_t handle, struct address_closure *ac, + struct fw_cdev_event_request *request, int i) +{ + struct allocation *allocation = (struct allocation *) ac; + struct request_response_block *rrb; + struct fw_cdev_send_response response; + arm_options_t type; + size_t in_length; + int offset; + + offset = request->offset - allocation->offset; + response.serial = request->serial; + + switch (request->tcode) { + case TCODE_WRITE_QUADLET_REQUEST: + case TCODE_WRITE_BLOCK_REQUEST: + printf("got write request, offset=0x%012llx, length=%d\n", + request->offset, request->length); + + type = RAW1394_ARM_WRITE; + in_length = request->length; + response.rcode = RCODE_COMPLETE; + response.length = 0; + response.data = 0; + break; + + case TCODE_READ_QUADLET_REQUEST: + case TCODE_READ_BLOCK_REQUEST: + printf("got read request, offset=0x%012llx, length=%d\n", + request->offset, request->length); + + type = RAW1394_ARM_READ; + in_length = 0; + response.rcode = RCODE_COMPLETE; + response.length = request->length; + response.data = ptr_to_u64(allocation->data + offset); + break; + + case TCODE_LOCK_REQUEST: + type = RAW1394_ARM_LOCK; + in_length = request->length; + response.length = 4; + break; + + default: + in_length = 0; + type = 0; + break; + } + + if (!(allocation->access_rights & type)) { + response.rcode = RCODE_TYPE_ERROR; + response.length = 0; + response.data = 0; + if (ioctl(handle->devices[i].fd, + FW_CDEV_IOC_SEND_RESPONSE, &response) < 0) + return -1; + } else if (!(allocation->client_transactions & type)) { + if (type == RAW1394_ARM_WRITE) + memcpy(allocation->data + offset, + request->data, request->length); + else if (type == RAW1394_ARM_LOCK) + /* FIXME: do lock ops here */; + + if (ioctl(handle->devices[i].fd, + FW_CDEV_IOC_SEND_RESPONSE, &response) < 0) + return -1; + } + + if (!(allocation->notification_options & type)) + return 0; + + rrb = malloc(sizeof *rrb + in_length + response.length); + + rrb->request_response.request = &rrb->request; + rrb->request_response.response = &rrb->response; + + rrb->request.destination_nodeid = handle->reset.local_node_id; + rrb->request.source_nodeid = handle->devices[i].node_id; + rrb->request.destination_offset = request->offset; + rrb->request.tlabel = 0; + if (request->tcode < 0x10) { + rrb->request.tcode = request->tcode; + rrb->request.extended_transaction_code = 0; + } else { + rrb->request.tcode = TCODE_LOCK_REQUEST; + rrb->request.extended_transaction_code = request->tcode - 0x10; + } + rrb->request.generation = handle->reset.generation; + rrb->request.buffer_length = in_length; + memcpy(rrb->request.buffer, request->data, in_length); + + rrb->response.response_code = response.rcode; + rrb->response.buffer_length = response.length; + memcpy(rrb->response.buffer, + allocation->data + offset, response.length); + + return handle->arm_tag_handler(handle, allocation->tag, type, + request->length, + &rrb->request_response); +} + +int +raw1394_arm_register(raw1394handle_t handle, nodeaddr_t start, + size_t length, byte_t *initial_value, + octlet_t arm_tag, arm_options_t access_rights, + arm_options_t notification_options, + arm_options_t client_transactions) +{ + struct fw_cdev_allocate request; + struct allocation *allocation; + int retval; + + allocation = malloc(sizeof *allocation + length); + if (allocation == NULL) + return -1; + + allocation->closure.callback = handle_arm_request; + allocation->buffer = initial_value; + allocation->tag = arm_tag; + allocation->access_rights = access_rights; + allocation->notification_options = notification_options; + allocation->client_transactions = client_transactions; + allocation->offset = start; + allocation->length = length; + if (initial_value != NULL) + memcpy(allocation->data, initial_value, length); + + request.offset = start; + request.length = length; + request.closure = ptr_to_u64(&allocation->closure); + + retval = ioctl(handle->local_fd, FW_CDEV_IOC_ALLOCATE, &request); + if (retval < 0) { + free(allocation); + return -1; + } + + allocation->next = handle->allocations; + handle->allocations = allocation; + + return 0; +} + +static struct allocation * +lookup_allocation(raw1394handle_t handle, nodeaddr_t start, int delete) +{ + struct allocation *a, **prev; + + prev = &handle->allocations; + for (a = handle->allocations; a != NULL; a = a->next) { + if (a->offset <= start && start < a->offset + a->length) + break; + prev = &a->next; + } + + if (a != NULL && delete) + *prev = a->next; + + return a; +} + +int +raw1394_arm_unregister(raw1394handle_t handle, nodeaddr_t start) +{ + struct fw_cdev_deallocate request; + struct allocation *allocation; + + allocation = lookup_allocation(handle, start, 1); + if (allocation == NULL) { + errno = EINVAL; + return -1; + } + + free(allocation); + + request.offset = start; + + return ioctl(handle->local_fd, FW_CDEV_IOC_DEALLOCATE, &request); +} + +int +raw1394_arm_set_buf(raw1394handle_t handle, nodeaddr_t start, + size_t length, void *buf) +{ + struct allocation *allocation; + + allocation = lookup_allocation(handle, start, 0); + if (allocation == NULL) { + errno = ENOENT; + return -1; + } + + memcpy(allocation->data + allocation->offset - start, buf, length); + + return 0; +} + +int +raw1394_arm_get_buf(raw1394handle_t handle, nodeaddr_t start, + size_t length, void *buf) +{ + struct allocation *allocation; + + allocation = lookup_allocation(handle, start, 0); + if (allocation == NULL) { + errno = ENOENT; + return -1; + } + + memcpy(buf, allocation->data + allocation->offset - start, length); + + return 0; +} + +int +raw1394_echo_request(raw1394handle_t handle, quadlet_t data) +{ + return write(handle->pipe_fds[1], &data, sizeof data); +} + +int raw1394_wake_up(raw1394handle_t handle) +{ + return raw1394_echo_request(handle, 0); +} + +int raw1394_phy_packet_write (raw1394handle_t handle, quadlet_t data) +{ + errno = ENOSYS; + return -1; +} + +int +raw1394_start_phy_packet_write(raw1394handle_t handle, + quadlet_t data, unsigned long tag) +{ + errno = ENOSYS; + return -1; +} + +static int +send_request(raw1394handle_t handle, int tcode, + nodeid_t node, nodeaddr_t addr, + size_t length, void *in, void *out, unsigned long tag) +{ + struct fw_cdev_send_request *request; + struct request_closure *closure; + int i; + + if (node > handle->reset.root_node_id) { + handle->err = -RCODE_NO_ACK; + errno = raw1394_errcode_to_errno(handle->err); + return -1; + } + + i = handle->nodes[node & 0x3f]; + if (i == -1) { + handle->err = -RCODE_NO_ACK; + errno = raw1394_errcode_to_errno(handle->err); + return -1; + } + + if (handle->generation != handle->devices[i].generation) { + handle->err = -RCODE_GENERATION; + errno = raw1394_errcode_to_errno(handle->err); + return -1; + } + + closure = malloc(sizeof *closure); + if (closure == NULL) { + handle->err = -RCODE_SEND_ERROR; + errno = raw1394_errcode_to_errno(handle->err); + return -1; + } + + closure->data = out; + closure->length = length; + closure->tag = tag; + + request = (struct fw_cdev_send_request *) handle->buffer; + request->tcode = tcode; + request->generation = handle->generation; + request->offset = addr; + request->length = length; + request->closure = ptr_to_u64(closure); + request->data = ptr_to_u64(in); + + return ioctl(handle->devices[i].fd, FW_CDEV_IOC_SEND_REQUEST, request); +} + +int +raw1394_start_read(raw1394handle_t handle, nodeid_t node, nodeaddr_t addr, + size_t length, quadlet_t *buffer, unsigned long tag) +{ + int tcode; + + if (length == 4) + tcode = TCODE_READ_QUADLET_REQUEST; + else + tcode = TCODE_READ_BLOCK_REQUEST; + + return send_request(handle, tcode, + node, addr, length, NULL, buffer, tag); +} + +int +raw1394_start_write(raw1394handle_t handle, nodeid_t node, nodeaddr_t addr, + size_t length, quadlet_t *data, unsigned long tag) +{ + int tcode; + + if (length == 4) + tcode = TCODE_WRITE_QUADLET_REQUEST; + else + tcode = TCODE_WRITE_BLOCK_REQUEST; + + return send_request(handle, tcode, + node, addr, length, data, NULL, tag); +} + +static int +setup_lock(int extcode, quadlet_t data, quadlet_t arg, quadlet_t *buffer) +{ + switch (extcode) { + case RAW1394_EXTCODE_FETCH_ADD: + case RAW1394_EXTCODE_LITTLE_ADD: + buffer[0] = data; + return sizeof buffer[0]; + + case RAW1394_EXTCODE_MASK_SWAP: + case RAW1394_EXTCODE_COMPARE_SWAP: + case RAW1394_EXTCODE_BOUNDED_ADD: + case RAW1394_EXTCODE_WRAP_ADD: + buffer[0] = arg; + buffer[1] = data; + return sizeof buffer; + + default: + errno = EINVAL; + return -1; + } +} + +static int +setup_lock64(int extcode, octlet_t data, octlet_t arg, octlet_t *buffer) +{ + switch (extcode) { + case RAW1394_EXTCODE_FETCH_ADD: + case RAW1394_EXTCODE_LITTLE_ADD: + buffer[0] = data; + return sizeof buffer[0]; + + case RAW1394_EXTCODE_MASK_SWAP: + case RAW1394_EXTCODE_COMPARE_SWAP: + case RAW1394_EXTCODE_BOUNDED_ADD: + case RAW1394_EXTCODE_WRAP_ADD: + buffer[0] = arg; + buffer[1] = data; + return sizeof buffer; + + default: + errno = EINVAL; + return -1; + } +} + +int +raw1394_start_lock(raw1394handle_t handle, nodeid_t node, nodeaddr_t addr, + unsigned int extcode, quadlet_t data, quadlet_t arg, + quadlet_t *result, unsigned long tag) +{ + quadlet_t buffer[2]; + int length; + + length = setup_lock(extcode, data, arg, buffer); + if (length < 0) + return length; + + return send_request(handle, 16 + extcode, + node, addr, length, buffer, result, tag); +} + +int +raw1394_start_lock64(raw1394handle_t handle, nodeid_t node, nodeaddr_t addr, + unsigned int extcode, octlet_t data, octlet_t arg, + octlet_t *result, unsigned long tag) +{ + octlet_t buffer[2]; + int length; + + length = setup_lock64(extcode, data, arg, buffer); + if (length < 0) + return length; + + return send_request(handle, 16 + extcode, + node, addr, length, buffer, result, tag); +} + +int +raw1394_start_async_stream(raw1394handle_t handle, unsigned int channel, + unsigned int tag, unsigned int sy, + unsigned int speed, size_t length, quadlet_t *data, + unsigned long rawtag) +{ + /* FIXME: implement this? */ + return -1; +} + + +int +raw1394_start_async_send(raw1394handle_t handle, + size_t length, size_t header_length, + unsigned int expect_response, + quadlet_t *data, unsigned long rawtag) +{ + /* FIXME: implement this? */ + return -1; +} + +struct sync_data { + raw1394_errcode_t err; + int done; +}; + +static int +sync_callback(raw1394handle_t handle, void *data, raw1394_errcode_t err) +{ + struct sync_data *sd = data; + + sd->err = err; + sd->done = 1; + + return 0; +} + +static int +send_request_sync(raw1394handle_t handle, int tcode, + nodeid_t node, nodeaddr_t addr, + size_t length, void *in, void *out) +{ + struct raw1394_reqhandle reqhandle; + struct sync_data sd = { 0, 0 }; + int err; + + reqhandle.callback = sync_callback; + reqhandle.data = &sd; + + err = send_request(handle, tcode, node, addr, + length, in, out, (unsigned long) &reqhandle); + + while (!sd.done) { + if (err < 0) + return err; + err = raw1394_loop_iterate(handle); + } + + handle->err = sd.err; + errno = raw1394_errcode_to_errno(sd.err); + + return (errno ? -1 : 0); +} + +int +raw1394_read(raw1394handle_t handle, nodeid_t node, nodeaddr_t addr, + size_t length, quadlet_t *buffer) +{ + int tcode; + + if (length == 4) + tcode = TCODE_READ_QUADLET_REQUEST; + else + tcode = TCODE_READ_BLOCK_REQUEST; + + return send_request_sync(handle, tcode, + node, addr, length, NULL, buffer); +} + +int +raw1394_write(raw1394handle_t handle, nodeid_t node, nodeaddr_t addr, + size_t length, quadlet_t *data) +{ + int tcode; + + if (length == 4) + tcode = TCODE_WRITE_QUADLET_REQUEST; + else + tcode = TCODE_WRITE_BLOCK_REQUEST; + + return send_request_sync(handle, tcode, + node, addr, length, data, NULL); +} + +int +raw1394_lock(raw1394handle_t handle, nodeid_t node, nodeaddr_t addr, + unsigned int extcode, quadlet_t data, quadlet_t arg, + quadlet_t *result) +{ + quadlet_t buffer[2]; + size_t length; + + length = setup_lock(extcode, data, arg, buffer); + if (length < 0) + return length; + + return send_request_sync(handle, 16 + extcode, node, addr, + length, buffer, result); +} + +int +raw1394_lock64(raw1394handle_t handle, nodeid_t node, nodeaddr_t addr, + unsigned int extcode, octlet_t data, octlet_t arg, + octlet_t *result) +{ + octlet_t buffer[2]; + size_t length; + + length = setup_lock64(extcode, data, arg, buffer); + if (length < 0) + return length; + + return send_request_sync(handle, 16 + extcode, node, addr, + length, buffer, result); +} + +int +raw1394_async_stream(raw1394handle_t handle, unsigned int channel, + unsigned int tag, unsigned int sy, unsigned int speed, + size_t length, quadlet_t *data) +{ + /* FIXME: implement this? */ + return -1; +} + +int +raw1394_async_send(raw1394handle_t handle, + size_t length, size_t header_length, + unsigned int expect_response, + quadlet_t *data) +{ + /* FIXME: implement this? */ + return -1; +} + +int +raw1394_start_fcp_listen(raw1394handle_t handle) +{ + struct fw_cdev_allocate request; + struct address_closure *closure; + + closure = malloc(sizeof *closure); + if (closure == NULL) + return -1; + + closure->callback = handle_fcp_request; + + request.offset = CSR_REGISTER_BASE + CSR_FCP_COMMAND; + request.length = CSR_FCP_END - CSR_FCP_COMMAND; + request.closure = ptr_to_u64(closure); + if (ioctl(handle->local_fd, FW_CDEV_IOC_ALLOCATE, &request) < 0) + return -1; + + return 0; +} + +int +raw1394_stop_fcp_listen(raw1394handle_t handle) +{ + struct fw_cdev_deallocate request; + + request.offset = CSR_REGISTER_BASE + CSR_FCP_COMMAND; + + return ioctl(handle->local_fd, FW_CDEV_IOC_DEALLOCATE, &request); +} + +const char * +raw1394_get_libversion(void) +{ + return VERSION " (Juju)"; +} + +int +raw1394_update_config_rom(raw1394handle_t handle, const quadlet_t *new_rom, + size_t size, unsigned char rom_version) +{ + return -1; +} + +int +raw1394_get_config_rom(raw1394handle_t handle, quadlet_t *buffer, + size_t buffersize, size_t *rom_size, + unsigned char *rom_version) +{ + struct fw_cdev_get_info get_info; + int err; + + get_info.version = FW_CDEV_VERSION; + get_info.rom = ptr_to_u64(buffer); + get_info.rom_length = buffersize; + get_info.bus_reset = 0; + + err = ioctl(handle->local_fd, FW_CDEV_IOC_GET_INFO, &get_info); + if (err) + return err; + + *rom_size = get_info.rom_length; + *rom_version = 0; + + return 0; +} + +#define MAXIMUM_BANDWIDTH 4915 + +int +raw1394_bandwidth_modify (raw1394handle_t handle, + unsigned int bandwidth, + enum raw1394_modify_mode mode) +{ + quadlet_t buffer, compare, swap; + nodeaddr_t addr; + int result; + + if (bandwidth == 0) + return 0; + + addr = CSR_REGISTER_BASE + CSR_BANDWIDTH_AVAILABLE; + /* Read current bandwidth usage from IRM. */ + result = raw1394_read (handle, raw1394_get_irm_id (handle), addr, + sizeof buffer, &buffer); + if (result < 0) + return -1; + + compare = ntohl (buffer); + switch (mode) { + case RAW1394_MODIFY_ALLOC: + swap = compare - bandwidth; + if (swap < 0) + return -1; + break; + + case RAW1394_MODIFY_FREE: + swap = compare + bandwidth; + if (swap > MAXIMUM_BANDWIDTH) + swap = MAXIMUM_BANDWIDTH; + break; + + default: + return -1; + } + + result = raw1394_lock(handle, raw1394_get_irm_id (handle), addr, + RAW1394_EXTCODE_COMPARE_SWAP, + htonl(swap), htonl(compare), &buffer); + if (result < 0 || ntohl(buffer) != compare) + return -1; + + return 0; +} + +int +raw1394_channel_modify (raw1394handle_t handle, + unsigned int channel, + enum raw1394_modify_mode mode) +{ + quadlet_t buffer, compare, swap, bit; + nodeaddr_t addr; + int result; + + if (channel >= 64) + return -1; + addr = CSR_REGISTER_BASE + + CSR_CHANNELS_AVAILABLE_HI + 4 * (channel / 32); + /* Read currently available channels from IRM. */ + result = raw1394_read(handle, raw1394_get_irm_id (handle), addr, + sizeof buffer, &buffer); + if (result < 0) + return -1; + + /* IEEE numbers bits from MSB (0) to LSB (31). */ + bit = 1 << (31 - (channel & 31)); + compare = ntohl(buffer); + switch (mode) { + case RAW1394_MODIFY_ALLOC: + if ((compare & bit) == 0) + return -1; + swap = buffer & ~bit; + break; + + case RAW1394_MODIFY_FREE: + if ((buffer & bit) != 0) + return -1; + swap = buffer | bit; + break; + + default: + return -1; + } + + result = raw1394_lock (handle, raw1394_get_irm_id (handle), addr, + RAW1394_EXTCODE_COMPARE_SWAP, + htonl(swap), htonl(compare), &buffer); + + if (result < 0 || ntohl(buffer) != compare) + return -1; + + return 0; +} diff --git a/tools/Makefile.am b/tools/Makefile.am index 29b250e..5be1b6f 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -2,4 +2,4 @@ MAINTAINERCLEANFILES = Makefile.in # testlibraw bin_PROGRAMS = testlibraw sendiso dumpiso -LDADD = ../src/libraw1394.la +LDADD = ../$(LIB_SUBDIR)/libraw1394.la diff --git a/tools/testlibraw.c b/tools/testlibraw.c index 5f73bd9..2f02a6d 100644 --- a/tools/testlibraw.c +++ b/tools/testlibraw.c @@ -1,4 +1,5 @@ -/* +/* -*- c-basic-offset: 8 -*- + * * libraw1394 - library for raw access to the 1394 bus with the Linux subsystem. * * Copyright (C) 1999,2000 Andreas Bombe @@ -13,12 +14,13 @@ #include #include #include +#include #include "../src/raw1394.h" #include "../src/csr.h" -#define TESTADDR (CSR_REGISTER_BASE + CSR_CYCLE_TIME) +#define TESTADDR (CSR_REGISTER_BASE + CSR_CONFIG_ROM) const char not_compatible[] = "\ This libraw1394 does not work with your version of Linux. You need a different\n\ @@ -45,12 +47,18 @@ int my_tag_handler(raw1394handle_t handle, unsigned long tag, return 0; } +static const unsigned char fcp_data[] = + { 0x1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }; + int my_fcp_handler(raw1394handle_t handle, nodeid_t nodeid, int response, size_t length, unsigned char *data) { printf("got fcp %s from node %d of %d bytes:", (response ? "response" : "command"), nodeid & 0x3f, length); + if (memcmp(fcp_data, data, sizeof fcp_data) != 0) + printf("ERROR: fcp payload not correct\n"); + while (length) { printf(" %02x", *data); data++; @@ -62,6 +70,47 @@ int my_fcp_handler(raw1394handle_t handle, nodeid_t nodeid, int response, return 0; } +static void +test_fcp(raw1394handle_t handle) +{ + printf("\ntesting FCP monitoring on local node\n"); + raw1394_set_fcp_handler(handle, my_fcp_handler); + raw1394_start_fcp_listen(handle); + raw1394_write(handle, raw1394_get_local_id(handle), + CSR_REGISTER_BASE + CSR_FCP_COMMAND, sizeof(fcp_data), + (quadlet_t *)fcp_data); + raw1394_write(handle, raw1394_get_local_id(handle), + CSR_REGISTER_BASE + CSR_FCP_RESPONSE, sizeof(fcp_data), + (quadlet_t *)fcp_data); +} + +static void +read_topology_map(raw1394handle_t handle) +{ + quadlet_t map[70]; + nodeid_t local_id; + int node_count, self_id_count, i, retval; + + local_id = raw1394_get_local_id(handle) | 0xffc0; + + retval = raw1394_read(handle, local_id, + CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP, 12, &map[0]); + if (retval < 0) + perror("topology map: raw1394_read failed with error"); + + self_id_count = ntohl(map[2]) & 0xffff; + node_count = ntohl(map[2]) >> 16; + retval = raw1394_read(handle, local_id, + CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP + 12, + self_id_count * sizeof map[0], &map[3]); + if (retval < 0) + perror("topology map: raw1394_read failed with error"); + + printf("topology map: %d nodes, %d self ids, generation %d\n", + node_count, self_id_count, ntohl(map[1])); + for (i = 0; i < self_id_count; i++) + printf(" 0x%08x\n", ntohl(map[3 + i])); +} int main(int argc, char **argv) { @@ -73,7 +122,6 @@ int main(int argc, char **argv) int retval; struct pollfd pfd; - unsigned char fcp_test[] = { 0x1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }; quadlet_t rom[0x100]; size_t rom_size; unsigned char rom_version; @@ -150,17 +198,8 @@ int main(int argc, char **argv) } } - printf("\ntesting FCP monitoring on local node\n"); - raw1394_set_fcp_handler(handle, my_fcp_handler); - raw1394_start_fcp_listen(handle); - raw1394_write(handle, raw1394_get_local_id(handle), - CSR_REGISTER_BASE + CSR_FCP_COMMAND, sizeof(fcp_test), - (quadlet_t *)fcp_test); - raw1394_write(handle, raw1394_get_local_id(handle), - CSR_REGISTER_BASE + CSR_FCP_RESPONSE, sizeof(fcp_test), - (quadlet_t *)fcp_test); - - + test_fcp(handle); + read_topology_map(handle); printf("testing config rom stuff\n"); retval=raw1394_get_config_rom(handle, rom, 0x100, &rom_size, &rom_version); @@ -176,16 +215,19 @@ int main(int argc, char **argv) retval=raw1394_update_config_rom(handle, rom, rom_size, rom_version); printf("update_config_rom returned %d\n",retval); + printf("\nposting 0xdeadbeef as an echo request\n"); + raw1394_echo_request(handle, 0xdeadbeef); - - printf("\npolling for leftover messages\n"); + printf("polling for leftover messages\n"); pfd.fd = raw1394_get_fd(handle); pfd.events = POLLIN; pfd.revents = 0; while (1) { retval = poll(&pfd, 1, 10); if (retval < 1) break; - raw1394_loop_iterate(handle); + retval = raw1394_loop_iterate(handle); + if (retval != 0) + printf("raw1394_loop_iterate() returned 0x%08x\n", retval); } if (retval < 0) perror("poll failed"); From 429167e36a4ebb994c838eaf44b7cfb7571cdf4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Wed, 28 Mar 2007 22:55:21 -0400 Subject: [PATCH 02/16] Get rawiso receive a little closer to working. --- juju/juju.h | 2 + juju/raw1394-iso.c | 170 +++++++++++++++++++++++++++++++-------------- juju/raw1394.c | 13 ++-- 3 files changed, 127 insertions(+), 58 deletions(-) diff --git a/juju/juju.h b/juju/juju.h index 5299cbf..882a131 100644 --- a/juju/juju.h +++ b/juju/juju.h @@ -98,6 +98,7 @@ struct raw1394_handle { 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; @@ -122,6 +123,7 @@ struct raw1394_handle { int irq_interval; int packet_index; int packet_phase; + int packet_tail; int buf_packets; int max_packet_size; enum raw1394_iso_dma_recv_mode recv_mode; diff --git a/juju/raw1394-iso.c b/juju/raw1394-iso.c index 6427d39..893d36a 100644 --- a/juju/raw1394-iso.c +++ b/juju/raw1394-iso.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -59,12 +60,12 @@ refill_xmit_buffer(raw1394handle_t handle, struct fw_cdev_queue_iso *queue_iso) data += handle->iso.max_packet_size; handle->iso.packet_index++; + handle->iso.packet_phase++; + if (handle->iso.packet_index == handle->iso.buf_packets) { handle->iso.packet_index = 0; break; } - - handle->iso.packet_phase++; if (handle->iso.packet_phase == handle->iso.irq_interval) handle->iso.packet_phase = 0; @@ -84,11 +85,12 @@ flush_xmit_packets(raw1394handle_t handle, int limit) struct fw_cdev_queue_iso queue_iso; int len; + handle->iso.packet_index -= handle->iso.irq_interval; + while (handle->iso.packet_index + handle->iso.irq_interval <= limit) { if (handle->iso.queue_iso.size == 0) refill_xmit_buffer(handle, &queue_iso); - len = ioctl(handle->iso.fd, - FW_CDEV_IOC_QUEUE_ISO, &queue_iso); + len = ioctl(handle->iso.fd, FW_CDEV_IOC_QUEUE_ISO, &queue_iso); if (len < 0) return -1; if (handle->iso.queue_iso.size > 0) @@ -117,10 +119,53 @@ int raw1394_iso_xmit_start(raw1394handle_t handle, int start_on_cycle, return flush_xmit_packets(handle, handle->iso.buf_packets); } + +static int +queue_recv_packets(raw1394handle_t handle) +{ + int i; + struct fw_cdev_queue_iso queue_iso; + struct fw_cdev_iso_packet *p = handle->iso.packets; + unsigned int len; + unsigned char *data, *buffer; + + buffer = handle->iso.buffer + + handle->iso.packet_index * handle->iso.max_packet_size; + data = buffer; + + for (i = 0; i < handle->iso.irq_interval; i++, p++) { + 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; + + data += handle->iso.max_packet_size; + handle->iso.packet_index++; + handle->iso.packet_phase++; + + if (handle->iso.packet_index == handle->iso.buf_packets) + handle->iso.packet_index = 0; + if (handle->iso.packet_phase == handle->iso.irq_interval) + handle->iso.packet_phase = 0; + } + + queue_iso.packets = ptr_to_u64(handle->iso.packets); + queue_iso.size = + handle->iso.irq_interval * sizeof handle->iso.packets[0]; + queue_iso.data = ptr_to_u64(buffer); + + len = ioctl(handle->iso.fd, FW_CDEV_IOC_QUEUE_ISO, &queue_iso); + if (len < 0) + return -1; + + return 0; +} static int -handle_recv_packets(raw1394handle_t handle, - struct fw_cdev_event_iso_interrupt *interrupt) +flush_recv_packets(raw1394handle_t handle, + struct fw_cdev_event_iso_interrupt *interrupt) { enum raw1394_iso_disposition d; quadlet_t header, *p, *end; @@ -131,7 +176,11 @@ handle_recv_packets(raw1394handle_t handle, p = interrupt->header; end = (void *) interrupt->header + interrupt->header_length; cycle = interrupt->cycle; - data = NULL; + dropped = 0; + + /* FIXME: compute real buffer index. */ + data = handle->iso.buffer + + handle->iso.packet_tail * handle->iso.max_packet_size; while (p < end) { header = be32_to_cpu(*p++); @@ -140,11 +189,18 @@ handle_recv_packets(raw1394handle_t handle, tag = header >> 8; sy = header >> 8; + printf("len=%d, channel=%d, tag=%d, sy=%d\n", + len, channel, tag, sy); + d = handle->iso.recv_handler(handle, data, len, channel, tag, sy, cycle, dropped); + + data += handle->iso.max_packet_size; cycle++; } + queue_recv_packets(handle); + return 0; } @@ -153,6 +209,10 @@ int raw1394_iso_recv_start(raw1394handle_t handle, int start_on_cycle, { struct fw_cdev_start_iso start_iso; + while (handle->iso.packet_index + 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; @@ -173,15 +233,14 @@ static int handle_iso_event(raw1394handle_t handle, return -1; interrupt = (struct fw_cdev_event_iso_interrupt *) handle->buffer; - if (interrupt->type != FW_CDEV_EVENT_BUS_RESET) + if (interrupt->type != FW_CDEV_EVENT_ISO_INTERRUPT) return 0; switch (handle->iso.type) { case FW_CDEV_ISO_CONTEXT_TRANSMIT: - handle->iso.packet_index -= handle->iso.irq_interval; return flush_xmit_packets(handle, handle->iso.buf_packets); case FW_CDEV_ISO_CONTEXT_RECEIVE: - return handle_recv_packets(handle, interrupt); + return flush_recv_packets(handle, interrupt); default: /* Doesn't happen. */ return -1; @@ -227,33 +286,41 @@ int raw1394_iso_recv_flush(raw1394handle_t handle) 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) +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; + int retval, prot; if (handle->iso.fd != -1) { errno = EBUSY; return -1; } - handle->iso.type = FW_CDEV_ISO_CONTEXT_TRANSMIT; - handle->iso.irq_interval = irq_interval; - handle->iso.xmit_handler = handler; + handle->iso.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_index = 0; handle->iso.packet_phase = 0; + handle->iso.packet_tail = 0; handle->iso.queue_iso.size = 0; handle->iso.packets = - malloc(irq_interval * sizeof handle->iso.packets[0]); + malloc(handle->iso.irq_interval * sizeof handle->iso.packets[0]); if (handle->iso.packets == NULL) return -1; @@ -273,9 +340,10 @@ int raw1394_iso_xmit_init(raw1394handle_t handle, return -1; } - create.type = FW_CDEV_ISO_CONTEXT_TRANSMIT; + 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); @@ -285,9 +353,18 @@ int raw1394_iso_xmit_init(raw1394handle_t handle, 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_READ | PROT_WRITE, MAP_SHARED, handle->iso.fd, 0); + prot, MAP_SHARED, handle->iso.fd, 0); if (handle->iso.buffer == MAP_FAILED) { close(handle->iso.fd); @@ -298,6 +375,19 @@ int raw1394_iso_xmit_init(raw1394handle_t handle, 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, @@ -306,35 +396,9 @@ int raw1394_iso_recv_init(raw1394handle_t handle, enum raw1394_iso_dma_recv_mode mode, int irq_interval) { - struct fw_cdev_create_iso_context create; - - if (handle->iso.fd != -1) { - errno = EBUSY; - return -1; - } - - /* FIXME: Do we need this? When would you ever want this...? */ - if (mode == RAW1394_DMA_PACKET_PER_BUFFER) - return -1; - - handle->iso.buffer = - mmap(NULL, buf_packets * max_packet_size, - PROT_READ, MAP_SHARED, handle->iso.fd, 0); - - if (handle->iso.buffer == MAP_FAILED) - return -1; - - create.type = FW_CDEV_ISO_CONTEXT_RECEIVE; - create.channel = channel; - create.speed = 0; - create.header_size = 0; /* Never strip any headers. */ - - handle->iso.type = FW_CDEV_ISO_CONTEXT_RECEIVE; - handle->iso.irq_interval = irq_interval; - handle->iso.recv_handler = handler; - - return ioctl(handle->iso.fd, - FW_CDEV_IOC_CREATE_ISO_CONTEXT, &create); + 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, diff --git a/juju/raw1394.c b/juju/raw1394.c index 6bfd7e1..fd5756d 100644 --- a/juju/raw1394.c +++ b/juju/raw1394.c @@ -219,7 +219,7 @@ handle_fcp_request(raw1394handle_t handle, struct address_closure *ac, struct fw_cdev_send_response response; int is_response; - response.serial = request->serial; + response.handle = request->handle; response.rcode = RCODE_COMPLETE; response.length = 0; response.data = 0; @@ -718,6 +718,7 @@ struct request_response_block { struct allocation { struct address_closure closure; struct allocation *next; + __u32 handle; byte_t *buffer; octlet_t tag; arm_options_t access_rights; @@ -740,7 +741,7 @@ handle_arm_request(raw1394handle_t handle, struct address_closure *ac, int offset; offset = request->offset - allocation->offset; - response.serial = request->serial; + response.handle = request->handle; switch (request->tcode) { case TCODE_WRITE_QUADLET_REQUEST: @@ -867,6 +868,7 @@ raw1394_arm_register(raw1394handle_t handle, nodeaddr_t start, return -1; } + allocation->handle = request.handle; allocation->next = handle->allocations; handle->allocations = allocation; @@ -903,10 +905,9 @@ raw1394_arm_unregister(raw1394handle_t handle, nodeaddr_t start) return -1; } + request.handle = allocation->handle; free(allocation); - request.offset = start; - return ioctl(handle->local_fd, FW_CDEV_IOC_DEALLOCATE, &request); } @@ -1290,6 +1291,8 @@ raw1394_start_fcp_listen(raw1394handle_t handle) if (ioctl(handle->local_fd, FW_CDEV_IOC_ALLOCATE, &request) < 0) return -1; + handle->fcp_allocation_handle = request.handle; + return 0; } @@ -1298,7 +1301,7 @@ raw1394_stop_fcp_listen(raw1394handle_t handle) { struct fw_cdev_deallocate request; - request.offset = CSR_REGISTER_BASE + CSR_FCP_COMMAND; + request.handle = handle->fcp_allocation_handle; return ioctl(handle->local_fd, FW_CDEV_IOC_DEALLOCATE, &request); } From 89281b576730c5f440bbd539e3efb5d5ab1036bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Sat, 31 Mar 2007 19:45:39 -0400 Subject: [PATCH 03/16] Decode iso headers properly. --- juju/raw1394-iso.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/juju/raw1394-iso.c b/juju/raw1394-iso.c index 893d36a..b65faf7 100644 --- a/juju/raw1394-iso.c +++ b/juju/raw1394-iso.c @@ -177,20 +177,19 @@ flush_recv_packets(raw1394handle_t handle, end = (void *) interrupt->header + interrupt->header_length; cycle = interrupt->cycle; dropped = 0; - - /* FIXME: compute real buffer index. */ data = handle->iso.buffer + handle->iso.packet_tail * handle->iso.max_packet_size; while (p < end) { header = be32_to_cpu(*p++); - len = header >> 8; - channel = header >> 8; - tag = header >> 8; - sy = header >> 8; + len = header >> 16; + tag = (header >> 14) & 0x3; + channel = (header >> 8) & 0x3f; + sy = header & 0x0f; - printf("len=%d, channel=%d, tag=%d, sy=%d\n", - len, channel, tag, sy); + fprintf(stderr, + "header: %08x, len=%d, channel=%d, tag=%d, sy=%d, packet_tail=0x%x\n", + header, len, channel, tag, sy, handle->iso.packet_tail); d = handle->iso.recv_handler(handle, data, len, channel, tag, sy, cycle, dropped); @@ -199,6 +198,10 @@ flush_recv_packets(raw1394handle_t handle, cycle++; } + handle->iso.packet_tail += interrupt->header_length / 4; + if (handle->iso.packet_tail >= handle->iso.buf_packets) + handle->iso.packet_tail -= handle->iso.buf_packets; + queue_recv_packets(handle); return 0; From d9b43daf480496babdacdf9e1562397fbdac1330 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Mon, 2 Apr 2007 17:33:07 -0400 Subject: [PATCH 04/16] More work on iso receive; handle payload wrapping. --- juju/juju.h | 1 + juju/raw1394-iso.c | 43 +++++++++++++++++++++++++++---------------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/juju/juju.h b/juju/juju.h index 882a131..f3c44e9 100644 --- a/juju/juju.h +++ b/juju/juju.h @@ -124,6 +124,7 @@ struct raw1394_handle { int packet_index; int packet_phase; int packet_tail; + int packet_count; int buf_packets; int max_packet_size; enum raw1394_iso_dma_recv_mode recv_mode; diff --git a/juju/raw1394-iso.c b/juju/raw1394-iso.c index b65faf7..e957787 100644 --- a/juju/raw1394-iso.c +++ b/juju/raw1394-iso.c @@ -60,6 +60,7 @@ refill_xmit_buffer(raw1394handle_t handle, struct fw_cdev_queue_iso *queue_iso) data += handle->iso.max_packet_size; handle->iso.packet_index++; + handle->iso.packet_count++; handle->iso.packet_phase++; if (handle->iso.packet_index == handle->iso.buf_packets) { @@ -123,11 +124,11 @@ int raw1394_iso_xmit_start(raw1394handle_t handle, int start_on_cycle, static int queue_recv_packets(raw1394handle_t handle) { - int i; struct fw_cdev_queue_iso queue_iso; struct fw_cdev_iso_packet *p = handle->iso.packets; unsigned int len; unsigned char *data, *buffer; + int i; buffer = handle->iso.buffer + handle->iso.packet_index * handle->iso.max_packet_size; @@ -143,17 +144,22 @@ queue_recv_packets(raw1394handle_t handle) data += handle->iso.max_packet_size; handle->iso.packet_index++; + handle->iso.packet_count++; handle->iso.packet_phase++; - if (handle->iso.packet_index == handle->iso.buf_packets) - handle->iso.packet_index = 0; if (handle->iso.packet_phase == handle->iso.irq_interval) handle->iso.packet_phase = 0; + if (handle->iso.packet_index == handle->iso.buf_packets) { + handle->iso.packet_index = 0; + /* We can't handle wrapping payloads, so we need to + * break in this case.*/ + i++; + break; + } } queue_iso.packets = ptr_to_u64(handle->iso.packets); - queue_iso.size = - handle->iso.irq_interval * sizeof handle->iso.packets[0]; + queue_iso.size = i * sizeof handle->iso.packets[0]; queue_iso.data = ptr_to_u64(buffer); len = ioctl(handle->iso.fd, FW_CDEV_IOC_QUEUE_ISO, &queue_iso); @@ -187,22 +193,23 @@ flush_recv_packets(raw1394handle_t handle, channel = (header >> 8) & 0x3f; sy = header & 0x0f; - fprintf(stderr, - "header: %08x, len=%d, channel=%d, tag=%d, sy=%d, packet_tail=0x%x\n", - header, len, channel, tag, sy, handle->iso.packet_tail); - d = handle->iso.recv_handler(handle, data, len, channel, tag, sy, cycle, dropped); data += handle->iso.max_packet_size; cycle++; + + handle->iso.packet_tail++; + handle->iso.packet_count--; + if (handle->iso.packet_tail == handle->iso.buf_packets) { + handle->iso.packet_tail = 0; + data = handle->iso.buffer; + } } - handle->iso.packet_tail += interrupt->header_length / 4; - if (handle->iso.packet_tail >= handle->iso.buf_packets) - handle->iso.packet_tail -= handle->iso.buf_packets; - - queue_recv_packets(handle); + while (handle->iso.packet_count + handle->iso.irq_interval <= + handle->iso.buf_packets) + queue_recv_packets(handle); return 0; } @@ -212,7 +219,7 @@ int raw1394_iso_recv_start(raw1394handle_t handle, int start_on_cycle, { struct fw_cdev_start_iso start_iso; - while (handle->iso.packet_index + handle->iso.irq_interval < + while (handle->iso.packet_count + handle->iso.irq_interval <= handle->iso.buf_packets) queue_recv_packets(handle); @@ -298,7 +305,6 @@ iso_init(raw1394handle_t handle, int type, unsigned char channel, enum raw1394_iso_speed speed, int irq_interval) - { struct fw_cdev_create_iso_context create; struct epoll_event ep; @@ -321,6 +327,7 @@ iso_init(raw1394handle_t handle, int type, handle->iso.packet_index = 0; handle->iso.packet_phase = 0; handle->iso.packet_tail = 0; + handle->iso.packet_count = 0; handle->iso.queue_iso.size = 0; handle->iso.packets = malloc(handle->iso.irq_interval * sizeof handle->iso.packets[0]); @@ -441,6 +448,10 @@ int raw1394_iso_recv_set_channel_mask(raw1394handle_t handle, u_int64_t mask) void raw1394_iso_stop(raw1394handle_t handle) { ioctl(handle->iso.fd, FW_CDEV_IOC_STOP_ISO); + handle->iso.packet_index = 0; + handle->iso.packet_tail = 0; + handle->iso.packet_phase = 0; + handle->iso.packet_count = 0; } void raw1394_iso_shutdown(raw1394handle_t handle) From aa70f855b3c17b340c22417b5c7e691c77cf5d9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Tue, 3 Apr 2007 13:31:36 -0400 Subject: [PATCH 05/16] Make raw1394_iso_xmit_write work. --- juju/juju.h | 5 +- juju/raw1394-iso.c | 131 ++++++++++++++++++++++++++++++++------------- 2 files changed, 98 insertions(+), 38 deletions(-) diff --git a/juju/juju.h b/juju/juju.h index f3c44e9..45fe5c8 100644 --- a/juju/juju.h +++ b/juju/juju.h @@ -127,10 +127,13 @@ struct raw1394_handle { 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, *head, *tail; + unsigned char *buffer; struct fw_cdev_queue_iso queue_iso; struct fw_cdev_iso_packet *packets; diff --git a/juju/raw1394-iso.c b/juju/raw1394-iso.c index e957787..fd3a39e 100644 --- a/juju/raw1394-iso.c +++ b/juju/raw1394-iso.c @@ -31,14 +31,14 @@ #include "juju.h" static int -refill_xmit_buffer(raw1394handle_t handle, struct fw_cdev_queue_iso *queue_iso) +queue_xmit_packets(raw1394handle_t handle) { - int i; 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, *data, *buffer; - int cycle; + int cycle, i; buffer = handle->iso.buffer + handle->iso.packet_index * handle->iso.max_packet_size; @@ -52,7 +52,8 @@ refill_xmit_buffer(raw1394handle_t handle, struct fw_cdev_queue_iso *queue_iso) /* FIXME: handle the different dispositions. */ p->payload_length = len; - p->interrupt = handle->iso.packet_phase == 0; + p->interrupt = + handle->iso.packet_phase == handle->iso.irq_interval - 1; p->skip = 0; p->tag = tag; p->sy = sy; @@ -63,19 +64,21 @@ refill_xmit_buffer(raw1394handle_t handle, struct fw_cdev_queue_iso *queue_iso) handle->iso.packet_count++; handle->iso.packet_phase++; + if (handle->iso.packet_phase == handle->iso.irq_interval) + handle->iso.packet_phase = 0; if (handle->iso.packet_index == handle->iso.buf_packets) { handle->iso.packet_index = 0; break; } - if (handle->iso.packet_phase == handle->iso.irq_interval) - handle->iso.packet_phase = 0; - } - queue_iso->packets = ptr_to_u64(handle->iso.packets); - queue_iso->size = - handle->iso.irq_interval * sizeof handle->iso.packets[0]; - queue_iso->data = ptr_to_u64(buffer); + queue_iso.packets = ptr_to_u64(handle->iso.packets); + queue_iso.size = i * sizeof handle->iso.packets[0]; + queue_iso.data = ptr_to_u64(buffer); + + len = ioctl(handle->iso.fd, FW_CDEV_IOC_QUEUE_ISO, &queue_iso); + if (len < 0) + return -1; return 0; } @@ -83,20 +86,16 @@ refill_xmit_buffer(raw1394handle_t handle, struct fw_cdev_queue_iso *queue_iso) static int flush_xmit_packets(raw1394handle_t handle, int limit) { - struct fw_cdev_queue_iso queue_iso; int len; - handle->iso.packet_index -= handle->iso.irq_interval; + if (handle->iso.xmit_handler == NULL) + return 0; - while (handle->iso.packet_index + handle->iso.irq_interval <= limit) { - if (handle->iso.queue_iso.size == 0) - refill_xmit_buffer(handle, &queue_iso); - len = ioctl(handle->iso.fd, FW_CDEV_IOC_QUEUE_ISO, &queue_iso); - if (len < 0) - return -1; - if (handle->iso.queue_iso.size > 0) - break; - } + if (limit < handle->iso.irq_interval) + limit = handle->iso.irq_interval; + + while (handle->iso.packet_count + handle->iso.irq_interval <= limit) + queue_xmit_packets(handle); return 0; } @@ -110,13 +109,19 @@ int raw1394_iso_xmit_start(raw1394handle_t handle, int start_on_cycle, 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); - start_iso.cycle = start_on_cycle; + 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; + 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); } @@ -248,6 +253,7 @@ static int handle_iso_event(raw1394handle_t handle, 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); @@ -261,25 +267,76 @@ 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; + struct fw_cdev_queue_iso queue_iso; + struct fw_cdev_start_iso start_iso; + struct fw_cdev_iso_packet *p; + void *buffer; + int first; - packet.payload_length = len; - packet.interrupt = handle->iso.packet_phase == 0; - packet.skip = 0; - packet.tag = tag; - packet.sy = sy; - packet.header_length = 0; + if (len > handle->iso.max_packet_size) { + errno = EINVAL; + return -1; + } + 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; + + buffer = handle->iso.buffer + + handle->iso.packet_index * handle->iso.max_packet_size; + memcpy(buffer, data, len); + + handle->iso.packet_index++; + handle->iso.packet_count++; handle->iso.packet_phase++; + handle->iso.packet_header_index++; + + first = handle->iso.packet_index - handle->iso.packet_header_index; + + if (handle->iso.packet_index == handle->iso.buf_packets) + handle->iso.packet_index = 0; if (handle->iso.packet_phase == handle->iso.irq_interval) handle->iso.packet_phase = 0; - /* FIXME: circular buffer goo. */ + /* 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.packet_index == 0) { + buffer = handle->iso.buffer + first * handle->iso.max_packet_size; - memcpy(handle->iso.head, data, len); - handle->iso.head += len; + 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(buffer); + handle->iso.packet_header_index = 0; - return -1; + 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) From 7e50d28e8af898c2fd8eeb8c585ee5f84c0a42de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Tue, 3 Apr 2007 21:00:06 -0400 Subject: [PATCH 06/16] Fix xmit payload packing, use pointers for circular buffer indices. --- juju/juju.h | 6 +-- juju/raw1394-iso.c | 115 ++++++++++++++++++++++----------------------- 2 files changed, 58 insertions(+), 63 deletions(-) diff --git a/juju/juju.h b/juju/juju.h index 45fe5c8..8c18630 100644 --- a/juju/juju.h +++ b/juju/juju.h @@ -121,9 +121,7 @@ struct raw1394_handle { int fd; int type; int irq_interval; - int packet_index; int packet_phase; - int packet_tail; int packet_count; int buf_packets; int max_packet_size; @@ -133,9 +131,9 @@ struct raw1394_handle { 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; + unsigned char *buffer, *buffer_end, *head; + unsigned char *tail, *first_payload; - struct fw_cdev_queue_iso queue_iso; struct fw_cdev_iso_packet *packets; } iso; diff --git a/juju/raw1394-iso.c b/juju/raw1394-iso.c index fd3a39e..b97bf87 100644 --- a/juju/raw1394-iso.c +++ b/juju/raw1394-iso.c @@ -37,17 +37,21 @@ queue_xmit_packets(raw1394handle_t handle) struct fw_cdev_queue_iso queue_iso; enum raw1394_iso_disposition d; unsigned int len, dropped; - unsigned char tag, sy, *data, *buffer; + unsigned char tag, sy, *first_payload; int cycle, i; - buffer = handle->iso.buffer + - handle->iso.packet_index * handle->iso.max_packet_size; - data = buffer; - + first_payload = handle->iso.head; for (i = 0; i < handle->iso.irq_interval; i++) { cycle = -1; dropped = 0; - d = handle->iso.xmit_handler(handle, data, + + 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); /* FIXME: handle the different dispositions. */ @@ -59,22 +63,17 @@ queue_xmit_packets(raw1394handle_t handle) p->sy = sy; p->header_length = 0; - data += handle->iso.max_packet_size; - handle->iso.packet_index++; + 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; - if (handle->iso.packet_index == handle->iso.buf_packets) { - handle->iso.packet_index = 0; - break; - } } queue_iso.packets = ptr_to_u64(handle->iso.packets); queue_iso.size = i * sizeof handle->iso.packets[0]; - queue_iso.data = ptr_to_u64(buffer); + queue_iso.data = ptr_to_u64(first_payload); len = ioctl(handle->iso.fd, FW_CDEV_IOC_QUEUE_ISO, &queue_iso); if (len < 0) @@ -132,14 +131,17 @@ 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 *data, *buffer; + unsigned char *first_payload; int i; - buffer = handle->iso.buffer + - handle->iso.packet_index * handle->iso.max_packet_size; - data = buffer; - + 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; @@ -147,25 +149,17 @@ queue_recv_packets(raw1394handle_t handle) p->sy = 0; p->header_length = 4; - data += handle->iso.max_packet_size; - handle->iso.packet_index++; + 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; - if (handle->iso.packet_index == handle->iso.buf_packets) { - handle->iso.packet_index = 0; - /* We can't handle wrapping payloads, so we need to - * break in this case.*/ - i++; - break; - } } queue_iso.packets = ptr_to_u64(handle->iso.packets); queue_iso.size = i * sizeof handle->iso.packets[0]; - queue_iso.data = ptr_to_u64(buffer); + queue_iso.data = ptr_to_u64(first_payload); len = ioctl(handle->iso.fd, FW_CDEV_IOC_QUEUE_ISO, &queue_iso); if (len < 0) @@ -188,8 +182,6 @@ flush_recv_packets(raw1394handle_t handle, end = (void *) interrupt->header + interrupt->header_length; cycle = interrupt->cycle; dropped = 0; - data = handle->iso.buffer + - handle->iso.packet_tail * handle->iso.max_packet_size; while (p < end) { header = be32_to_cpu(*p++); @@ -198,18 +190,14 @@ flush_recv_packets(raw1394handle_t handle, channel = (header >> 8) & 0x3f; sy = header & 0x0f; - d = handle->iso.recv_handler(handle, data, len, channel, - tag, sy, cycle, dropped); - - data += handle->iso.max_packet_size; + d = handle->iso.recv_handler(handle, handle->iso.tail, len, + channel, tag, sy, cycle, dropped); cycle++; - handle->iso.packet_tail++; + handle->iso.tail += handle->iso.max_packet_size; handle->iso.packet_count--; - if (handle->iso.packet_tail == handle->iso.buf_packets) { - handle->iso.packet_tail = 0; - data = handle->iso.buffer; - } + if (handle->iso.tail == handle->iso.buffer_end) + handle->iso.tail = handle->iso.buffer; } while (handle->iso.packet_count + handle->iso.irq_interval <= @@ -270,15 +258,24 @@ int raw1394_iso_xmit_write(raw1394handle_t handle, unsigned char *data, struct fw_cdev_queue_iso queue_iso; struct fw_cdev_start_iso start_iso; struct fw_cdev_iso_packet *p; - void *buffer; - int first; + + { + 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; } - while (handle->iso.packet_count + handle->iso.irq_interval > handle->iso.buf_packets) + /* 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]; @@ -290,32 +287,28 @@ int raw1394_iso_xmit_write(raw1394handle_t handle, unsigned char *data, p->sy = sy; p->header_length = 0; - buffer = handle->iso.buffer + - handle->iso.packet_index * handle->iso.max_packet_size; - memcpy(buffer, data, len); + memcpy(handle->iso.head, data, len); - handle->iso.packet_index++; + handle->iso.head += len; handle->iso.packet_count++; handle->iso.packet_phase++; handle->iso.packet_header_index++; - first = handle->iso.packet_index - handle->iso.packet_header_index; - - if (handle->iso.packet_index == handle->iso.buf_packets) - handle->iso.packet_index = 0; 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.packet_index == 0) { - buffer = handle->iso.buffer + first * handle->iso.max_packet_size; - + 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(buffer); + 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) @@ -381,11 +374,8 @@ iso_init(raw1394handle_t handle, int type, handle->iso.recv_handler = recv_handler; handle->iso.buf_packets = buf_packets; handle->iso.max_packet_size = max_packet_size; - handle->iso.packet_index = 0; handle->iso.packet_phase = 0; - handle->iso.packet_tail = 0; handle->iso.packet_count = 0; - handle->iso.queue_iso.size = 0; handle->iso.packets = malloc(handle->iso.irq_interval * sizeof handle->iso.packets[0]); if (handle->iso.packets == NULL) @@ -439,6 +429,12 @@ iso_init(raw1394handle_t handle, int type, 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; } @@ -505,8 +501,9 @@ int raw1394_iso_recv_set_channel_mask(raw1394handle_t handle, u_int64_t mask) void raw1394_iso_stop(raw1394handle_t handle) { ioctl(handle->iso.fd, FW_CDEV_IOC_STOP_ISO); - handle->iso.packet_index = 0; - handle->iso.packet_tail = 0; + 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; } From 18c6919398b63c714040f0971e98fc940bb3b32d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Tue, 3 Apr 2007 21:23:08 -0400 Subject: [PATCH 07/16] Handle rawiso dispositions. --- juju/raw1394-iso.c | 44 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/juju/raw1394-iso.c b/juju/raw1394-iso.c index b97bf87..bbf49f0 100644 --- a/juju/raw1394-iso.c +++ b/juju/raw1394-iso.c @@ -30,7 +30,7 @@ #include "juju.h" -static int +static enum raw1394_iso_disposition queue_xmit_packets(raw1394handle_t handle) { struct fw_cdev_iso_packet *p = handle->iso.packets; @@ -53,7 +53,8 @@ queue_xmit_packets(raw1394handle_t handle) d = handle->iso.xmit_handler(handle, handle->iso.head, &len, &tag, &sy, cycle, dropped); - /* FIXME: handle the different dispositions. */ + if (d != RAW1394_ISO_OK) + break; p->payload_length = len; p->interrupt = @@ -77,14 +78,15 @@ queue_xmit_packets(raw1394handle_t handle) len = ioctl(handle->iso.fd, FW_CDEV_IOC_QUEUE_ISO, &queue_iso); if (len < 0) - return -1; + return RAW1394_ISO_ERROR; - return 0; + 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) @@ -93,8 +95,19 @@ flush_xmit_packets(raw1394handle_t handle, int limit) if (limit < handle->iso.irq_interval) limit = handle->iso.irq_interval; - while (handle->iso.packet_count + handle->iso.irq_interval <= limit) - queue_xmit_packets(handle); + 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; } @@ -168,7 +181,7 @@ queue_recv_packets(raw1394handle_t handle) return 0; } -static int +static enum raw1394_iso_disposition flush_recv_packets(raw1394handle_t handle, struct fw_cdev_event_iso_interrupt *interrupt) { @@ -192,6 +205,10 @@ flush_recv_packets(raw1394handle_t handle, 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; @@ -200,6 +217,19 @@ flush_recv_packets(raw1394handle_t handle, 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); From 760378898f27aeeca553cf7bdfd177a24233e30e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Tue, 3 Apr 2007 22:07:40 -0400 Subject: [PATCH 08/16] Implement raw1394_iso_xmit_sync(), remove debug code. --- juju/raw1394-iso.c | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/juju/raw1394-iso.c b/juju/raw1394-iso.c index bbf49f0..18dc83b 100644 --- a/juju/raw1394-iso.c +++ b/juju/raw1394-iso.c @@ -289,15 +289,6 @@ int raw1394_iso_xmit_write(raw1394handle_t handle, unsigned char *data, 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; @@ -364,7 +355,39 @@ int raw1394_iso_xmit_write(raw1394handle_t handle, unsigned char *data, int raw1394_iso_xmit_sync(raw1394handle_t handle) { - /* FIXME: queue a skip packet and wait for that interrupt. */ + struct fw_cdev_iso_packet skip; + struct fw_cdev_queue_iso queue_iso; + int len; + + skip.payload_length = 0; + skip.interrupt = 1; + skip.skip = 1; + skip.tag = 0; + skip.sy = 0; + skip.header_length = 0; + + queue_iso.packets = ptr_to_u64(&skip); + queue_iso.size = sizeof skip; + queue_iso.data = 0; + + len = ioctl(handle->iso.fd, FW_CDEV_IOC_QUEUE_ISO, &queue_iso); + if (len < 0) + return -1; + + /* Now that we've queued the skip packet, we'll get an + * interrupt when the transmit buffer is flushed, so all we do + * here is wait. */ + while (handle->iso.packet_count > 0) + raw1394_loop_iterate(handle); + + /* The iso mainloop thinks that interrutps indicate another + * irq_interval number of packets was sent, so the skip + * interrupt makes it go out of whack. We just reset it. */ + handle->iso.head = handle->iso.buffer; + handle->iso.tail = handle->iso.buffer; + handle->iso.first_payload = handle->iso.buffer; + handle->iso.packet_phase = 0; + handle->iso.packet_count = 0; return 0; } From d9fd708f825d1781ff10f4fa8097b2794c2d0683 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Tue, 3 Apr 2007 22:10:39 -0400 Subject: [PATCH 09/16] Fix warnings. --- juju/raw1394-iso.c | 27 ++++++++++++++++----------- juju/raw1394.c | 1 + 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/juju/raw1394-iso.c b/juju/raw1394-iso.c index 18dc83b..fc0b396 100644 --- a/juju/raw1394-iso.c +++ b/juju/raw1394-iso.c @@ -41,6 +41,7 @@ queue_xmit_packets(raw1394handle_t handle) int cycle, i; first_payload = handle->iso.head; + d = RAW1394_ISO_OK; for (i = 0; i < handle->iso.irq_interval; i++) { cycle = -1; dropped = 0; @@ -87,7 +88,6 @@ 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; @@ -100,6 +100,7 @@ flush_xmit_packets(raw1394handle_t handle, int limit) switch (d) { case RAW1394_ISO_DEFER: case RAW1394_ISO_AGAIN: + default: return 0; case RAW1394_ISO_ERROR: return -1; @@ -189,12 +190,12 @@ flush_recv_packets(raw1394handle_t handle, 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; + d = RAW1394_ISO_OK; while (p < end) { header = be32_to_cpu(*p++); @@ -220,6 +221,7 @@ flush_recv_packets(raw1394handle_t handle, switch (d) { case RAW1394_ISO_OK: case RAW1394_ISO_DEFER: + default: break; case RAW1394_ISO_ERROR: @@ -418,6 +420,18 @@ iso_init(raw1394handle_t handle, int type, return -1; } + switch (type) { + case FW_CDEV_ISO_CONTEXT_TRANSMIT: + prot = PROT_READ | PROT_WRITE; + break; + case FW_CDEV_ISO_CONTEXT_RECEIVE: + prot = PROT_READ; + break; + default: + errno = EINVAL; + return -1; + } + handle->iso.type = type; if (irq_interval < 0) handle->iso.irq_interval = 256; @@ -463,15 +477,6 @@ iso_init(raw1394handle_t handle, int type, 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); diff --git a/juju/raw1394.c b/juju/raw1394.c index fd5756d..56bd104 100644 --- a/juju/raw1394.c +++ b/juju/raw1394.c @@ -29,6 +29,7 @@ #include #include #include +#include /* for ntohl and htonl */ #include "juju.h" From 194edcc9cd3ba9d451b644ed45011d9d48e9e72e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Wed, 11 Apr 2007 18:22:36 -0400 Subject: [PATCH 10/16] Refactor packet queueing and use for both xmit and recv. --- juju/juju.h | 2 +- juju/raw1394-iso.c | 181 +++++++++++++-------------------------------- 2 files changed, 54 insertions(+), 129 deletions(-) diff --git a/juju/juju.h b/juju/juju.h index 8c18630..d78d362 100644 --- a/juju/juju.h +++ b/juju/juju.h @@ -123,9 +123,9 @@ struct raw1394_handle { int irq_interval; int packet_phase; int packet_count; + int packet_index; 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; diff --git a/juju/raw1394-iso.c b/juju/raw1394-iso.c index fc0b396..732727f 100644 --- a/juju/raw1394-iso.c +++ b/juju/raw1394-iso.c @@ -30,74 +30,70 @@ #include "juju.h" -static enum raw1394_iso_disposition -queue_xmit_packets(raw1394handle_t handle) +static int +queue_packet(raw1394handle_t handle, + unsigned int length, unsigned int header_length, + unsigned char tag, unsigned char sy) { - 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; + struct fw_cdev_iso_packet *p; + int err; - first_payload = handle->iso.head; - d = RAW1394_ISO_OK; - for (i = 0; i < handle->iso.irq_interval; i++) { - cycle = -1; - dropped = 0; + p = &handle->iso.packets[handle->iso.packet_index]; + p->payload_length = length; + p->interrupt = + handle->iso.packet_phase == handle->iso.irq_interval - 1; + p->skip = 0; + p->tag = tag; + p->sy = sy; + p->header_length = header_length; - if (handle->iso.head + handle->iso.max_packet_size > - handle->iso.buffer_end) { - handle->iso.head = handle->iso.buffer; - break; - } + handle->iso.head += length; + handle->iso.packet_count++; + handle->iso.packet_phase++; + handle->iso.packet_index++; - d = handle->iso.xmit_handler(handle, handle->iso.head, - &len, &tag, &sy, cycle, dropped); - if (d != RAW1394_ISO_OK) - break; + if (handle->iso.packet_phase == handle->iso.irq_interval) + handle->iso.packet_phase = 0; - 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; + if (handle->iso.head + handle->iso.max_packet_size > handle->iso.buffer_end) + handle->iso.head = handle->iso.buffer; - handle->iso.head += len; - handle->iso.packet_count++; - handle->iso.packet_phase++; + /* Queue the packets in the kernel if we filled up the packets + * array or wrapped the payload buffer. */ + if (handle->iso.packet_index == handle->iso.irq_interval || + handle->iso.head == handle->iso.buffer) { + queue_iso.packets = ptr_to_u64(handle->iso.packets); + queue_iso.size = handle->iso.packet_index * sizeof handle->iso.packets[0]; + queue_iso.data = ptr_to_u64(handle->iso.first_payload); + handle->iso.packet_index = 0; + handle->iso.first_payload = handle->iso.head; - if (handle->iso.packet_phase == handle->iso.irq_interval) - handle->iso.packet_phase = 0; + err = ioctl(handle->iso.fd, FW_CDEV_IOC_QUEUE_ISO, &queue_iso); + if (err < 0) + return -1; } - - 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) +queue_xmit_packets(raw1394handle_t handle, int limit) { enum raw1394_iso_disposition d; + unsigned char tag, sy; + int len, cycle, dropped; if (handle->iso.xmit_handler == NULL) return 0; - if (limit < handle->iso.irq_interval) - limit = handle->iso.irq_interval; + while (handle->iso.packet_count < limit) { + + d = handle->iso.xmit_handler(handle, handle->iso.head, + &len, &tag, &sy, cycle, dropped); - while (handle->iso.packet_count + handle->iso.irq_interval <= limit) { - d = queue_xmit_packets(handle); switch (d) { + case RAW1394_ISO_OK: + queue_packet(handle, len, 0, tag, sy); + break; case RAW1394_ISO_DEFER: case RAW1394_ISO_AGAIN: default: @@ -125,7 +121,7 @@ int raw1394_iso_xmit_start(raw1394handle_t handle, int start_on_cycle, handle->iso.prebuffer = prebuffer_packets; handle->iso.start_on_cycle = start_on_cycle; - flush_xmit_packets(handle, prebuffer_packets); + queue_xmit_packets(handle, prebuffer_packets); if (handle->iso.prebuffer <= handle->iso.packet_count) { start_iso.cycle = start_on_cycle; @@ -136,48 +132,14 @@ int raw1394_iso_xmit_start(raw1394handle_t handle, int start_on_cycle, return retval; } - return flush_xmit_packets(handle, handle->iso.buf_packets); + return queue_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; + while (handle->iso.packet_count <= handle->iso.buf_packets) + queue_packet(handle, handle->iso.max_packet_size, 4, 0, 0); return 0; } @@ -232,9 +194,7 @@ flush_recv_packets(raw1394handle_t handle, return 0; } - while (handle->iso.packet_count + handle->iso.irq_interval <= - handle->iso.buf_packets) - queue_recv_packets(handle); + queue_recv_packets(handle); return 0; } @@ -244,9 +204,7 @@ int raw1394_iso_recv_start(raw1394handle_t handle, int start_on_cycle, { struct fw_cdev_start_iso start_iso; - while (handle->iso.packet_count + handle->iso.irq_interval <= - handle->iso.buf_packets) - queue_recv_packets(handle); + queue_recv_packets(handle); start_iso.cycle = start_on_cycle; start_iso.tags = @@ -274,7 +232,7 @@ static int handle_iso_event(raw1394handle_t handle, 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); + return queue_xmit_packets(handle, handle->iso.buf_packets); case FW_CDEV_ISO_CONTEXT_RECEIVE: return flush_recv_packets(handle, interrupt); default: @@ -300,43 +258,10 @@ int raw1394_iso_xmit_write(raw1394handle_t handle, unsigned char *data, 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; - } + if (queue_packet(handle, len, 0, tag, sy) < 0) + return -1; /* Start the streaming if it's not already running and if * we've buffered up enough packets. */ From fb1570efbf4cb8ff4ef45937408cee43874c863a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Thu, 12 Apr 2007 14:11:20 -0400 Subject: [PATCH 11/16] Wrap receive tail pointer correctly. --- juju/raw1394-iso.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/juju/raw1394-iso.c b/juju/raw1394-iso.c index 732727f..06ece9a 100644 --- a/juju/raw1394-iso.c +++ b/juju/raw1394-iso.c @@ -176,7 +176,8 @@ flush_recv_packets(raw1394handle_t handle, handle->iso.tail += handle->iso.max_packet_size; handle->iso.packet_count--; - if (handle->iso.tail == handle->iso.buffer_end) + + if (handle->iso.tail + handle->iso.max_packet_size > handle->iso.buffer_end) handle->iso.tail = handle->iso.buffer; } From 7096501f0d4d40ad4df67e250e66e3db16de2832 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Thu, 12 Apr 2007 14:11:48 -0400 Subject: [PATCH 12/16] Use power-of-two max packet sizes. --- juju/raw1394-iso.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/juju/raw1394-iso.c b/juju/raw1394-iso.c index 06ece9a..a320440 100644 --- a/juju/raw1394-iso.c +++ b/juju/raw1394-iso.c @@ -327,6 +327,18 @@ int raw1394_iso_recv_flush(raw1394handle_t handle) return 0; } +static unsigned int +round_to_power_of_two(unsigned int value) +{ + unsigned int pot; + + pot = 1; + while (pot < value) + pot <<= 1; + + return pot; +} + static int iso_init(raw1394handle_t handle, int type, raw1394_iso_xmit_handler_t xmit_handler, @@ -366,7 +378,7 @@ iso_init(raw1394handle_t handle, int type, 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.max_packet_size = round_to_power_of_two(max_packet_size); handle->iso.packet_phase = 0; handle->iso.packet_count = 0; handle->iso.packets = From c896d53c9932b612407c4b197d3ba1b03bfef055 Mon Sep 17 00:00:00 2001 From: Jay Fenlason Date: Thu, 12 Apr 2007 14:39:24 -0400 Subject: [PATCH 13/16] Use correct payload size for two-operand lock transactions. --- juju/raw1394.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/juju/raw1394.c b/juju/raw1394.c index 56bd104..7f73b3b 100644 --- a/juju/raw1394.c +++ b/juju/raw1394.c @@ -1066,7 +1066,7 @@ setup_lock(int extcode, quadlet_t data, quadlet_t arg, quadlet_t *buffer) case RAW1394_EXTCODE_WRAP_ADD: buffer[0] = arg; buffer[1] = data; - return sizeof buffer; + return 2 * sizeof buffer[0]; default: errno = EINVAL; @@ -1089,7 +1089,7 @@ setup_lock64(int extcode, octlet_t data, octlet_t arg, octlet_t *buffer) case RAW1394_EXTCODE_WRAP_ADD: buffer[0] = arg; buffer[1] = data; - return sizeof buffer; + return 2 * sizeof buffer[0]; default: errno = EINVAL; From fcba731c21fc7aadd952a9e5fb4f7635e64af4e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Tue, 17 Apr 2007 20:06:14 -0400 Subject: [PATCH 14/16] Follow ioctl changes and header file move. --- juju/juju.h | 2 +- juju/raw1394-iso.c | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/juju/juju.h b/juju/juju.h index d78d362..c7a2ebd 100644 --- a/juju/juju.h +++ b/juju/juju.h @@ -24,7 +24,7 @@ #include #include -#include +#include #include "../src/raw1394.h" #include "../src/csr.h" #include "config.h" diff --git a/juju/raw1394-iso.c b/juju/raw1394-iso.c index a320440..5e18dab 100644 --- a/juju/raw1394-iso.c +++ b/juju/raw1394-iso.c @@ -66,6 +66,7 @@ queue_packet(raw1394handle_t handle, queue_iso.packets = ptr_to_u64(handle->iso.packets); queue_iso.size = handle->iso.packet_index * sizeof handle->iso.packets[0]; queue_iso.data = ptr_to_u64(handle->iso.first_payload); + queue_iso.handle = 0; handle->iso.packet_index = 0; handle->iso.first_payload = handle->iso.head; @@ -124,7 +125,8 @@ int raw1394_iso_xmit_start(raw1394handle_t handle, int start_on_cycle, queue_xmit_packets(handle, prebuffer_packets); if (handle->iso.prebuffer <= handle->iso.packet_count) { - start_iso.cycle = start_on_cycle; + start_iso.cycle = start_on_cycle; + start_iso.handle = 0; retval = ioctl(handle->iso.fd, FW_CDEV_IOC_START_ISO, &start_iso); @@ -212,6 +214,7 @@ int raw1394_iso_recv_start(raw1394handle_t handle, int start_on_cycle, tag_mask == -1 ? FW_CDEV_ISO_CONTEXT_MATCH_ALL_TAGS : tag_mask; /* sync is documented as 'not used' */ start_iso.sync = 0; + start_iso.handle = 0; return ioctl(handle->iso.fd, FW_CDEV_IOC_START_ISO, &start_iso); } @@ -270,7 +273,8 @@ int raw1394_iso_xmit_write(raw1394handle_t handle, unsigned char *data, handle->iso.packet_count >= handle->iso.prebuffer) { /* Set this to 0 to indicate that we're running. */ handle->iso.prebuffer = 0; - start_iso.cycle = handle->iso.start_on_cycle; + start_iso.cycle = handle->iso.start_on_cycle; + start_iso.handle = 0; len = ioctl(handle->iso.fd, FW_CDEV_IOC_START_ISO, &start_iso); @@ -297,6 +301,7 @@ int raw1394_iso_xmit_sync(raw1394handle_t handle) queue_iso.packets = ptr_to_u64(&skip); queue_iso.size = sizeof skip; queue_iso.data = 0; + queue_iso.handle = 0; len = ioctl(handle->iso.fd, FW_CDEV_IOC_QUEUE_ISO, &queue_iso); if (len < 0) @@ -496,7 +501,11 @@ int raw1394_iso_recv_set_channel_mask(raw1394handle_t handle, u_int64_t mask) void raw1394_iso_stop(raw1394handle_t handle) { + struct fw_cdev_stop_iso stop_iso; + + stop_iso.handle = 0; ioctl(handle->iso.fd, FW_CDEV_IOC_STOP_ISO); + handle->iso.head = handle->iso.buffer; handle->iso.tail = handle->iso.buffer; handle->iso.first_payload = handle->iso.buffer; From 78a77758c766142bb02dcc02a8aab7c331202b45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Wed, 13 Jun 2007 18:31:59 -0400 Subject: [PATCH 15/16] Update the juju implementation to follow the recent bitfield changes. --- juju/juju.h | 2 -- juju/raw1394-iso.c | 23 +++++++++-------------- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/juju/juju.h b/juju/juju.h index c7a2ebd..8746ac2 100644 --- a/juju/juju.h +++ b/juju/juju.h @@ -29,8 +29,6 @@ #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)) diff --git a/juju/raw1394-iso.c b/juju/raw1394-iso.c index 5e18dab..b1e493c 100644 --- a/juju/raw1394-iso.c +++ b/juju/raw1394-iso.c @@ -40,13 +40,14 @@ queue_packet(raw1394handle_t handle, int err; p = &handle->iso.packets[handle->iso.packet_index]; - p->payload_length = length; - p->interrupt = - handle->iso.packet_phase == handle->iso.irq_interval - 1; - p->skip = 0; - p->tag = tag; - p->sy = sy; - p->header_length = header_length; + p->control = + FW_CDEV_ISO_PAYLOAD_LENGTH(length) | + FW_CDEV_ISO_TAG(tag) | + FW_CDEV_ISO_SY(sy) | + FW_CDEV_ISO_HEADER_LENGTH(header_length); + + if (handle->iso.packet_phase == handle->iso.irq_interval - 1) + p->control |= FW_CDEV_ISO_INTERRUPT; handle->iso.head += length; handle->iso.packet_count++; @@ -291,13 +292,7 @@ int raw1394_iso_xmit_sync(raw1394handle_t handle) struct fw_cdev_queue_iso queue_iso; int len; - skip.payload_length = 0; - skip.interrupt = 1; - skip.skip = 1; - skip.tag = 0; - skip.sy = 0; - skip.header_length = 0; - + skip.control = FW_CDEV_ISO_INTERRUPT | FW_CDEV_ISO_SKIP; queue_iso.packets = ptr_to_u64(&skip); queue_iso.size = sizeof skip; queue_iso.data = 0; From 8085c633bce9fed1a74dd2037d7f3a95f839a4e2 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Wed, 24 Oct 2007 16:50:24 -0400 Subject: [PATCH 16/16] Set handle->iso.packets to NULL after freeing to avoid double-frees. --- juju/raw1394-iso.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/juju/raw1394-iso.c b/juju/raw1394-iso.c index b1e493c..ae8aaad 100644 --- a/juju/raw1394-iso.c +++ b/juju/raw1394-iso.c @@ -389,6 +389,7 @@ iso_init(raw1394handle_t handle, int type, handle->iso.fd = open(handle->local_filename, O_RDWR); if (handle->iso.fd < 0) { free(handle->iso.packets); + handle->iso.packets = NULL; return -1; } @@ -399,6 +400,7 @@ iso_init(raw1394handle_t handle, int type, handle->iso.fd, &ep) < 0) { close(handle->iso.fd); free(handle->iso.packets); + handle->iso.packets = NULL; return -1; } @@ -412,6 +414,7 @@ iso_init(raw1394handle_t handle, int type, if (retval < 0) { close(handle->iso.fd); free(handle->iso.packets); + handle->iso.packets = NULL; return retval; } @@ -422,6 +425,7 @@ iso_init(raw1394handle_t handle, int type, if (handle->iso.buffer == MAP_FAILED) { close(handle->iso.fd); free(handle->iso.packets); + handle->iso.packets = NULL; return -1; } @@ -514,4 +518,5 @@ void raw1394_iso_shutdown(raw1394handle_t handle) handle->iso.buf_packets * handle->iso.max_packet_size); close(handle->iso.fd); free(handle->iso.packets); + handle->iso.packets = NULL; }