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>