summaryrefslogtreecommitdiffstats
path: root/lib/libusb/libusb10_io.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libusb/libusb10_io.c')
-rw-r--r--lib/libusb/libusb10_io.c748
1 files changed, 748 insertions, 0 deletions
diff --git a/lib/libusb/libusb10_io.c b/lib/libusb/libusb10_io.c
new file mode 100644
index 0000000..4eb30c4
--- /dev/null
+++ b/lib/libusb/libusb10_io.c
@@ -0,0 +1,748 @@
+/* $FreeBSD$ */
+/*-
+ * Copyright (c) 2009 Sylvestre Gallon. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/queue.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <poll.h>
+#include <pthread.h>
+#include <time.h>
+#include <errno.h>
+
+#include "libusb20.h"
+#include "libusb20_desc.h"
+#include "libusb20_int.h"
+#include "libusb.h"
+#include "libusb10.h"
+
+static int
+get_next_timeout(libusb_context *ctx, struct timeval *tv, struct timeval *out)
+{
+ struct timeval timeout;
+ int ret;
+
+ ret = libusb_get_next_timeout(ctx, &timeout);
+
+ if (ret) {
+ if (timerisset(&timeout) == 0)
+ return 1;
+ if (timercmp(&timeout, tv, <) != 0)
+ *out = timeout;
+ else
+ *out = *tv;
+ } else {
+ *out = *tv;
+ }
+
+ return (0);
+}
+
+static int
+handle_timeouts(struct libusb_context *ctx)
+{
+ struct timespec sys_ts;
+ struct timeval sys_tv;
+ struct timeval *cur_tv;
+ struct usb_transfer *xfer;
+ struct libusb_transfer *uxfer;
+ int ret;
+
+ GET_CONTEXT(ctx);
+ ret = 0;
+
+ pthread_mutex_lock(&ctx->flying_transfers_lock);
+ if (USB_LIST_EMPTY(&ctx->flying_transfers))
+ goto out;
+
+ ret = clock_gettime(CLOCK_MONOTONIC, &sys_ts);
+ TIMESPEC_TO_TIMEVAL(&sys_tv, &sys_ts);
+
+ LIST_FOREACH_ENTRY(xfer, &ctx->flying_transfers, list) {
+ cur_tv = &xfer->timeout;
+
+ if (timerisset(cur_tv) == 0)
+ goto out;
+
+ if (xfer->flags & USB_TIMED_OUT)
+ continue;
+
+ if ((cur_tv->tv_sec > sys_tv.tv_sec) || (cur_tv->tv_sec == sys_tv.tv_sec &&
+ cur_tv->tv_usec > sys_tv.tv_usec))
+ goto out;
+
+ xfer->flags |= USB_TIMED_OUT;
+ uxfer = (libusb_transfer *) ((uint8_t *)xfer +
+ sizeof(struct usb_transfer));
+ ret = libusb_cancel_transfer(uxfer);
+ }
+out:
+ pthread_mutex_unlock(&ctx->flying_transfers_lock);
+ return (ret);
+}
+
+static int
+handle_events(struct libusb_context *ctx, struct timeval *tv)
+{
+ struct libusb_pollfd *tmppollfd;
+ struct libusb_device_handle *devh;
+ struct usb_pollfd *ipollfd;
+ struct usb_transfer *cur;
+ struct usb_transfer *cancel;
+ struct libusb_transfer *xfer;
+ struct pollfd *fds;
+ struct pollfd *tfds;
+ nfds_t nfds;
+ int tmpfd;
+ int tmp;
+ int ret;
+ int timeout;
+ int i;
+
+ GET_CONTEXT(ctx);
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "handle_events enter");
+
+ nfds = 0;
+ i = -1;
+
+ pthread_mutex_lock(&ctx->pollfds_lock);
+ LIST_FOREACH_ENTRY(ipollfd, &ctx->pollfds, list)
+ nfds++;
+
+ fds = malloc(sizeof(*fds) * nfds);
+ if (fds == NULL)
+ return (LIBUSB_ERROR_NO_MEM);
+
+ LIST_FOREACH_ENTRY(ipollfd, &ctx->pollfds, list) {
+ tmppollfd = &ipollfd->pollfd;
+ tmpfd = tmppollfd->fd;
+ i++;
+ fds[i].fd = tmpfd;
+ fds[i].events = tmppollfd->events;
+ fds[i].revents = 0;
+ }
+
+ pthread_mutex_unlock(&ctx->pollfds_lock);
+
+ timeout = (tv->tv_sec * 1000) + (tv->tv_usec / 1000);
+ if (tv->tv_usec % 1000)
+ timeout++;
+
+ ret = poll(fds, nfds, timeout);
+ if (ret == 0) {
+ free(fds);
+ return (handle_timeouts(ctx));
+ } else if (ret == -1 && errno == EINTR) {
+ free(fds);
+ return (LIBUSB_ERROR_INTERRUPTED);
+ } else if (ret < 0) {
+ free(fds);
+ return (LIBUSB_ERROR_IO);
+ }
+
+ if (fds[0].revents) {
+ if (ret == 1){
+ ret = 0;
+ goto handled;
+ } else {
+ fds[0].revents = 0;
+ ret--;
+ }
+ }
+
+ pthread_mutex_lock(&ctx->open_devs_lock);
+ for (i = 0 ; i < nfds && ret > 0 ; i++) {
+
+ tfds = &fds[i];
+ if (!tfds->revents)
+ continue;
+
+ ret--;
+ LIST_FOREACH_ENTRY(devh, &ctx->open_devs, list) {
+ if (libusb20_dev_get_fd(devh->os_priv) == tfds->fd)
+ break ;
+ }
+
+ if (tfds->revents & POLLERR) {
+ usb_remove_pollfd(ctx, libusb20_dev_get_fd(devh->os_priv));
+ usb_handle_disconnect(devh);
+ continue ;
+ }
+
+
+ pthread_mutex_lock(&libusb20_lock);
+ dprintf(ctx, LIBUSB_DEBUG_TRANSFER, "LIBUSB20_PROCESS");
+ ret = libusb20_dev_process(devh->os_priv);
+ pthread_mutex_unlock(&libusb20_lock);
+
+
+ if (ret == 0 || ret == LIBUSB20_ERROR_NO_DEVICE)
+ continue;
+ else if (ret < 0)
+ goto out;
+ }
+
+ ret = 0;
+out:
+ pthread_mutex_unlock(&ctx->open_devs_lock);
+
+handled:
+ free(fds);
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "handle_events leave");
+ return ret;
+}
+
+/* Polling and timing */
+
+int
+libusb_try_lock_events(libusb_context * ctx)
+{
+ int ret;
+
+ GET_CONTEXT(ctx);
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_try_lock_events enter");
+
+ pthread_mutex_lock(&ctx->pollfd_modify_lock);
+ ret = ctx->pollfd_modify;
+ pthread_mutex_unlock(&ctx->pollfd_modify_lock);
+
+ if (ret != 0)
+ return (1);
+
+ ret = pthread_mutex_trylock(&ctx->events_lock);
+
+ if (ret != 0)
+ return (1);
+
+ ctx->event_handler_active = 1;
+
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_try_lock_events leave");
+ return (0);
+}
+
+void
+libusb_lock_events(libusb_context * ctx)
+{
+ GET_CONTEXT(ctx);
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_lock_events enter");
+
+ pthread_mutex_lock(&ctx->events_lock);
+ ctx->event_handler_active = 1;
+
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_lock_events leave");
+}
+
+void
+libusb_unlock_events(libusb_context * ctx)
+{
+ GET_CONTEXT(ctx);
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_unlock_events enter");
+
+ ctx->event_handler_active = 0;
+ pthread_mutex_unlock(&ctx->events_lock);
+
+ pthread_mutex_lock(&ctx->event_waiters_lock);
+ pthread_cond_broadcast(&ctx->event_waiters_cond);
+ pthread_mutex_unlock(&ctx->event_waiters_lock);
+
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_unlock_events leave");
+}
+
+int
+libusb_event_handling_ok(libusb_context * ctx)
+{
+ int ret;
+
+ GET_CONTEXT(ctx);
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_event_handling_ok enter");
+
+ pthread_mutex_lock(&ctx->pollfd_modify_lock);
+ ret = ctx->pollfd_modify;
+ pthread_mutex_unlock(&ctx->pollfd_modify_lock);
+
+ if (ret != 0)
+ return (0);
+
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_event_handling_ok leave");
+ return (1);
+}
+
+int
+libusb_event_handler_active(libusb_context * ctx)
+{
+ int ret;
+
+ GET_CONTEXT(ctx);
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_event_handler_active enter");
+
+ pthread_mutex_lock(&ctx->pollfd_modify_lock);
+ ret = ctx->pollfd_modify;
+ pthread_mutex_unlock(&ctx->pollfd_modify_lock);
+
+ if (ret != 0)
+ return (1);
+
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_event_handler_active leave");
+ return (ctx->event_handler_active);
+}
+
+void
+libusb_lock_event_waiters(libusb_context * ctx)
+{
+ GET_CONTEXT(ctx);
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_lock_event_waiters enter");
+
+ pthread_mutex_lock(&ctx->event_waiters_lock);
+
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_lock_event_waiters leave");
+}
+
+void
+libusb_unlock_event_waiters(libusb_context * ctx)
+{
+ GET_CONTEXT(ctx);
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_unlock_event_waiters enter");
+
+ pthread_mutex_unlock(&ctx->event_waiters_lock);
+
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_unlock_event_waiters leave");
+}
+
+int
+libusb_wait_for_event(libusb_context * ctx, struct timeval *tv)
+{
+ int ret;
+ struct timespec ts;
+
+ GET_CONTEXT(ctx);
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_wait_for_event enter");
+
+ if (tv == NULL) {
+ pthread_cond_wait(&ctx->event_waiters_cond,
+ &ctx->event_waiters_lock);
+ return (0);
+ }
+
+ ret = clock_gettime(CLOCK_REALTIME, &ts);
+ if (ret < 0)
+ return (LIBUSB_ERROR_OTHER);
+
+ ts.tv_sec = tv->tv_sec;
+ ts.tv_nsec = tv->tv_usec * 1000;
+ if (ts.tv_nsec > 1000000000) {
+ ts.tv_nsec -= 1000000000;
+ ts.tv_sec++;
+ }
+
+ ret = pthread_cond_timedwait(&ctx->event_waiters_cond,
+ &ctx->event_waiters_lock, &ts);
+
+ if (ret == ETIMEDOUT)
+ return (1);
+
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_wait_for_event leave");
+ return (0);
+}
+
+int
+libusb_handle_events_timeout(libusb_context * ctx, struct timeval *tv)
+{
+ struct timeval timeout;
+ struct timeval poll_timeout;
+ int ret;
+
+ GET_CONTEXT(ctx);
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events_timeout enter");
+
+ ret = get_next_timeout(ctx, tv, &poll_timeout);
+ if (ret != 0) {
+ return handle_timeouts(ctx);
+ }
+retry:
+ if (libusb_try_lock_events(ctx) == 0) {
+ ret = handle_events(ctx, &poll_timeout);
+ libusb_unlock_events(ctx);
+ return ret;
+ }
+
+ libusb_lock_event_waiters(ctx);
+ if (libusb_event_handler_active(ctx) == 0) {
+ libusb_unlock_event_waiters(ctx);
+ goto retry;
+ }
+
+ ret = libusb_wait_for_event(ctx, &poll_timeout);
+ libusb_unlock_event_waiters(ctx);
+
+ if (ret < 0)
+ return ret;
+ else if (ret == 1)
+ return (handle_timeouts(ctx));
+
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events_timeout leave");
+ return (0);
+}
+
+int
+libusb_handle_events(libusb_context * ctx)
+{
+ struct timeval tv;
+ int ret;
+
+ GET_CONTEXT(ctx);
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events enter");
+
+ tv.tv_sec = 2;
+ tv.tv_usec = 0;
+ ret = libusb_handle_events_timeout(ctx, &tv);
+
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events leave");
+ return (ret);
+}
+
+int
+libusb_handle_events_locked(libusb_context * ctx, struct timeval *tv)
+{
+ int ret;
+ struct timeval poll_tv;
+
+ GET_CONTEXT(ctx);
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events_locked enter");
+
+ ret = get_next_timeout(ctx, tv, &poll_tv);
+ if (ret != 0) {
+ return handle_timeouts(ctx);
+ }
+
+ ret = handle_events(ctx, &poll_tv);
+
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events_locked leave");
+ return (ret);
+}
+
+int
+libusb_get_next_timeout(libusb_context * ctx, struct timeval *tv)
+{
+ struct usb_transfer *xfer;
+ struct timeval *next_tv;
+ struct timeval cur_tv;
+ struct timespec cur_ts;
+ int found;
+ int ret;
+
+ GET_CONTEXT(ctx);
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_next_timeout enter");
+
+ found = 0;
+ pthread_mutex_lock(&ctx->flying_transfers_lock);
+ if (USB_LIST_EMPTY(&ctx->flying_transfers)) {
+ pthread_mutex_unlock(&ctx->flying_transfers_lock);
+ return (0);
+ }
+
+ LIST_FOREACH_ENTRY(xfer, &ctx->flying_transfers, list) {
+ if (!(xfer->flags & USB_TIMED_OUT)) {
+ found = 1;
+ break ;
+ }
+ }
+ pthread_mutex_unlock(&ctx->flying_transfers_lock);
+
+ if (found == 0) {
+ return 0;
+ }
+
+ next_tv = &xfer->timeout;
+ if (timerisset(next_tv) == 0)
+ return (0);
+
+ ret = clock_gettime(CLOCK_MONOTONIC, &cur_ts);
+ if (ret < 0)
+ return (LIBUSB_ERROR_OTHER);
+ TIMESPEC_TO_TIMEVAL(&cur_tv, &cur_ts);
+
+ if (timercmp(&cur_tv, next_tv, >=) != 0)
+ timerclear(tv);
+ else
+ timersub(next_tv, &cur_tv, tv);
+
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_next_timeout leave");
+ return (1);
+}
+
+void
+libusb_set_pollfd_notifiers(libusb_context * ctx,
+ libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb,
+ void *user_data)
+{
+ GET_CONTEXT(ctx);
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_set_pollfd_notifiers enter");
+
+ ctx->fd_added_cb = added_cb;
+ ctx->fd_removed_cb = removed_cb;
+ ctx->fd_cb_user_data = user_data;
+
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_set_pollfd_notifiers leave");
+}
+
+struct libusb_pollfd **
+libusb_get_pollfds(libusb_context * ctx)
+{
+ struct usb_pollfd *pollfd;
+ libusb_pollfd **ret;
+ int i;
+
+ GET_CONTEXT(ctx);
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_pollfds enter");
+
+ i = 0;
+ pthread_mutex_lock(&ctx->pollfds_lock);
+ LIST_FOREACH_ENTRY(pollfd, &ctx->pollfds, list)
+ i++;
+
+ ret = calloc(i + 1 , sizeof(struct libusb_pollfd *));
+ if (ret == NULL) {
+ pthread_mutex_unlock(&ctx->pollfds_lock);
+ return (ret);
+ }
+
+ i = 0;
+ LIST_FOREACH_ENTRY(pollfd, &ctx->pollfds, list)
+ ret[i++] = (struct libusb_pollfd *) pollfd;
+ ret[i] = NULL;
+
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_pollfds leave");
+ return (ret);
+}
+
+
+/* Synchronous device I/O */
+
+static void ctrl_tr_cb(struct libusb_transfer *transfer)
+{
+ libusb_context *ctx;
+ int *complet;
+
+ ctx = NULL;
+ GET_CONTEXT(ctx);
+ dprintf(ctx, LIBUSB_DEBUG_TRANSFER, "CALLBACK ENTER");
+
+ complet = transfer->user_data;
+ *complet = 1;
+}
+
+int
+libusb_control_transfer(libusb_device_handle * devh,
+ uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
+ unsigned char *data, uint16_t wLength, unsigned int timeout)
+{
+ struct libusb_transfer *xfer;
+ struct libusb_control_setup *ctr;
+ libusb_context *ctx;
+ unsigned char *buff;
+ int complet;
+ int ret;
+
+ ctx = devh->dev->ctx;
+ GET_CONTEXT(ctx);
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_control_transfer enter");
+
+ if (devh == NULL || data == NULL)
+ return (LIBUSB_ERROR_NO_MEM);
+
+ xfer = libusb_alloc_transfer(0);
+ if (xfer == NULL)
+ return (LIBUSB_ERROR_NO_MEM);
+
+ buff = malloc(sizeof(libusb_control_setup) + wLength);
+ if (buff == NULL) {
+ libusb_free_transfer(xfer);
+ return (LIBUSB_ERROR_NO_MEM);
+ }
+
+ ctr = (libusb_control_setup *)buff;
+ ctr->bmRequestType = bmRequestType;
+ ctr->bRequest = bRequest;
+ ctr->wValue = wValue;
+ ctr->wIndex = wIndex;
+ ctr->wLength = wLength;
+ if ((bmRequestType & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT)
+ memcpy(buff + sizeof(libusb_control_setup), data, wLength);
+
+ xfer->dev_handle = devh;
+ xfer->endpoint = 0;
+ xfer->type = LIBUSB_TRANSFER_TYPE_CONTROL;
+ xfer->timeout = timeout;
+ xfer->buffer = buff;
+ xfer->length = sizeof(libusb_control_setup) + wLength;
+ xfer->user_data = &complet;
+ xfer->callback = ctrl_tr_cb;
+ xfer->flags = LIBUSB_TRANSFER_FREE_TRANSFER;
+ complet = 0;
+
+ if ((ret = libusb_submit_transfer(xfer)) < 0) {
+ libusb_free_transfer(xfer);
+ return (ret);
+ }
+
+ while (complet == 0)
+ if ((ret = libusb_handle_events(ctx)) < 0) {
+ libusb_cancel_transfer(xfer);
+ while (complet == 0)
+ if (libusb_handle_events(ctx) < 0) {
+ break;
+ }
+ libusb_free_transfer(xfer);
+ return (ret);
+ }
+
+
+ if ((bmRequestType & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN)
+ memcpy(data, buff + sizeof(libusb_control_setup), wLength);
+
+ switch (xfer->status) {
+ case LIBUSB_TRANSFER_COMPLETED:
+ ret = xfer->actual_length;
+ break;
+ case LIBUSB_TRANSFER_TIMED_OUT:
+ case LIBUSB_TRANSFER_STALL:
+ case LIBUSB_TRANSFER_NO_DEVICE:
+ ret = xfer->status;
+ break;
+ default:
+ ret = LIBUSB_ERROR_OTHER;
+ }
+ libusb_free_transfer(xfer);
+
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_control_transfer leave");
+ return (ret);
+}
+
+static int
+do_transfer(struct libusb_device_handle *devh,
+ unsigned char endpoint, unsigned char *data, int length,
+ int *transferred, unsigned int timeout, int type)
+{
+ struct libusb_transfer *xfer;
+ libusb_context *ctx;
+ int complet;
+ int ret;
+
+ if (devh == NULL || data == NULL)
+ return (LIBUSB_ERROR_NO_MEM);
+
+ xfer = libusb_alloc_transfer(0);
+ if (xfer == NULL)
+ return (LIBUSB_ERROR_NO_MEM);
+
+ ctx = devh->dev->ctx;
+
+ xfer->dev_handle = devh;
+ xfer->endpoint = endpoint;
+ xfer->type = type;
+ xfer->timeout = timeout;
+ xfer->buffer = data;
+ xfer->length = length;
+ xfer->user_data = &complet;
+ xfer->callback = ctrl_tr_cb;
+ complet = 0;
+
+ if ((ret = libusb_submit_transfer(xfer)) < 0) {
+ libusb_free_transfer(xfer);
+ return (ret);
+ }
+
+ while (complet == 0) {
+ if ((ret = libusb_handle_events(ctx)) < 0) {
+ libusb_cancel_transfer(xfer);
+ libusb_free_transfer(xfer);
+ while (complet == 0) {
+ if (libusb_handle_events(ctx) < 0)
+ break ;
+ }
+ return (ret);
+ }
+ }
+
+ *transferred = xfer->actual_length;
+ switch (xfer->status) {
+ case LIBUSB_TRANSFER_COMPLETED:
+ ret = xfer->actual_length;
+ break;
+ case LIBUSB_TRANSFER_TIMED_OUT:
+ case LIBUSB_TRANSFER_OVERFLOW:
+ case LIBUSB_TRANSFER_STALL:
+ case LIBUSB_TRANSFER_NO_DEVICE:
+ ret = xfer->status;
+ break;
+ default:
+ ret = LIBUSB_ERROR_OTHER;
+ }
+
+ libusb_free_transfer(xfer);
+ return (ret);
+}
+
+int
+libusb_bulk_transfer(struct libusb_device_handle *devh,
+ unsigned char endpoint, unsigned char *data, int length,
+ int *transferred, unsigned int timeout)
+{
+ libusb_context *ctx;
+ int ret;
+
+ ctx = NULL;
+ GET_CONTEXT(ctx);
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_bulk_transfer enter");
+
+ ret = do_transfer(devh, endpoint, data, length, transferred,
+ timeout, LIBUSB_TRANSFER_TYPE_BULK);
+
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_bulk_transfer leave");
+ return (ret);
+}
+
+/*
+ * Need to fix xfer->type
+ */
+int
+libusb_interrupt_transfer(struct libusb_device_handle *devh,
+ unsigned char endpoint, unsigned char *data, int length,
+ int *transferred, unsigned int timeout)
+{
+ libusb_context *ctx;
+ int ret;
+
+ ctx = NULL;
+ GET_CONTEXT(ctx);
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_interrupt_transfer enter");
+
+ ret = do_transfer(devh, endpoint, data, length, transferred,
+ timeout, LIBUSB_TRANSFER_TYPE_INTERRUPT);
+
+ dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_interrupt_transfer leave");
+ return (ret);
+}
OpenPOWER on IntegriCloud