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