summaryrefslogtreecommitdiff
path: root/libusb/os/linux_usbfs.c
diff options
context:
space:
mode:
authorDaniel Drake <dsd@gentoo.org>2008-03-25 16:24:30 +0000
committerDaniel Drake <dsd@gentoo.org>2008-03-30 22:17:34 +0100
commit211f80c9f2a4a58cd2bbf5b7751f45089c8961e7 (patch)
treeebeb072dd0d3c20883e956e2b727ffe55d019597 /libusb/os/linux_usbfs.c
parentb1ade6fca668d8aa156d5b5bf3a933f116144dc2 (diff)
downloadlibusb-211f80c9f2a4a58cd2bbf5b7751f45089c8961e7.tar.gz
Isochronous endpoint I/O
Due to variable-sized structures, this involved changing allocation mechanism. All transfers must now be allocated and freed through libusb. A synchronous function is missing, and I could do with writing a few more helper functions to simplify things.
Diffstat (limited to 'libusb/os/linux_usbfs.c')
-rw-r--r--libusb/os/linux_usbfs.c81
1 files changed, 55 insertions, 26 deletions
diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c
index f173930..0b746a2 100644
--- a/libusb/os/linux_usbfs.c
+++ b/libusb/os/linux_usbfs.c
@@ -46,10 +46,6 @@ struct linux_device_handle_priv {
int fd;
};
-struct linux_transfer_priv {
- struct usbfs_urb urb;
-};
-
static struct linux_device_priv *__device_priv(struct libusb_device *dev)
{
return (struct linux_device_priv *) dev->os_priv;
@@ -61,16 +57,6 @@ static struct linux_device_handle_priv *__device_handle_priv(
return (struct linux_device_handle_priv *) handle->os_priv;
}
-static struct linux_transfer_priv *__transfer_priv(
- struct usbi_transfer *transfer)
-{
- return (struct linux_transfer_priv *) transfer->os_priv;
-}
-
-#define TRANSFER_PRIV_GET_ITRANSFER(tpriv) \
- ((struct usbi_transfer *) \
- container_of((tpriv), struct usbi_transfer, os_priv))
-
static int check_usb_vfs(const char *dirname)
{
DIR *dir;
@@ -432,15 +418,22 @@ static void op_destroy_device(struct libusb_device *dev)
static int submit_transfer(struct usbi_transfer *itransfer)
{
- struct libusb_transfer *transfer = &itransfer->pub;
- struct usbfs_urb *urb = &__transfer_priv(itransfer)->urb;
+ struct libusb_transfer *transfer =
+ __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct usbfs_urb *urb = usbi_transfer_get_os_priv(itransfer);
struct linux_device_handle_priv *dpriv =
__device_handle_priv(transfer->dev_handle);
int to_be_transferred = transfer->length - itransfer->transferred;
int r;
urb->buffer = transfer->buffer + itransfer->transferred;
- urb->buffer_length = MIN(to_be_transferred, MAX_URB_BUFFER_LENGTH);
+ if (urb->type == USBFS_URB_TYPE_ISO) {
+ /* FIXME: iso stuff needs reworking. if a big transfer is submitted,
+ * split it up into multiple URBs. */
+ urb->buffer_length = to_be_transferred;
+ } else {
+ urb->buffer_length = MIN(to_be_transferred, MAX_URB_BUFFER_LENGTH);
+ }
/* FIXME: for requests that we have to split into multiple URBs, we should
* submit all the URBs instantly: submit, submit, submit, reap, reap, reap
@@ -457,12 +450,29 @@ static int submit_transfer(struct usbi_transfer *itransfer)
return r;
}
+static void fill_iso_packet_descriptors(struct usbfs_urb *urb,
+ struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer =
+ __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ int i;
+
+ for (i = 0; i < transfer->num_iso_packets; i++) {
+ struct usbfs_iso_packet_desc *urb_desc = &urb->iso_frame_desc[i];
+ struct libusb_iso_packet_descriptor *lib_desc =
+ &transfer->iso_packet_desc[i];
+ urb_desc->length = lib_desc->length;
+ }
+}
+
static int op_submit_transfer(struct usbi_transfer *itransfer)
{
- struct usbfs_urb *urb = &__transfer_priv(itransfer)->urb;
- struct libusb_transfer *transfer = &itransfer->pub;
+ struct usbfs_urb *urb = usbi_transfer_get_os_priv(itransfer);
+ struct libusb_transfer *transfer =
+ __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
memset(urb, 0, sizeof(*urb));
+ urb->usercontext = itransfer;
switch (transfer->endpoint_type) {
case LIBUSB_ENDPOINT_TYPE_CONTROL:
urb->type = USBFS_URB_TYPE_CONTROL;
@@ -473,6 +483,13 @@ static int op_submit_transfer(struct usbi_transfer *itransfer)
case LIBUSB_ENDPOINT_TYPE_INTERRUPT:
urb->type = USBFS_URB_TYPE_INTERRUPT;
break;
+ case LIBUSB_ENDPOINT_TYPE_ISOCHRONOUS:
+ urb->type = USBFS_URB_TYPE_ISO;
+ /* FIXME: interface for non-ASAP data? */
+ urb->flags = USBFS_URB_ISO_ASAP;
+ fill_iso_packet_descriptors(urb, itransfer);
+ urb->number_of_packets = transfer->num_iso_packets;
+ break;
default:
usbi_err("unknown endpoint type %d", transfer->endpoint_type);
return -EINVAL;
@@ -484,8 +501,9 @@ static int op_submit_transfer(struct usbi_transfer *itransfer)
static int op_cancel_transfer(struct usbi_transfer *itransfer)
{
- struct usbfs_urb *urb = &__transfer_priv(itransfer)->urb;
- struct libusb_transfer *transfer = &itransfer->pub;
+ struct usbfs_urb *urb = usbi_transfer_get_os_priv(itransfer);
+ struct libusb_transfer *transfer =
+ __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
struct linux_device_handle_priv *dpriv =
__device_handle_priv(transfer->dev_handle);
@@ -497,7 +515,6 @@ static int reap_for_handle(struct libusb_device_handle *handle)
struct linux_device_handle_priv *hpriv = __device_handle_priv(handle);
int r;
struct usbfs_urb *urb;
- struct linux_transfer_priv *tpriv;
struct usbi_transfer *itransfer;
struct libusb_transfer *transfer;
int trf_requested;
@@ -511,9 +528,8 @@ static int reap_for_handle(struct libusb_device_handle *handle)
return r;
}
- tpriv = container_of(urb, struct linux_transfer_priv, urb);
- itransfer = TRANSFER_PRIV_GET_ITRANSFER(tpriv);
- transfer = &itransfer->pub;
+ itransfer = urb->usercontext;
+ transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
usbi_dbg("urb type=%d status=%d transferred=%d", urb->type, urb->status,
urb->actual_length);
@@ -528,6 +544,18 @@ static int reap_for_handle(struct libusb_device_handle *handle)
if (urb->status != 0)
usbi_warn("unrecognised urb status %d", urb->status);
+ /* copy isochronous packet results back */
+ if (transfer->endpoint_type == LIBUSB_ENDPOINT_TYPE_ISOCHRONOUS) {
+ int i;
+ for (i = 0; i < urb->number_of_packets; i++) {
+ struct usbfs_iso_packet_desc *urb_desc = &urb->iso_frame_desc[i];
+ struct libusb_iso_packet_descriptor *lib_desc =
+ &transfer->iso_packet_desc[i];
+ lib_desc->status = urb_desc->status;
+ lib_desc->actual_length = urb_desc->actual_length;
+ }
+ }
+
/* determine how much data was asked for */
length = transfer->length;
if (transfer->endpoint_type == LIBUSB_ENDPOINT_TYPE_CONTROL)
@@ -598,6 +626,7 @@ const struct usbi_os_backend linux_usbfs_backend = {
.device_priv_size = sizeof(struct linux_device_priv),
.device_handle_priv_size = sizeof(struct linux_device_handle_priv),
- .transfer_priv_size = sizeof(struct linux_transfer_priv),
+ .transfer_priv_size = sizeof(struct usbfs_urb),
+ .add_iso_packet_size = sizeof(struct usbfs_iso_packet_desc),
};