From 12bf7672a198d5490967f585b3a15dfe099ef47e Mon Sep 17 00:00:00 2001 From: hselasky Date: Wed, 29 Jun 2016 11:06:13 +0000 Subject: [PATCH] MFC r301956, r301957, r301964, r301966, r301968, r301969, r302080, r302125 and r302171: Added multiple new LibUSB v1.0 API functions. Streams support is only available in FreeBSD 10+. Refer to the individual commits for more details. git-svn-id: svn://svn.freebsd.org/base/stable/9@302276 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- lib/libusb/Makefile | 18 +++ lib/libusb/libusb.3 | 162 ++++++++++++++++++++++- lib/libusb/libusb.h | 85 ++++++++++++ lib/libusb/libusb10.c | 79 +++++++++++- lib/libusb/libusb10.h | 19 +++ lib/libusb/libusb10_desc.c | 168 ++++++++++++++++++++++++ lib/libusb/libusb10_hotplug.c | 237 ++++++++++++++++++++++++++++++++++ lib/libusb/libusb10_io.c | 44 +++++++ lib/libusb/libusb20.c | 6 + lib/libusb/libusb20_int.h | 3 + 10 files changed, 814 insertions(+), 7 deletions(-) create mode 100644 lib/libusb/libusb10_hotplug.c diff --git a/lib/libusb/Makefile b/lib/libusb/Makefile index 93180d80a..06cdf75f5 100644 --- a/lib/libusb/Makefile +++ b/lib/libusb/Makefile @@ -31,6 +31,7 @@ SRCS+= libusb01.c INCS+= libusb.h SRCS+= libusb10.c SRCS+= libusb10_desc.c +SRCS+= libusb10_hotplug.c SRCS+= libusb10_io.c .if defined(COMPAT_32BIT) @@ -40,6 +41,7 @@ CFLAGS+= -DCOMPAT_32BIT .include # LibUSB v1.0 +MLINKS += libusb.3 libusb_get_version.3 MLINKS += libusb.3 libusb_init.3 MLINKS += libusb.3 libusb_exit.3 MLINKS += libusb.3 libusb_strerror.3 @@ -48,6 +50,7 @@ MLINKS += libusb.3 libusb_set_debug.3 MLINKS += libusb.3 libusb_get_device_list.3 MLINKS += libusb.3 libusb_free_device_list.3 MLINKS += libusb.3 libusb_get_bus_number.3 +MLINKS += libusb.3 libusb_get_port_number.3 MLINKS += libusb.3 libusb_get_device_address.3 MLINKS += libusb.3 libusb_get_device_speed.3 MLINKS += libusb.3 libusb_get_max_packet_size.3 @@ -72,6 +75,7 @@ MLINKS += libusb.3 libusb_get_driver_np.3 MLINKS += libusb.3 libusb_detach_kernel_driver.3 MLINKS += libusb.3 libusb_detach_kernel_driver_np.3 MLINKS += libusb.3 libusb_attach_kernel_driver.3 +MLINKS += libusb.3 libusb_set_auto_detach_kernel_driver.3 MLINKS += libusb.3 libusb_get_device_descriptor.3 MLINKS += libusb.3 libusb_get_active_config_descriptor.3 MLINKS += libusb.3 libusb_get_config_descriptor.3 @@ -81,10 +85,22 @@ MLINKS += libusb.3 libusb_get_string_descriptor.3 MLINKS += libusb.3 libusb_get_string_descriptor_ascii.3 MLINKS += libusb.3 libusb_parse_ss_endpoint_comp.3 MLINKS += libusb.3 libusb_free_ss_endpoint_comp.3 +MLINKS += libusb.3 libusb_get_ss_endpoint_companion_descriptor.3 +MLINKS += libusb.3 libusb_free_ss_endpoint_companion_descriptor.3 MLINKS += libusb.3 libusb_parse_bos_descriptor.3 MLINKS += libusb.3 libusb_free_bos_descriptor.3 +MLINKS += libusb.3 libusb_get_usb_2_0_extension_descriptor.3 +MLINKS += libusb.3 libusb_free_usb_2_0_extension_descriptor.3 +MLINKS += libusb.3 libusb_get_ss_usb_device_capability_descriptor.3 +MLINKS += libusb.3 libusb_free_ss_usb_device_capability_descriptor.3 +MLINKS += libusb.3 libusb_get_container_id_descriptor.3 +MLINKS += libusb.3 libusb_free_container_id_descriptor.3 +MLINKS += libusb.3 libusb_alloc_streams.3 +MLINKS += libusb.3 libusb_free_streams.3 MLINKS += libusb.3 libusb_alloc_transfer.3 MLINKS += libusb.3 libusb_free_transfer.3 +MLINKS += libusb.3 libusb_transfer_set_stream_id.3 +MLINKS += libusb.3 libusb_transfer_get_stream_id.3 MLINKS += libusb.3 libusb_submit_transfer.3 MLINKS += libusb.3 libusb_cancel_transfer.3 MLINKS += libusb.3 libusb_control_transfer.3 @@ -106,6 +122,8 @@ MLINKS += libusb.3 libusb_handle_events_locked.3 MLINKS += libusb.3 libusb_get_next_timeout.3 MLINKS += libusb.3 libusb_set_pollfd_notifiers.3 MLINKS += libusb.3 libusb_get_pollfds.3 +MLINKS += libusb.3 libusb_hotplug_register_callback.3 +MLINKS += libusb.3 libusb_hotplug_deregister_callback.3 # LibUSB v0.1 MLINKS += libusb.3 usb_open.3 diff --git a/lib/libusb/libusb.3 b/lib/libusb/libusb.3 index 785c8c475..c6f4082c7 100644 --- a/lib/libusb/libusb.3 +++ b/lib/libusb/libusb.3 @@ -26,7 +26,7 @@ .\" .\" $FreeBSD$ .\" -.Dd January 5, 2014 +.Dd June 23, 2016 .Dt LIBUSB 3 .Os .Sh NAME @@ -43,6 +43,10 @@ The library contains interfaces for directly managing a usb device. The current implementation supports v1.0 of the libusb API. .Sh LIBRARY INITIALISATION / DEINITIALISATION +.Ft "const struct libusb_version *" +.Fn libusb_get_version "void" +This function returns version information about LibUSB. +.Pp .Ft int .Fn libusb_init libusb_context **ctx This function initialises libusb. @@ -102,6 +106,12 @@ counter decremented once. Returns the number of the bus contained by the device .Fa dev . .Pp +.Ft uint8_t +.Fn libusb_get_port_number "libusb_device *dev" +Returns the port number which the device given by +.Fa dev +is attached to. +.Pp .Ft int .Fn libusb_get_port_numbers "libusb_device *dev" "uint8_t *buf" "uint8_t bufsize" Stores, in the buffer @@ -288,6 +298,18 @@ LIBUSB_ERROR_NO_DEVICE if the device has been disconnected, LIBUSB_ERROR_BUSY if the driver cannot be attached because the interface is claimed by a program or driver and a LIBUSB_ERROR code on failure. +.Pp +.Ft int +.Fn libusb_set_auto_detach_kernel_driver "libusb_device_handle *devh" "int enable" +This function enables automatic kernel interface driver detach when an +interface is claimed. +When the interface is restored the kernel driver is allowed to be re-attached. +If the +.Fa enable +argument is non-zero the feature is enabled. +Else disabled. +Returns 0 on success and a LIBUSB_ERROR code on +failure. .Sh USB DESCRIPTORS .Ft int .Fn libusb_get_device_descriptor "libusb_device *dev" "libusb_device_descriptor *desc" @@ -354,7 +376,31 @@ freed using the libusb_free_ss_endpoint_comp function. .Pp .Ft void .Fn libusb_free_ss_endpoint_comp "libusb_ss_endpoint_companion_descriptor *ep_comp" -This function is NULL safe and frees a parsed USB 3.0 endpoint companion descriptor. +This function is NULL safe and frees a parsed USB 3.0 endpoint companion descriptor given by +.Fa ep_comp . +.Pp +.Ft int +.Fn libusb_get_ss_endpoint_companion_descriptor "struct libusb_context *ctx" "const struct libusb_endpoint_descriptor *endpoint" "struct libusb_ss_endpoint_companion_descriptor **ep_comp" +This function finds and parses the USB 3.0 endpoint companion descriptor given by +.Fa endpoint . +Returns zero on success and a LIBUSB_ERROR code on failure. +On success the parsed USB 3.0 endpoint companion descriptor must be +freed using the libusb_free_ss_endpoint_companion_descriptor function. +.Pp +.Ft void +.Fn libusb_free_ss_endpoint_companion_descriptor "struct libusb_ss_endpoint_companion_descriptor *ep_comp" +This function is NULL safe and frees a parsed USB 3.0 endpoint companion descriptor given by +.Fa ep_comp . +.Pp +.Ft int +.Fn libusb_get_bos_descriptor "libusb_device_handle *handle" "struct libusb_bos_descriptor **bos" +This function queries the USB device given by +.Fa handle +and stores a pointer to a parsed BOS descriptor into +.Fa bos . +Returns zero on success and a LIBUSB_ERROR code on failure. +On success the parsed BOS descriptor must be +freed using the libusb_free_bos_descriptor function. .Pp .Ft int .Fn libusb_parse_bos_descriptor "const void *buf" "int len" "libusb_bos_descriptor **bos" @@ -370,7 +416,53 @@ libusb_free_bos_descriptor function. .Pp .Ft void .Fn libusb_free_bos_descriptor "libusb_bos_descriptor *bos" -This function is NULL safe and frees a parsed BOS descriptor. +This function is NULL safe and frees a parsed BOS descriptor given by +.Fa bos . +.Pp +.Ft int +.Fn libusb_get_usb_2_0_extension_descriptor "struct libusb_context *ctx" "struct libusb_bos_dev_capability_descriptor *dev_cap" "struct libusb_usb_2_0_extension_descriptor **usb_2_0_extension" +This function parses the USB 2.0 extension descriptor from the descriptor given by +.Fa dev_cap +and stores a pointer to the parsed descriptor into +.Fa usb_2_0_extension . +Returns zero on success and a LIBUSB_ERROR code on failure. +On success the parsed USB 2.0 extension descriptor must be freed using the +libusb_free_usb_2_0_extension_descriptor function. +.Pp +.Ft void +.Fn libusb_free_usb_2_0_extension_descriptor "struct libusb_usb_2_0_extension_descriptor *usb_2_0_extension" +This function is NULL safe and frees a parsed USB 2.0 extension descriptor given by +.Fa usb_2_0_extension . +.Pp +.Ft int +.Fn libusb_get_ss_usb_device_capability_descriptor "struct libusb_context *ctx" "struct libusb_bos_dev_capability_descriptor *dev_cap" "struct libusb_ss_usb_device_capability_descriptor **ss_usb_device_capability" +This function parses the SuperSpeed device capability descriptor from the descriptor given by +.Fa dev_cap +and stores a pointer to the parsed descriptor into +.Fa ss_usb_device_capability . +Returns zero on success and a LIBUSB_ERROR code on failure. +On success the parsed SuperSpeed device capability descriptor must be freed using the +libusb_free_ss_usb_device_capability_descriptor function. +.Pp +.Ft void +.Fn libusb_free_ss_usb_device_capability_descriptor "struct libusb_ss_usb_device_capability_descriptor *ss_usb_device_capability" +This function is NULL safe and frees a parsed SuperSpeed device capability descriptor given by +.Fa ss_usb_device_capability . +.Pp +.Ft int +.Fn libusb_get_container_id_descriptor "struct libusb_context *ctx" "struct libusb_bos_dev_capability_descriptor *dev_cap" "struct libusb_container_id_descriptor **container_id" +This function parses the container ID descriptor from the descriptor given by +.Fa dev_cap +and stores a pointer to the parsed descriptor into +.Fa container_id . +Returns zero on success and a LIBUSB_ERROR code on failure. +On success the parsed container ID descriptor must be freed using the +libusb_free_container_id_descriptor function. +.Pp +.Ft void +.Fn libusb_free_container_id_descriptor "struct libusb_container_id_descriptor *container_id" +This function is NULL safe and frees a parsed container ID descriptor given by +.Fa container_id . .Sh USB ASYNCHRONOUS I/O .Ft struct libusb_transfer * .Fn libusb_alloc_transfer "int iso_packets" @@ -429,6 +521,29 @@ if the transfer timed out, LIBUSB_ERROR_PIPE if the control request was not supported, LIBUSB_ERROR_OVERFLOW if the device offered more data, LIBUSB_ERROR_NO_DEVICE if the device has been disconnected and a LIBUSB_ERROR code on other failure. +.Sh USB STREAMS SUPPORT +.Ft int +.Fn libusb_alloc_streams "libusb_device_handle *dev" "uint32_t num_streams" "unsigned char *endpoints" "int num_endpoints" +This function verifies that the given number of streams using the +given number of endpoints is allowed and allocates the resources +needed to use so-called USB streams. +Currently only a single stream per endpoint is supported to simplify +the internals of LibUSB. +This function returns 0 on success or a LIBUSB_ERROR code on failure. +.Pp +.Ft int +.Fn libusb_free_streams "libusb_device_handle *dev" "unsigned char *endpoints" "int num_endpoints" +This function release resources needed for streams usage. +Returns 0 on success or a LIBUSB_ERROR code on failure. +.Pp +.Ft void +.Fn libusb_transfer_set_stream_id "struct libusb_transfer *transfer" "uint32_t stream_id" +This function sets the stream ID for the given USB transfer. +.Pp +.Ft uint32_t +.Fn libusb_transfer_get_stream_id "struct libusb_transfer *transfer" +This function returns the stream ID for the given USB transfer. +If no stream ID is used a value of zero is returned. .Sh USB EVENTS .Ft int .Fn libusb_try_lock_events "libusb_context *ctx" @@ -550,6 +665,47 @@ that libusb uses as an event source. Retrive a list of file descriptors that should be polled by your main loop as libusb event sources. Returns a NULL-terminated list on success or NULL on failure. +.Pp +.Ft int +.Fn libusb_hotplug_register_callback "libusb_context *ctx" "libusb_hotplug_event events" "libusb_hotplug_flag flags" "int vendor_id" "int product_id" "int dev_class" "libusb_hotplug_callback_fn cb_fn" "void *user_data" "libusb_hotplug_callback_handle *handle" +This function registers a hotplug filter. +The +.Fa events +argument select which events makes the hotplug filter trigger. +Available event values are LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED and LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT. +One or more events must be specified. +The +.Fa vendor_id , +.Fa product_id +and +.Fa dev_class +arguments can be set to LIBUSB_HOTPLUG_MATCH_ANY to match any value in the USB device descriptor. +Else the specified value is used for matching. +If the +.Fa flags +argument is set to LIBUSB_HOTPLUG_ENUMERATE, all currently attached and matching USB devices will be passed to the hotplug filter, given by the +.Fa cb_fn +argument. +Else the +.Fa flags +argument should be set to LIBUSB_HOTPLUG_NO_FLAGS. +This function returns 0 upon success or a LIBUSB_ERROR code on failure. +.Pp +.Ft int +.Fn libusb_hotplug_callback_fn "libusb_context *ctx" "libusb_device *device" "libusb_hotplug_event event" "void *user_data" +The hotplug filter function. +If this function returns non-zero, the filter is removed. +Else the filter is kept and can receive more events. +The +.Fa user_data +argument is the same as given when the filter was registered. +The +.Fa event +argument can be either of LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED or LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT. +.Pp +.Ft void +.Fn libusb_hotplug_deregister_callback "libusb_context *ctx" "libusb_hotplug_callback_handle handle" +This function unregisters a hotplug filter. .Sh LIBUSB VERSION 0.1 COMPATIBILITY The library is also compliant with LibUSB version 0.1.12. .Pp diff --git a/lib/libusb/libusb.h b/lib/libusb/libusb.h index d2c534e1b..5819fc04c 100644 --- a/lib/libusb/libusb.h +++ b/lib/libusb/libusb.h @@ -30,6 +30,8 @@ #include #include +#define LIBUSB_API_VERSION 0x01000102 + #define LIBUSB_CALL #ifdef __cplusplus @@ -96,6 +98,10 @@ enum libusb_device_capability_type { #define LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY_SIZE 7 #define LIBUSB_SS_USB_DEVICE_CAPABILITY_SIZE 10 +#define LIBUSB_BT_USB_2_0_EXTENSION_SIZE 7 +#define LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE 10 +#define LIBUSB_BT_CONTAINER_ID_SIZE 20 + #define LIBUSB_ENDPOINT_ADDRESS_MASK 0x0f #define LIBUSB_ENDPOINT_DIR_MASK 0x80 @@ -160,6 +166,13 @@ enum libusb_iso_usage_type { LIBUSB_ISO_USAGE_TYPE_IMPLICIT = 2, }; +enum libusb_bos_type { + LIBUSB_BT_WIRELESS_USB_DEVICE_CAPABILITY = 1, + LIBUSB_BT_USB_2_0_EXTENSION = 2, + LIBUSB_BT_SS_USB_DEVICE_CAPABILITY = 3, + LIBUSB_BT_CONTAINER_ID = 4, +}; + enum libusb_error { LIBUSB_SUCCESS = 0, LIBUSB_ERROR_IO = -1, @@ -207,24 +220,47 @@ enum libusb_debug_level { LIBUSB_DEBUG_TRANSFER=2, }; +#define LIBUSB_HOTPLUG_MATCH_ANY -1 + +typedef enum { + LIBUSB_HOTPLUG_NO_FLAGS = 0, + LIBUSB_HOTPLUG_ENUMERATE = 1 << 0, +} libusb_hotplug_flag; + +typedef enum { + LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED = 1, + LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT = 2, +} libusb_hotplug_event; + /* libusb structures */ struct libusb_context; struct libusb_device; struct libusb_transfer; struct libusb_device_handle; +struct libusb_hotplug_callback_handle_struct; struct libusb_pollfd { int fd; short events; }; +struct libusb_version { + const uint16_t major; + const uint16_t minor; + const uint16_t micro; + const uint16_t nano; + const char *rc; + const char *describe; +}; + typedef struct libusb_context libusb_context; typedef struct libusb_device libusb_device; typedef struct libusb_device_handle libusb_device_handle; typedef struct libusb_pollfd libusb_pollfd; typedef void (*libusb_pollfd_added_cb) (int fd, short events, void *user_data); typedef void (*libusb_pollfd_removed_cb) (int fd, void *user_data); +typedef struct libusb_hotplug_callback_handle_struct *libusb_hotplug_callback_handle; typedef struct libusb_device_descriptor { uint8_t bLength; @@ -322,6 +358,13 @@ typedef struct libusb_ss_usb_device_capability_descriptor { uint16_t wU2DevExitLat; } libusb_ss_usb_device_capability_descriptor __aligned(sizeof(void *)); +typedef struct libusb_bos_dev_capability_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDevCapabilityType; + uint8_t dev_capability_data[0]; +} libusb_bos_dev_capability_descriptor __aligned(sizeof(void *)); + typedef struct libusb_bos_descriptor { uint8_t bLength; uint8_t bDescriptorType; @@ -331,6 +374,21 @@ typedef struct libusb_bos_descriptor { struct libusb_ss_usb_device_capability_descriptor *ss_usb_cap; } libusb_bos_descriptor __aligned(sizeof(void *)); +typedef struct libusb_usb_2_0_extension_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDevCapabilityType; + uint32_t bmAttributes; +} libusb_usb_2_0_extension_descriptor __aligned(sizeof(void *)); + +typedef struct libusb_container_id_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDevCapabilityType; + uint8_t bReserved; + uint8_t ContainerID[16]; +} libusb_container_id_descriptor __aligned(sizeof(void *)); + typedef struct libusb_control_setup { uint8_t bmRequestType; uint8_t bRequest; @@ -369,6 +427,7 @@ typedef struct libusb_transfer { /* Library initialisation */ void libusb_set_debug(libusb_context * ctx, int level); +const struct libusb_version *libusb_get_version(void); const char *libusb_strerror(int code); const char *libusb_error_name(int code); int libusb_init(libusb_context ** context); @@ -379,6 +438,7 @@ void libusb_exit(struct libusb_context *ctx); ssize_t libusb_get_device_list(libusb_context * ctx, libusb_device *** list); void libusb_free_device_list(libusb_device ** list, int unref_devices); uint8_t libusb_get_bus_number(libusb_device * dev); +uint8_t libusb_get_port_number(libusb_device * dev); int libusb_get_port_numbers(libusb_device *dev, uint8_t *buf, uint8_t bufsize); int libusb_get_port_path(libusb_context *ctx, libusb_device *dev, uint8_t *buf, uint8_t bufsize); uint8_t libusb_get_device_address(libusb_device * dev); @@ -404,6 +464,7 @@ int libusb_get_driver(libusb_device_handle * devh, int interface, char *name, in int libusb_detach_kernel_driver_np(libusb_device_handle * devh, int interface); int libusb_detach_kernel_driver(libusb_device_handle * devh, int interface); int libusb_attach_kernel_driver(libusb_device_handle * devh, int interface); +int libusb_set_auto_detach_kernel_driver(libusb_device_handle *dev, int enable); int libusb_set_interface_alt_setting(libusb_device_handle * devh, int interface_number, int alternate_setting); /* USB Descriptors */ @@ -413,6 +474,8 @@ int libusb_get_active_config_descriptor(libusb_device * dev, struct libusb_confi int libusb_get_config_descriptor(libusb_device * dev, uint8_t config_index, struct libusb_config_descriptor **config); int libusb_get_config_descriptor_by_value(libusb_device * dev, uint8_t bConfigurationValue, struct libusb_config_descriptor **config); void libusb_free_config_descriptor(struct libusb_config_descriptor *config); +int libusb_get_ss_endpoint_companion_descriptor(struct libusb_context *ctx, const struct libusb_endpoint_descriptor *endpoint, struct libusb_ss_endpoint_companion_descriptor **ep_comp); +void libusb_free_ss_endpoint_companion_descriptor(struct libusb_ss_endpoint_companion_descriptor *ep_comp); int libusb_get_string_descriptor(libusb_device_handle * devh, uint8_t desc_index, uint16_t langid, unsigned char *data, int length); int libusb_get_string_descriptor_ascii(libusb_device_handle * devh, uint8_t desc_index, uint8_t *data, int length); int libusb_get_descriptor(libusb_device_handle * devh, uint8_t desc_type, uint8_t desc_index, uint8_t *data, int length); @@ -420,6 +483,13 @@ int libusb_parse_ss_endpoint_comp(const void *buf, int len, struct libusb_ss_end void libusb_free_ss_endpoint_comp(struct libusb_ss_endpoint_companion_descriptor *ep_comp); int libusb_parse_bos_descriptor(const void *buf, int len, struct libusb_bos_descriptor **bos); void libusb_free_bos_descriptor(struct libusb_bos_descriptor *bos); +int libusb_get_bos_descriptor(libusb_device_handle *handle, struct libusb_bos_descriptor **bos); +int libusb_get_usb_2_0_extension_descriptor(struct libusb_context *ctx, struct libusb_bos_dev_capability_descriptor *dev_cap, struct libusb_usb_2_0_extension_descriptor **usb_2_0_extension); +void libusb_free_usb_2_0_extension_descriptor(struct libusb_usb_2_0_extension_descriptor *usb_2_0_extension); +int libusb_get_ss_usb_device_capability_descriptor(struct libusb_context *ctx, struct libusb_bos_dev_capability_descriptor *dev_cap, struct libusb_ss_usb_device_capability_descriptor **ss_usb_device_capability); +void libusb_free_ss_usb_device_capability_descriptor(struct libusb_ss_usb_device_capability_descriptor *ss_usb_device_capability); +int libusb_get_container_id_descriptor(struct libusb_context *ctx, struct libusb_bos_dev_capability_descriptor *dev_cap, struct libusb_container_id_descriptor **container_id); +void libusb_free_container_id_descriptor(struct libusb_container_id_descriptor *container_id); /* Asynchronous device I/O */ @@ -468,6 +538,21 @@ int libusb_interrupt_transfer(libusb_device_handle * devh, uint8_t endpoint, uin uint16_t libusb_cpu_to_le16(uint16_t x); uint16_t libusb_le16_to_cpu(uint16_t x); +/* Hotplug support */ + +typedef int (*libusb_hotplug_callback_fn)(libusb_context *ctx, + libusb_device *device, libusb_hotplug_event event, void *user_data); + +int libusb_hotplug_register_callback(libusb_context *ctx, libusb_hotplug_event events, libusb_hotplug_flag flags, int vendor_id, int product_id, int dev_class, libusb_hotplug_callback_fn cb_fn, void *user_data, libusb_hotplug_callback_handle *handle); +void libusb_hotplug_deregister_callback(libusb_context *ctx, libusb_hotplug_callback_handle handle); + +/* Streams support */ + +int libusb_alloc_streams(libusb_device_handle *dev, uint32_t num_streams, unsigned char *endpoints, int num_endpoints); +int libusb_free_streams(libusb_device_handle *dev, unsigned char *endpoints, int num_endpoints); +void libusb_transfer_set_stream_id(struct libusb_transfer *transfer, uint32_t stream_id); +uint32_t libusb_transfer_get_stream_id(struct libusb_transfer *transfer); + #if 0 { /* indent fix */ #endif diff --git a/lib/libusb/libusb10.c b/lib/libusb/libusb10.c index 4ca10d99a..5dab600a1 100644 --- a/lib/libusb/libusb10.c +++ b/lib/libusb/libusb10.c @@ -63,6 +63,22 @@ static void libusb10_submit_transfer_sub(struct libusb20_device *, uint8_t); /* Library initialisation / deinitialisation */ +static const struct libusb_version libusb_version = { + .major = 1, + .minor = 0, + .micro = 0, + .nano = 2016, + .rc = "", + .describe = "http://www.freebsd.org" +}; + +const struct libusb_version * +libusb_get_version(void) +{ + + return (&libusb_version); +} + void libusb_set_debug(libusb_context *ctx, int level) { @@ -112,24 +128,34 @@ libusb_init(libusb_context **context) } TAILQ_INIT(&ctx->pollfds); TAILQ_INIT(&ctx->tr_done); + TAILQ_INIT(&ctx->hotplug_cbh); + TAILQ_INIT(&ctx->hotplug_devs); if (pthread_mutex_init(&ctx->ctx_lock, NULL) != 0) { free(ctx); return (LIBUSB_ERROR_NO_MEM); } + if (pthread_mutex_init(&ctx->hotplug_lock, NULL) != 0) { + pthread_mutex_destroy(&ctx->ctx_lock); + free(ctx); + return (LIBUSB_ERROR_NO_MEM); + } if (pthread_condattr_init(&attr) != 0) { pthread_mutex_destroy(&ctx->ctx_lock); + pthread_mutex_destroy(&ctx->hotplug_lock); free(ctx); return (LIBUSB_ERROR_NO_MEM); } if (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC) != 0) { pthread_mutex_destroy(&ctx->ctx_lock); + pthread_mutex_destroy(&ctx->hotplug_lock); pthread_condattr_destroy(&attr); free(ctx); return (LIBUSB_ERROR_OTHER); } if (pthread_cond_init(&ctx->ctx_cond, &attr) != 0) { pthread_mutex_destroy(&ctx->ctx_lock); + pthread_mutex_destroy(&ctx->hotplug_lock); pthread_condattr_destroy(&attr); free(ctx); return (LIBUSB_ERROR_NO_MEM); @@ -137,10 +163,12 @@ libusb_init(libusb_context **context) pthread_condattr_destroy(&attr); ctx->ctx_handler = NO_THREAD; + ctx->hotplug_handler = NO_THREAD; ret = pipe(ctx->ctrl_pipe); if (ret < 0) { pthread_mutex_destroy(&ctx->ctx_lock); + pthread_mutex_destroy(&ctx->hotplug_lock); pthread_cond_destroy(&ctx->ctx_cond); free(ctx); return (LIBUSB_ERROR_OTHER); @@ -173,12 +201,27 @@ libusb_exit(libusb_context *ctx) if (ctx == NULL) return; + /* stop hotplug thread, if any */ + + if (ctx->hotplug_handler != NO_THREAD) { + pthread_t td; + void *ptr; + + HOTPLUG_LOCK(ctx); + td = ctx->hotplug_handler; + ctx->hotplug_handler = NO_THREAD; + HOTPLUG_UNLOCK(ctx); + + pthread_join(td, &ptr); + } + /* XXX cleanup devices */ libusb10_remove_pollfd(ctx, &ctx->ctx_poll); close(ctx->ctrl_pipe[0]); close(ctx->ctrl_pipe[1]); pthread_mutex_destroy(&ctx->ctx_lock); + pthread_mutex_destroy(&ctx->hotplug_lock); pthread_cond_destroy(&ctx->ctx_cond); pthread_mutex_lock(&default_context_lock); @@ -286,6 +329,14 @@ libusb_get_bus_number(libusb_device *dev) return (libusb20_dev_get_bus_number(dev->os_priv)); } +uint8_t +libusb_get_port_number(libusb_device *dev) +{ + if (dev == NULL) + return (0); /* should not happen */ + return (libusb20_dev_get_parent_port(dev->os_priv)); +} + int libusb_get_port_numbers(libusb_device *dev, uint8_t *buf, uint8_t bufsize) { @@ -607,6 +658,7 @@ int libusb_claim_interface(struct libusb20_device *pdev, int interface_number) { libusb_device *dev; + int err = 0; dev = libusb_get_device(pdev); if (dev == NULL) @@ -615,11 +667,17 @@ libusb_claim_interface(struct libusb20_device *pdev, int interface_number) if (interface_number < 0 || interface_number > 31) return (LIBUSB_ERROR_INVALID_PARAM); + if (pdev->auto_detach != 0) { + err = libusb_detach_kernel_driver(pdev, interface_number); + if (err != 0) + goto done; + } + CTX_LOCK(dev->ctx); dev->claimed_interfaces |= (1 << interface_number); CTX_UNLOCK(dev->ctx); - - return (0); +done: + return (err); } int @@ -635,13 +693,19 @@ libusb_release_interface(struct libusb20_device *pdev, int interface_number) if (interface_number < 0 || interface_number > 31) return (LIBUSB_ERROR_INVALID_PARAM); + if (pdev->auto_detach != 0) { + err = libusb_attach_kernel_driver(pdev, interface_number); + if (err != 0) + goto done; + } + CTX_LOCK(dev->ctx); if (!(dev->claimed_interfaces & (1 << interface_number))) err = LIBUSB_ERROR_NOT_FOUND; - - if (!err) + else dev->claimed_interfaces &= ~(1 << interface_number); CTX_UNLOCK(dev->ctx); +done: return (err); } @@ -843,6 +907,13 @@ libusb_attach_kernel_driver(struct libusb20_device *pdev, int interface) return (0); } +int +libusb_set_auto_detach_kernel_driver(libusb_device_handle *dev, int enable) +{ + dev->auto_detach = (enable ? 1 : 0); + return (0); +} + /* Asynchronous device I/O */ struct libusb_transfer * diff --git a/lib/libusb/libusb10.h b/lib/libusb/libusb10.h index d2a2bd7c1..0260dbca6 100644 --- a/lib/libusb/libusb10.h +++ b/lib/libusb/libusb10.h @@ -34,6 +34,8 @@ #define CTX_LOCK(ctx) pthread_mutex_lock(&(ctx)->ctx_lock) #define CTX_TRYLOCK(ctx) pthread_mutex_trylock(&(ctx)->ctx_lock) #define CTX_UNLOCK(ctx) pthread_mutex_unlock(&(ctx)->ctx_lock) +#define HOTPLUG_LOCK(ctx) pthread_mutex_lock(&(ctx)->hotplug_lock) +#define HOTPLUG_UNLOCK(ctx) pthread_mutex_unlock(&(ctx)->hotplug_lock) #define DPRINTF(ctx, dbg, format, args...) do { \ if ((ctx)->debug == dbg) { \ @@ -65,11 +67,22 @@ struct libusb_super_transfer { uint8_t *curr_data; uint32_t rem_len; uint32_t last_len; + uint32_t stream_id; uint8_t state; #define LIBUSB_SUPER_XFER_ST_NONE 0 #define LIBUSB_SUPER_XFER_ST_PEND 1 }; +struct libusb_hotplug_callback_handle_struct { + TAILQ_ENTRY(libusb_hotplug_callback_handle_struct) entry; + int events; + int vendor; + int product; + int devclass; + libusb_hotplug_callback_fn fn; + void *user_data; +}; + struct libusb_context { int debug; int debug_fixed; @@ -78,12 +91,16 @@ struct libusb_context { int tr_done_gen; pthread_mutex_t ctx_lock; + pthread_mutex_t hotplug_lock; pthread_cond_t ctx_cond; + pthread_t hotplug_handler; pthread_t ctx_handler; #define NO_THREAD ((pthread_t)-1) TAILQ_HEAD(, libusb_super_pollfd) pollfds; TAILQ_HEAD(, libusb_super_transfer) tr_done; + TAILQ_HEAD(, libusb_hotplug_callback_handle_struct) hotplug_cbh; + TAILQ_HEAD(, libusb_device) hotplug_devs; struct libusb_super_pollfd ctx_poll; @@ -101,6 +118,8 @@ struct libusb_device { struct libusb_context *ctx; + TAILQ_ENTRY(libusb_device) hotplug_entry; + TAILQ_HEAD(, libusb_super_transfer) tr_head; struct libusb20_device *os_priv; diff --git a/lib/libusb/libusb10_desc.c b/lib/libusb/libusb10_desc.c index 11e201f37..93c3c6942 100644 --- a/lib/libusb/libusb10_desc.c +++ b/lib/libusb/libusb10_desc.c @@ -404,6 +404,23 @@ libusb_free_ss_endpoint_comp(struct libusb_ss_endpoint_companion_descriptor *ep_ free(ep_comp); } +int +libusb_get_ss_endpoint_companion_descriptor(struct libusb_context *ctx, + const struct libusb_endpoint_descriptor *endpoint, + struct libusb_ss_endpoint_companion_descriptor **ep_comp) +{ + if (endpoint == NULL) + return (LIBUSB_ERROR_INVALID_PARAM); + return (libusb_parse_ss_endpoint_comp(endpoint->extra, endpoint->extra_length, ep_comp)); +} + +void +libusb_free_ss_endpoint_companion_descriptor(struct libusb_ss_endpoint_companion_descriptor *ep_comp) +{ + + libusb_free_ss_endpoint_comp(ep_comp); +} + int libusb_parse_bos_descriptor(const void *buf, int len, struct libusb_bos_descriptor **bos) @@ -515,3 +532,154 @@ libusb_free_bos_descriptor(struct libusb_bos_descriptor *bos) free(bos); } + +int +libusb_get_bos_descriptor(libusb_device_handle *handle, + struct libusb_bos_descriptor **bos) +{ + uint8_t bos_header[LIBUSB_DT_BOS_SIZE] = {0}; + uint16_t wTotalLength; + uint8_t *bos_data; + int err; + + err = libusb_get_descriptor(handle, LIBUSB_DT_BOS, 0, + bos_header, sizeof(bos_header)); + if (err < 0) + return (err); + + wTotalLength = bos_header[2] | (bos_header[3] << 8); + if (wTotalLength < LIBUSB_DT_BOS_SIZE) + return (LIBUSB_ERROR_INVALID_PARAM); + + bos_data = calloc(wTotalLength, 1); + if (bos_data == NULL) + return (LIBUSB_ERROR_NO_MEM); + + err = libusb_get_descriptor(handle, LIBUSB_DT_BOS, 0, + bos_data, wTotalLength); + if (err < 0) + goto done; + + /* avoid descriptor length mismatches */ + bos_data[2] = (wTotalLength & 0xFF); + bos_data[3] = (wTotalLength >> 8); + + err = libusb_parse_bos_descriptor(bos_data, wTotalLength, bos); +done: + free(bos_data); + return (err); +} + +int +libusb_get_usb_2_0_extension_descriptor(struct libusb_context *ctx, + struct libusb_bos_dev_capability_descriptor *dev_cap, + struct libusb_usb_2_0_extension_descriptor **usb_2_0_extension) +{ + struct libusb_usb_2_0_extension_descriptor *desc; + + if (dev_cap == NULL || usb_2_0_extension == NULL || + dev_cap->bDevCapabilityType != LIBUSB_BT_USB_2_0_EXTENSION) + return (LIBUSB_ERROR_INVALID_PARAM); + if (dev_cap->bLength < LIBUSB_BT_USB_2_0_EXTENSION_SIZE) + return (LIBUSB_ERROR_IO); + + desc = malloc(sizeof(*desc)); + if (desc == NULL) + return (LIBUSB_ERROR_NO_MEM); + + desc->bLength = LIBUSB_BT_USB_2_0_EXTENSION_SIZE; + desc->bDescriptorType = dev_cap->bDescriptorType; + desc->bDevCapabilityType = dev_cap->bDevCapabilityType; + desc->bmAttributes = + (dev_cap->dev_capability_data[0]) | + (dev_cap->dev_capability_data[1] << 8) | + (dev_cap->dev_capability_data[2] << 16) | + (dev_cap->dev_capability_data[3] << 24); + + *usb_2_0_extension = desc; + return (0); +} + +void +libusb_free_usb_2_0_extension_descriptor( + struct libusb_usb_2_0_extension_descriptor *usb_2_0_extension) +{ + + free(usb_2_0_extension); +} + +int +libusb_get_ss_usb_device_capability_descriptor(struct libusb_context *ctx, + struct libusb_bos_dev_capability_descriptor *dev_cap, + struct libusb_ss_usb_device_capability_descriptor **ss_usb_device_capability) +{ + struct libusb_ss_usb_device_capability_descriptor *desc; + + if (dev_cap == NULL || ss_usb_device_capability == NULL || + dev_cap->bDevCapabilityType != LIBUSB_BT_SS_USB_DEVICE_CAPABILITY) + return (LIBUSB_ERROR_INVALID_PARAM); + if (dev_cap->bLength < LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE) + return (LIBUSB_ERROR_IO); + + desc = malloc(sizeof(*desc)); + if (desc == NULL) + return (LIBUSB_ERROR_NO_MEM); + + desc->bLength = LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE; + desc->bDescriptorType = dev_cap->bDescriptorType; + desc->bDevCapabilityType = dev_cap->bDevCapabilityType; + desc->bmAttributes = dev_cap->dev_capability_data[0]; + desc->wSpeedSupported = dev_cap->dev_capability_data[1] | + (dev_cap->dev_capability_data[2] << 8); + desc->bFunctionalitySupport = dev_cap->dev_capability_data[3]; + desc->bU1DevExitLat = dev_cap->dev_capability_data[4]; + desc->wU2DevExitLat = dev_cap->dev_capability_data[5] | + (dev_cap->dev_capability_data[6] << 8); + + *ss_usb_device_capability = desc; + return (0); +} + +void +libusb_free_ss_usb_device_capability_descriptor( + struct libusb_ss_usb_device_capability_descriptor *ss_usb_device_capability) +{ + + free(ss_usb_device_capability); +} + +int +libusb_get_container_id_descriptor(struct libusb_context *ctx, + struct libusb_bos_dev_capability_descriptor *dev_cap, + struct libusb_container_id_descriptor **container_id) +{ + struct libusb_container_id_descriptor *desc; + + if (dev_cap == NULL || container_id == NULL || + dev_cap->bDevCapabilityType != LIBUSB_BT_CONTAINER_ID) + return (LIBUSB_ERROR_INVALID_PARAM); + if (dev_cap->bLength < LIBUSB_BT_CONTAINER_ID_SIZE) + return (LIBUSB_ERROR_IO); + + desc = malloc(sizeof(*desc)); + if (desc == NULL) + return (LIBUSB_ERROR_NO_MEM); + + desc->bLength = LIBUSB_BT_CONTAINER_ID_SIZE; + desc->bDescriptorType = dev_cap->bDescriptorType; + desc->bDevCapabilityType = dev_cap->bDevCapabilityType; + desc->bReserved = dev_cap->dev_capability_data[0]; + memcpy(desc->ContainerID, dev_cap->dev_capability_data + 1, + sizeof(desc->ContainerID)); + + *container_id = desc; + return (0); +} + +void +libusb_free_container_id_descriptor( + struct libusb_container_id_descriptor *container_id) +{ + + free(container_id); +} diff --git a/lib/libusb/libusb10_hotplug.c b/lib/libusb/libusb10_hotplug.c new file mode 100644 index 000000000..162cf2bbb --- /dev/null +++ b/lib/libusb/libusb10_hotplug.c @@ -0,0 +1,237 @@ +/* $FreeBSD$ */ +/*- + * Copyright (c) 2016 Hans Petter Selasky. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef LIBUSB_GLOBAL_INCLUDE_FILE +#include LIBUSB_GLOBAL_INCLUDE_FILE +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#define libusb_device_handle libusb20_device + +#include "libusb20.h" +#include "libusb20_desc.h" +#include "libusb20_int.h" +#include "libusb.h" +#include "libusb10.h" + +static int +libusb_hotplug_equal(libusb_device *_adev, libusb_device *_bdev) +{ + struct libusb20_device *adev = _adev->os_priv; + struct libusb20_device *bdev = _bdev->os_priv; + + if (adev->bus_number != bdev->bus_number) + return (0); + if (adev->device_address != bdev->device_address) + return (0); + if (memcmp(&adev->ddesc, &bdev->ddesc, sizeof(adev->ddesc))) + return (0); + if (memcmp(&adev->session_data, &bdev->session_data, sizeof(adev->session_data))) + return (0); + return (1); +} + +static int +libusb_hotplug_filter(libusb_context *ctx, libusb_hotplug_callback_handle pcbh, + libusb_device *dev, libusb_hotplug_event event) +{ + if (!(pcbh->events & event)) + return (0); + if (pcbh->vendor != LIBUSB_HOTPLUG_MATCH_ANY && + pcbh->vendor != libusb20_dev_get_device_desc(dev->os_priv)->idVendor) + return (0); + if (pcbh->product != LIBUSB_HOTPLUG_MATCH_ANY && + pcbh->product != libusb20_dev_get_device_desc(dev->os_priv)->idProduct) + return (0); + if (pcbh->devclass != LIBUSB_HOTPLUG_MATCH_ANY && + pcbh->devclass != libusb20_dev_get_device_desc(dev->os_priv)->bDeviceClass) + return (0); + return (pcbh->fn(ctx, dev, event, pcbh->user_data)); +} + +static void * +libusb_hotplug_scan(void *arg) +{ + TAILQ_HEAD(, libusb_device) hotplug_devs; + libusb_hotplug_callback_handle acbh; + libusb_hotplug_callback_handle bcbh; + libusb_context *ctx = arg; + libusb_device **ppdev; + libusb_device *temp; + libusb_device *adev; + libusb_device *bdev; + unsigned do_loop = 1; + ssize_t count; + ssize_t x; + + while (do_loop) { + usleep(4000000); + + HOTPLUG_LOCK(ctx); + + TAILQ_INIT(&hotplug_devs); + + if (ctx->hotplug_handler != NO_THREAD) { + count = libusb_get_device_list(ctx, &ppdev); + if (count < 0) + continue; + for (x = 0; x != count; x++) { + TAILQ_INSERT_TAIL(&hotplug_devs, ppdev[x], + hotplug_entry); + } + libusb_free_device_list(ppdev, 0); + } else { + do_loop = 0; + } + + /* figure out which devices are gone */ + TAILQ_FOREACH_SAFE(adev, &ctx->hotplug_devs, hotplug_entry, temp) { + TAILQ_FOREACH(bdev, &hotplug_devs, hotplug_entry) { + if (libusb_hotplug_equal(adev, bdev)) + break; + } + if (bdev == NULL) { + TAILQ_REMOVE(&ctx->hotplug_devs, adev, hotplug_entry); + TAILQ_FOREACH_SAFE(acbh, &ctx->hotplug_cbh, entry, bcbh) { + if (libusb_hotplug_filter(ctx, acbh, adev, + LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) == 0) + continue; + TAILQ_REMOVE(&ctx->hotplug_cbh, acbh, entry); + free(acbh); + } + libusb_unref_device(adev); + } + } + + /* figure out which devices are new */ + TAILQ_FOREACH_SAFE(adev, &hotplug_devs, hotplug_entry, temp) { + TAILQ_FOREACH(bdev, &ctx->hotplug_devs, hotplug_entry) { + if (libusb_hotplug_equal(adev, bdev)) + break; + } + if (bdev == NULL) { + TAILQ_REMOVE(&hotplug_devs, adev, hotplug_entry); + TAILQ_INSERT_TAIL(&ctx->hotplug_devs, adev, hotplug_entry); + TAILQ_FOREACH_SAFE(acbh, &ctx->hotplug_cbh, entry, bcbh) { + if (libusb_hotplug_filter(ctx, acbh, adev, + LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) == 0) + continue; + TAILQ_REMOVE(&ctx->hotplug_cbh, acbh, entry); + free(acbh); + } + } + } + HOTPLUG_UNLOCK(ctx); + + /* unref remaining devices */ + while ((adev = TAILQ_FIRST(&hotplug_devs)) != NULL) { + TAILQ_REMOVE(&hotplug_devs, adev, hotplug_entry); + libusb_unref_device(adev); + } + } + return (NULL); +} + +int libusb_hotplug_register_callback(libusb_context *ctx, + libusb_hotplug_event events, libusb_hotplug_flag flags, + int vendor_id, int product_id, int dev_class, + libusb_hotplug_callback_fn cb_fn, void *user_data, + libusb_hotplug_callback_handle *phandle) +{ + libusb_hotplug_callback_handle handle; + struct libusb_device *adev; + + ctx = GET_CONTEXT(ctx); + + if (ctx == NULL || cb_fn == NULL || events == 0 || + vendor_id < -1 || vendor_id > 0xffff || + product_id < -1 || product_id > 0xffff || + dev_class < -1 || dev_class > 0xff) + return (LIBUSB_ERROR_INVALID_PARAM); + + handle = malloc(sizeof(*handle)); + if (handle == NULL) + return (LIBUSB_ERROR_NO_MEM); + + HOTPLUG_LOCK(ctx); + if (ctx->hotplug_handler == NO_THREAD) { + if (pthread_create(&ctx->hotplug_handler, NULL, + &libusb_hotplug_scan, ctx) != 0) + ctx->hotplug_handler = NO_THREAD; + } + handle->events = events; + handle->vendor = vendor_id; + handle->product = product_id; + handle->devclass = dev_class; + handle->fn = cb_fn; + handle->user_data = user_data; + + if (flags & LIBUSB_HOTPLUG_ENUMERATE) { + TAILQ_FOREACH(adev, &ctx->hotplug_devs, hotplug_entry) { + if (libusb_hotplug_filter(ctx, handle, adev, + LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) == 0) + continue; + free(handle); + handle = NULL; + break; + } + } + if (handle != NULL) + TAILQ_INSERT_TAIL(&ctx->hotplug_cbh, handle, entry); + HOTPLUG_UNLOCK(ctx); + + if (phandle != NULL) + *phandle = handle; + return (LIBUSB_SUCCESS); +} + +void libusb_hotplug_deregister_callback(libusb_context *ctx, + libusb_hotplug_callback_handle handle) +{ + ctx = GET_CONTEXT(ctx); + + if (ctx == NULL || handle == NULL) + return; + + HOTPLUG_LOCK(ctx); + TAILQ_REMOVE(&ctx->hotplug_cbh, handle, entry); + HOTPLUG_UNLOCK(ctx); + + free(handle); +} diff --git a/lib/libusb/libusb10_io.c b/lib/libusb/libusb10_io.c index 066f5c76e..e8ea62461 100644 --- a/lib/libusb/libusb10_io.c +++ b/lib/libusb/libusb10_io.c @@ -762,3 +762,47 @@ libusb_fill_iso_transfer(struct libusb_transfer *transfer, transfer->callback = callback; } +int +libusb_alloc_streams(libusb_device_handle *dev, uint32_t num_streams, + unsigned char *endpoints, int num_endpoints) +{ + + return (LIBUSB_ERROR_NOT_SUPPORTED); +} + +int +libusb_free_streams(libusb_device_handle *dev, unsigned char *endpoints, int num_endpoints) +{ + + return (0); +} + +void +libusb_transfer_set_stream_id(struct libusb_transfer *transfer, uint32_t stream_id) +{ + struct libusb_super_transfer *sxfer; + + if (transfer == NULL) + return; + + sxfer = (struct libusb_super_transfer *)( + ((uint8_t *)transfer) - sizeof(*sxfer)); + + /* set stream ID */ + sxfer->stream_id = stream_id; +} + +uint32_t +libusb_transfer_get_stream_id(struct libusb_transfer *transfer) +{ + struct libusb_super_transfer *sxfer; + + if (transfer == NULL) + return (0); + + sxfer = (struct libusb_super_transfer *)( + ((uint8_t *)transfer) - sizeof(*sxfer)); + + /* get stream ID */ + return (sxfer->stream_id); +} diff --git a/lib/libusb/libusb20.c b/lib/libusb/libusb20.c index b90ce43b3..6b5a0b408 100644 --- a/lib/libusb/libusb20.c +++ b/lib/libusb/libusb20.c @@ -590,6 +590,12 @@ libusb20_dev_close(struct libusb20_device *pdev) */ pdev->claimed_interface = 0; + /* + * The following variable is only used by the libusb v1.0 + * compat layer: + */ + pdev->auto_detach = 0; + return (error); } diff --git a/lib/libusb/libusb20_int.h b/lib/libusb/libusb20_int.h index 72c0c6619..28588fa61 100644 --- a/lib/libusb/libusb20_int.h +++ b/lib/libusb/libusb20_int.h @@ -213,6 +213,9 @@ struct libusb20_device { /* claimed interface */ uint8_t claimed_interface; + /* auto detach kernel driver */ + uint8_t auto_detach; + /* device file handle */ int file; -- 2.45.0