summaryrefslogtreecommitdiffstats
path: root/src/iso.c
diff options
context:
space:
mode:
authorGravatar ddennedy 2002-11-18 07:40:21 +0000
committerGravatar ddennedy 2002-11-18 07:40:21 +0000
commitb9de121a85abef26f07da8d55530964eb9797f17 (patch)
tree7321424534f5afcc1cf3671a9afff9dc567aa443 /src/iso.c
parentadded missing arm.c from weihs branch (diff)
merged rawiso branch
git-svn-id: svn://svn.linux1394.org/libraw1394/trunk@93 53a565d1-3bb7-0310-b661-cf11e63c67ab
Diffstat (limited to 'src/iso.c')
-rw-r--r--src/iso.c329
1 files changed, 329 insertions, 0 deletions
diff --git a/src/iso.c b/src/iso.c
index 3d7131e..007d72c 100644
--- a/src/iso.c
+++ b/src/iso.c
@@ -2,6 +2,7 @@
* libraw1394 - library for raw access to the 1394 bus with the Linux subsystem.
*
* Copyright (C) 1999,2000,2001,2002 Andreas Bombe
+ * new ISO API by Dan Maas
*
* This library is licensed under the GNU Lesser General Public License (LGPL),
* version 2.1 or later. See the file COPYING.LIB in the distribution for
@@ -11,11 +12,15 @@
#include <config.h>
#include <errno.h>
#include <unistd.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
#include "raw1394.h"
#include "kernel-raw1394.h"
#include "raw1394_private.h"
+/* old ISO API - kept for backwards compatibility */
static int do_iso_listen(struct raw1394_handle *handle, int channel)
{
@@ -86,3 +91,327 @@ int raw1394_stop_iso_rcv(struct raw1394_handle *handle, unsigned int channel)
return do_iso_listen(handle, ~channel);
}
+
+
+
+/* new ISO API */
+
+
+/* reset the dropped counter each time it is seen */
+static unsigned int _raw1394_iso_dropped(raw1394handle_t handle)
+{
+ unsigned int retval = handle->iso_packets_dropped;
+ handle->iso_packets_dropped = 0;
+ return retval;
+}
+
+
+/* common code for iso_xmit_init and iso_recv_init */
+static int do_iso_init(raw1394handle_t handle,
+ unsigned int buf_packets,
+ unsigned int max_packet_size,
+ int channel,
+ enum raw1394_iso_speed speed,
+ int irq_interval,
+ int xmit)
+{
+ size_t pgsize;
+
+ /* already initialized? */
+ if(handle->iso_buffer)
+ return -1;
+
+ handle->iso_status.config.buf_packets = buf_packets;
+ handle->iso_status.config.max_packet_size = max_packet_size;
+ handle->iso_status.config.channel = channel;
+ handle->iso_status.config.speed = speed;
+ handle->iso_status.config.irq_interval = irq_interval;
+
+ if(ioctl(handle->fd, xmit ? RAW1394_ISO_XMIT_INIT : RAW1394_ISO_RECV_INIT, &handle->iso_status))
+ return -1;
+
+ handle->iso_buffer_bytes = handle->iso_status.config.buf_packets * handle->iso_status.buf_stride;
+
+ /* make sure buffer is a multiple of the page size (for mmap) */
+ pgsize = getpagesize();
+ if(handle->iso_buffer_bytes % pgsize)
+ handle->iso_buffer_bytes += pgsize - (handle->iso_buffer_bytes % pgsize);
+
+ /* mmap the DMA buffer */
+ handle->iso_buffer = mmap(NULL, handle->iso_buffer_bytes, PROT_READ | PROT_WRITE,
+ MAP_SHARED, handle->fd, 0);
+
+ if(handle->iso_buffer == (unsigned char*) MAP_FAILED) {
+ handle->iso_buffer = NULL;
+ ioctl(handle->fd, RAW1394_ISO_SHUTDOWN, 0);
+ return -1;
+ }
+
+ handle->iso_status.overflows = 0;
+ handle->iso_packets_dropped = 0;
+
+ handle->iso_xmit_handler = NULL;
+ handle->iso_recv_handler = NULL;
+
+ return 0;
+}
+
+/**
+ * raw1394_iso_xmit_init - initialize isochronous transmission
+ * @handler: handler function for queueing packets
+ * @buf_packets: number of isochronous packets to buffer
+ * @max_packet_size: largest packet you need to handle, in bytes (not including the 8-byte isochronous header)
+ * @channel: isochronous channel on which to transmit
+ * @speed: speed at which to transmit
+ * @irq_interval: maximum latency of wake-ups, in packets (-1 if you don't care)
+ *
+ * Allocates all user and kernel resources necessary for isochronous transmission.
+ **/
+int raw1394_iso_xmit_init(raw1394handle_t handle,
+ raw1394_iso_xmit_handler_t handler,
+ unsigned int buf_packets,
+ unsigned int max_packet_size,
+ int channel,
+ enum raw1394_iso_speed speed,
+ int irq_interval)
+{
+ if(do_iso_init(handle, buf_packets, max_packet_size, channel, speed, irq_interval, 1))
+ return -1;
+
+ handle->iso_xmit_handler = handler;
+ return 0;
+}
+
+/**
+ * raw1394_iso_recv_init - initialize isochronous reception
+ * @handler: handler function for receiving packets
+ * @buf_packets: number of isochronous packets to buffer
+ * @max_packet_size: largest packet you need to handle, in bytes (not including the 8-byte isochronous header)
+ * @channel: isochronous channel to receive
+ * @speed: speed at which to receive
+ * @irq_interval: maximum latency of wake-ups, in packets (-1 if you don't care)
+ *
+ * Allocates all user and kernel resources necessary for isochronous reception.
+ **/
+int raw1394_iso_recv_init(raw1394handle_t handle,
+ raw1394_iso_recv_handler_t handler,
+ unsigned int buf_packets,
+ unsigned int max_packet_size,
+ int channel,
+ int irq_interval)
+{
+ /* any speed will work */
+ if(do_iso_init(handle, buf_packets, max_packet_size, channel, RAW1394_ISO_SPEED_100, irq_interval, 0))
+ return -1;
+
+ handle->iso_recv_handler = handler;
+ return 0;
+}
+
+/**
+ * raw1394_iso_recv_start - begin isochronous reception
+ * @start_on_cycle: isochronous cycle number on which to start (-1 if you don't care)
+ **/
+int raw1394_iso_recv_start(raw1394handle_t handle, int start_on_cycle)
+{
+ if(!handle->iso_buffer)
+ return -1;
+ if(!handle->iso_recv_handler)
+ return -1;
+
+ if(ioctl(handle->fd, RAW1394_ISO_RECV_START, start_on_cycle))
+ return -1;
+
+ return 0;
+}
+
+
+static int _raw1394_iso_xmit_queue_packets(raw1394handle_t handle)
+{
+ struct raw1394_iso_status *stat = &handle->iso_status;
+ int retval = 0, packets_done = 0;
+
+ if(!handle->iso_buffer)
+ return -1;
+
+ if(!handle->iso_xmit_handler)
+ return -1;
+
+ while(stat->n_packets > 0) {
+ enum raw1394_iso_disposition disp;
+ unsigned char *packet_data;
+ struct raw1394_iso_packet_info *info;
+ unsigned int len;
+ unsigned char tag, sy;
+
+ packet_data = handle->iso_buffer + stat->first_packet * stat->buf_stride
+ + stat->packet_data_offset;
+
+ info = (struct raw1394_iso_packet_info*) (handle->iso_buffer
+ + stat->first_packet * stat->buf_stride
+ + stat->packet_info_offset);
+
+ /* call handler */
+ disp = handle->iso_xmit_handler(handle,
+ packet_data,
+ &len, &tag, &sy,
+ info->cycle,
+ _raw1394_iso_dropped(handle));
+
+ /* check if packet is too long */
+ if(len > stat->config.max_packet_size) {
+ retval = -1;
+ break;
+ }
+
+ /* set packet metadata */
+ info->len = len;
+ info->tag = tag;
+ info->sy = sy;
+
+ /* advance packet cursors and cycle counter */
+ stat->n_packets--;
+ stat->first_packet = (stat->first_packet + 1) % stat->config.buf_packets;
+ packets_done++;
+
+ if(disp == RAW1394_ISO_DEFER) {
+ break;
+ } else if(disp == RAW1394_ISO_ERROR) {
+ retval = -1;
+ break;
+ }
+ }
+
+ if(packets_done > 0) {
+ if(ioctl(handle->fd, RAW1394_ISO_PRODUCE_CONSUME, packets_done))
+ return -1;
+ }
+
+ return retval;
+}
+
+
+/**
+ * raw1394_iso_xmit_start - begin isochronous transmission
+ * @start_on_cycle: isochronous cycle number on which to start (-1 if you don't care)
+ * @prebuffer_packets: number of packets to queue up before starting transmission (-1 if you don't care)
+ **/
+int raw1394_iso_xmit_start(raw1394handle_t handle, int start_on_cycle, int prebuffer_packets)
+{
+ int args[2];
+
+ if(!handle->iso_buffer)
+ return -1;
+ if(!handle->iso_xmit_handler)
+ return -1;
+
+ args[0] = start_on_cycle;
+ args[1] = prebuffer_packets;
+
+ if(ioctl(handle->fd, RAW1394_ISO_XMIT_START, &args[0]))
+ return -1;
+
+ return 0;
+}
+
+/**
+ * raw1394_iso_stop - halt isochronous transmission or reception
+ **/
+void raw1394_iso_stop(raw1394handle_t handle)
+{
+ if(!handle->iso_buffer)
+ return;
+
+ ioctl(handle->fd, RAW1394_ISO_STOP, 0);
+}
+
+/**
+ * raw1394_iso_shutdown - clean up and deallocate all resources for isochronous transmission or reception
+ **/
+void raw1394_iso_shutdown(raw1394handle_t handle)
+{
+ if(handle->iso_buffer) {
+ raw1394_iso_stop(handle);
+ munmap(handle->iso_buffer, handle->iso_buffer_bytes);
+ ioctl(handle->fd, RAW1394_ISO_SHUTDOWN, 0);
+ handle->iso_buffer = NULL;
+ }
+}
+
+static int _raw1394_iso_recv_packets(raw1394handle_t handle)
+{
+ struct raw1394_iso_status *stat = &handle->iso_status;
+ struct raw1394_iso_packet_info *info;
+
+ int retval = 0, packets_done = 0;
+
+ if(!handle->iso_buffer)
+ return -1;
+
+ if(!handle->iso_recv_handler)
+ return -1;
+
+ while(stat->n_packets > 0) {
+ unsigned char *packet_data;
+ struct raw1394_iso_packet_info *info;
+ enum raw1394_iso_disposition disp;
+
+ packet_data = handle->iso_buffer + stat->first_packet * stat->buf_stride
+ + stat->packet_data_offset;
+
+ info = (struct raw1394_iso_packet_info*) (handle->iso_buffer
+ + stat->first_packet * stat->buf_stride
+ + stat->packet_info_offset);
+
+ /* call handler */
+ disp = handle->iso_recv_handler(handle,
+ packet_data,
+ info->len, info->channel,
+ info->tag, info->sy,
+ info->cycle,
+ _raw1394_iso_dropped(handle));
+
+ /* advance packet cursors */
+ stat->n_packets--;
+ stat->first_packet = (stat->first_packet + 1) % stat->config.buf_packets;
+ packets_done++;
+
+ if(disp == RAW1394_ISO_DEFER) {
+ break;
+ } else if(disp == RAW1394_ISO_ERROR) {
+ retval = -1;
+ break;
+ }
+ }
+
+ if(packets_done > 0) {
+ if(ioctl(handle->fd, RAW1394_ISO_PRODUCE_CONSUME, packets_done))
+ return -1;
+ }
+
+ return retval;
+}
+
+/* run the ISO state machine; called from raw1394_loop_iterate() */
+int _raw1394_iso_iterate(raw1394handle_t handle)
+{
+ int err;
+
+ if(!handle->iso_buffer)
+ return 0;
+
+ err = ioctl(handle->fd, RAW1394_ISO_GET_STATUS, &handle->iso_status);
+ if(err != 0)
+ return err;
+
+ handle->iso_packets_dropped += handle->iso_status.overflows;
+
+ if(handle->iso_xmit_handler) {
+ return _raw1394_iso_xmit_queue_packets(handle);
+ } else if(handle->iso_recv_handler) {
+ return _raw1394_iso_recv_packets(handle);
+ }
+
+ return 0;
+}
+