From 2ecf31c96d7a1dac61188c247ca7fe6a65e6b578 Mon Sep 17 00:00:00 2001 From: dmaas Date: Wed, 15 Jan 2003 13:14:47 +0000 Subject: [PATCH] add iso_xmit_sync() and iso_xmit_write(); clean up iso handling a bit git-svn-id: svn://svn.linux1394.org/libraw1394/trunk@102 53a565d1-3bb7-0310-b661-cf11e63c67ab --- src/iso.c | 175 +++++++++++++++++++++++++++++++++--------- src/kernel-raw1394.h | 5 +- src/main.c | 3 +- src/raw1394.h | 15 ++++ src/raw1394_private.h | 2 + 5 files changed, 161 insertions(+), 39 deletions(-) diff --git a/src/iso.c b/src/iso.c index de9881c..842f6ba 100644 --- a/src/iso.c +++ b/src/iso.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -118,7 +119,7 @@ static int do_iso_init(raw1394handle_t handle, unsigned int bufsize, stride; /* already initialized? */ - if(handle->iso_buffer) + if(handle->iso_mode != ISO_INACTIVE) return -1; /* choose a power-of-two stride for the packet data buffer, @@ -160,6 +161,8 @@ static int do_iso_init(raw1394handle_t handle, handle->iso_xmit_handler = NULL; handle->iso_recv_handler = NULL; + handle->iso_state = ISO_STOP; + return 0; } @@ -186,6 +189,7 @@ int raw1394_iso_xmit_init(raw1394handle_t handle, irq_interval, RAW1394_ISO_XMIT_INIT)) return -1; + handle->iso_mode = ISO_XMIT; handle->iso_xmit_handler = handler; handle->next_packet = 0; @@ -215,6 +219,7 @@ int raw1394_iso_recv_init(raw1394handle_t handle, irq_interval, RAW1394_ISO_RECV_INIT)) return -1; + handle->iso_mode = ISO_RECV; handle->iso_recv_handler = handler; return 0; } @@ -240,6 +245,7 @@ int raw1394_iso_multichannel_recv_init(raw1394handle_t handle, irq_interval, RAW1394_ISO_RECV_INIT)) return -1; + handle->iso_mode = ISO_RECV; handle->iso_recv_handler = handler; return 0; } @@ -249,10 +255,10 @@ int raw1394_iso_multichannel_recv_init(raw1394handle_t handle, **/ int raw1394_iso_recv_listen_channel(raw1394handle_t handle, unsigned char channel) { - if(!handle->iso_buffer) - return -1; - if(!handle->iso_recv_handler) + if(handle->iso_mode != ISO_RECV) { + errno = EINVAL; return -1; + } return ioctl(handle->fd, RAW1394_ISO_RECV_LISTEN_CHANNEL, channel); } @@ -262,10 +268,10 @@ int raw1394_iso_recv_listen_channel(raw1394handle_t handle, unsigned char channe **/ int raw1394_iso_recv_unlisten_channel(raw1394handle_t handle, unsigned char channel) { - if(!handle->iso_buffer) - return -1; - if(!handle->iso_recv_handler) + if(handle->iso_mode != ISO_RECV) { + errno = EINVAL; return -1; + } return ioctl(handle->fd, RAW1394_ISO_RECV_UNLISTEN_CHANNEL, channel); } @@ -279,10 +285,10 @@ int raw1394_iso_recv_unlisten_channel(raw1394handle_t handle, unsigned char chan **/ 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) + if(handle->iso_mode != ISO_RECV) { + errno = EINVAL; return -1; + } return ioctl(handle->fd, RAW1394_ISO_RECV_SET_CHANNEL_MASK, (void*) &mask); } @@ -297,10 +303,10 @@ int raw1394_iso_recv_start(raw1394handle_t handle, int start_on_cycle, int tag_m { int args[3]; - if(!handle->iso_buffer) - return -1; - if(!handle->iso_recv_handler) + if(handle->iso_mode != ISO_RECV) { + errno = EINVAL; return -1; + } args[0] = start_on_cycle; args[1] = tag_mask; @@ -309,6 +315,7 @@ int raw1394_iso_recv_start(raw1394handle_t handle, int start_on_cycle, int tag_m if(ioctl(handle->fd, RAW1394_ISO_RECV_START, &args[0])) return -1; + handle->iso_state = ISO_GO; return 0; } @@ -318,12 +325,12 @@ static int _raw1394_iso_xmit_queue_packets(raw1394handle_t handle) struct raw1394_iso_status *stat = &handle->iso_status; struct raw1394_iso_packets packets; int retval = -1; + int stop_sync = 0; - if(!handle->iso_buffer) - goto out; - - if(!handle->iso_xmit_handler) + if(handle->iso_mode != ISO_XMIT) { + errno = EINVAL; goto out; + } /* we could potentially send up to stat->n_packets packets */ packets.n_packets = 0; @@ -360,6 +367,12 @@ static int _raw1394_iso_xmit_queue_packets(raw1394handle_t handle) if(ioctl(handle->fd, RAW1394_ISO_QUEUE_ACTIVITY, 0)) goto out_produce; break; + } else if(disp == RAW1394_ISO_STOP) { + stop_sync = 1; + break; + } else if(disp == RAW1394_ISO_STOP_NOSYNC) { + raw1394_iso_stop(handle); + break; } else if(disp == RAW1394_ISO_ERROR) { goto out_produce; } @@ -375,10 +388,70 @@ out_produce: } out_free: free(packets.infos); -out: +out: + if(stop_sync) { + if(raw1394_iso_xmit_sync(handle)) + return -1; + raw1394_iso_stop(handle); + } + return retval; } +/** + * raw1394_iso_xmit_write - alternative blocking-write API for ISO transmission + * @data: pointer to packet data buffer + * @len: length of packet, in bytes + * @tag: tag field + * @sy: sync field + **/ +int raw1394_iso_xmit_write(raw1394handle_t handle, unsigned char *data, unsigned int len, + unsigned char tag, unsigned char sy) +{ + struct raw1394_iso_status *stat = &handle->iso_status; + struct raw1394_iso_packets packets; + struct raw1394_iso_packet_info info; + + if(handle->iso_mode != ISO_XMIT || handle->iso_xmit_handler != NULL) { + errno = EINVAL; + return -1; + } + + /* wait until buffer space is available */ + while(handle->iso_status.n_packets == 0) { + /* if the file descriptor has been set non-blocking, + return immediately */ + if(fcntl(handle->fd, F_GETFL) & O_NONBLOCK) { + errno = EAGAIN; + return -1; + } + + if(raw1394_loop_iterate(handle)) { + return -1; + } + } + + /* copy the data to the packet buffer */ + info.offset = handle->next_packet * handle->iso_buf_stride; + info.len = len; + info.tag = tag; + info.sy = sy; + + memcpy(handle->iso_buffer + info.offset, data, len); + + packets.n_packets = 1; + packets.infos = &info; + + if(ioctl(handle->fd, RAW1394_ISO_XMIT_PACKETS, &packets)) + return -1; + + stat->n_packets--; + handle->next_packet = (handle->next_packet + 1) % stat->config.buf_packets; + if(stat->xmit_cycle != -1) + stat->xmit_cycle = (stat->xmit_cycle + 1) % 8000; + + return 0; +} /** * raw1394_iso_xmit_start - begin isochronous transmission @@ -389,10 +462,10 @@ int raw1394_iso_xmit_start(raw1394handle_t handle, int start_on_cycle, int prebu { int args[2]; - if(!handle->iso_buffer) - return -1; - if(!handle->iso_xmit_handler) + if(handle->iso_mode != ISO_XMIT) { + errno = EINVAL; return -1; + } args[0] = start_on_cycle; args[1] = prebuffer_packets; @@ -400,18 +473,33 @@ int raw1394_iso_xmit_start(raw1394handle_t handle, int start_on_cycle, int prebu if(ioctl(handle->fd, RAW1394_ISO_XMIT_START, &args[0])) return -1; + handle->iso_state = ISO_GO; return 0; } +/** + * raw1394_iso_xmit_sync - wait until all queued packets have been sent + **/ +int raw1394_iso_xmit_sync(raw1394handle_t handle) +{ + if(handle->iso_mode != ISO_XMIT) { + errno = EINVAL; + return -1; + } + return ioctl(handle->fd, RAW1394_ISO_XMIT_SYNC, 0); +} + /** * raw1394_iso_stop - halt isochronous transmission or reception **/ void raw1394_iso_stop(raw1394handle_t handle) { - if(!handle->iso_buffer) + if(handle->iso_mode == ISO_INACTIVE) { return; + } - ioctl(handle->fd, RAW1394_ISO_STOP, 0); + ioctl(handle->fd, RAW1394_ISO_XMIT_RECV_STOP, 0); + handle->iso_state = ISO_STOP; } /** @@ -420,11 +508,16 @@ void raw1394_iso_stop(raw1394handle_t handle) void raw1394_iso_shutdown(raw1394handle_t handle) { if(handle->iso_buffer) { - raw1394_iso_stop(handle); munmap(handle->iso_buffer, handle->iso_status.config.data_buf_size); - ioctl(handle->fd, RAW1394_ISO_SHUTDOWN, 0); handle->iso_buffer = NULL; } + + if(handle->iso_mode != ISO_INACTIVE) { + raw1394_iso_stop(handle); + ioctl(handle->fd, RAW1394_ISO_SHUTDOWN, 0); + } + + handle->iso_mode = ISO_INACTIVE; } static int _raw1394_iso_recv_packets(raw1394handle_t handle) @@ -434,12 +527,11 @@ static int _raw1394_iso_recv_packets(raw1394handle_t handle) int retval = -1, packets_done = 0; - if(!handle->iso_buffer) - goto out; - - if(!handle->iso_recv_handler) - goto out; - + if(handle->iso_mode != ISO_RECV) { + errno = EINVAL; + return -1; + } + /* 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)); @@ -472,6 +564,9 @@ static int _raw1394_iso_recv_packets(raw1394handle_t handle) if(ioctl(handle->fd, RAW1394_ISO_QUEUE_ACTIVITY, 0)) goto out_consume; break; + } else if(disp == RAW1394_ISO_STOP || disp == RAW1394_ISO_STOP_NOSYNC) { + raw1394_iso_stop(handle); + break; } else if(disp == RAW1394_ISO_ERROR) { goto out_consume; } @@ -496,7 +591,7 @@ int _raw1394_iso_iterate(raw1394handle_t handle) { int err; - if(!handle->iso_buffer) + if(handle->iso_mode == ISO_INACTIVE) return 0; err = ioctl(handle->fd, RAW1394_ISO_GET_STATUS, &handle->iso_status); @@ -505,10 +600,18 @@ int _raw1394_iso_iterate(raw1394handle_t handle) 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); + if(handle->iso_state == ISO_GO) { + if(handle->iso_mode == ISO_XMIT) { + if(handle->iso_xmit_handler) { + return _raw1394_iso_xmit_queue_packets(handle); + } + } + + if(handle->iso_mode == ISO_RECV) { + if(handle->iso_recv_handler) { + return _raw1394_iso_recv_packets(handle); + } + } } return 0; diff --git a/src/kernel-raw1394.h b/src/kernel-raw1394.h index f19afd6..ed636aa 100644 --- a/src/kernel-raw1394.h +++ b/src/kernel-raw1394.h @@ -122,7 +122,7 @@ typedef struct arm_request_response { #define RAW1394_ISO_RECV_INIT 2 /* arg: raw1394_iso_status* */ #define RAW1394_ISO_RECV_START 3 /* arg: int[3], { starting cycle, tag, sync } */ #define RAW1394_ISO_XMIT_START 8 /* arg: int[2], { starting cycle, prebuffer } */ -#define RAW1394_ISO_STOP 4 +#define RAW1394_ISO_XMIT_RECV_STOP 4 #define RAW1394_ISO_GET_STATUS 5 /* arg: raw1394_iso_status* */ #define RAW1394_ISO_PRODUCE_CONSUME 6 /* no longer used */ #define RAW1394_ISO_SHUTDOWN 7 @@ -133,7 +133,8 @@ typedef struct arm_request_response { #define RAW1394_ISO_RECV_PACKETS 13 /* arg: struct raw1394_iso_packets* */ #define RAW1394_ISO_RECV_RELEASE_PACKETS 14 /* arg: int n_packets */ #define RAW1394_ISO_XMIT_PACKETS 15 /* arg: struct raw1394_iso_packets* */ - +#define RAW1394_ISO_XMIT_SYNC 16 + /* per-packet metadata embedded in the ringbuffer */ /* must be identical to hpsb_iso_packet_info in iso.h! */ struct raw1394_iso_packet_info { diff --git a/src/main.c b/src/main.c index 1c6f190..452d92f 100644 --- a/src/main.c +++ b/src/main.c @@ -150,6 +150,7 @@ struct raw1394_handle *raw1394_new_handle(void) handle->arm_tag_handler = arm_tag_handler_default; memset(handle->iso_handler, 0, sizeof(handle->iso_handler)); handle->iso_buffer = NULL; + handle->iso_mode = ISO_INACTIVE; return handle; } @@ -164,7 +165,7 @@ struct raw1394_handle *raw1394_new_handle(void) void raw1394_destroy_handle(struct raw1394_handle *handle) { if (handle) { - if(handle->iso_buffer) { + if(handle->iso_mode != ISO_INACTIVE) { raw1394_iso_shutdown(handle); } close(handle->fd); diff --git a/src/raw1394.h b/src/raw1394.h index d0b0794..15401d2 100644 --- a/src/raw1394.h +++ b/src/raw1394.h @@ -66,6 +66,12 @@ enum raw1394_iso_disposition { /* return from raw1394_loop_iterate() immediately, which will return an error */ RAW1394_ISO_ERROR = 2, + + /* return from raw1394_loop_iterate() immediately, and stop receiving packets */ + RAW1394_ISO_STOP = 3, + + /* (transmission only) - like ISO_STOP, but don't wait for the buffer to empty */ + RAW1394_ISO_STOP_NOSYNC = 4, }; #ifdef __cplusplus @@ -120,6 +126,15 @@ int raw1394_iso_recv_set_channel_mask(raw1394handle_t handle, u_int64_t mask); int raw1394_iso_xmit_start(raw1394handle_t handle, int start_on_cycle, int prebuffer_packets); int raw1394_iso_recv_start(raw1394handle_t handle, int start_on_cycle, int tag_mask, int sync); +/* write() style API - do NOT use this if you have set an xmit_handler + * if buffer is full, waits for more space UNLESS the file descriptor is + * set to non-blocking, in which case xmit_write() will return -1 with errno = EAGAIN */ +int raw1394_iso_xmit_write(raw1394handle_t handle, unsigned char *data, unsigned int len, + unsigned char tag, unsigned char sy); + +/* wait until all queued packets have been sent */ +int raw1394_iso_xmit_sync(raw1394handle_t handle); + void raw1394_iso_stop(raw1394handle_t handle); void raw1394_iso_shutdown(raw1394handle_t handle); diff --git a/src/raw1394_private.h b/src/raw1394_private.h index 98e073d..c873a80 100644 --- a/src/raw1394_private.h +++ b/src/raw1394_private.h @@ -27,6 +27,8 @@ struct raw1394_handle { /* memory mapping of the DMA buffer */ unsigned char *iso_buffer; + enum { ISO_INACTIVE, ISO_XMIT, ISO_RECV } iso_mode; + enum { ISO_STOP, ISO_GO } iso_state; /* iso XMIT only: */ unsigned int iso_buf_stride; /* offset between successive packets */