Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ca6fe5fd authored by Mike Lockwood's avatar Mike Lockwood Committed by Android Git Automerger
Browse files

am e533c5f1: libusbhost: Support for multiple pending requests on a single endpoint

* commit 'e533c5f1':
  libusbhost: Support for multiple pending requests on a single endpoint
parents 0fb9a1cf e533c5f1
Loading
Loading
Loading
Loading
+23 −27
Original line number Diff line number Diff line
@@ -39,6 +39,17 @@ struct usb_descriptor_iter {
    unsigned char*  curr_desc;
};

struct usb_request
{
    struct usb_device *dev;
    void* buffer;
    int buffer_length;
    int actual_length;
    int max_packet_size;
    void *private_data; /* struct usbdevfs_urb* */
    void *client_data;  /* free for use by client */
};

/* Callback for notification when new USB devices are attached.
 * Return true to exit from usb_host_run.
 */
@@ -170,38 +181,23 @@ int usb_device_claim_interface(struct usb_device *device, unsigned int interface
/* Releases the specified interface of a USB device */
int usb_device_release_interface(struct usb_device *device, unsigned int interface);

/* Creates a new usb_request. */
struct usb_request *usb_request_new(struct usb_device *dev,
        const struct usb_endpoint_descriptor *ep_desc);

/* Creates a new usb_endpoint for the specified endpoint of a USB device.
 * This can be used to read or write data across the endpoint.
 */
struct usb_endpoint *usb_endpoint_open(struct usb_device *dev,
                const struct usb_endpoint_descriptor *desc);

/* Releases all resources associated with the endpoint */
void usb_endpoint_close(struct usb_endpoint *ep);
/* Releases all resources associated with the request */
void usb_request_free(struct usb_request *req);

/* Begins a read or write operation on the specified endpoint */
int usb_endpoint_queue(struct usb_endpoint *ep, void *data, int len);
/* Submits a read or write request on the specified device */
int usb_request_queue(struct usb_request *req);

 /* Waits for the results of a previous usb_endpoint_queue operation on the
  * specified endpoint.  Returns number of bytes transferred, or a negative
  * value for error.
 /* Waits for the results of a previous usb_request_queue operation.
  * Returns a usb_request, or NULL for error.
  */
int usb_endpoint_wait(struct usb_device *device, int *out_ep_num);
struct usb_request *usb_request_wait(struct usb_device *dev);

/* Cancels a pending usb_endpoint_queue() operation on an endpoint. */
int usb_endpoint_cancel(struct usb_endpoint *ep);

/* Returns the usb_device for the given endpoint */
struct usb_device *usb_endpoint_get_device(struct usb_endpoint *ep);

/* Returns the endpoint address for the given endpoint */
int usb_endpoint_number(struct usb_endpoint *ep);

/* Returns the maximum packet size for the given endpoint.
 * For bulk endpoints this should be 512 for highspeed or 64 for fullspeed.
 */
int usb_endpoint_max_packet(struct usb_endpoint *ep);
/* Cancels a pending usb_request_queue() operation. */
int usb_request_cancel(struct usb_request *req);

#ifdef __cplusplus
}
+3 −0
Original line number Diff line number Diff line
@@ -40,4 +40,7 @@ LOCAL_SRC_FILES := usbhost.c

LOCAL_CFLAGS := -g -DUSE_LIBLOG

# needed for logcat
LOCAL_SHARED_LIBRARIES := libcutils

include $(BUILD_SHARED_LIBRARY)
+49 −56
Original line number Diff line number Diff line
@@ -45,12 +45,6 @@
#include <pthread.h>

#include <linux/usbdevice_fs.h>
#include <linux/version.h>
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
#include <linux/usb/ch9.h>
#else
#include <linux/usb_ch9.h>
#endif
#include <asm/byteorder.h>

#include "usbhost/usbhost.h"
@@ -72,13 +66,6 @@ struct usb_device {
    int writeable;
};

struct usb_endpoint
{
    struct usb_device *dev;
    struct usb_endpoint_descriptor  desc;
    struct usbdevfs_urb urb;
};

static inline int badname(const char *name)
{
    while(*name) {
@@ -465,83 +452,89 @@ int usb_device_release_interface(struct usb_device *device, unsigned int interfa
    return ioctl(device->fd, USBDEVFS_RELEASEINTERFACE, &interface);
}

struct usb_endpoint *usb_endpoint_open(struct usb_device *dev,
        const struct usb_endpoint_descriptor *desc)
struct usb_request *usb_request_new(struct usb_device *dev,
        const struct usb_endpoint_descriptor *ep_desc)
{
    struct usb_endpoint *ep = calloc(1, sizeof(struct usb_endpoint));
    memcpy(&ep->desc, desc, sizeof(ep->desc));
    ep->dev = dev;
    return ep;
    struct usbdevfs_urb *urb = calloc(1, sizeof(struct usbdevfs_urb));
    if (!urb)
        return NULL;

    if ((ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)
        urb->type = USBDEVFS_URB_TYPE_BULK;
    else if ((ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)
        urb->type = USBDEVFS_URB_TYPE_INTERRUPT;
    else {
        D("Unsupported endpoint type %d", ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
        free(urb);
        return NULL;
    }
    urb->endpoint = ep_desc->bEndpointAddress;

void usb_endpoint_close(struct usb_endpoint *ep)
    struct usb_request *req = calloc(1, sizeof(struct usb_request));
    if (!req) {
        free(urb);
        return NULL;
    }

    req->dev = dev;
    req->max_packet_size = __le16_to_cpu(ep_desc->wMaxPacketSize);
    req->private_data = urb;
    urb->usercontext = req;

    return req;
}

void usb_request_free(struct usb_request *req)
{
    // cancel IO here?
    free(ep);
    free(req->private_data);
    free(req);
}

int usb_endpoint_queue(struct usb_endpoint *ep, void *data, int len)
int usb_request_queue(struct usb_request *req)
{
    struct usbdevfs_urb *urb = &ep->urb;
    struct usbdevfs_urb *urb = (struct usbdevfs_urb*)req->private_data;
    int res;

    D("usb_endpoint_queue\n");
    memset(urb, 0, sizeof(*urb));
    urb->type = USBDEVFS_URB_TYPE_BULK;
    urb->endpoint = ep->desc.bEndpointAddress;
    urb->status = -1;
    urb->buffer = data;
    urb->buffer_length = len;
    urb->buffer = req->buffer;
    urb->buffer_length = req->buffer_length;

    do {
        res = ioctl(ep->dev->fd, USBDEVFS_SUBMITURB, urb);
        res = ioctl(req->dev->fd, USBDEVFS_SUBMITURB, urb);
    } while((res < 0) && (errno == EINTR));

    return res;
}

int usb_endpoint_wait(struct usb_device *dev, int *out_ep_num)
struct usb_request *usb_request_wait(struct usb_device *dev)
{
    struct usbdevfs_urb *out = NULL;
    struct usbdevfs_urb *urb = NULL;
    struct usb_request *req = NULL;
    int res;

    while (1) {
        res = ioctl(dev->fd, USBDEVFS_REAPURB, &out);
        int res = ioctl(dev->fd, USBDEVFS_REAPURB, &urb);
        D("USBDEVFS_REAPURB returned %d\n", res);
        if (res < 0) {
            if(errno == EINTR) {
                continue;
            }
            D("[ reap urb - error ]\n");
            *out_ep_num = -1;
            return NULL;
        } else {
            D("[ urb @%p status = %d, actual = %d ]\n",
                out, out->status, out->actual_length);
            res = out->actual_length;
            *out_ep_num = out->endpoint;
                urb, urb->status, urb->actual_length);
            req = (struct usb_request*)urb->usercontext;
            req->actual_length = urb->actual_length;
        }
        break;
    }
    return res;
}

int usb_endpoint_cancel(struct usb_endpoint *ep)
{
    return ioctl(ep->dev->fd, USBDEVFS_DISCARDURB, &ep->urb);
}

struct usb_device *usb_endpoint_get_device(struct usb_endpoint *ep)
{
    return ep->dev;
}

int usb_endpoint_number(struct usb_endpoint *ep)
{
    return ep->desc.bEndpointAddress;
    return req;
}

int usb_endpoint_max_packet(struct usb_endpoint *ep)
int usb_request_cancel(struct usb_request *req)
{
    return __le16_to_cpu(ep->desc.wMaxPacketSize);
    struct usbdevfs_urb *urb = ((struct usbdevfs_urb*)req->private_data);
    return ioctl(req->dev->fd, USBDEVFS_DISCARDURB, &urb);
}