Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 14 Feb 2010 12:04:34 GMT
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 174691 for review
Message-ID:  <201002141204.o1EC4YTt011427@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/chv.cgi?CH=174691

Change 174691 by hselasky@hselasky_laptop001 on 2010/02/14 12:03:51

	USB CORE and LibUSB 2.0:
		- new feature add support for USB attach and
		detach events in userspace through LibUSB.
		- patch done by: HPS @
		- feature requested by: Markus Rechberger
		- this patch also includes a one-line-fix to the get
		template IOCTL in the kernel which previously always
		returned failure.
		- to be MFC'ed to 8-stable after one week.

Affected files ...

.. //depot/projects/usb/src/lib/libusb/libusb20.3#8 edit
.. //depot/projects/usb/src/lib/libusb/libusb20.c#16 edit
.. //depot/projects/usb/src/lib/libusb/libusb20.h#11 edit
.. //depot/projects/usb/src/lib/libusb/libusb20_int.h#10 edit
.. //depot/projects/usb/src/lib/libusb/libusb20_ugen20.c#13 edit
.. //depot/projects/usb/src/sys/dev/usb/usb_dev.c#40 edit
.. //depot/projects/usb/src/sys/dev/usb/usb_dev.h#18 edit
.. //depot/projects/usb/src/sys/dev/usb/usb_device.c#63 edit
.. //depot/projects/usb/src/sys/dev/usb/usb_ioctl.h#6 edit

Differences ...

==== //depot/projects/usb/src/lib/libusb/libusb20.3#8 (text+ko) ====

@@ -177,6 +177,8 @@
 .Ft int
 .Fn libusb20_be_set_template "struct libusb20_backend *pbe" "int temp"
 .Ft int
+.Fn libusb20_be_wait_enumeration "struct libusb20_backend *pbe" "int timeout" "int flag"
+.Ft int
 .Fn libusb20_be_get_dev_quirk "struct libusb20_backend *pber", "uint16_t index" "struct libusb20_quirk *pq"
 .Ft int
 .Fn libusb20_be_get_quirk_name "struct libusb20_backend *pbe" "uint16_t index" "struct libusb20_quirk *pq"
@@ -831,6 +833,23 @@
 .
 .Pp
 .
+.Fn libusb20_be_wait_enumeration
+will block until a new USB device is enumerated or an existing USB
+device is detached. All devices belonging to the backend will be
+dequeued and freed, but not the backend itself.
+If the
+.Fa timeout
+argument is non-zero the function will return after the given number
+of milliseconds.
+A timeout is not regarded like an error.
+The
+.Fa flag
+argument is current reserved and must be set to zero.
+This function returns zero on success else a LIBUSB20_ERROR value is
+returned.
+.
+.Pp
+.
 .Fn libusb20_be_get_dev_quirk
 This function will return the device quirk according to
 .Fa index

==== //depot/projects/usb/src/lib/libusb/libusb20.c#16 (text+ko) ====

@@ -1113,6 +1113,21 @@
 	return (pbe->methods->root_get_template(pbe, ptemp));
 }
 
+int
+libusb20_be_wait_enumeration(struct libusb20_backend *pbe, int timeout, int flag)
+{
+	struct libusb20_device *pdev;
+
+	/* clean up all existing devices */
+
+	while ((pdev = libusb20_be_device_foreach(pbe, NULL))) {
+		libusb20_be_dequeue_device(pbe, pdev);
+		libusb20_dev_free(pdev);
+	}
+
+	return (pbe->methods->root_wait_enumeration(pbe, timeout, flag));
+}
+
 struct libusb20_device *
 libusb20_be_device_foreach(struct libusb20_backend *pbe, struct libusb20_device *pdev)
 {

==== //depot/projects/usb/src/lib/libusb/libusb20.h#11 (text+ko) ====

@@ -277,6 +277,7 @@
 int	libusb20_be_remove_dev_quirk(struct libusb20_backend *pbe, struct libusb20_quirk *pq);
 int	libusb20_be_get_template(struct libusb20_backend *pbe, int *ptemp);
 int	libusb20_be_set_template(struct libusb20_backend *pbe, int temp);
+int	libusb20_be_wait_enumeration(struct libusb20_backend *pbe, int, int);
 
 /* USB backend operations */
 

==== //depot/projects/usb/src/lib/libusb/libusb20_int.h#10 (text+ko) ====

@@ -56,6 +56,7 @@
 typedef void (libusb20_exit_backend_t)(struct libusb20_backend *pbe);
 typedef int (libusb20_root_set_template_t)(struct libusb20_backend *pbe, int temp);
 typedef int (libusb20_root_get_template_t)(struct libusb20_backend *pbe, int *ptemp);
+typedef int (libusb20_root_wait_enumeration_t)(struct libusb20_backend *pbe, int, int);
 
 #define	LIBUSB20_DEFINE(n,field) \
   libusb20_##field##_t *field;
@@ -77,6 +78,7 @@
   m(n, root_remove_dev_quirk) \
   m(n, root_set_template) \
   m(n, root_get_template) \
+  m(n, root_wait_enumeration) \
   /* mandatory device methods */ \
   m(n, open_device) \
   m(n, close_device) \

==== //depot/projects/usb/src/lib/libusb/libusb20_ugen20.c#13 (text+ko) ====

@@ -56,6 +56,7 @@
 static libusb20_root_remove_dev_quirk_t ugen20_root_remove_dev_quirk;
 static libusb20_root_set_template_t ugen20_root_set_template;
 static libusb20_root_get_template_t ugen20_root_get_template;
+static libusb20_root_wait_enumeration_t ugen20_root_wait_enumeration;
 
 const struct libusb20_backend_methods libusb20_ugen20_backend = {
 	LIBUSB20_BACKEND(LIBUSB20_DECLARE, ugen20)
@@ -1013,3 +1014,27 @@
 {
 	return (ugen20_be_ioctl(USB_GET_TEMPLATE, ptemp));
 }
+
+static int
+ugen20_root_wait_enumeration(struct libusb20_backend *pbe, int timeout, int flag)
+{
+	struct usb_wait_enumeration info;
+	int error;
+
+	if (timeout < 0)
+		timeout = 0;
+	else if (timeout > 65535)
+		timeout = 65535;
+
+	memset(&info, 0, sizeof(info));
+
+	info.timeout = timeout;
+	info.flag = flag;
+
+	error = ugen20_be_ioctl(USB_WAIT_ENUMERATION, &info);
+
+	if (error)
+		usleep(25000);		/* nice it */
+
+	return (error);
+}

==== //depot/projects/usb/src/sys/dev/usb/usb_dev.c#40 (text+ko) ====

@@ -153,6 +153,8 @@
 
 static TAILQ_HEAD(, usb_symlink) usb_sym_head;
 static struct sx usb_sym_lock;
+static struct cv usb_enum_cv;
+static int usb_enum_tick;
 
 struct mtx usb_ref_lock;
 
@@ -172,6 +174,21 @@
 }
 
 /*------------------------------------------------------------------------*
+ *	usb_enum_broadcast
+ *
+ * This function is used to wakeup userland threads waiting for USB
+ * enumeration.
+ *------------------------------------------------------------------------*/
+void
+usb_enum_broadcast(void)
+{
+	mtx_lock(&usb_ref_lock);
+	usb_enum_tick = ticks;
+	cv_broadcast(&usb_enum_cv);
+	mtx_unlock(&usb_ref_lock);
+}
+
+/*------------------------------------------------------------------------*
  *	usb_ref_device
  *
  * This function is used to atomically refer an USB device by its
@@ -934,6 +951,8 @@
 {
 	mtx_init(&usb_ref_lock, "USB ref mutex", NULL, MTX_DEF);
 	sx_init(&usb_sym_lock, "USB sym mutex");
+	cv_init(&usb_enum_cv, "USB enumeration");
+
 	TAILQ_INIT(&usb_sym_head);
 
 	/* check the UGEN methods */
@@ -966,8 +985,16 @@
 		usb_dev = NULL;
 	
 	}
+
+	/* wake up any left-overs */
+	usb_enum_broadcast();
+
+	/* wait for any left-overs to return */
+	pause("WENUM", hz / 2);
+
 	mtx_destroy(&usb_ref_lock);
 	sx_destroy(&usb_sym_lock);
+	cv_destroy(&usb_enum_cv);
 }
 
 SYSUNINIT(usb_dev_uninit, SI_SUB_KICK_SCHEDULER, SI_ORDER_ANY, usb_dev_uninit, NULL);
@@ -1454,33 +1481,76 @@
 {
 	union {
 		struct usb_read_dir *urd;
+		struct usb_wait_enumeration *uwe;
 		void* data;
 	} u;
-	int err = ENOTTY;
+	int error;
+	int delta;
+	int timeout;
 
 	u.data = data;
 	switch (cmd) {
 		case USB_READ_DIR:
-			err = usb_read_symlink(u.urd->urd_data,
+			error = usb_read_symlink(u.urd->urd_data,
 			    u.urd->urd_startentry, u.urd->urd_maxlen);
 			break;
 		case USB_DEV_QUIRK_GET:
 		case USB_QUIRK_NAME_GET:
 		case USB_DEV_QUIRK_ADD:
 		case USB_DEV_QUIRK_REMOVE:
-			err = usb_quirk_ioctl_p(cmd, data, fflag, td);
+			error = usb_quirk_ioctl_p(cmd, data, fflag, td);
 			break;
 		case USB_GET_TEMPLATE:
 			*(int *)data = usb_template;
+			error = 0;
 			break;
 		case USB_SET_TEMPLATE:
-			err = priv_check(curthread, PRIV_DRIVER);
-			if (err)
+			error = priv_check(curthread, PRIV_DRIVER);
+			if (error)
 				break;
 			usb_template = *(int *)data;
 			break;
+		case USB_WAIT_ENUMERATION:
+			mtx_lock(&usb_ref_lock);
+			/* 
+			 * Check if there was a recent enumeration or
+			 * detach event. Else wait for the next
+			 * enumeration event.
+			 */
+			delta = ticks - usb_enum_tick;
+			if ((delta >= 0) && (delta <= (hz / 4))) {
+				error = 0;
+			} else if (u.uwe->timeout != 0) {
+
+				/* subtract post-delay from timeout */
+				timeout = u.uwe->timeout;
+				if (timeout >= 251)
+					timeout -= 250;
+				else
+					timeout = 1;
+
+				/* wait for enumeration or timeout */
+				error = cv_timedwait_sig(&usb_enum_cv,
+				    &usb_ref_lock, USB_MS_TO_TICKS(timeout));
+
+				/* timeouts are not considered errors */
+				if (error == EWOULDBLOCK)
+					error = 0;
+			} else {
+				/* wait for enumeration */
+				error = cv_wait_sig(&usb_enum_cv,
+				    &usb_ref_lock);
+			}
+			mtx_unlock(&usb_ref_lock);
+
+			/* Wait a little bit for stuff to stabilise */
+			usb_pause_mtx(NULL, hz / 4);
+			break;
+		default:
+			error = ENOTTY;
+			break;
 	}
-	return (err);
+	return (error);
 }
 
 static int

==== //depot/projects/usb/src/sys/dev/usb/usb_dev.h#18 (text+ko) ====

@@ -150,5 +150,6 @@
 void	usb_free_symlink(struct usb_symlink *ps);
 int	usb_read_symlink(uint8_t *user_ptr, uint32_t startentry,
 	    uint32_t user_len);
+void	usb_enum_broadcast(void);
 
 #endif					/* _USB_DEV_H_ */

==== //depot/projects/usb/src/sys/dev/usb/usb_device.c#63 (text+ko) ====

@@ -2393,6 +2393,8 @@
 		device_get_nameunit(device_get_parent(udev->bus->bdev)));
 
 	devctl_queue_data(data);
+
+	usb_enum_broadcast();
 }
 
 /*------------------------------------------------------------------------*

==== //depot/projects/usb/src/sys/dev/usb/usb_ioctl.h#6 (text+ko) ====

@@ -59,6 +59,11 @@
 	uint8_t	uai_alt_index;
 };
 
+struct usb_wait_enumeration {
+	uint16_t timeout;	/* milliseconds, if set */
+	uint16_t flag;
+};
+
 struct usb_gen_descriptor {
 	void   *ugd_data;
 	uint16_t ugd_lang_id;
@@ -248,6 +253,7 @@
 #define	USB_GET_POWER_MODE	_IOR ('U', 146, int)
 #define	USB_SET_TEMPLATE	_IOW ('U', 147, int)
 #define	USB_GET_TEMPLATE	_IOR ('U', 148, int)
+#define	USB_WAIT_ENUMERATION	_IOW ('U', 149, struct usb_wait_enumeration)
 
 /* Modem device */
 #define	USB_GET_CM_OVER_DATA	_IOR ('U', 180, int)



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201002141204.o1EC4YTt011427>