PERFORCE change 174691 for review
Hans Petter Selasky
hselasky at FreeBSD.org
Sun Feb 14 12:04:35 UTC 2010
http://p4web.freebsd.org/chv.cgi?CH=174691
Change 174691 by hselasky at 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)
More information about the p4-projects
mailing list