From 385413d23e8efab86d391bfa09776bfbdbab30ff Mon Sep 17 00:00:00 2001 From: dmaas Date: Tue, 24 Dec 2002 03:01:11 +0000 Subject: [PATCH] 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 --- src/iso.c | 257 ++++++++++++++++++++++++++++-------------- src/kernel-raw1394.h | 69 +++++++----- src/raw1394.h | 24 +++- src/raw1394_private.h | 9 +- 4 files changed, 236 insertions(+), 123 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)) + + if(ioctl(handle->fd, cmd, &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, + /* (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,17 +207,86 @@ 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; return 0; } +/** + * 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; } diff --git a/src/kernel-raw1394.h b/src/kernel-raw1394.h index 428070c..f3b5716 100644 --- a/src/kernel-raw1394.h +++ b/src/kernel-raw1394.h @@ -118,31 +118,53 @@ typedef struct arm_request_response { /* rawiso API */ /* ioctls */ -#define RAW1394_ISO_XMIT_INIT 1 /* arg: raw1394_iso_status* */ -#define RAW1394_ISO_RECV_INIT 2 /* arg: raw1394_iso_status* */ -#define RAW1394_ISO_RECV_START 3 /* arg: int, starting cycle */ -#define RAW1394_ISO_XMIT_START 8 /* arg: int[2], { starting cycle, prebuffer } */ -#define RAW1394_ISO_STOP 4 -#define RAW1394_ISO_GET_STATUS 5 /* arg: raw1394_iso_status* */ -#define RAW1394_ISO_PRODUCE_CONSUME 6 /* arg: int, # of packets */ -#define RAW1394_ISO_SHUTDOWN 7 -#define RAW1394_ISO_QUEUE_ACTIVITY 9 - +#define RAW1394_ISO_XMIT_INIT 1 /* arg: raw1394_iso_status* */ +#define RAW1394_ISO_RECV_INIT 2 /* arg: raw1394_iso_status* */ +#define RAW1394_ISO_RECV_START 3 /* arg: int, starting cycle */ +#define RAW1394_ISO_XMIT_START 8 /* arg: int[2], { starting cycle, prebuffer } */ +#define RAW1394_ISO_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 +#define RAW1394_ISO_QUEUE_ACTIVITY 9 +#define RAW1394_ISO_RECV_LISTEN_CHANNEL 10 /* arg: channel number */ +#define RAW1394_ISO_RECV_UNLISTEN_CHANNEL 11 /* arg: channel number */ +#define RAW1394_ISO_RECV_SET_CHANNEL_MASK 12 /* arg: pointer to 64-bit mask */ +#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* */ + /* per-packet metadata embedded in the ringbuffer */ /* must be identical to hpsb_iso_packet_info in iso.h! */ struct raw1394_iso_packet_info { + __u32 offset; __u16 len; - __u16 cycle; + __u16 cycle; /* recv only */ __u8 channel; /* recv only */ __u8 tag; - __u8 sy; + __u8 sy; +}; + +/* argument for RAW1394_ISO_RECV/XMIT_PACKETS ioctls */ +struct raw1394_iso_packets { + __u32 n_packets; + struct raw1394_iso_packet_info *infos; }; struct raw1394_iso_config { + /* size of packet data buffer, in bytes (will be rounded up to PAGE_SIZE) */ + __u32 data_buf_size; + + /* # of packets to buffer */ __u32 buf_packets; - __u32 max_packet_size; - __u32 channel; - __u32 speed; /* xmit only */ + + /* iso channel (set to -1 for multi-channel recv) */ + __s32 channel; + + /* xmit only - iso transmission speed */ + __u8 speed; + + /* max. latency of buffer, in packets (-1 if you don't care) */ __s32 irq_interval; }; @@ -150,19 +172,6 @@ struct raw1394_iso_config { struct raw1394_iso_status { /* current settings */ struct raw1394_iso_config config; - - /* byte offset between successive packets in the buffer */ - __s32 buf_stride; - - /* byte offset of data payload within each packet */ - __s32 packet_data_offset; - - /* byte offset of struct iso_packet_info within each packet */ - __s32 packet_info_offset; - - /* index of next packet to fill with data (ISO transmission) - or next packet containing data recieved (ISO reception) */ - __u32 first_packet; /* number of packets waiting to be filled with data (ISO transmission) or containing data received (ISO reception) */ @@ -172,6 +181,10 @@ struct raw1394_iso_status { underflow of the packet buffer (a value of zero guarantees that no packets have been dropped) */ __u32 overflows; + + /* cycle number at which next packet will be transmitted; + -1 if not known */ + __s16 xmit_cycle; }; #endif /* IEEE1394_RAW1394_H */ diff --git a/src/raw1394.h b/src/raw1394.h index 7dc567d..c3e8c04 100644 --- a/src/raw1394.h +++ b/src/raw1394.h @@ -55,7 +55,7 @@ enum raw1394_iso_speed { RAW1394_ISO_SPEED_400 = 2, }; -/* return values from xmit/recv handlers */ +/* return values from isochronous xmit/recv handlers */ enum raw1394_iso_disposition { /* continue on to the next packet */ @@ -72,14 +72,16 @@ enum raw1394_iso_disposition { extern "C" { #endif +/* handlers for transmitting/receiving isochronous packets */ + typedef enum raw1394_iso_disposition (*raw1394_iso_xmit_handler_t)(raw1394handle_t, unsigned char *data, unsigned int *len, unsigned char *tag, unsigned char *sy, - unsigned int cycle, + int cycle, /* -1 if unknown */ unsigned int dropped); - + typedef enum raw1394_iso_disposition (*raw1394_iso_recv_handler_t)(raw1394handle_t, unsigned char *data, unsigned int len, @@ -93,7 +95,7 @@ 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); @@ -101,13 +103,23 @@ 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); +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); + +/* listen/unlisten on a specific channel (multi-channel mode ONLY) */ +int raw1394_iso_recv_listen_channel(raw1394handle_t handle, unsigned char channel); +int raw1394_iso_recv_unlisten_channel(raw1394handle_t handle, unsigned char channel); +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); - + 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 9c0b345..98e073d 100644 --- a/src/raw1394_private.h +++ b/src/raw1394_private.h @@ -27,8 +27,11 @@ struct raw1394_handle { /* memory mapping of the DMA buffer */ unsigned char *iso_buffer; - unsigned long iso_buffer_bytes; - + + /* iso XMIT only: */ + unsigned int iso_buf_stride; /* offset between successive packets */ + unsigned int next_packet; /* index of next packet to be transmitted */ + /* status buffer, updated from _raw1394_iso_iterate() */ struct raw1394_iso_status iso_status; unsigned int iso_packets_dropped; @@ -36,7 +39,7 @@ struct raw1394_handle { /* user-supplied handlers */ raw1394_iso_xmit_handler_t iso_xmit_handler; raw1394_iso_recv_handler_t iso_recv_handler; - + struct raw1394_request req; quadlet_t buffer[HBUF_SIZE/4]; /* 2048 */ };