diff options
| author | 2002-12-24 03:01:11 +0000 | |
|---|---|---|
| committer | 2002-12-24 03:01:11 +0000 | |
| commit | 385413d23e8efab86d391bfa09776bfbdbab30ff (patch) | |
| tree | 84b9025faa6d9103820a286aee87caa04f2c64b6 /src/iso.c | |
| parent | oops, 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.c | 257 |
1 files changed, 171 insertions, 86 deletions
@@ -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; } |
