PERFORCE change 166129 for review
Hans Petter Selasky
hselasky at FreeBSD.org
Wed Jul 15 13:14:56 UTC 2009
http://perforce.freebsd.org/chv.cgi?CH=166129
Change 166129 by hselasky at hselasky_laptop001 on 2009/07/15 13:14:05
LibUSB v1.0 - fix transfer completion. LibUSB compiles again.
Affected files ...
.. //depot/projects/usb/src/lib/libusb/libusb10.c#9 edit
.. //depot/projects/usb/src/lib/libusb/libusb10.h#7 edit
.. //depot/projects/usb/src/lib/libusb/libusb10_io.c#6 edit
Differences ...
==== //depot/projects/usb/src/lib/libusb/libusb10.c#9 (text+ko) ====
@@ -31,6 +31,8 @@
#include <pthread.h>
#include <time.h>
#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/filio.h>
#include <sys/queue.h>
#include "libusb20.h"
@@ -44,14 +46,15 @@
/* Prototypes */
-static struct libusb20_transfer *libusb10_get_transfer(struct libusb20_device *pdev, uint8_t endpoint, uint8_t index);
-static int libusb10_get_maxframe(struct libusb20_device *pdev, libusb_transfer *xfer);
-static int libusb10_get_buffsize(struct libusb20_device *pdev, libusb_transfer *xfer);
+static struct libusb20_transfer *libusb10_get_transfer(struct libusb20_device *, uint8_t, uint8_t);
+static int libusb10_get_maxframe(struct libusb20_device *, libusb_transfer *);
+static int libusb10_get_buffsize(struct libusb20_device *, libusb_transfer *);
static int libusb10_convert_error(uint8_t status);
-static void libusb10_isoc_proxy(struct libusb20_transfer *pxfer);
-static void libusb10_bulk_intr_proxy(struct libusb20_transfer *pxfer);
-static void libusb10_ctrl_proxy(struct libusb20_transfer *pxfer);
-static void libusb10_submit_transfer_sub(struct libusb20_device *pdev, uint8_t endpoint);
+static void libusb10_complete_transfer(struct libusb20_transfer *, struct libusb_super_transfer *, int);
+static void libusb10_isoc_proxy(struct libusb20_transfer *);
+static void libusb10_bulk_intr_proxy(struct libusb20_transfer *);
+static void libusb10_ctrl_proxy(struct libusb20_transfer *);
+static void libusb10_submit_transfer_sub(struct libusb20_device *, uint8_t);
/* Library initialisation / deinitialisation */
@@ -83,10 +86,13 @@
ctx->debug_fixed = 1;
}
TAILQ_INIT(&ctx->pollfds);
+ TAILQ_INIT(&ctx->tr_done);
pthread_mutex_init(&ctx->ctx_lock, NULL);
pthread_cond_init(&ctx->ctx_cond, NULL);
+ ctx->ctx_handler = NO_THREAD;
+
ret = pipe(ctx->ctrl_pipe);
if (ret < 0) {
pthread_mutex_destroy(&ctx->ctx_lock);
@@ -94,6 +100,12 @@
free(ctx);
return (LIBUSB_ERROR_OTHER);
}
+ /* set non-blocking mode on the control pipe to avoid deadlock */
+ ret = 1;
+ ioctl(ctx->ctrl_pipe[0], FIONBIO, &ret);
+ ret = 1;
+ ioctl(ctx->ctrl_pipe[1], FIONBIO, &ret);
+
libusb10_add_pollfd(ctx, &ctx->ctx_poll, NULL, ctx->ctrl_pipe[0], POLLIN);
pthread_mutex_lock(&default_context_lock);
@@ -190,7 +202,6 @@
/* init transfer queues */
TAILQ_INIT(&dev->tr_head);
- TAILQ_INIT(&dev->tr_done);
/* set context we belong to */
dev->ctx = ctx;
@@ -477,10 +488,10 @@
set_config:
+ libusb10_cancel_all_transfer(dev);
+
libusb10_remove_pollfd(dev->ctx, &dev->dev_poll);
- usb_cancel_all_dev(dev);
-
err = libusb20_dev_set_config_index(pdev, i);
libusb10_add_pollfd(dev->ctx, &dev->dev_poll, pdev, libusb20_dev_get_fd(pdev), POLLIN |
@@ -557,10 +568,10 @@
if (err)
return (err);
+ libusb10_cancel_all_transfer(dev);
+
libusb10_remove_pollfd(dev->ctx, &dev->dev_poll);
- usb_cancel_all_dev(dev);
-
err = libusb20_dev_set_alt_index(pdev,
interface_number, alternate_setting);
@@ -627,10 +638,10 @@
if (dev == NULL)
return (LIBUSB20_ERROR_INVALID_PARAM);
+ libusb10_cancel_all_transfer(dev);
+
libusb10_remove_pollfd(dev->ctx, &dev->dev_poll);
- usb_cancel_all_dev(dev);
-
err = libusb20_dev_reset(pdev);
libusb10_add_pollfd(dev->ctx, &dev->dev_poll,
@@ -801,7 +812,31 @@
}
}
+/* This function must be called locked */
+
static void
+libusb10_complete_transfer(struct libusb20_transfer *pxfer,
+ struct libusb_super_transfer *sxfer, int status)
+{
+ struct libusb_transfer *uxfer;
+ struct libusb_device *dev;
+
+ uxfer = (struct libusb_transfer *)(
+ ((uint8_t *)sxfer) + sizeof(*sxfer));
+
+ if (pxfer != NULL)
+ libusb20_tr_set_priv_sc1(pxfer, NULL);
+
+ uxfer->status = status;
+
+ dev = libusb_get_device(uxfer->dev_handle);
+
+ TAILQ_INSERT_TAIL(&dev->ctx->tr_done, sxfer, entry);
+}
+
+/* This function must be called locked */
+
+static void
libusb10_isoc_proxy(struct libusb20_transfer *pxfer)
{
struct libusb_super_transfer *sxfer;
@@ -843,7 +878,7 @@
uxfer->iso_packet_desc[i].actual_length =
libusb20_tr_get_length(pxfer, i);
}
- libusb_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED);
+ libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED);
break;
case LIBUSB20_TRANSFER_START:
@@ -868,11 +903,13 @@
break;
default:
- libusb_complete_transfer(pxfer, sxfer, libusb10_convert_error(status));
+ libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status));
break;
}
}
+/* This function must be called locked */
+
static void
libusb10_bulk_intr_proxy(struct libusb20_transfer *pxfer)
{
@@ -904,15 +941,15 @@
/* check for short packet */
if (sxfer->last_len != actlen) {
if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) {
- libusb_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR);
+ libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR);
} else {
- libusb_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED);
+ libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED);
}
break;
}
/* check for end of data */
if (sxfer->rem_len == 0) {
- libusb_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED);
+ libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED);
break;
}
/* FALLTHROUGH */
@@ -938,11 +975,13 @@
break;
default:
- libusb_complete_transfer(pxfer, sxfer, libusb10_convert_error(status));
+ libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status));
break;
}
}
+/* This function must be called locked */
+
static void
libusb10_ctrl_proxy(struct libusb20_transfer *pxfer)
{
@@ -977,15 +1016,15 @@
/* check for short packet */
if (sxfer->last_len != actlen) {
if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) {
- libusb_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR);
+ libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR);
} else {
- libusb_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED);
+ libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED);
}
break;
}
/* check for end of data */
if (sxfer->rem_len == 0) {
- libusb_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED);
+ libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED);
break;
}
/* FALLTHROUGH */
@@ -1025,7 +1064,7 @@
break;
default:
- libusb_complete_transfer(pxfer, sxfer, libusb10_convert_error(status));
+ libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status));
break;
}
}
@@ -1044,6 +1083,7 @@
int buffsize;
int maxframe;
int temp;
+ uint8_t dummy;
dev = libusb_get_device(pdev);
@@ -1115,17 +1155,15 @@
break;
case LIBUSB_TRANSFER_TYPE_CONTROL:
libusb20_tr_set_callback(pxfer0, libusb10_ctrl_proxy);
- if (sxfer->rem_len < 8) {
- libusb_complete_transfer(pxfer0, sxfer, LIBUSB_TRANSFER_ERROR);
- return;
- }
+ if (sxfer->rem_len < 8)
+ goto failure;
+
/* remove SETUP packet from data */
sxfer->rem_len -= 8;
sxfer->curr_data += 8;
break;
default:
- libusb_complete_transfer(pxfer0, sxfer, LIBUSB_TRANSFER_ERROR);
- return;
+ goto failure;
}
buffsize = libusb10_get_buffsize(pdev, uxfer);
@@ -1134,50 +1172,17 @@
/* make sure the transfer is opened */
err = libusb20_tr_open(pxfer0, buffsize, maxframe, endpoint);
if (err && (err != LIBUSB20_ERROR_BUSY)) {
- libusb_complete_transfer(pxfer0, sxfer, LIBUSB_TRANSFER_ERROR);
- return;
+ goto failure;
}
libusb20_tr_start(pxfer0);
-}
+ return;
-/* The following function must be called locked */
+failure:
+ libusb10_complete_transfer(pxfer0, sxfer, LIBUSB_TRANSFER_ERROR);
-UNEXPORTED void
-libusb10_complete_transfer_sub(struct libusb20_device *pdev)
-{
- struct libusb_device *dev;
- struct libusb_super_transfer *sxfer;
- struct libusb_transfer *uxfer;
-
- dev = libusb_get_device(pdev);
-
- while ((sxfer = TAILQ_FIRST(&dev->tr_done))) {
- TAILQ_REMOVE(&dev->tr_done, sxfer, entry);
- sxfer->entry.tqe_prev = NULL;
-
- dev->tr_done_ref++;
-
- CTX_UNLOCK(dev->ctx);
-
- uxfer = (struct libusb_transfer *)(
- ((uint8_t *)sxfer) + sizeof(*sxfer));
-
- if (uxfer->callback != NULL)
- (uxfer->callback) (uxfer);
-
- if (uxfer->flags & LIBUSB_TRANSFER_FREE_BUFFER)
- free(uxfer->buffer);
-
- if (uxfer->flags & LIBUSB_TRANSFER_FREE_TRANSFER)
- libusb_free_transfer(uxfer);
-
- CTX_LOCK(dev->ctx);
-
- pthread_cond_broadcast(&dev->ctx->ctx_cond);
-
- dev->tr_done_ref--;
- dev->tr_done_gen++;
- }
+ /* make sure our event loop spins the done handler */
+ dummy = 0;
+ write(dev->ctx->ctrl_pipe[1], &dummy, sizeof(dummy));
}
/* The following function must be called unlocked */
@@ -1237,6 +1242,8 @@
return (err);
}
+/* Asynchronous transfer cancel */
+
int
libusb_cancel_transfer(struct libusb_transfer *uxfer)
{
@@ -1245,7 +1252,6 @@
struct libusb_super_transfer *sxfer;
struct libusb_device *dev;
unsigned int endpoint;
- int err;
if (uxfer == NULL)
return (LIBUSB_ERROR_INVALID_PARAM);
@@ -1274,43 +1280,34 @@
/* we are lucky - transfer is on a queue */
TAILQ_REMOVE(&dev->tr_head, sxfer, entry);
sxfer->entry.tqe_prev = NULL;
- err = 0;
+ libusb10_complete_transfer(NULL, sxfer, LIBUSB_TRANSFER_CANCELLED);
} else if (pxfer0 == NULL || pxfer1 == NULL) {
- err = LIBUSB_ERROR_OTHER;
+ /* not started */
} else if (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) {
- libusb20_tr_set_priv_sc1(pxfer0, NULL);
+ libusb10_complete_transfer(pxfer0, sxfer, LIBUSB_TRANSFER_CANCELLED);
libusb20_tr_stop(pxfer0);
/* make sure the queue doesn't stall */
libusb10_submit_transfer_sub(
uxfer->dev_handle, endpoint);
- err = 0;
} else if (libusb20_tr_get_priv_sc1(pxfer1) == sxfer) {
- libusb20_tr_set_priv_sc1(pxfer1, NULL);
+ libusb10_complete_transfer(pxfer1, sxfer, LIBUSB_TRANSFER_CANCELLED);
libusb20_tr_stop(pxfer1);
/* make sure the queue doesn't stall */
libusb10_submit_transfer_sub(
uxfer->dev_handle, endpoint);
- err = 0;
} else {
- /*
- * Check if any callback is pending and wait for it to
- * complete:
- */
- if (dev->tr_done_ref != 0) {
- int my_gen = dev->tr_done_gen;
-
- while (dev->tr_done_gen == my_gen) {
- pthread_cond_wait(&dev->ctx->ctx_cond,
- &dev->ctx->ctx_lock);
- }
- }
/* not started */
- err = 0;
}
CTX_UNLOCK(dev->ctx);
- DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer leave %d", err);
+ DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer leave");
+
+ return (0);
+}
- return (err);
+UNEXPORTED void
+libusb10_cancel_all_transfer(libusb_device *dev)
+{
+ /* TODO */
}
==== //depot/projects/usb/src/lib/libusb/libusb10.h#7 (text+ko) ====
@@ -60,7 +60,7 @@
};
struct libusb_super_transfer {
- TAILQ_ENTRY(libusb_super_transfer)entry;
+ TAILQ_ENTRY(libusb_super_transfer) entry;
uint8_t *curr_data;
uint32_t rem_len;
uint32_t last_len;
@@ -71,6 +71,8 @@
int debug;
int debug_fixed;
int ctrl_pipe[2];
+ int tr_done_ref;
+ int tr_done_gen;
pthread_mutex_t ctx_lock;
pthread_cond_t ctx_cond;
@@ -78,6 +80,7 @@
#define NO_THREAD ((pthread_t)-1)
TAILQ_HEAD(, libusb_super_pollfd) pollfds;
+ TAILQ_HEAD(, libusb_super_transfer) tr_done;
struct libusb_super_pollfd ctx_poll;
@@ -88,8 +91,6 @@
struct libusb_device {
int refcnt;
- int tr_done_ref;
- int tr_done_gen;
uint32_t claimed_interfaces;
@@ -97,8 +98,7 @@
struct libusb_context *ctx;
- TAILQ_HEAD(, libusb_super_transfer)tr_head;
- TAILQ_HEAD(, libusb_super_transfer)tr_done;
+ TAILQ_HEAD(, libusb_super_transfer) tr_head;
struct libusb20_device *os_priv;
};
@@ -107,6 +107,6 @@
void libusb10_add_pollfd(libusb_context *ctx, struct libusb_super_pollfd *pollfd, struct libusb20_device *pdev, int fd, short events);
void libusb10_remove_pollfd(libusb_context *ctx, struct libusb_super_pollfd *pollfd);
-void libusb10_complete_transfer_sub(libusb_device_handle *devh);
+void libusb10_cancel_all_transfer(libusb_device *dev);
#endif /* __LIBUSB10_H__ */
==== //depot/projects/usb/src/lib/libusb/libusb10_io.c#6 (text+ko) ====
@@ -86,9 +86,12 @@
static int
libusb10_handle_events_sub(struct libusb_context *ctx, struct timeval *tv)
{
+ struct libusb_device *dev;
struct libusb20_device **ppdev;
struct libusb_super_pollfd *pfd;
struct pollfd *fds;
+ struct libusb_super_transfer *sxfer;
+ struct libusb_transfer *uxfer;
nfds_t nfds;
int timeout;
int i;
@@ -135,21 +138,32 @@
if (err < 1) {
for (i = 0; i != nfds; i++) {
- if (ppdev[i] != NULL)
- libusb_unref_device_locked(libusb_get_device(ppdev[i]));
+ if (ppdev[i] != NULL) {
+ CTX_UNLOCK(ctx);
+ libusb_unref_device(libusb_get_device(ppdev[i]));
+ CTX_LOCK(ctx);
+ }
}
- return (err);
+ goto do_done;
}
for (i = 0; i != nfds; i++) {
if (fds[i].revents == 0)
continue;
if (ppdev[i] != NULL) {
+ dev = libusb_get_device(ppdev[i]);
+
err = libusb20_dev_process(ppdev[i]);
if (err) {
- XXX_device_is_gone();
+ /* cancel all transfers - device is gone */
+ libusb10_cancel_all_transfer(dev);
+ /*
+ * make sure we don't go into an infinite
+ * loop
+ */
+ libusb10_remove_pollfd(dev->ctx, &dev->dev_poll);
}
CTX_UNLOCK(ctx);
- libusb_unref_device(libusb_get_device(ppdev[i]));
+ libusb_unref_device(dev);
CTX_LOCK(ctx);
} else {
@@ -161,7 +175,43 @@
}
}
}
- return (0);
+
+ err = 0;
+
+do_done:
+
+ /* Do all done callbacks */
+
+ while ((sxfer = TAILQ_FIRST(&ctx->tr_done))) {
+ TAILQ_REMOVE(&ctx->tr_done, sxfer, entry);
+ sxfer->entry.tqe_prev = NULL;
+
+ ctx->tr_done_ref++;
+
+ CTX_UNLOCK(ctx);
+
+ uxfer = (struct libusb_transfer *)(
+ ((uint8_t *)sxfer) + sizeof(*sxfer));
+
+ if (uxfer->callback != NULL)
+ (uxfer->callback) (uxfer);
+
+ if (uxfer->flags & LIBUSB_TRANSFER_FREE_BUFFER)
+ free(uxfer->buffer);
+
+ if (uxfer->flags & LIBUSB_TRANSFER_FREE_TRANSFER)
+ libusb_free_transfer(uxfer);
+
+ CTX_LOCK(ctx);
+
+ ctx->tr_done_ref--;
+ ctx->tr_done_gen++;
+ }
+
+ /* Wakeup other waiters */
+ pthread_cond_broadcast(&ctx->ctx_cond);
+
+ return (err);
}
/* Polling and timing */
@@ -453,20 +503,10 @@
libusb_free_transfer(xfer);
return (ret);
}
- XXX_locking();
-
while (complet == 0) {
if ((ret = libusb_handle_events(ctx)) < 0) {
libusb_cancel_transfer(xfer);
- libusb_free_transfer(xfer);
-
- XXX();
-
- while (complet == 0) {
- if (libusb_handle_events(ctx) < 0)
- break;
- }
- return (ret);
+ usleep(1000); /* nice it */
}
}
More information about the p4-projects
mailing list