diff --git a/src/Makefile.am b/src/Makefile.am index b6a0140..ea1acd1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,4 +18,4 @@ libraw1394_la_SOURCES = \ raw1394_private.h # headers to be installed -pkginclude_HEADERS = raw1394.h csr.h ieee1394.h kernel-raw1394.h +pkginclude_HEADERS = raw1394.h csr.h ieee1394.h diff --git a/src/eventloop.c b/src/eventloop.c index 4eb83b6..c360a63 100644 --- a/src/eventloop.c +++ b/src/eventloop.c @@ -94,9 +94,15 @@ int raw1394_loop_iterate(struct raw1394_handle *handle) int2ptr(req->recvb)); } break; + case RAW1394_REQ_ECHO: retval=req->misc; break; + + case RAW1394_REQ_RAWISO_ACTIVITY: + retval = _raw1394_iso_iterate(handle); + break; + default: if (handle->tag_handler) { retval = handle->tag_handler(handle, req->tag, 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 #include #include +#include +#include +#include #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; +} + diff --git a/src/kernel-raw1394.h b/src/kernel-raw1394.h index 1fe55d0..c6e5c59 100644 --- a/src/kernel-raw1394.h +++ b/src/kernel-raw1394.h @@ -40,6 +40,7 @@ #define RAW1394_REQ_ISO_RECEIVE 10001 #define RAW1394_REQ_FCP_REQUEST 10002 #define RAW1394_REQ_ARM 10003 +#define RAW1394_REQ_RAWISO_ACTIVITY 10004 /* error codes */ #define RAW1394_ERROR_NONE 0 @@ -118,6 +119,64 @@ 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 + +/* per-packet metadata embedded in the ringbuffer */ +/* must be identical to hpsb_iso_packet_info in iso.h! */ +struct raw1394_iso_packet_info { + unsigned short len; + unsigned short cycle; + unsigned char channel; /* recv only */ + unsigned char tag; + unsigned char sy; +}; + +struct raw1394_iso_config { + unsigned int buf_packets; + unsigned int max_packet_size; + int channel; + int speed; /* xmit only */ + int irq_interval; +}; + +/* argument to RAW1394_ISO_XMIT/RECV_INIT and RAW1394_ISO_GET_STATUS */ +struct raw1394_iso_status { + /* current settings */ + struct raw1394_iso_config config; + + /* byte offset between successive packets in the buffer */ + int buf_stride; + + /* byte offset of data payload within each packet */ + int packet_data_offset; + + /* byte offset of struct iso_packet_info within each packet */ + int packet_info_offset; + + /* index of next packet to fill with data (ISO transmission) + or next packet containing data recieved (ISO reception) */ + unsigned int first_packet; + + /* number of packets waiting to be filled with data (ISO transmission) + or containing data received (ISO reception) */ + unsigned int n_packets; + + /* approximate number of packets dropped due to overflow or + underflow of the packet buffer (a value of zero guarantees + that no packets have been dropped) */ + unsigned int overflows; +}; + #ifdef __KERNEL__ struct iso_block_store { @@ -126,6 +185,10 @@ struct iso_block_store { quadlet_t data[0]; }; +enum raw1394_iso_state { RAW1394_ISO_INACTIVE = 0, + RAW1394_ISO_RECV = 1, + RAW1394_ISO_XMIT = 2 }; + struct file_info { struct list_head list; @@ -144,11 +207,16 @@ struct file_info { u8 *fcp_buffer; + /* old ISO API */ u64 listen_channels; quadlet_t *iso_buffer; size_t iso_buffer_length; u8 notification; /* (busreset-notification) RAW1394_NOTIFY_OFF/ON */ + + /* new rawiso API */ + enum raw1394_iso_state iso_state; + struct hpsb_iso *iso_handle; }; struct arm_addr { @@ -166,7 +234,7 @@ struct pending_request { struct list_head list; struct file_info *file_info; struct hpsb_packet *packet; - struct tq_struct tq; +/* struct tq_struct tq; */ struct iso_block_store *ibs; quadlet_t *data; int free_data; diff --git a/src/main.c b/src/main.c index 7bb847a..b1c69f8 100644 --- a/src/main.c +++ b/src/main.c @@ -149,6 +149,7 @@ struct raw1394_handle *raw1394_new_handle(void) handle->tag_handler = tag_handler_default; handle->arm_tag_handler = arm_tag_handler_default; memset(handle->iso_handler, 0, sizeof(handle->iso_handler)); + handle->iso_buffer = NULL; return handle; } @@ -162,10 +163,13 @@ struct raw1394_handle *raw1394_new_handle(void) **/ void raw1394_destroy_handle(struct raw1394_handle *handle) { - if (handle) { - close(handle->fd); - free(handle); - } + if (handle) { + if(handle->iso_buffer) { + raw1394_iso_shutdown(handle); + } + close(handle->fd); + free(handle); + } } /** diff --git a/src/raw1394.h b/src/raw1394.h index c1f7b16..4c317bc 100644 --- a/src/raw1394.h +++ b/src/raw1394.h @@ -47,6 +47,66 @@ typedef struct arm_request_response { struct arm_response *response; } *arm_request_response_t; +/* new ISO API */ + +enum raw1394_iso_speed { + RAW1394_ISO_SPEED_100 = 0, + RAW1394_ISO_SPEED_200 = 1, + RAW1394_ISO_SPEED_400 = 2, +}; + +/* return values from xmit/recv handlers */ + +enum raw1394_iso_disposition { + /* continue on to the next packet */ + RAW1394_ISO_OK = 0, + + /* no error, but return from raw1394_loop_iterate() immediately */ + RAW1394_ISO_DEFER = 1, + + /* return from raw1394_loop_iterate() immediately, which will return an error */ + RAW1394_ISO_ERROR = 2, +}; + +typedef int (*raw1394_iso_xmit_handler_t)(raw1394handle_t, + unsigned char *data, + unsigned int *len, + unsigned char *tag, + unsigned char *sy, + unsigned int cycle, + unsigned int dropped); + +typedef int (*raw1394_iso_recv_handler_t)(raw1394handle_t, + unsigned char *data, + unsigned int len, + unsigned char channel, + unsigned char tag, + unsigned char sy, + unsigned int cycle, + unsigned int dropped); + +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); + +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); + + +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); + #ifdef __cplusplus extern "C" { #endif diff --git a/src/raw1394_private.h b/src/raw1394_private.h index 733feae..9c0b345 100644 --- a/src/raw1394_private.h +++ b/src/raw1394_private.h @@ -23,6 +23,20 @@ struct raw1394_handle { fcp_handler_t fcp_handler; iso_handler_t iso_handler[64]; + /* new ISO API */ + + /* memory mapping of the DMA buffer */ + unsigned char *iso_buffer; + unsigned long iso_buffer_bytes; + + /* status buffer, updated from _raw1394_iso_iterate() */ + struct raw1394_iso_status iso_status; + unsigned int iso_packets_dropped; + + /* 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 */ }; @@ -33,6 +47,7 @@ struct sync_cb_data { }; int _raw1394_sync_cb(struct raw1394_handle*, struct sync_cb_data*, int); +int _raw1394_iso_iterate(raw1394handle_t handle); #define CLEAR_REQ(reqp) memset((reqp), 0, sizeof(struct raw1394_request))