summaryrefslogtreecommitdiffstats
path: root/src/iso.c
diff options
context:
space:
mode:
authorGravatar dmaas 2002-12-24 03:01:11 +0000
committerGravatar dmaas 2002-12-24 03:01:11 +0000
commit385413d23e8efab86d391bfa09776bfbdbab30ff (patch)
tree84b9025faa6d9103820a286aee87caa04f2c64b6 /src/iso.c
parentoops, irq_interval needs to be signed (diff)
update iso API for multi-channel reception and new packet buffer layout
git-svn-id: svn://svn.linux1394.org/libraw1394/trunk@98 53a565d1-3bb7-0310-b661-cf11e63c67ab
Diffstat (limited to 'src/iso.c')
-rw-r--r--src/iso.c257
1 files changed, 171 insertions, 86 deletions
diff --git a/src/iso.c b/src/iso.c
index 36d5d25..bacde60 100644
--- a/src/iso.c
+++ b/src/iso.c
@@ -113,34 +113,41 @@ static int do_iso_init(raw1394handle_t handle,
int channel,
enum raw1394_iso_speed speed,
int irq_interval,
- int xmit)
+ int cmd)
{
- size_t pgsize;
+ unsigned int bufsize, stride;
/* already initialized? */
if(handle->iso_buffer)
return -1;
-
+
+ /* choose a power-of-two stride for the packet data buffer,
+ so that an even number of packets fits on one page */
+ for(stride = 4; stride < max_packet_size; stride *= 2);
+
+ if(stride > getpagesize()) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ handle->iso_buf_stride = stride;
+
+ handle->iso_status.config.data_buf_size = stride * buf_packets;
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);
+ if(ioctl(handle->fd, cmd, &handle->iso_status))
+ return -1;
/* mmap the DMA buffer */
- handle->iso_buffer = mmap(NULL, handle->iso_buffer_bytes, PROT_READ | PROT_WRITE,
+ /* (we assume the kernel sets buf_size to an even number of pages) */
+ handle->iso_buffer = mmap(NULL,
+ handle->iso_status.config.data_buf_size,
+ 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);
@@ -149,10 +156,10 @@ static int do_iso_init(raw1394handle_t handle,
handle->iso_status.overflows = 0;
handle->iso_packets_dropped = 0;
-
+
handle->iso_xmit_handler = NULL;
handle->iso_recv_handler = NULL;
-
+
return 0;
}
@@ -171,14 +178,17 @@ 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,
+ unsigned char channel,
enum raw1394_iso_speed speed,
int irq_interval)
{
- if(do_iso_init(handle, buf_packets, max_packet_size, channel, speed, irq_interval, 1))
+ if(do_iso_init(handle, buf_packets, max_packet_size, channel, speed,
+ irq_interval, RAW1394_ISO_XMIT_INIT))
return -1;
-
+
handle->iso_xmit_handler = handler;
+ handle->next_packet = 0;
+
return 0;
}
@@ -197,11 +207,12 @@ 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,
+ unsigned char 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))
+ if(do_iso_init(handle, buf_packets, max_packet_size, channel, RAW1394_ISO_SPEED_100,
+ irq_interval, RAW1394_ISO_RECV_INIT))
return -1;
handle->iso_recv_handler = handler;
@@ -209,6 +220,74 @@ int raw1394_iso_recv_init(raw1394handle_t handle,
}
/**
+ * raw1394_iso_multichannel_recv_init - initialize multi-channel 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 isochronous header)
+ * @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_multichannel_recv_init(raw1394handle_t handle,
+ raw1394_iso_recv_handler_t handler,
+ unsigned int buf_packets,
+ unsigned int max_packet_size,
+ int irq_interval)
+{
+ /* any speed will work */
+ if(do_iso_init(handle, buf_packets, max_packet_size, -1, RAW1394_ISO_SPEED_100,
+ irq_interval, RAW1394_ISO_RECV_INIT))
+ return -1;
+
+ handle->iso_recv_handler = handler;
+ return 0;
+}
+
+/**
+ * raw1394_iso_recv_listen_channel - listen to a specific channel in multi-channel mode
+ **/
+int raw1394_iso_recv_listen_channel(raw1394handle_t handle, unsigned char channel)
+{
+ if(!handle->iso_buffer)
+ return -1;
+ if(!handle->iso_recv_handler)
+ return -1;
+
+ return ioctl(handle->fd, RAW1394_ISO_RECV_LISTEN_CHANNEL, channel);
+}
+
+/**
+ * raw1394_iso_recv_unlisten_channel - stop listening to a specific channel in multi-channel mode
+ **/
+int raw1394_iso_recv_unlisten_channel(raw1394handle_t handle, unsigned char channel)
+{
+ if(!handle->iso_buffer)
+ return -1;
+ if(!handle->iso_recv_handler)
+ return -1;
+
+ return ioctl(handle->fd, RAW1394_ISO_RECV_UNLISTEN_CHANNEL, channel);
+}
+
+/**
+ * raw1394_iso_recv_set_channel_mask - listen or unlisten to a whole bunch of channels at once
+ * @mask: 64-bit mask of channels, 1 means listen, 0 means unlisten,
+ * channel 0 is LSB, channel 63 is MSB
+ *
+ * for multi-channel reception mode only
+ **/
+int raw1394_iso_recv_set_channel_mask(raw1394handle_t handle, u_int64_t mask)
+{
+ if(!handle->iso_buffer)
+ return -1;
+ if(!handle->iso_recv_handler)
+ return -1;
+
+ return ioctl(handle->fd, RAW1394_ISO_RECV_SET_CHANNEL_MASK, (void*) &mask);
+}
+
+/**
* raw1394_iso_recv_start - begin isochronous reception
* @start_on_cycle: isochronous cycle number on which to start (-1 if you don't care)
**/
@@ -218,7 +297,7 @@ int raw1394_iso_recv_start(raw1394handle_t handle, int start_on_cycle)
return -1;
if(!handle->iso_recv_handler)
return -1;
-
+
if(ioctl(handle->fd, RAW1394_ISO_RECV_START, start_on_cycle))
return -1;
@@ -229,67 +308,66 @@ int raw1394_iso_recv_start(raw1394handle_t handle, int start_on_cycle)
static int _raw1394_iso_xmit_queue_packets(raw1394handle_t handle)
{
struct raw1394_iso_status *stat = &handle->iso_status;
- int retval = 0, packets_done = 0;
-
+ struct raw1394_iso_packets packets;
+ int retval = -1;
+
if(!handle->iso_buffer)
- return -1;
+ goto out;
if(!handle->iso_xmit_handler)
- return -1;
-
+ goto out;
+
+ /* we could potentially send up to stat->n_packets packets */
+ packets.n_packets = 0;
+ packets.infos = malloc(stat->n_packets * sizeof(struct raw1394_iso_packet_info));
+ if(packets.infos == NULL)
+ goto out;
+
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);
+ struct raw1394_iso_packet_info *info = &packets.infos[packets.n_packets];
+
+ info->offset = handle->iso_buf_stride * handle->next_packet;
/* call handler */
disp = handle->iso_xmit_handler(handle,
- packet_data,
- &len, &tag, &sy,
- info->cycle,
+ handle->iso_buffer + info->offset,
+ &len,
+ &info->tag, &info->sy,
+ stat->xmit_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++;
+ handle->next_packet = (handle->next_packet + 1) % stat->config.buf_packets;
+ if(stat->xmit_cycle != -1)
+ stat->xmit_cycle = (stat->xmit_cycle + 1) % 8000;
+ packets.n_packets++;
if(disp == RAW1394_ISO_DEFER) {
/* queue an event so that we don't hang in the next read() */
if(ioctl(handle->fd, RAW1394_ISO_QUEUE_ACTIVITY, 0))
- return -1;
+ goto out_produce;
break;
} else if(disp == RAW1394_ISO_ERROR) {
- retval = -1;
- break;
+ goto out_produce;
}
}
- if(packets_done > 0) {
- if(ioctl(handle->fd, RAW1394_ISO_PRODUCE_CONSUME, packets_done))
- return -1;
+ /* success */
+ retval = 0;
+
+out_produce:
+ if(packets.n_packets > 0) {
+ if(ioctl(handle->fd, RAW1394_ISO_XMIT_PACKETS, &packets))
+ retval = -1;
}
-
+out_free:
+ free(packets.infos);
+out:
return retval;
}
@@ -302,7 +380,7 @@ static int _raw1394_iso_xmit_queue_packets(raw1394handle_t handle)
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)
@@ -310,10 +388,10 @@ int raw1394_iso_xmit_start(raw1394handle_t handle, int start_on_cycle, int prebu
args[0] = start_on_cycle;
args[1] = prebuffer_packets;
-
+
if(ioctl(handle->fd, RAW1394_ISO_XMIT_START, &args[0]))
return -1;
-
+
return 0;
}
@@ -324,7 +402,7 @@ void raw1394_iso_stop(raw1394handle_t handle)
{
if(!handle->iso_buffer)
return;
-
+
ioctl(handle->fd, RAW1394_ISO_STOP, 0);
}
@@ -335,7 +413,7 @@ void raw1394_iso_shutdown(raw1394handle_t handle)
{
if(handle->iso_buffer) {
raw1394_iso_stop(handle);
- munmap(handle->iso_buffer, handle->iso_buffer_bytes);
+ munmap(handle->iso_buffer, handle->iso_status.config.data_buf_size);
ioctl(handle->fd, RAW1394_ISO_SHUTDOWN, 0);
handle->iso_buffer = NULL;
}
@@ -344,31 +422,34 @@ void raw1394_iso_shutdown(raw1394handle_t handle)
static int _raw1394_iso_recv_packets(raw1394handle_t handle)
{
struct raw1394_iso_status *stat = &handle->iso_status;
- struct raw1394_iso_packet_info *info;
+ struct raw1394_iso_packets packets;
+
+ int retval = -1, packets_done = 0;
- int retval = 0, packets_done = 0;
-
if(!handle->iso_buffer)
- return -1;
+ goto out;
if(!handle->iso_recv_handler)
- return -1;
-
+ goto out;
+
+ /* ask the kernel to fill an array with packet info structs */
+ packets.n_packets = stat->n_packets;
+ packets.infos = malloc(packets.n_packets * sizeof(struct raw1394_iso_packet_info));
+ if(packets.infos == NULL)
+ goto out;
+
+ if(ioctl(handle->fd, RAW1394_ISO_RECV_PACKETS, &packets) < 0)
+ goto out_free;
+
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);
+ info = &packets.infos[packets_done];
/* call handler */
disp = handle->iso_recv_handler(handle,
- packet_data,
+ handle->iso_buffer + info->offset,
info->len, info->channel,
info->tag, info->sy,
info->cycle,
@@ -376,25 +457,29 @@ static int _raw1394_iso_recv_packets(raw1394handle_t 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) {
/* queue an event so that we don't hang in the next read() */
if(ioctl(handle->fd, RAW1394_ISO_QUEUE_ACTIVITY, 0))
- return -1;
+ goto out_consume;
break;
} else if(disp == RAW1394_ISO_ERROR) {
- retval = -1;
- break;
+ goto out_consume;
}
}
+ /* success */
+ retval = 0;
+
+out_consume:
if(packets_done > 0) {
- if(ioctl(handle->fd, RAW1394_ISO_PRODUCE_CONSUME, packets_done))
- return -1;
+ if(ioctl(handle->fd, RAW1394_ISO_RECV_RELEASE_PACKETS, packets_done))
+ retval = -1;
}
-
+out_free:
+ free(packets.infos);
+out:
return retval;
}
@@ -417,7 +502,7 @@ int _raw1394_iso_iterate(raw1394handle_t handle)
} else if(handle->iso_recv_handler) {
return _raw1394_iso_recv_packets(handle);
}
-
+
return 0;
}