summaryrefslogtreecommitdiffstats
path: root/lib/libusb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libusb')
-rw-r--r--lib/libusb/Makefile220
-rw-r--r--lib/libusb/libusb.3550
-rw-r--r--lib/libusb/libusb.h462
-rw-r--r--lib/libusb/libusb01.c1015
-rw-r--r--lib/libusb/libusb10.c1546
-rw-r--r--lib/libusb/libusb10.h115
-rw-r--r--lib/libusb/libusb10_desc.c498
-rw-r--r--lib/libusb/libusb10_io.c738
-rw-r--r--lib/libusb/libusb20.31031
-rw-r--r--lib/libusb/libusb20.c1320
-rw-r--r--lib/libusb/libusb20.h309
-rw-r--r--lib/libusb/libusb20_desc.c792
-rw-r--r--lib/libusb/libusb20_desc.h593
-rw-r--r--lib/libusb/libusb20_int.h238
-rw-r--r--lib/libusb/libusb20_ugen20.c1022
-rw-r--r--lib/libusb/usb.h313
16 files changed, 10762 insertions, 0 deletions
diff --git a/lib/libusb/Makefile b/lib/libusb/Makefile
new file mode 100644
index 0000000..538b8e6
--- /dev/null
+++ b/lib/libusb/Makefile
@@ -0,0 +1,220 @@
+#
+# $FreeBSD$
+#
+# Makefile for the FreeBSD specific LibUSB 2.0
+#
+
+LIB= usb
+SHLIB_MAJOR= 2
+SHLIB_MINOR= 0
+SRCS= libusb20.c
+SRCS+= libusb20_desc.c
+SRCS+= libusb20_ugen20.c
+INCS+= libusb20.h
+INCS+= libusb20_desc.h
+MAN= libusb.3 libusb20.3
+MKLINT= no
+NOGCCERROR=
+
+WARNS?= 2
+
+MLINKS+= libusb.3 usb.3
+
+# libusb 0.1 compat
+INCS+= usb.h
+SRCS+= libusb01.c
+
+# libusb 1.0 compat
+INCS+= libusb.h
+SRCS+= libusb10.c
+SRCS+= libusb10_desc.c
+SRCS+= libusb10_io.c
+
+.if defined(COMPAT_32BIT)
+CFLAGS+= -DCOMPAT_32BIT
+.endif
+
+.include <bsd.lib.mk>
+
+# LibUSB v1.0
+MLINKS += libusb.3 libusb_init.3
+MLINKS += libusb.3 libusb_exit.3
+MLINKS += libusb.3 libusb_strerror.3
+MLINKS += libusb.3 libusb_error_name.3
+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_device_address.3
+MLINKS += libusb.3 libusb_get_device_speed.3
+MLINKS += libusb.3 libusb_get_max_packet_size.3
+MLINKS += libusb.3 libusb_get_max_iso_packet_size.3
+MLINKS += libusb.3 libusb_ref_device.3
+MLINKS += libusb.3 libusb_unref_device.3
+MLINKS += libusb.3 libusb_open.3
+MLINKS += libusb.3 libusb_open_device_with_vid_pid.3
+MLINKS += libusb.3 libusb_close.3
+MLINKS += libusb.3 libusb_get_device.3
+MLINKS += libusb.3 libusb_get_configuration.3
+MLINKS += libusb.3 libusb_set_configuration.3
+MLINKS += libusb.3 libusb_claim_interface.3
+MLINKS += libusb.3 libusb_release_interface.3
+MLINKS += libusb.3 libusb_set_interface_alt_setting.3
+MLINKS += libusb.3 libusb_clear_halt.3
+MLINKS += libusb.3 libusb_reset_device.3
+MLINKS += libusb.3 libusb_check_connected.3
+MLINKS += libusb.3 libusb_kernel_driver_active.3
+MLINKS += libusb.3 libusb_get_driver.3
+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_get_device_descriptor.3
+MLINKS += libusb.3 libsub_get_active_config_descriptor.3
+MLINKS += libusb.3 libusb_get_config_descriptor.3
+MLINKS += libusb.3 libusb_get_config_descriptor_by_value.3
+MLINKS += libusb.3 libusb_free_config_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_parse_bos_descriptor.3
+MLINKS += libusb.3 libusb_free_bos_descriptor.3
+MLINKS += libusb.3 libusb_alloc_transfer.3
+MLINKS += libusb.3 libusb_free_transfer.3
+MLINKS += libusb.3 libusb_submit_transfer.3
+MLINKS += libusb.3 libusb_cancel_transfer.3
+MLINKS += libusb.3 libusb_control_transfer.3
+MLINKS += libusb.3 libusb_bulk_transfer.3
+MLINKS += libusb.3 libusb_interrupt_transfer.3
+MLINKS += libusb.3 libusb_try_lock_events.3
+MLINKS += libusb.3 libusb_lock_events.3
+MLINKS += libusb.3 libusb_unlock_events.3
+MLINKS += libusb.3 libusb_event_handling_ok.3
+MLINKS += libusb.3 libusb_event_handler_active.3
+MLINKS += libusb.3 libusb_lock_event_waiters.3
+MLINKS += libusb.3 libusb_unlock_event_waiters.3
+MLINKS += libusb.3 libusb_wait_for_event.3
+MLINKS += libusb.3 libusb_handle_events_timeout.3
+MLINKS += libusb.3 libusb_handle_events.3
+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
+
+# LibUSB v0.1
+MLINKS += libusb.3 usb_open.3
+MLINKS += libusb.3 usb_close.3
+MLINKS += libusb.3 usb_get_string.3
+MLINKS += libusb.3 usb_get_string_simple.3
+MLINKS += libusb.3 usb_get_descriptor_by_endpoint.3
+MLINKS += libusb.3 usb_get_descriptor.3
+MLINKS += libusb.3 usb_parse_descriptor.3
+MLINKS += libusb.3 usb_parse_configuration.3
+MLINKS += libusb.3 usb_destroy_configuration.3
+MLINKS += libusb.3 usb_fetch_and_parse_descriptors.3
+MLINKS += libusb.3 usb_bulk_write.3
+MLINKS += libusb.3 usb_bulk_read.3
+MLINKS += libusb.3 usb_interrupt_write.3
+MLINKS += libusb.3 usb_interrupt_read.3
+MLINKS += libusb.3 usb_control_msg.3
+MLINKS += libusb.3 usb_set_configuration.3
+MLINKS += libusb.3 usb_claim_interface.3
+MLINKS += libusb.3 usb_release_interface.3
+MLINKS += libusb.3 usb_set_altinterface.3
+MLINKS += libusb.3 usb_resetep.3
+MLINKS += libusb.3 usb_clear_halt.3
+MLINKS += libusb.3 usb_reset.3
+MLINKS += libusb.3 usb_strerror.3
+MLINKS += libusb.3 usb_init.3
+MLINKS += libusb.3 usb_set_debug.3
+MLINKS += libusb.3 usb_find_busses.3
+MLINKS += libusb.3 usb_find_devices.3
+MLINKS += libusb.3 usb_device.3
+MLINKS += libusb.3 usb_get_busses.3
+MLINKS += libusb.3 usb_check_connected.3
+
+# LibUSB v2.0
+MLINKS += libusb20.3 libusb20_tr_close.3
+MLINKS += libusb20.3 libusb20_tr_open.3
+MLINKS += libusb20.3 libusb20_tr_get_pointer.3
+MLINKS += libusb20.3 libusb20_tr_get_time_complete.3
+MLINKS += libusb20.3 libusb20_tr_get_actual_frames.3
+MLINKS += libusb20.3 libusb20_tr_get_actual_length.3
+MLINKS += libusb20.3 libusb20_tr_get_max_frames.3
+MLINKS += libusb20.3 libusb20_tr_get_max_packet_length.3
+MLINKS += libusb20.3 libusb20_tr_get_max_total_length.3
+MLINKS += libusb20.3 libusb20_tr_get_status.3
+MLINKS += libusb20.3 libusb20_tr_pending.3
+MLINKS += libusb20.3 libusb20_tr_callback_wrapper.3
+MLINKS += libusb20.3 libusb20_tr_clear_stall_sync.3
+MLINKS += libusb20.3 libusb20_tr_drain.3
+MLINKS += libusb20.3 libusb20_tr_set_buffer.3
+MLINKS += libusb20.3 libusb20_tr_set_callback.3
+MLINKS += libusb20.3 libusb20_tr_set_flags.3
+MLINKS += libusb20.3 libusb20_tr_get_length.3
+MLINKS += libusb20.3 libusb20_tr_set_length.3
+MLINKS += libusb20.3 libusb20_tr_set_priv_sc0.3
+MLINKS += libusb20.3 libusb20_tr_set_priv_sc1.3
+MLINKS += libusb20.3 libusb20_tr_set_timeout.3
+MLINKS += libusb20.3 libusb20_tr_set_total_frames.3
+MLINKS += libusb20.3 libusb20_tr_setup_bulk.3
+MLINKS += libusb20.3 libusb20_tr_setup_control.3
+MLINKS += libusb20.3 libusb20_tr_setup_intr.3
+MLINKS += libusb20.3 libusb20_tr_setup_isoc.3
+MLINKS += libusb20.3 libusb20_tr_bulk_intr_sync.3
+MLINKS += libusb20.3 libusb20_tr_start.3
+MLINKS += libusb20.3 libusb20_tr_stop.3
+MLINKS += libusb20.3 libusb20_tr_submit.3
+MLINKS += libusb20.3 libusb20_tr_get_priv_sc0.3
+MLINKS += libusb20.3 libusb20_tr_get_priv_sc1.3
+MLINKS += libusb20.3 libusb20_dev_get_backend_name.3
+MLINKS += libusb20.3 libusb20_dev_get_info.3
+MLINKS += libusb20.3 libusb20_dev_get_iface_desc.3
+MLINKS += libusb20.3 libusb20_dev_get_desc.3
+MLINKS += libusb20.3 libusb20_dev_close.3
+MLINKS += libusb20.3 libusb20_dev_detach_kernel_driver.3
+MLINKS += libusb20.3 libusb20_dev_set_config_index.3
+MLINKS += libusb20.3 libusb20_dev_get_debug.3
+MLINKS += libusb20.3 libusb20_dev_get_fd.3
+MLINKS += libusb20.3 libusb20_dev_kernel_driver_active.3
+MLINKS += libusb20.3 libusb20_dev_open.3
+MLINKS += libusb20.3 libusb20_dev_process.3
+MLINKS += libusb20.3 libusb20_dev_request_sync.3
+MLINKS += libusb20.3 libusb20_dev_req_string_sync.3
+MLINKS += libusb20.3 libusb20_dev_req_string_simple_sync.3
+MLINKS += libusb20.3 libusb20_dev_reset.3
+MLINKS += libusb20.3 libusb20_dev_check_connected.3
+MLINKS += libusb20.3 libusb20_dev_set_power_mode.3
+MLINKS += libusb20.3 libusb20_dev_get_power_mode.3
+MLINKS += libusb20.3 libusb20_dev_set_alt_index.3
+MLINKS += libusb20.3 libusb20_dev_get_device_desc.3
+MLINKS += libusb20.3 libusb20_dev_alloc_config.3
+MLINKS += libusb20.3 libusb20_dev_alloc.3
+MLINKS += libusb20.3 libusb20_dev_get_address.3
+MLINKS += libusb20.3 libusb20_dev_get_parent_address.3
+MLINKS += libusb20.3 libusb20_dev_get_parent_port.3
+MLINKS += libusb20.3 libusb20_dev_get_bus_number.3
+MLINKS += libusb20.3 libusb20_dev_get_mode.3
+MLINKS += libusb20.3 libusb20_dev_get_speed.3
+MLINKS += libusb20.3 libusb20_dev_get_config_index.3
+MLINKS += libusb20.3 libusb20_dev_free.3
+MLINKS += libusb20.3 libusb20_dev_set_debug.3
+MLINKS += libusb20.3 libusb20_dev_wait_process.3
+MLINKS += libusb20.3 libusb20_be_get_template.3
+MLINKS += libusb20.3 libusb20_be_set_template.3
+MLINKS += libusb20.3 libusb20_be_get_dev_quirk.3
+MLINKS += libusb20.3 libusb20_be_get_quirk_name.3
+MLINKS += libusb20.3 libusb20_be_add_dev_quirk.3
+MLINKS += libusb20.3 libusb20_be_remove_dev_quirk.3
+MLINKS += libusb20.3 libusb20_be_alloc_default.3
+MLINKS += libusb20.3 libusb20_be_device_foreach.3
+MLINKS += libusb20.3 libusb20_be_dequeue_device.3
+MLINKS += libusb20.3 libusb20_be_enqueue_device.3
+MLINKS += libusb20.3 libusb20_be_free.3
+MLINKS += libusb20.3 libusb20_me_get_1.3
+MLINKS += libusb20.3 libusb20_me_get_2.3
+MLINKS += libusb20.3 libusb20_me_encode.3
+MLINKS += libusb20.3 libusb20_me_decode.3
+MLINKS += libusb20.3 libusb20_desc_foreach.3
+MLINKS += libusb20.3 libusb20_strerror.3
+MLINKS += libusb20.3 libusb20_error_name.3
diff --git a/lib/libusb/libusb.3 b/lib/libusb/libusb.3
new file mode 100644
index 0000000..a5bf677
--- /dev/null
+++ b/lib/libusb/libusb.3
@@ -0,0 +1,550 @@
+.\"
+.\" Copyright (c) 2009 Sylvestre Gallon
+.\"
+.\" 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd April 12, 2012
+.Dt LIBUSB 3
+.Os
+.Sh NAME
+.Nm libusb
+.Nd "USB access library"
+.Sh LIBRARY
+USB access library
+.Pq libusb, -lusb
+.Sh SYNOPSIS
+.In libusb.h
+.Sh DESCRIPTION
+The
+.Nm
+library contains interfaces for directly managing a usb device.
+The current implementation supports v1.0 of the libusb API.
+.Sh LIBRARY INITIALISATION / DEINITIALISATION
+.Ft int
+.Fn libusb_init libusb_context **ctx
+This function initialises libusb.
+It must be called at the beginning
+of the program, before other libusb routines are used.
+This function returns 0 on success or LIBUSB_ERROR on
+failure.
+.Pp
+.Ft void
+.Fn libusb_exit "libusb_context *ctx"
+Deinitialise libusb.
+Must be called at the end of the application.
+Other libusb routines may not be called after this function.
+.Pp
+.Ft const char *
+.Fn libusb_strerror "int code"
+Get the ASCII representation of the error given by the
+.Fa code
+argument.
+This function does not return NULL.
+.Pp
+.Ft const char *
+.Fn libusb_error_name "int code"
+Get the ASCII representation of the error enum given by the
+.Fa code
+argument.
+This function does not return NULL.
+.Pp
+.Ft void
+.Fn libusb_set_debug "libusb_context *ctx" "int level"
+Set the debug level to
+.Fa level .
+.Pp
+.Ft ssize_t
+.Fn libusb_get_device_list "libusb_context *ctx" "libusb_device ***list"
+Populate
+.Fa list
+with the list of usb devices available, adding a reference to each
+device in the list.
+All the list entries created by this
+function must have their reference counter
+decremented when you are done with them,
+and the list itself must be freed.
+This
+function returns the number of devices in the list or a LIBUSB_ERROR code.
+.Pp
+.Ft void
+.Fn libusb_free_device_list "libusb_device **list" "int unref_devices"
+Free the list of devices discovered by libusb_get_device_list.
+If
+.Fa unref_device
+is set to 1 all devices in the list have their reference
+counter decremented once.
+.Pp
+.Ft uint8_t
+.Fn libusb_get_bus_number "libusb_device *dev"
+Returns the number of the bus contained by the device
+.Fa dev.
+.Pp
+.Ft uint8_t
+.Fn libusb_get_device_address "libusb_device *dev"
+Returns the device_address contained by the device
+.Fa dev.
+.Pp
+.Ft enum libusb_speed
+.Fn libusb_get_device_speed "libusb_device *dev"
+Returns the wire speed at which the device is connected.
+See the LIBUSB_SPEED_XXX enums for more information.
+LIBUSB_SPEED_UNKNOWN is returned in case of unknown wire speed.
+.Pp
+.Ft int
+.Fn libusb_get_max_packet_size "libusb_device *dev" "unsigned char endpoint"
+Returns the wMaxPacketSize value on success, LIBUSB_ERROR_NOT_FOUND if the
+endpoint does not exist and LIBUSB_ERROR_OTHERS on other failure.
+.Pp
+.Ft int
+.Fn libusb_get_max_iso_packet_size "libusb_device *dev" "unsigned char endpoint"
+Returns the packet size multiplied by the packet multiplier on success,
+LIBUSB_ERROR_NOT_FOUND if the endpoint does not exist and
+LIBUSB_ERROR_OTHERS on other failure.
+.Pp
+.Ft libusb_device *
+.Fn libusb_ref_device "libusb_device *dev"
+Increment the reference counter of the device
+.Fa dev.
+.Pp
+.Ft void
+.Fn libusb_unref_device "libusb_device *dev"
+Decrement the reference counter of the device
+.Fa dev.
+.Pp
+.Ft int
+.Fn libusb_open "libusb_device *dev" "libusb_device_handle **devh"
+Open a device and obtain a device_handle.
+Returns 0 on success,
+LIBUSB_ERROR_NO_MEM on memory allocation problems, LIBUSB_ERROR_ACCESS
+on permissions problems, LIBUSB_ERROR_NO_DEVICE if the device has been
+disconnected and a LIBUSB_ERROR code on other errors.
+.Pp
+.Ft libusb_device_handle *
+.Fn libusb_open_device_with_vid_pid "libusb_context *ctx" "uint16_t vid" "uint16_t pid"
+A convenience function to open a device by vendor and product IDs
+.Fa vid
+and
+.Fa pid.
+Returns NULL on error.
+.Pp
+.Ft void
+.Fn libusb_close "libusb_device_handle *devh"
+Close a device handle.
+.Pp
+.Ft libusb_device *
+.Fn libusb_get_device "libusb_device_handle *devh"
+Get the device contained by devh.
+Returns NULL on error.
+.Pp
+.Ft int
+.Fn libusb_get_configuration "libusb_device_handle *devh" "int *config"
+Returns the bConfiguration value of the current configuration.
+Returns 0
+on success, LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
+and a LIBUSB_ERROR code on error.
+.Pp
+.Ft int
+.Fn libusb_set_configuration "libusb_device_handle *devh" "int config"
+Set the active configuration to
+.Fa config
+for the device contained by
+.Fa devh.
+This function returns 0 on success, LIBUSB_ERROR_NOT_FOUND if the requested
+configuration does not exist, LIBUSB_ERROR_BUSY if the interfaces are currently
+claimed, LIBUSB_ERROR_NO_DEVICE if the device has been disconnected and a
+LIBUSB_ERROR code on failure.
+.Pp
+.Ft int
+.Fn libusb_claim_interface "libusb_device_handle *devh" "int interface_number"
+Claim an interface in a given libusb_handle
+.Fa devh.
+This is a non-blocking function.
+It returns 0 on success, LIBUSB_ERROR_NOT_FOUND
+if the requested interface does not exist, LIBUSB_ERROR_BUSY if a program or
+driver has claimed the interface, LIBUSB_ERROR_NO_DEVICE if the device has
+been disconnected and a LIBUSB_ERROR code on failure.
+.Pp
+.Ft int
+.Fn libusb_release_interface "libusb_device_handle *devh" "int interface_number"
+This function releases an interface.
+All the claimed interfaces on a device must be released
+before closing the device.
+Returns 0 on success, LIBUSB_ERROR_NOT_FOUND if the
+interface was not claimed, LIBUSB_ERROR_NO_DEVICE if the device has been
+disconnected and LIBUSB_ERROR on failure.
+.Pp
+.Ft int
+.Fn libusb_set_interface_alt_setting "libusb_device_handle *dev" "int interface_number" "int alternate_setting"
+Activate an alternate setting for an interface.
+Returns 0 on success,
+LIBUSB_ERROR_NOT_FOUND if the interface was not claimed or the requested
+setting does not exist, LIBUSB_ERROR_NO_DEVICE if the device has been
+disconnected and a LIBUSB_ERROR code on failure.
+.Pp
+.Ft int
+.Fn libusb_clear_halt "libusb_device_handle *devh" "unsigned char endpoint"
+Clear an halt/stall for a endpoint.
+Returns 0 on success, LIBUSB_ERROR_NOT_FOUND
+if the endpoint does not exist, LIBUSB_ERROR_NO_DEVICE if the device has been
+disconnected and a LIBUSB_ERROR code on failure.
+.Pp
+.Ft int
+.Fn libusb_reset_device "libusb_device_handle *devh"
+Perform an USB port reset for an usb device.
+Returns 0 on success,
+LIBUSB_ERROR_NOT_FOUND if re-enumeration is required or if the device has
+been disconnected and a LIBUSB_ERROR code on failure.
+.Pp
+.Ft int
+.Fn libusb_check_connected "libusb_device_handle *devh"
+Test if the USB device is still connected.
+Returns 0 on success,
+LIBUSB_ERROR_NO_DEVICE if it has been disconnected and a LIBUSB_ERROR
+code on failure.
+.Pp
+.Ft int
+.Fn libusb_kernel_driver_active "libusb_device_handle *devh" "int interface"
+Determine if a driver is active on a interface.
+Returns 0 if no kernel driver is active
+and 1 if a kernel driver is active, LIBUSB_ERROR_NO_DEVICE
+if the device has been disconnected and a LIBUSB_ERROR code on failure.
+.Pp
+.Ft int
+.Fn libusb_get_driver "libusb_device_handle *devh" "int interface" "char *name" "int namelen"
+or
+.Ft int
+.Fn libusb_get_driver_np "libusb_device_handle *devh" "int interface" "char *name" "int namelen"
+Copy the name of the driver attached to the given
+.Fa device
+and
+.Fa interface
+into the buffer
+.Fa name
+of length
+.Fa namelen .
+Returns 0 on success, LIBUSB_ERROR_NOT_FOUND if no kernel driver is attached
+to the given interface and LIBUSB_ERROR_INVALID_PARAM if the interface does
+not exist.
+This function is non-portable.
+The buffer pointed to by
+.Fa name
+is only zero terminated on success.
+.Pp
+.Ft int
+.Fn libusb_detach_kernel_driver "libusb_device_handle *devh" "int interface"
+or
+.Ft int
+.Fn libusb_detach_kernel_driver_np "libusb_device_handle *devh" "int interface"
+Detach a kernel driver from an interface.
+This is needed to claim an interface already claimed by a kernel driver.
+Returns 0 on success, LIBUSB_ERROR_NOT_FOUND if no kernel driver was active,
+LIBUSB_ERROR_INVALID_PARAM if the interface does not exist,
+LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
+and a LIBUSB_ERROR code on failure.
+This function is non-portable.
+.Pp
+.Ft int
+.Fn libusb_attach_kernel_driver "libusb_device_handle *devh" "int interface"
+Re-attach an interface kernel driver that was previously detached.
+Returns 0 on success,
+LIBUSB_ERROR_INVALID_PARAM if the interface does not exist,
+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.
+.Sh USB DESCRIPTORS
+.Ft int
+.Fn libusb_get_device_descriptor "libusb_device *dev" "libusb_device_descriptor *desc"
+Get the USB device descriptor for the device
+.Fa dev.
+This is a non-blocking function.
+Returns 0 on success and a LIBUSB_ERROR code on
+failure.
+.Pp
+.Ft int
+.Fn libsub_get_active_config_descriptor "libusb_device *dev" "struct libusb_config_descriptor **config"
+Get the USB configuration descriptor for the active configuration.
+Returns 0 on
+success, LIBUSB_ERROR_NOT_FOUND if the device is in
+an unconfigured state
+and a LIBUSB_ERROR code on error.
+.Pp
+.Ft int
+.Fn libusb_get_config_descriptor "libusb_device *dev" "uint8_t config_index" "libusb_config_descriptor **config"
+Get a USB configuration descriptor based on its index
+.Fa idx.
+Returns 0 on success, LIBUSB_ERROR_NOT_FOUND if the configuration does not exist
+and a LIBUSB_ERROR code on error.
+.Pp
+.Ft int
+.Fn libusb_get_config_descriptor_by_value "libusb_device *dev" "uint8 bConfigurationValue" "libusb_config_descriptor **config"
+Get a USB configuration descriptor with a specific bConfigurationValue.
+This is
+a non-blocking function which does not send a request through the device.
+Returns 0
+on success, LIBUSB_ERROR_NOT_FOUND if the configuration
+does not exist and a
+LIBUSB_ERROR code on failure.
+.Pp
+.Ft void
+.Fn libusb_free_config_descriptor "libusb_config_descriptor *config"
+Free a configuration descriptor.
+.Pp
+.Ft int
+.Fn libusb_get_string_descriptor_ascii "libusb_device_handle *devh" "uint8_t desc_idx" "unsigned char *data" "int length"
+Retrieve a string descriptor in C style ASCII.
+Returns the positive number of bytes in the resulting ASCII string
+on success and a LIBUSB_ERROR code on failure.
+.Pp
+.Ft int
+.Fn libusb_parse_ss_endpoint_comp "const void *buf" "int len" "libusb_ss_endpoint_companion_descriptor **ep_comp"
+This function parses the USB 3.0 endpoint companion descriptor in host endian format pointed to by
+.Fa buf
+and having a length of
+.Fa len.
+Typically these arguments are the extra and extra_length fields of the
+endpoint descriptor.
+On success the pointer to resulting descriptor is stored at the location given by
+.Fa ep_comp.
+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_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.
+.Pp
+.Ft int
+.Fn libusb_parse_bos_descriptor "const void *buf" "int len" "libusb_bos_descriptor **bos"
+This function parses a Binary Object Store, BOS, descriptor into host endian format pointed to by
+.Fa buf
+and having a length of
+.Fa len.
+On success the pointer to resulting descriptor is stored at the location given by
+.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 void
+.Fn libusb_free_bos_descriptor "libusb_bos_descriptor *bos"
+This function is NULL safe and frees a parsed BOS descriptor.
+.Sh USB ASYNCHRONOUS I/O
+.Ft struct libusb_transfer *
+.Fn libusb_alloc_transfer "int iso_packets"
+Allocate a transfer with the number of isochronous packet descriptors
+specified by
+.Fa iso_packets .
+Returns NULL on error.
+.Pp
+.Ft void
+.Fn libusb_free_transfer "struct libusb_transfer *tr"
+Free a transfer.
+.Pp
+.Ft int
+.Fn libusb_submit_transfer "struct libusb_transfer *tr"
+This function will submit a transfer and returns immediately.
+Returns 0 on success, LIBUSB_ERROR_NO_DEVICE if
+the device has been disconnected and a
+LIBUSB_ERROR code on other failure.
+.Pp
+.Ft int
+.Fn libusb_cancel_transfer "struct libusb_transfer *tr"
+This function asynchronously cancels a transfer.
+Returns 0 on success and a LIBUSB_ERROR code on failure.
+.Sh USB SYNCHRONOUS I/O
+.Ft int
+.Fn libusb_control_transfer "libusb_device_handle *devh" "uint8_t bmRequestType" "uint8_t bRequest" "uint16_t wValue" "uint16_t wIndex" "unsigned char *data" "uint16_t wLength" "unsigned int timeout"
+Perform a USB control transfer.
+Returns the actual number of bytes
+transferred on success, in the range from and including zero up to and
+including
+.Fa wLength .
+On error a LIBUSB_ERROR code is returned, for example
+LIBUSB_ERROR_TIMEOUT if the transfer timed out, LIBUSB_ERROR_PIPE if the
+control request was not supported, LIBUSB_ERROR_NO_DEVICE if the
+device has been disconnected and another LIBUSB_ERROR code on other failures.
+The LIBUSB_ERROR codes are all negative.
+.Pp
+.Ft int
+.Fn libusb_bulk_transfer "struct libusb_device_handle *devh" "unsigned char endpoint" "unsigned char *data" "int length" "int *transferred" "unsigned int timeout"
+Perform an USB bulk transfer.
+A timeout value of zero means no timeout.
+The timeout value is given in milliseconds.
+Returns 0 on success, LIBUSB_ERROR_TIMEOUT
+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.
+.Pp
+.Ft int
+.Fn libusb_interrupt_transfer "struct libusb_device_handle *devh" "unsigned char endpoint" "unsigned char *data" "int length" "int *transferred" "unsigned int timeout"
+Perform an USB Interrupt transfer.
+A timeout value of zero means no timeout.
+The timeout value is given in milliseconds.
+Returns 0 on success, LIBUSB_ERROR_TIMEOUT
+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 EVENTS
+.Ft int
+.Fn libusb_try_lock_events "libusb_context *ctx"
+Try to acquire the event handling lock.
+Returns 0 if the lock was obtained and 1 if not.
+.Pp
+.Ft void
+.Fn libusb_lock_events "libusb_context *ctx"
+Acquire the event handling lock.
+This function is blocking.
+.Pp
+.Ft void
+.Fn libusb_unlock_events "libusb_context *ctx"
+Release the event handling lock.
+This will wake up any thread blocked
+on
+.Fn libusb_wait_for_event .
+.Pp
+.Ft int
+.Fn libusb_event_handling_ok "libusb_context *ctx"
+Determine if it still OK for this thread to be doing event handling.
+Returns 1
+if event handling can start or continue.
+Returns 0 if this thread must give up
+the events lock.
+.Pp
+.Ft int
+.Fn libusb_event_handler_active "libusb_context *ctx"
+Determine if an active thread is handling events.
+Returns 1 if there is a thread handling events and 0 if there
+are no threads currently handling events.
+.Pp
+.Ft void
+.Fn libusb_lock_event_waiters "libusb_context *ctx"
+Acquire the event_waiters lock.
+This lock is designed to be obtained in the
+situation where you want to be aware when events are completed, but some other
+thread is event handling so calling libusb_handle_events() is not allowed.
+.Pp
+.Ft void
+.Fn libusb_unlock_event_waiters "libusb_context *ctx"
+Release the event_waiters lock.
+.Pp
+.Ft int
+.Fn libusb_wait_for_event "libusb_context *ctx" "struct timeval *tv"
+Wait for another thread to signal completion of an event.
+Must be called
+with the event waiters lock held, see libusb_lock_event_waiters().
+This will
+block until the timeout expires or a transfer completes or a thread releases
+the event handling lock through libusb_unlock_events().
+Returns 0 after a
+transfer completes or another thread stops event handling, and 1 if the
+timeout expired.
+.Pp
+.Ft int
+.Fn libusb_handle_events_timeout "libusb_context *ctx" "struct timeval *tv"
+Handle any pending events by checking if timeouts have expired and by
+checking the set of file descriptors for activity.
+Returns 0 on success, or a
+LIBUSB_ERROR code on failure.
+.Pp
+.Ft int
+.Fn libusb_handle_events "libusb_context *ctx"
+Handle any pending events in blocking mode with a sensible timeout.
+Returns 0
+on success and a LIBUSB_ERROR code on failure.
+.Pp
+.Ft int
+.Fn libusb_handle_events_locked "libusb_context *ctx" "struct timeval *tv"
+Handle any pending events by polling file descriptors, without checking if
+another thread is already doing so.
+Must be called with the event lock held.
+.Pp
+.Ft int
+.Fn libusb_get_next_timeout "libusb_context *ctx" "struct timeval *tv"
+Determine the next internal timeout that libusb needs to handle.
+Returns 0
+if there are no pending timeouts, 1 if a timeout was returned, or a LIBUSB_ERROR
+code on failure.
+.Pp
+.Ft void
+.Fn libusb_set_pollfd_notifiers "libusb_context *ctx" "libusb_pollfd_added_cb added_cb" "libusb_pollfd_removed_cb remove_cb" "void *user_data"
+Register notification functions for file descriptor additions/removals.
+These functions will be invoked for every new or removed file descriptor
+that libusb uses as an event source.
+.Pp
+.Ft const struct libusb_pollfd **
+.Fn libusb_get_pollfds "libusb_context *ctx"
+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.
+.Sh LIBUSB VERSION 0.1 COMPATIBILITY
+The library is also compliant with LibUSB version 0.1.12.
+.Pp
+.Fn usb_open
+.Fn usb_close
+.Fn usb_get_string
+.Fn usb_get_string_simple
+.Fn usb_get_descriptor_by_endpoint
+.Fn usb_get_descriptor
+.Fn usb_parse_descriptor
+.Fn usb_parse_configuration
+.Fn usb_destroy_configuration
+.Fn usb_fetch_and_parse_descriptors
+.Fn usb_bulk_write
+.Fn usb_bulk_read
+.Fn usb_interrupt_write
+.Fn usb_interrupt_read
+.Fn usb_control_msg
+.Fn usb_set_configuration
+.Fn usb_claim_interface
+.Fn usb_release_interface
+.Fn usb_set_altinterface
+.Fn usb_resetep
+.Fn usb_clear_halt
+.Fn usb_reset
+.Fn usb_strerror
+.Fn usb_init
+.Fn usb_set_debug
+.Fn usb_find_busses
+.Fn usb_find_devices
+.Fn usb_device
+.Fn usb_get_busses
+.Fn usb_check_connected
+.Fn usb_get_driver_np
+.Fn usb_detach_kernel_driver_np
+.Sh SEE ALSO
+.Xr libusb20 3 ,
+.Xr usb 4 ,
+.Xr usbconfig 8 ,
+.Xr usbdump 8
+.Pp
+.Pa http://libusb.sourceforge.net/
+.Sh HISTORY
+.Nm
+support first appeared in
+.Fx 8.0 .
diff --git a/lib/libusb/libusb.h b/lib/libusb/libusb.h
new file mode 100644
index 0000000..5f821b6
--- /dev/null
+++ b/lib/libusb/libusb.h
@@ -0,0 +1,462 @@
+/* $FreeBSD$ */
+/*-
+ * Copyright (c) 2009 Sylvestre Gallon. 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.
+ */
+
+#ifndef __LIBUSB_H__
+#define __LIBUSB_H__
+
+#include <sys/time.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#if 0
+} /* indent fix */
+
+#endif
+
+/* libusb enums */
+
+enum libusb_class_code {
+ LIBUSB_CLASS_PER_INTERFACE = 0,
+ LIBUSB_CLASS_AUDIO = 1,
+ LIBUSB_CLASS_COMM = 2,
+ LIBUSB_CLASS_HID = 3,
+ LIBUSB_CLASS_PTP = 6,
+ LIBUSB_CLASS_PRINTER = 7,
+ LIBUSB_CLASS_MASS_STORAGE = 8,
+ LIBUSB_CLASS_HUB = 9,
+ LIBUSB_CLASS_DATA = 10,
+ LIBUSB_CLASS_VENDOR_SPEC = 0xff,
+};
+
+enum libusb_descriptor_type {
+ LIBUSB_DT_DEVICE = 0x01,
+ LIBUSB_DT_CONFIG = 0x02,
+ LIBUSB_DT_STRING = 0x03,
+ LIBUSB_DT_INTERFACE = 0x04,
+ LIBUSB_DT_ENDPOINT = 0x05,
+ LIBUSB_DT_HID = 0x21,
+ LIBUSB_DT_REPORT = 0x22,
+ LIBUSB_DT_PHYSICAL = 0x23,
+ LIBUSB_DT_HUB = 0x29,
+ LIBUSB_DT_BOS = 0x0f,
+ LIBUSB_DT_DEVICE_CAPABILITY = 0x10,
+ LIBUSB_DT_SS_ENDPOINT_COMPANION = 0x30,
+};
+
+enum libusb_device_capability_type {
+ LIBUSB_WIRELESS_USB_DEVICE_CAPABILITY = 0x1,
+ LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY = 0x2,
+ LIBUSB_SS_USB_DEVICE_CAPABILITY = 0x3,
+ LIBUSB_CONTAINER_ID_DEVICE_CAPABILITY = 0x4,
+};
+
+#define LIBUSB_DT_DEVICE_SIZE 18
+#define LIBUSB_DT_CONFIG_SIZE 9
+#define LIBUSB_DT_INTERFACE_SIZE 9
+#define LIBUSB_DT_ENDPOINT_SIZE 7
+#define LIBUSB_DT_ENDPOINT_AUDIO_SIZE 9
+#define LIBUSB_DT_HUB_NONVAR_SIZE 7
+#define LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE 6
+#define LIBUSB_DT_BOS_SIZE 5
+#define LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY_SIZE 7
+#define LIBUSB_SS_USB_DEVICE_CAPABILITY_SIZE 10
+
+#define LIBUSB_ENDPOINT_ADDRESS_MASK 0x0f
+#define LIBUSB_ENDPOINT_DIR_MASK 0x80
+
+enum libusb_endpoint_direction {
+ LIBUSB_ENDPOINT_IN = 0x80,
+ LIBUSB_ENDPOINT_OUT = 0x00,
+};
+
+#define LIBUSB_TRANSFER_TYPE_MASK 0x03
+
+enum libusb_transfer_type {
+ LIBUSB_TRANSFER_TYPE_CONTROL = 0,
+ LIBUSB_TRANSFER_TYPE_ISOCHRONOUS = 1,
+ LIBUSB_TRANSFER_TYPE_BULK = 2,
+ LIBUSB_TRANSFER_TYPE_INTERRUPT = 3,
+};
+
+enum libusb_standard_request {
+ LIBUSB_REQUEST_GET_STATUS = 0x00,
+ LIBUSB_REQUEST_CLEAR_FEATURE = 0x01,
+ LIBUSB_REQUEST_SET_FEATURE = 0x03,
+ LIBUSB_REQUEST_SET_ADDRESS = 0x05,
+ LIBUSB_REQUEST_GET_DESCRIPTOR = 0x06,
+ LIBUSB_REQUEST_SET_DESCRIPTOR = 0x07,
+ LIBUSB_REQUEST_GET_CONFIGURATION = 0x08,
+ LIBUSB_REQUEST_SET_CONFIGURATION = 0x09,
+ LIBUSB_REQUEST_GET_INTERFACE = 0x0A,
+ LIBUSB_REQUEST_SET_INTERFACE = 0x0B,
+ LIBUSB_REQUEST_SYNCH_FRAME = 0x0C,
+};
+
+enum libusb_request_type {
+ LIBUSB_REQUEST_TYPE_STANDARD = (0x00 << 5),
+ LIBUSB_REQUEST_TYPE_CLASS = (0x01 << 5),
+ LIBUSB_REQUEST_TYPE_VENDOR = (0x02 << 5),
+ LIBUSB_REQUEST_TYPE_RESERVED = (0x03 << 5),
+};
+
+enum libusb_request_recipient {
+ LIBUSB_RECIPIENT_DEVICE = 0x00,
+ LIBUSB_RECIPIENT_INTERFACE = 0x01,
+ LIBUSB_RECIPIENT_ENDPOINT = 0x02,
+ LIBUSB_RECIPIENT_OTHER = 0x03,
+};
+
+#define LIBUSB_ISO_SYNC_TYPE_MASK 0x0C
+
+enum libusb_iso_sync_type {
+ LIBUSB_ISO_SYNC_TYPE_NONE = 0,
+ LIBUSB_ISO_SYNC_TYPE_ASYNC = 1,
+ LIBUSB_ISO_SYNC_TYPE_ADAPTIVE = 2,
+ LIBUSB_ISO_SYNC_TYPE_SYNC = 3,
+};
+
+#define LIBUSB_ISO_USAGE_TYPE_MASK 0x30
+
+enum libusb_iso_usage_type {
+ LIBUSB_ISO_USAGE_TYPE_DATA = 0,
+ LIBUSB_ISO_USAGE_TYPE_FEEDBACK = 1,
+ LIBUSB_ISO_USAGE_TYPE_IMPLICIT = 2,
+};
+
+enum libusb_error {
+ LIBUSB_SUCCESS = 0,
+ LIBUSB_ERROR_IO = -1,
+ LIBUSB_ERROR_INVALID_PARAM = -2,
+ LIBUSB_ERROR_ACCESS = -3,
+ LIBUSB_ERROR_NO_DEVICE = -4,
+ LIBUSB_ERROR_NOT_FOUND = -5,
+ LIBUSB_ERROR_BUSY = -6,
+ LIBUSB_ERROR_TIMEOUT = -7,
+ LIBUSB_ERROR_OVERFLOW = -8,
+ LIBUSB_ERROR_PIPE = -9,
+ LIBUSB_ERROR_INTERRUPTED = -10,
+ LIBUSB_ERROR_NO_MEM = -11,
+ LIBUSB_ERROR_NOT_SUPPORTED = -12,
+ LIBUSB_ERROR_OTHER = -99,
+};
+
+enum libusb_speed {
+ LIBUSB_SPEED_UNKNOWN = 0,
+ LIBUSB_SPEED_LOW = 1,
+ LIBUSB_SPEED_FULL = 2,
+ LIBUSB_SPEED_HIGH = 3,
+ LIBUSB_SPEED_SUPER = 4,
+};
+
+enum libusb_transfer_status {
+ LIBUSB_TRANSFER_COMPLETED,
+ LIBUSB_TRANSFER_ERROR,
+ LIBUSB_TRANSFER_TIMED_OUT,
+ LIBUSB_TRANSFER_CANCELLED,
+ LIBUSB_TRANSFER_STALL,
+ LIBUSB_TRANSFER_NO_DEVICE,
+ LIBUSB_TRANSFER_OVERFLOW,
+};
+
+enum libusb_transfer_flags {
+ LIBUSB_TRANSFER_SHORT_NOT_OK = 1 << 0,
+ LIBUSB_TRANSFER_FREE_BUFFER = 1 << 1,
+ LIBUSB_TRANSFER_FREE_TRANSFER = 1 << 2,
+};
+
+enum libusb_debug_level {
+ LIBUSB_DEBUG_NO=0,
+ LIBUSB_DEBUG_FUNCTION=1,
+ LIBUSB_DEBUG_TRANSFER=2,
+};
+
+/* libusb structures */
+
+struct libusb_context;
+struct libusb_device;
+struct libusb_transfer;
+struct libusb_device_handle;
+
+struct libusb_pollfd {
+ int fd;
+ short events;
+};
+
+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_device_descriptor {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint16_t bcdUSB;
+ uint8_t bDeviceClass;
+ uint8_t bDeviceSubClass;
+ uint8_t bDeviceProtocol;
+ uint8_t bMaxPacketSize0;
+ uint16_t idVendor;
+ uint16_t idProduct;
+ uint16_t bcdDevice;
+ uint8_t iManufacturer;
+ uint8_t iProduct;
+ uint8_t iSerialNumber;
+ uint8_t bNumConfigurations;
+} libusb_device_descriptor;
+
+typedef struct libusb_endpoint_descriptor {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bEndpointAddress;
+ uint8_t bmAttributes;
+ uint16_t wMaxPacketSize;
+ uint8_t bInterval;
+ uint8_t bRefresh;
+ uint8_t bSynchAddress;
+ uint8_t *extra;
+ int extra_length;
+} libusb_endpoint_descriptor __aligned(sizeof(void *));
+
+typedef struct libusb_ss_endpoint_companion_descriptor {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bMaxBurst;
+ uint8_t bmAttributes;
+ uint16_t wBytesPerInterval;
+} libusb_ss_endpoint_companion_descriptor __aligned(sizeof(void *));
+
+typedef struct libusb_interface_descriptor {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bInterfaceNumber;
+ uint8_t bAlternateSetting;
+ uint8_t bNumEndpoints;
+ uint8_t bInterfaceClass;
+ uint8_t bInterfaceSubClass;
+ uint8_t bInterfaceProtocol;
+ uint8_t iInterface;
+ struct libusb_endpoint_descriptor *endpoint;
+ uint8_t *extra;
+ int extra_length;
+} libusb_interface_descriptor __aligned(sizeof(void *));
+
+typedef struct libusb_interface {
+ struct libusb_interface_descriptor *altsetting;
+ int num_altsetting;
+} libusb_interface __aligned(sizeof(void *));
+
+typedef struct libusb_config_descriptor {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint16_t wTotalLength;
+ uint8_t bNumInterfaces;
+ uint8_t bConfigurationValue;
+ uint8_t iConfiguration;
+ uint8_t bmAttributes;
+ uint8_t MaxPower;
+ struct libusb_interface *interface;
+ uint8_t *extra;
+ int extra_length;
+} libusb_config_descriptor __aligned(sizeof(void *));
+
+typedef struct libusb_usb_2_0_device_capability_descriptor {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bDevCapabilityType;
+ uint32_t bmAttributes;
+#define LIBUSB_USB_2_0_CAPABILITY_LPM_SUPPORT (1 << 1)
+} libusb_usb_2_0_device_capability_descriptor __aligned(sizeof(void *));
+
+typedef struct libusb_ss_usb_device_capability_descriptor {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bDevCapabilityType;
+ uint8_t bmAttributes;
+#define LIBUSB_SS_USB_CAPABILITY_LPM_SUPPORT (1 << 1)
+ uint16_t wSpeedSupported;
+#define LIBUSB_CAPABILITY_LOW_SPEED_OPERATION (1)
+#define LIBUSB_CAPABILITY_FULL_SPEED_OPERATION (1 << 1)
+#define LIBUSB_CAPABILITY_HIGH_SPEED_OPERATION (1 << 2)
+#define LIBUSB_CAPABILITY_5GBPS_OPERATION (1 << 3)
+ uint8_t bFunctionalitySupport;
+ uint8_t bU1DevExitLat;
+ uint16_t wU2DevExitLat;
+} libusb_ss_usb_device_capability_descriptor __aligned(sizeof(void *));
+
+typedef struct libusb_bos_descriptor {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint16_t wTotalLength;
+ uint8_t bNumDeviceCapabilities;
+ struct libusb_usb_2_0_device_capability_descriptor *usb_2_0_ext_cap;
+ struct libusb_ss_usb_device_capability_descriptor *ss_usb_cap;
+} libusb_bos_descriptor __aligned(sizeof(void *));
+
+typedef struct libusb_control_setup {
+ uint8_t bmRequestType;
+ uint8_t bRequest;
+ uint16_t wValue;
+ uint16_t wIndex;
+ uint16_t wLength;
+} libusb_control_setup;
+
+#define LIBUSB_CONTROL_SETUP_SIZE 8 /* bytes */
+
+typedef struct libusb_iso_packet_descriptor {
+ uint32_t length;
+ uint32_t actual_length;
+ enum libusb_transfer_status status;
+} libusb_iso_packet_descriptor __aligned(sizeof(void *));
+
+typedef void (*libusb_transfer_cb_fn) (struct libusb_transfer *transfer);
+
+typedef struct libusb_transfer {
+ libusb_device_handle *dev_handle;
+ uint8_t flags;
+ uint32_t endpoint;
+ uint8_t type;
+ uint32_t timeout;
+ enum libusb_transfer_status status;
+ int length;
+ int actual_length;
+ libusb_transfer_cb_fn callback;
+ void *user_data;
+ uint8_t *buffer;
+ void *os_priv;
+ int num_iso_packets;
+ struct libusb_iso_packet_descriptor iso_packet_desc[0];
+} libusb_transfer __aligned(sizeof(void *));
+
+/* Library initialisation */
+
+void libusb_set_debug(libusb_context * ctx, int level);
+const char *libusb_strerror(int code);
+const char *libusb_error_name(int code);
+int libusb_init(libusb_context ** context);
+void libusb_exit(struct libusb_context *ctx);
+
+/* Device handling and enumeration */
+
+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_device_address(libusb_device * dev);
+enum libusb_speed libusb_get_device_speed(libusb_device * dev);
+int libusb_clear_halt(libusb_device_handle *devh, uint8_t endpoint);
+int libusb_get_max_packet_size(libusb_device * dev, uint8_t endpoint);
+int libusb_get_max_iso_packet_size(libusb_device * dev, uint8_t endpoint);
+libusb_device *libusb_ref_device(libusb_device * dev);
+void libusb_unref_device(libusb_device * dev);
+int libusb_open(libusb_device * dev, libusb_device_handle ** devh);
+libusb_device_handle *libusb_open_device_with_vid_pid(libusb_context * ctx, uint16_t vendor_id, uint16_t product_id);
+void libusb_close(libusb_device_handle * devh);
+libusb_device *libusb_get_device(libusb_device_handle * devh);
+int libusb_get_configuration(libusb_device_handle * devh, int *config);
+int libusb_set_configuration(libusb_device_handle * devh, int configuration);
+int libusb_claim_interface(libusb_device_handle * devh, int interface_number);
+int libusb_release_interface(libusb_device_handle * devh, int interface_number);
+int libusb_reset_device(libusb_device_handle * devh);
+int libusb_check_connected(libusb_device_handle * devh);
+int libusb_kernel_driver_active(libusb_device_handle * devh, int interface);
+int libusb_get_driver_np(libusb_device_handle * devh, int interface, char *name, int namelen);
+int libusb_get_driver(libusb_device_handle * devh, int interface, char *name, int namelen);
+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_interface_alt_setting(libusb_device_handle * devh, int interface_number, int alternate_setting);
+
+/* USB Descriptors */
+
+int libusb_get_device_descriptor(libusb_device * dev, struct libusb_device_descriptor *desc);
+int libusb_get_active_config_descriptor(libusb_device * dev, struct libusb_config_descriptor **config);
+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_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);
+int libusb_parse_ss_endpoint_comp(const void *buf, int len, struct libusb_ss_endpoint_companion_descriptor **ep_comp);
+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);
+
+/* Asynchronous device I/O */
+
+struct libusb_transfer *libusb_alloc_transfer(int iso_packets);
+void libusb_free_transfer(struct libusb_transfer *transfer);
+int libusb_submit_transfer(struct libusb_transfer *transfer);
+int libusb_cancel_transfer(struct libusb_transfer *transfer);
+uint8_t *libusb_get_iso_packet_buffer(struct libusb_transfer *transfer, uint32_t index);
+uint8_t *libusb_get_iso_packet_buffer_simple(struct libusb_transfer *transfer, uint32_t index);
+void libusb_set_iso_packet_lengths(struct libusb_transfer *transfer, uint32_t length);
+uint8_t *libusb_control_transfer_get_data(struct libusb_transfer *transfer);
+struct libusb_control_setup *libusb_control_transfer_get_setup(struct libusb_transfer *transfer);
+void libusb_fill_control_setup(uint8_t *buf, uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint16_t wLength);
+void libusb_fill_control_transfer(struct libusb_transfer *transfer, libusb_device_handle *devh, uint8_t *buf, libusb_transfer_cb_fn callback, void *user_data, uint32_t timeout);
+void libusb_fill_bulk_transfer(struct libusb_transfer *transfer, libusb_device_handle *devh, uint8_t endpoint, uint8_t *buf, int length, libusb_transfer_cb_fn callback, void *user_data, uint32_t timeout);
+void libusb_fill_interrupt_transfer(struct libusb_transfer *transfer, libusb_device_handle *devh, uint8_t endpoint, uint8_t *buf, int length, libusb_transfer_cb_fn callback, void *user_data, uint32_t timeout);
+void libusb_fill_iso_transfer(struct libusb_transfer *transfer, libusb_device_handle *devh, uint8_t endpoint, uint8_t *buf, int length, int npacket, libusb_transfer_cb_fn callback, void *user_data, uint32_t timeout);
+
+/* Polling and timing */
+
+int libusb_try_lock_events(libusb_context * ctx);
+void libusb_lock_events(libusb_context * ctx);
+void libusb_unlock_events(libusb_context * ctx);
+int libusb_event_handling_ok(libusb_context * ctx);
+int libusb_event_handler_active(libusb_context * ctx);
+void libusb_lock_event_waiters(libusb_context * ctx);
+void libusb_unlock_event_waiters(libusb_context * ctx);
+int libusb_wait_for_event(libusb_context * ctx, struct timeval *tv);
+int libusb_handle_events_timeout(libusb_context * ctx, struct timeval *tv);
+int libusb_handle_events(libusb_context * ctx);
+int libusb_handle_events_locked(libusb_context * ctx, struct timeval *tv);
+int libusb_get_next_timeout(libusb_context * ctx, struct timeval *tv);
+void libusb_set_pollfd_notifiers(libusb_context * ctx, libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb, void *user_data);
+struct libusb_pollfd **libusb_get_pollfds(libusb_context * ctx);
+
+/* Synchronous device I/O */
+
+int libusb_control_transfer(libusb_device_handle * devh, uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint8_t *data, uint16_t wLength, uint32_t timeout);
+int libusb_bulk_transfer(libusb_device_handle * devh, uint8_t endpoint, uint8_t *data, int length, int *transferred, uint32_t timeout);
+int libusb_interrupt_transfer(libusb_device_handle * devh, uint8_t endpoint, uint8_t *data, int length, int *transferred, uint32_t timeout);
+
+/* Byte-order */
+
+uint16_t libusb_cpu_to_le16(uint16_t x);
+uint16_t libusb_le16_to_cpu(uint16_t x);
+
+#if 0
+{ /* indent fix */
+#endif
+#ifdef __cplusplus
+}
+
+#endif
+
+#endif /* __LIBUSB_H__ */
diff --git a/lib/libusb/libusb01.c b/lib/libusb/libusb01.c
new file mode 100644
index 0000000..17edb0e
--- /dev/null
+++ b/lib/libusb/libusb01.c
@@ -0,0 +1,1015 @@
+/* $FreeBSD$ */
+/*-
+ * Copyright (c) 2008 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.
+ */
+
+/*
+ * This file contains the emulation layer for LibUSB v0.1 from sourceforge.
+ */
+
+#include <sys/queue.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "libusb20.h"
+#include "libusb20_desc.h"
+#include "libusb20_int.h"
+#include "usb.h"
+
+/*
+ * The two following macros were taken from the original LibUSB v0.1
+ * for sake of compatibility:
+ */
+#define LIST_ADD(begin, ent) \
+ do { \
+ if (begin) { \
+ ent->next = begin; \
+ ent->next->prev = ent; \
+ } else { \
+ ent->next = NULL; \
+ } \
+ ent->prev = NULL; \
+ begin = ent; \
+ } while(0)
+
+#define LIST_DEL(begin, ent) \
+ do { \
+ if (ent->prev) { \
+ ent->prev->next = ent->next; \
+ } else { \
+ begin = ent->next; \
+ } \
+ if (ent->next) { \
+ ent->next->prev = ent->prev; \
+ } \
+ ent->prev = NULL; \
+ ent->next = NULL; \
+ } while (0)
+
+struct usb_bus *usb_busses = NULL;
+
+static struct usb_bus usb_global_bus = {
+ .dirname = {"/dev/usb"},
+ .root_dev = NULL,
+ .devices = NULL,
+};
+
+static struct libusb20_backend *usb_backend = NULL;
+
+struct usb_parse_state {
+
+ struct {
+ struct libusb20_endpoint *currep;
+ struct libusb20_interface *currifc;
+ struct libusb20_config *currcfg;
+ struct libusb20_me_struct *currextra;
+ } a;
+
+ struct {
+ struct usb_config_descriptor *currcfg;
+ struct usb_interface_descriptor *currifc;
+ struct usb_endpoint_descriptor *currep;
+ struct usb_interface *currifcw;
+ uint8_t *currextra;
+ } b;
+
+ uint8_t preparse;
+};
+
+static struct libusb20_transfer *
+usb_get_transfer_by_ep_no(usb_dev_handle * dev, uint8_t ep_no)
+{
+ struct libusb20_device *pdev = (void *)dev;
+ struct libusb20_transfer *xfer;
+ int err;
+ uint32_t bufsize;
+ uint8_t x;
+ uint8_t speed;
+
+ x = (ep_no & LIBUSB20_ENDPOINT_ADDRESS_MASK) * 2;
+
+ if (ep_no & LIBUSB20_ENDPOINT_DIR_MASK) {
+ /* this is an IN endpoint */
+ x |= 1;
+ }
+ speed = libusb20_dev_get_speed(pdev);
+
+ /* select a sensible buffer size */
+ if (speed == LIBUSB20_SPEED_LOW) {
+ bufsize = 256;
+ } else if (speed == LIBUSB20_SPEED_FULL) {
+ bufsize = 4096;
+ } else {
+ bufsize = 16384;
+ }
+
+ xfer = libusb20_tr_get_pointer(pdev, x);
+
+ if (xfer == NULL)
+ return (xfer);
+
+ err = libusb20_tr_open(xfer, bufsize, 1, ep_no);
+ if (err == LIBUSB20_ERROR_BUSY) {
+ /* already opened */
+ return (xfer);
+ } else if (err) {
+ return (NULL);
+ }
+ /* success */
+ return (xfer);
+}
+
+usb_dev_handle *
+usb_open(struct usb_device *dev)
+{
+ int err;
+
+ err = libusb20_dev_open(dev->dev, 16 * 2);
+ if (err == LIBUSB20_ERROR_BUSY) {
+ /*
+ * Workaround buggy USB applications which open the USB
+ * device multiple times:
+ */
+ return (dev->dev);
+ }
+ if (err)
+ return (NULL);
+
+ /*
+ * Dequeue USB device from backend queue so that it does not get
+ * freed when the backend is re-scanned:
+ */
+ libusb20_be_dequeue_device(usb_backend, dev->dev);
+
+ return (dev->dev);
+}
+
+int
+usb_close(usb_dev_handle * udev)
+{
+ struct usb_device *dev;
+ int err;
+
+ err = libusb20_dev_close((void *)udev);
+
+ if (err)
+ return (-1);
+
+ if (usb_backend != NULL) {
+ /*
+ * Enqueue USB device to backend queue so that it gets freed
+ * when the backend is re-scanned:
+ */
+ libusb20_be_enqueue_device(usb_backend, (void *)udev);
+ } else {
+ /*
+ * The backend is gone. Free device data so that we
+ * don't start leaking memory!
+ */
+ dev = usb_device(udev);
+ libusb20_dev_free((void *)udev);
+ LIST_DEL(usb_global_bus.devices, dev);
+ free(dev);
+ }
+ return (0);
+}
+
+int
+usb_get_string(usb_dev_handle * dev, int strindex,
+ int langid, char *buf, size_t buflen)
+{
+ int err;
+
+ if (dev == NULL)
+ return (-1);
+
+ if (buflen > 65535)
+ buflen = 65535;
+
+ err = libusb20_dev_req_string_sync((void *)dev,
+ strindex, langid, buf, buflen);
+
+ if (err)
+ return (-1);
+
+ return (0);
+}
+
+int
+usb_get_string_simple(usb_dev_handle * dev, int strindex,
+ char *buf, size_t buflen)
+{
+ int err;
+
+ if (dev == NULL)
+ return (-1);
+
+ if (buflen > 65535)
+ buflen = 65535;
+
+ err = libusb20_dev_req_string_simple_sync((void *)dev,
+ strindex, buf, buflen);
+
+ if (err)
+ return (-1);
+
+ return (strlen(buf));
+}
+
+int
+usb_get_descriptor_by_endpoint(usb_dev_handle * udev, int ep, uint8_t type,
+ uint8_t ep_index, void *buf, int size)
+{
+ memset(buf, 0, size);
+
+ if (udev == NULL)
+ return (-1);
+
+ if (size > 65535)
+ size = 65535;
+
+ return (usb_control_msg(udev, ep | USB_ENDPOINT_IN,
+ USB_REQ_GET_DESCRIPTOR, (type << 8) + ep_index, 0,
+ buf, size, 1000));
+}
+
+int
+usb_get_descriptor(usb_dev_handle * udev, uint8_t type, uint8_t desc_index,
+ void *buf, int size)
+{
+ memset(buf, 0, size);
+
+ if (udev == NULL)
+ return (-1);
+
+ if (size > 65535)
+ size = 65535;
+
+ return (usb_control_msg(udev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
+ (type << 8) + desc_index, 0, buf, size, 1000));
+}
+
+int
+usb_parse_descriptor(uint8_t *source, char *description, void *dest)
+{
+ uint8_t *sp = source;
+ uint8_t *dp = dest;
+ uint16_t w;
+ uint32_t d;
+ char *cp;
+
+ for (cp = description; *cp; cp++) {
+ switch (*cp) {
+ case 'b': /* 8-bit byte */
+ *dp++ = *sp++;
+ break;
+ /*
+ * 16-bit word, convert from little endian to CPU
+ */
+ case 'w':
+ w = (sp[1] << 8) | sp[0];
+ sp += 2;
+ /* Align to word boundary */
+ dp += ((dp - (uint8_t *)0) & 1);
+ *((uint16_t *)dp) = w;
+ dp += 2;
+ break;
+ /*
+ * 32-bit dword, convert from little endian to CPU
+ */
+ case 'd':
+ d = (sp[3] << 24) | (sp[2] << 16) |
+ (sp[1] << 8) | sp[0];
+ sp += 4;
+ /* Align to word boundary */
+ dp += ((dp - (uint8_t *)0) & 1);
+ /* Align to double word boundary */
+ dp += ((dp - (uint8_t *)0) & 2);
+ *((uint32_t *)dp) = d;
+ dp += 4;
+ break;
+ }
+ }
+ return (sp - source);
+}
+
+static void
+usb_parse_extra(struct usb_parse_state *ps, uint8_t **pptr, int *plen)
+{
+ void *ptr;
+ uint16_t len;
+
+ ptr = ps->a.currextra->ptr;
+ len = ps->a.currextra->len;
+
+ if (ps->preparse == 0) {
+ memcpy(ps->b.currextra, ptr, len);
+ *pptr = ps->b.currextra;
+ *plen = len;
+ }
+ ps->b.currextra += len;
+ return;
+}
+
+static void
+usb_parse_endpoint(struct usb_parse_state *ps)
+{
+ struct usb_endpoint_descriptor *bep;
+ struct libusb20_endpoint *aep;
+
+ aep = ps->a.currep;
+ bep = ps->b.currep++;
+
+ if (ps->preparse == 0) {
+ /* copy descriptor fields */
+ bep->bLength = aep->desc.bLength;
+ bep->bDescriptorType = aep->desc.bDescriptorType;
+ bep->bEndpointAddress = aep->desc.bEndpointAddress;
+ bep->bmAttributes = aep->desc.bmAttributes;
+ bep->wMaxPacketSize = aep->desc.wMaxPacketSize;
+ bep->bInterval = aep->desc.bInterval;
+ bep->bRefresh = aep->desc.bRefresh;
+ bep->bSynchAddress = aep->desc.bSynchAddress;
+ }
+ ps->a.currextra = &aep->extra;
+ usb_parse_extra(ps, &bep->extra, &bep->extralen);
+ return;
+}
+
+static void
+usb_parse_iface_sub(struct usb_parse_state *ps)
+{
+ struct libusb20_interface *aifc;
+ struct usb_interface_descriptor *bifc;
+ uint8_t x;
+
+ aifc = ps->a.currifc;
+ bifc = ps->b.currifc++;
+
+ if (ps->preparse == 0) {
+ /* copy descriptor fields */
+ bifc->bLength = aifc->desc.bLength;
+ bifc->bDescriptorType = aifc->desc.bDescriptorType;
+ bifc->bInterfaceNumber = aifc->desc.bInterfaceNumber;
+ bifc->bAlternateSetting = aifc->desc.bAlternateSetting;
+ bifc->bNumEndpoints = aifc->num_endpoints;
+ bifc->bInterfaceClass = aifc->desc.bInterfaceClass;
+ bifc->bInterfaceSubClass = aifc->desc.bInterfaceSubClass;
+ bifc->bInterfaceProtocol = aifc->desc.bInterfaceProtocol;
+ bifc->iInterface = aifc->desc.iInterface;
+ bifc->endpoint = ps->b.currep;
+ }
+ for (x = 0; x != aifc->num_endpoints; x++) {
+ ps->a.currep = aifc->endpoints + x;
+ usb_parse_endpoint(ps);
+ }
+
+ ps->a.currextra = &aifc->extra;
+ usb_parse_extra(ps, &bifc->extra, &bifc->extralen);
+ return;
+}
+
+static void
+usb_parse_iface(struct usb_parse_state *ps)
+{
+ struct libusb20_interface *aifc;
+ struct usb_interface *bifc;
+ uint8_t x;
+
+ aifc = ps->a.currifc;
+ bifc = ps->b.currifcw++;
+
+ if (ps->preparse == 0) {
+ /* initialise interface wrapper */
+ bifc->altsetting = ps->b.currifc;
+ bifc->num_altsetting = aifc->num_altsetting + 1;
+ }
+ usb_parse_iface_sub(ps);
+
+ for (x = 0; x != aifc->num_altsetting; x++) {
+ ps->a.currifc = aifc->altsetting + x;
+ usb_parse_iface_sub(ps);
+ }
+ return;
+}
+
+static void
+usb_parse_config(struct usb_parse_state *ps)
+{
+ struct libusb20_config *acfg;
+ struct usb_config_descriptor *bcfg;
+ uint8_t x;
+
+ acfg = ps->a.currcfg;
+ bcfg = ps->b.currcfg;
+
+ if (ps->preparse == 0) {
+ /* initialise config wrapper */
+ bcfg->bLength = acfg->desc.bLength;
+ bcfg->bDescriptorType = acfg->desc.bDescriptorType;
+ bcfg->wTotalLength = acfg->desc.wTotalLength;
+ bcfg->bNumInterfaces = acfg->num_interface;
+ bcfg->bConfigurationValue = acfg->desc.bConfigurationValue;
+ bcfg->iConfiguration = acfg->desc.iConfiguration;
+ bcfg->bmAttributes = acfg->desc.bmAttributes;
+ bcfg->MaxPower = acfg->desc.bMaxPower;
+ bcfg->interface = ps->b.currifcw;
+ }
+ for (x = 0; x != acfg->num_interface; x++) {
+ ps->a.currifc = acfg->interface + x;
+ usb_parse_iface(ps);
+ }
+
+ ps->a.currextra = &acfg->extra;
+ usb_parse_extra(ps, &bcfg->extra, &bcfg->extralen);
+ return;
+}
+
+int
+usb_parse_configuration(struct usb_config_descriptor *config,
+ uint8_t *buffer)
+{
+ struct usb_parse_state ps;
+ uint8_t *ptr;
+ uint32_t a;
+ uint32_t b;
+ uint32_t c;
+ uint32_t d;
+
+ if ((buffer == NULL) || (config == NULL)) {
+ return (-1);
+ }
+ memset(&ps, 0, sizeof(ps));
+
+ ps.a.currcfg = libusb20_parse_config_desc(buffer);
+ ps.b.currcfg = config;
+ if (ps.a.currcfg == NULL) {
+ /* could not parse config or out of memory */
+ return (-1);
+ }
+ /* do the pre-parse */
+ ps.preparse = 1;
+ usb_parse_config(&ps);
+
+ a = ((uint8_t *)(ps.b.currifcw) - ((uint8_t *)0));
+ b = ((uint8_t *)(ps.b.currifc) - ((uint8_t *)0));
+ c = ((uint8_t *)(ps.b.currep) - ((uint8_t *)0));
+ d = ((uint8_t *)(ps.b.currextra) - ((uint8_t *)0));
+
+ /* allocate memory for our configuration */
+ ptr = malloc(a + b + c + d);
+ if (ptr == NULL) {
+ /* free config structure */
+ free(ps.a.currcfg);
+ return (-1);
+ }
+
+ /* "currifcw" must be first, hence this pointer is freed */
+ ps.b.currifcw = (void *)(ptr);
+ ps.b.currifc = (void *)(ptr + a);
+ ps.b.currep = (void *)(ptr + a + b);
+ ps.b.currextra = (void *)(ptr + a + b + c);
+
+ /* generate a libusb v0.1 compatible structure */
+ ps.preparse = 0;
+ usb_parse_config(&ps);
+
+ /* free config structure */
+ free(ps.a.currcfg);
+
+ return (0); /* success */
+}
+
+void
+usb_destroy_configuration(struct usb_device *dev)
+{
+ uint8_t c;
+
+ if (dev->config == NULL) {
+ return;
+ }
+ for (c = 0; c != dev->descriptor.bNumConfigurations; c++) {
+ struct usb_config_descriptor *cf = &dev->config[c];
+
+ if (cf->interface != NULL) {
+ free(cf->interface);
+ cf->interface = NULL;
+ }
+ }
+
+ free(dev->config);
+ dev->config = NULL;
+ return;
+}
+
+void
+usb_fetch_and_parse_descriptors(usb_dev_handle * udev)
+{
+ struct usb_device *dev;
+ struct libusb20_device *pdev;
+ uint8_t *ptr;
+ int error;
+ uint32_t size;
+ uint16_t len;
+ uint8_t x;
+
+ if (udev == NULL) {
+ /* be NULL safe */
+ return;
+ }
+ dev = usb_device(udev);
+ pdev = (void *)udev;
+
+ if (dev->descriptor.bNumConfigurations == 0) {
+ /* invalid device */
+ return;
+ }
+ size = dev->descriptor.bNumConfigurations *
+ sizeof(struct usb_config_descriptor);
+
+ dev->config = malloc(size);
+ if (dev->config == NULL) {
+ /* out of memory */
+ return;
+ }
+ memset(dev->config, 0, size);
+
+ for (x = 0; x != dev->descriptor.bNumConfigurations; x++) {
+
+ error = (pdev->methods->get_config_desc_full) (
+ pdev, &ptr, &len, x);
+
+ if (error) {
+ usb_destroy_configuration(dev);
+ return;
+ }
+ usb_parse_configuration(dev->config + x, ptr);
+
+ /* free config buffer */
+ free(ptr);
+ }
+ return;
+}
+
+static int
+usb_std_io(usb_dev_handle * dev, int ep, char *bytes, int size,
+ int timeout, int is_intr)
+{
+ struct libusb20_transfer *xfer;
+ uint32_t temp;
+ uint32_t maxsize;
+ uint32_t actlen;
+ char *oldbytes;
+
+ xfer = usb_get_transfer_by_ep_no(dev, ep);
+ if (xfer == NULL)
+ return (-1);
+
+ if (libusb20_tr_pending(xfer)) {
+ /* there is already a transfer ongoing */
+ return (-1);
+ }
+ maxsize = libusb20_tr_get_max_total_length(xfer);
+ oldbytes = bytes;
+
+ /*
+ * We allow transferring zero bytes which is the same
+ * equivalent to a zero length USB packet.
+ */
+ do {
+
+ temp = size;
+ if (temp > maxsize) {
+ /* find maximum possible length */
+ temp = maxsize;
+ }
+ if (is_intr)
+ libusb20_tr_setup_intr(xfer, bytes, temp, timeout);
+ else
+ libusb20_tr_setup_bulk(xfer, bytes, temp, timeout);
+
+ libusb20_tr_start(xfer);
+
+ while (1) {
+
+ if (libusb20_dev_process((void *)dev) != 0) {
+ /* device detached */
+ return (-1);
+ }
+ if (libusb20_tr_pending(xfer) == 0) {
+ /* transfer complete */
+ break;
+ }
+ /* wait for USB event from kernel */
+ libusb20_dev_wait_process((void *)dev, -1);
+ }
+
+ switch (libusb20_tr_get_status(xfer)) {
+ case 0:
+ /* success */
+ break;
+ case LIBUSB20_TRANSFER_TIMED_OUT:
+ /* transfer timeout */
+ return (-ETIMEDOUT);
+ default:
+ /* other transfer error */
+ return (-ENXIO);
+ }
+ actlen = libusb20_tr_get_actual_length(xfer);
+
+ bytes += actlen;
+ size -= actlen;
+
+ if (actlen != temp) {
+ /* short transfer */
+ break;
+ }
+ } while (size > 0);
+
+ return (bytes - oldbytes);
+}
+
+int
+usb_bulk_write(usb_dev_handle * dev, int ep, char *bytes,
+ int size, int timeout)
+{
+ return (usb_std_io(dev, ep & ~USB_ENDPOINT_DIR_MASK,
+ bytes, size, timeout, 0));
+}
+
+int
+usb_bulk_read(usb_dev_handle * dev, int ep, char *bytes,
+ int size, int timeout)
+{
+ return (usb_std_io(dev, ep | USB_ENDPOINT_DIR_MASK,
+ bytes, size, timeout, 0));
+}
+
+int
+usb_interrupt_write(usb_dev_handle * dev, int ep, char *bytes,
+ int size, int timeout)
+{
+ return (usb_std_io(dev, ep & ~USB_ENDPOINT_DIR_MASK,
+ bytes, size, timeout, 1));
+}
+
+int
+usb_interrupt_read(usb_dev_handle * dev, int ep, char *bytes,
+ int size, int timeout)
+{
+ return (usb_std_io(dev, ep | USB_ENDPOINT_DIR_MASK,
+ bytes, size, timeout, 1));
+}
+
+int
+usb_control_msg(usb_dev_handle * dev, int requesttype, int request,
+ int value, int wIndex, char *bytes, int size, int timeout)
+{
+ struct LIBUSB20_CONTROL_SETUP_DECODED req;
+ int err;
+ uint16_t actlen;
+
+ LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req);
+
+ req.bmRequestType = requesttype;
+ req.bRequest = request;
+ req.wValue = value;
+ req.wIndex = wIndex;
+ req.wLength = size;
+
+ err = libusb20_dev_request_sync((void *)dev, &req, bytes,
+ &actlen, timeout, 0);
+
+ if (err)
+ return (-1);
+
+ return (actlen);
+}
+
+int
+usb_set_configuration(usb_dev_handle * udev, int bConfigurationValue)
+{
+ struct usb_device *dev;
+ int err;
+ uint8_t i;
+
+ /*
+ * Need to translate from "bConfigurationValue" to
+ * configuration index:
+ */
+
+ if (bConfigurationValue == 0) {
+ /* unconfigure */
+ i = 255;
+ } else {
+ /* lookup configuration index */
+ dev = usb_device(udev);
+
+ /* check if the configuration array is not there */
+ if (dev->config == NULL) {
+ return (-1);
+ }
+ for (i = 0;; i++) {
+ if (i == dev->descriptor.bNumConfigurations) {
+ /* "bConfigurationValue" not found */
+ return (-1);
+ }
+ if ((dev->config + i)->bConfigurationValue ==
+ bConfigurationValue) {
+ break;
+ }
+ }
+ }
+
+ err = libusb20_dev_set_config_index((void *)udev, i);
+
+ if (err)
+ return (-1);
+
+ return (0);
+}
+
+int
+usb_claim_interface(usb_dev_handle * dev, int interface)
+{
+ struct libusb20_device *pdev = (void *)dev;
+
+ pdev->claimed_interface = interface;
+
+ return (0);
+}
+
+int
+usb_release_interface(usb_dev_handle * dev, int interface)
+{
+ /* do nothing */
+ return (0);
+}
+
+int
+usb_set_altinterface(usb_dev_handle * dev, int alternate)
+{
+ struct libusb20_device *pdev = (void *)dev;
+ int err;
+ uint8_t iface;
+
+ iface = pdev->claimed_interface;
+
+ err = libusb20_dev_set_alt_index((void *)dev, iface, alternate);
+
+ if (err)
+ return (-1);
+
+ return (0);
+}
+
+int
+usb_resetep(usb_dev_handle * dev, unsigned int ep)
+{
+ /* emulate an endpoint reset through clear-STALL */
+ return (usb_clear_halt(dev, ep));
+}
+
+int
+usb_clear_halt(usb_dev_handle * dev, unsigned int ep)
+{
+ struct libusb20_transfer *xfer;
+
+ xfer = usb_get_transfer_by_ep_no(dev, ep);
+ if (xfer == NULL)
+ return (-1);
+
+ libusb20_tr_clear_stall_sync(xfer);
+
+ return (0);
+}
+
+int
+usb_reset(usb_dev_handle * dev)
+{
+ int err;
+
+ err = libusb20_dev_reset((void *)dev);
+
+ if (err)
+ return (-1);
+
+ /*
+ * Be compatible with LibUSB from sourceforge and close the
+ * handle after reset!
+ */
+ return (usb_close(dev));
+}
+
+int
+usb_check_connected(usb_dev_handle * dev)
+{
+ int err;
+
+ err = libusb20_dev_check_connected((void *)dev);
+
+ if (err)
+ return (-1);
+
+ return (0);
+}
+
+const char *
+usb_strerror(void)
+{
+ /* TODO */
+ return ("Unknown error");
+}
+
+void
+usb_init(void)
+{
+ /* nothing to do */
+ return;
+}
+
+void
+usb_set_debug(int level)
+{
+ /* use kernel UGEN debugging if you need to see what is going on */
+ return;
+}
+
+int
+usb_find_busses(void)
+{
+ usb_busses = &usb_global_bus;
+ return (1);
+}
+
+int
+usb_find_devices(void)
+{
+ struct libusb20_device *pdev;
+ struct usb_device *udev;
+ struct LIBUSB20_DEVICE_DESC_DECODED *ddesc;
+ int devnum;
+ int err;
+
+ /* cleanup after last device search */
+ /* close all opened devices, if any */
+
+ while ((pdev = libusb20_be_device_foreach(usb_backend, NULL))) {
+ udev = pdev->privLuData;
+ libusb20_be_dequeue_device(usb_backend, pdev);
+ libusb20_dev_free(pdev);
+ if (udev != NULL) {
+ LIST_DEL(usb_global_bus.devices, udev);
+ free(udev);
+ }
+ }
+
+ /* free old USB backend, if any */
+
+ libusb20_be_free(usb_backend);
+
+ /* do a new backend device search */
+ usb_backend = libusb20_be_alloc_default();
+ if (usb_backend == NULL) {
+ return (-1);
+ }
+ /* iterate all devices */
+
+ devnum = 1;
+ pdev = NULL;
+ while ((pdev = libusb20_be_device_foreach(usb_backend, pdev))) {
+ udev = malloc(sizeof(*udev));
+ if (udev == NULL)
+ break;
+
+ memset(udev, 0, sizeof(*udev));
+
+ udev->bus = &usb_global_bus;
+
+ snprintf(udev->filename, sizeof(udev->filename),
+ "/dev/ugen%u.%u",
+ libusb20_dev_get_bus_number(pdev),
+ libusb20_dev_get_address(pdev));
+
+ ddesc = libusb20_dev_get_device_desc(pdev);
+
+ udev->descriptor.bLength = sizeof(udev->descriptor);
+ udev->descriptor.bDescriptorType = ddesc->bDescriptorType;
+ udev->descriptor.bcdUSB = ddesc->bcdUSB;
+ udev->descriptor.bDeviceClass = ddesc->bDeviceClass;
+ udev->descriptor.bDeviceSubClass = ddesc->bDeviceSubClass;
+ udev->descriptor.bDeviceProtocol = ddesc->bDeviceProtocol;
+ udev->descriptor.bMaxPacketSize0 = ddesc->bMaxPacketSize0;
+ udev->descriptor.idVendor = ddesc->idVendor;
+ udev->descriptor.idProduct = ddesc->idProduct;
+ udev->descriptor.bcdDevice = ddesc->bcdDevice;
+ udev->descriptor.iManufacturer = ddesc->iManufacturer;
+ udev->descriptor.iProduct = ddesc->iProduct;
+ udev->descriptor.iSerialNumber = ddesc->iSerialNumber;
+ udev->descriptor.bNumConfigurations =
+ ddesc->bNumConfigurations;
+ if (udev->descriptor.bNumConfigurations > USB_MAXCONFIG) {
+ /* truncate number of configurations */
+ udev->descriptor.bNumConfigurations = USB_MAXCONFIG;
+ }
+ udev->devnum = devnum++;
+ /* link together the two structures */
+ udev->dev = pdev;
+ pdev->privLuData = udev;
+
+ err = libusb20_dev_open(pdev, 0);
+ if (err == 0) {
+ /* XXX get all config descriptors by default */
+ usb_fetch_and_parse_descriptors((void *)pdev);
+ libusb20_dev_close(pdev);
+ }
+ LIST_ADD(usb_global_bus.devices, udev);
+ }
+
+ return (devnum - 1); /* success */
+}
+
+struct usb_device *
+usb_device(usb_dev_handle * dev)
+{
+ struct libusb20_device *pdev;
+
+ pdev = (void *)dev;
+
+ return (pdev->privLuData);
+}
+
+struct usb_bus *
+usb_get_busses(void)
+{
+ return (usb_busses);
+}
+
+int
+usb_get_driver_np(usb_dev_handle * dev, int interface, char *name, int namelen)
+{
+ struct libusb20_device *pdev;
+ char *ptr;
+ int err;
+
+ pdev = (void *)dev;
+
+ if (pdev == NULL)
+ return (-1);
+ if (namelen < 1)
+ return (-1);
+ if (namelen > 255)
+ namelen = 255;
+
+ err = libusb20_dev_get_iface_desc(pdev, interface, name, namelen);
+ if (err != 0)
+ return (-1);
+
+ /* we only want the driver name */
+ ptr = strstr(name, ":");
+ if (ptr != NULL)
+ *ptr = 0;
+
+ return (0);
+}
+
+int
+usb_detach_kernel_driver_np(usb_dev_handle * dev, int interface)
+{
+ struct libusb20_device *pdev;
+ int err;
+
+ pdev = (void *)dev;
+
+ if (pdev == NULL)
+ return (-1);
+
+ err = libusb20_dev_detach_kernel_driver(pdev, interface);
+ if (err != 0)
+ return (-1);
+
+ return (0);
+}
diff --git a/lib/libusb/libusb10.c b/lib/libusb/libusb10.c
new file mode 100644
index 0000000..02ad315
--- /dev/null
+++ b/lib/libusb/libusb10.c
@@ -0,0 +1,1546 @@
+/* $FreeBSD$ */
+/*-
+ * Copyright (c) 2009 Sylvestre Gallon. All rights reserved.
+ * Copyright (c) 2009 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.
+ */
+
+#include <sys/fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/queue.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <poll.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define libusb_device_handle libusb20_device
+
+#include "libusb20.h"
+#include "libusb20_desc.h"
+#include "libusb20_int.h"
+#include "libusb.h"
+#include "libusb10.h"
+
+static pthread_mutex_t default_context_lock = PTHREAD_MUTEX_INITIALIZER;
+struct libusb_context *usbi_default_context = NULL;
+
+/* Prototypes */
+
+static struct libusb20_transfer *libusb10_get_transfer(struct libusb20_device *, uint8_t, uint8_t);
+static int libusb10_get_buffsize(struct libusb20_device *, libusb_transfer *);
+static int libusb10_convert_error(uint8_t status);
+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 */
+
+void
+libusb_set_debug(libusb_context *ctx, int level)
+{
+ ctx = GET_CONTEXT(ctx);
+ if (ctx)
+ ctx->debug = level;
+}
+
+static void
+libusb_set_nonblocking(int f)
+{
+ int flags;
+
+ /*
+ * We ignore any failures in this function, hence the
+ * non-blocking flag is not critical to the operation of
+ * libUSB. We use F_GETFL and F_SETFL to be compatible with
+ * Linux.
+ */
+
+ flags = fcntl(f, F_GETFL, NULL);
+ if (flags == -1)
+ return;
+ flags |= O_NONBLOCK;
+ fcntl(f, F_SETFL, flags);
+}
+
+int
+libusb_init(libusb_context **context)
+{
+ struct libusb_context *ctx;
+ char *debug;
+ int ret;
+
+ ctx = malloc(sizeof(*ctx));
+ if (!ctx)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ memset(ctx, 0, sizeof(*ctx));
+
+ debug = getenv("LIBUSB_DEBUG");
+ if (debug != NULL) {
+ ctx->debug = atoi(debug);
+ if (ctx->debug != 0)
+ 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);
+ pthread_cond_destroy(&ctx->ctx_cond);
+ free(ctx);
+ return (LIBUSB_ERROR_OTHER);
+ }
+ /* set non-blocking mode on the control pipe to avoid deadlock */
+ libusb_set_nonblocking(ctx->ctrl_pipe[0]);
+ libusb_set_nonblocking(ctx->ctrl_pipe[1]);
+
+ libusb10_add_pollfd(ctx, &ctx->ctx_poll, NULL, ctx->ctrl_pipe[0], POLLIN);
+
+ pthread_mutex_lock(&default_context_lock);
+ if (usbi_default_context == NULL) {
+ usbi_default_context = ctx;
+ }
+ pthread_mutex_unlock(&default_context_lock);
+
+ if (context)
+ *context = ctx;
+
+ DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_init complete");
+
+ return (0);
+}
+
+void
+libusb_exit(libusb_context *ctx)
+{
+ ctx = GET_CONTEXT(ctx);
+
+ if (ctx == NULL)
+ return;
+
+ /* 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_cond_destroy(&ctx->ctx_cond);
+
+ pthread_mutex_lock(&default_context_lock);
+ if (ctx == usbi_default_context) {
+ usbi_default_context = NULL;
+ }
+ pthread_mutex_unlock(&default_context_lock);
+
+ free(ctx);
+}
+
+/* Device handling and initialisation. */
+
+ssize_t
+libusb_get_device_list(libusb_context *ctx, libusb_device ***list)
+{
+ struct libusb20_backend *usb_backend;
+ struct libusb20_device *pdev;
+ struct libusb_device *dev;
+ int i;
+
+ ctx = GET_CONTEXT(ctx);
+
+ if (ctx == NULL)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ if (list == NULL)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ usb_backend = libusb20_be_alloc_default();
+ if (usb_backend == NULL)
+ return (LIBUSB_ERROR_NO_MEM);
+
+ /* figure out how many USB devices are present */
+ pdev = NULL;
+ i = 0;
+ while ((pdev = libusb20_be_device_foreach(usb_backend, pdev)))
+ i++;
+
+ /* allocate device pointer list */
+ *list = malloc((i + 1) * sizeof(void *));
+ if (*list == NULL) {
+ libusb20_be_free(usb_backend);
+ return (LIBUSB_ERROR_NO_MEM);
+ }
+ /* create libusb v1.0 compliant devices */
+ i = 0;
+ while ((pdev = libusb20_be_device_foreach(usb_backend, NULL))) {
+
+ dev = malloc(sizeof(*dev));
+ if (dev == NULL) {
+ while (i != 0) {
+ libusb_unref_device((*list)[i - 1]);
+ i--;
+ }
+ free(*list);
+ *list = NULL;
+ libusb20_be_free(usb_backend);
+ return (LIBUSB_ERROR_NO_MEM);
+ }
+ /* get device into libUSB v1.0 list */
+ libusb20_be_dequeue_device(usb_backend, pdev);
+
+ memset(dev, 0, sizeof(*dev));
+
+ /* init transfer queues */
+ TAILQ_INIT(&dev->tr_head);
+
+ /* set context we belong to */
+ dev->ctx = ctx;
+
+ /* link together the two structures */
+ dev->os_priv = pdev;
+ pdev->privLuData = dev;
+
+ (*list)[i] = libusb_ref_device(dev);
+ i++;
+ }
+ (*list)[i] = NULL;
+
+ libusb20_be_free(usb_backend);
+ return (i);
+}
+
+void
+libusb_free_device_list(libusb_device **list, int unref_devices)
+{
+ int i;
+
+ if (list == NULL)
+ return; /* be NULL safe */
+
+ if (unref_devices) {
+ for (i = 0; list[i] != NULL; i++)
+ libusb_unref_device(list[i]);
+ }
+ free(list);
+}
+
+uint8_t
+libusb_get_bus_number(libusb_device *dev)
+{
+ if (dev == NULL)
+ return (0); /* should not happen */
+ return (libusb20_dev_get_bus_number(dev->os_priv));
+}
+
+uint8_t
+libusb_get_device_address(libusb_device *dev)
+{
+ if (dev == NULL)
+ return (0); /* should not happen */
+ return (libusb20_dev_get_address(dev->os_priv));
+}
+
+enum libusb_speed
+libusb_get_device_speed(libusb_device *dev)
+{
+ if (dev == NULL)
+ return (LIBUSB_SPEED_UNKNOWN); /* should not happen */
+
+ switch (libusb20_dev_get_speed(dev->os_priv)) {
+ case LIBUSB20_SPEED_LOW:
+ return (LIBUSB_SPEED_LOW);
+ case LIBUSB20_SPEED_FULL:
+ return (LIBUSB_SPEED_FULL);
+ case LIBUSB20_SPEED_HIGH:
+ return (LIBUSB_SPEED_HIGH);
+ case LIBUSB20_SPEED_SUPER:
+ return (LIBUSB_SPEED_SUPER);
+ default:
+ break;
+ }
+ return (LIBUSB_SPEED_UNKNOWN);
+}
+
+int
+libusb_get_max_packet_size(libusb_device *dev, uint8_t endpoint)
+{
+ struct libusb_config_descriptor *pdconf;
+ struct libusb_interface *pinf;
+ struct libusb_interface_descriptor *pdinf;
+ struct libusb_endpoint_descriptor *pdend;
+ int i;
+ int j;
+ int k;
+ int ret;
+
+ if (dev == NULL)
+ return (LIBUSB_ERROR_NO_DEVICE);
+
+ ret = libusb_get_active_config_descriptor(dev, &pdconf);
+ if (ret < 0)
+ return (ret);
+
+ ret = LIBUSB_ERROR_NOT_FOUND;
+ for (i = 0; i < pdconf->bNumInterfaces; i++) {
+ pinf = &pdconf->interface[i];
+ for (j = 0; j < pinf->num_altsetting; j++) {
+ pdinf = &pinf->altsetting[j];
+ for (k = 0; k < pdinf->bNumEndpoints; k++) {
+ pdend = &pdinf->endpoint[k];
+ if (pdend->bEndpointAddress == endpoint) {
+ ret = pdend->wMaxPacketSize;
+ goto out;
+ }
+ }
+ }
+ }
+
+out:
+ libusb_free_config_descriptor(pdconf);
+ return (ret);
+}
+
+int
+libusb_get_max_iso_packet_size(libusb_device *dev, uint8_t endpoint)
+{
+ int multiplier;
+ int ret;
+
+ ret = libusb_get_max_packet_size(dev, endpoint);
+
+ switch (libusb20_dev_get_speed(dev->os_priv)) {
+ case LIBUSB20_SPEED_LOW:
+ case LIBUSB20_SPEED_FULL:
+ break;
+ default:
+ if (ret > -1) {
+ multiplier = (1 + ((ret >> 11) & 3));
+ if (multiplier > 3)
+ multiplier = 3;
+ ret = (ret & 0x7FF) * multiplier;
+ }
+ break;
+ }
+ return (ret);
+}
+
+libusb_device *
+libusb_ref_device(libusb_device *dev)
+{
+ if (dev == NULL)
+ return (NULL); /* be NULL safe */
+
+ CTX_LOCK(dev->ctx);
+ dev->refcnt++;
+ CTX_UNLOCK(dev->ctx);
+
+ return (dev);
+}
+
+void
+libusb_unref_device(libusb_device *dev)
+{
+ if (dev == NULL)
+ return; /* be NULL safe */
+
+ CTX_LOCK(dev->ctx);
+ dev->refcnt--;
+ CTX_UNLOCK(dev->ctx);
+
+ if (dev->refcnt == 0) {
+ libusb20_dev_free(dev->os_priv);
+ free(dev);
+ }
+}
+
+int
+libusb_open(libusb_device *dev, libusb_device_handle **devh)
+{
+ libusb_context *ctx = dev->ctx;
+ struct libusb20_device *pdev = dev->os_priv;
+ uint8_t dummy;
+ int err;
+
+ if (devh == NULL)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ /* set default device handle value */
+ *devh = NULL;
+
+ dev = libusb_ref_device(dev);
+ if (dev == NULL)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ err = libusb20_dev_open(pdev, 16 * 4 /* number of endpoints */ );
+ if (err) {
+ libusb_unref_device(dev);
+ return (LIBUSB_ERROR_NO_MEM);
+ }
+ libusb10_add_pollfd(ctx, &dev->dev_poll, pdev, libusb20_dev_get_fd(pdev), POLLIN |
+ POLLOUT | POLLRDNORM | POLLWRNORM);
+
+ /* make sure our event loop detects the new device */
+ dummy = 0;
+ err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy));
+ if (err < (int)sizeof(dummy)) {
+ /* ignore error, if any */
+ DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open write failed!");
+ }
+ *devh = pdev;
+
+ return (0);
+}
+
+libusb_device_handle *
+libusb_open_device_with_vid_pid(libusb_context *ctx, uint16_t vendor_id,
+ uint16_t product_id)
+{
+ struct libusb_device **devs;
+ struct libusb20_device *pdev;
+ struct LIBUSB20_DEVICE_DESC_DECODED *pdesc;
+ int i;
+ int j;
+
+ ctx = GET_CONTEXT(ctx);
+ if (ctx == NULL)
+ return (NULL); /* be NULL safe */
+
+ DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_width_vid_pid enter");
+
+ if ((i = libusb_get_device_list(ctx, &devs)) < 0)
+ return (NULL);
+
+ pdev = NULL;
+ for (j = 0; j < i; j++) {
+ struct libusb20_device *tdev;
+
+ tdev = devs[j]->os_priv;
+ pdesc = libusb20_dev_get_device_desc(tdev);
+ /*
+ * NOTE: The USB library will automatically swap the
+ * fields in the device descriptor to be of host
+ * endian type!
+ */
+ if (pdesc->idVendor == vendor_id &&
+ pdesc->idProduct == product_id) {
+ libusb_open(devs[j], &pdev);
+ break;
+ }
+ }
+
+ libusb_free_device_list(devs, 1);
+ DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_width_vid_pid leave");
+ return (pdev);
+}
+
+void
+libusb_close(struct libusb20_device *pdev)
+{
+ libusb_context *ctx;
+ struct libusb_device *dev;
+ uint8_t dummy;
+ int err;
+
+ if (pdev == NULL)
+ return; /* be NULL safe */
+
+ dev = libusb_get_device(pdev);
+ ctx = dev->ctx;
+
+ libusb10_remove_pollfd(ctx, &dev->dev_poll);
+
+ libusb20_dev_close(pdev);
+
+ /* unref will free the "pdev" when the refcount reaches zero */
+ libusb_unref_device(dev);
+
+ /* make sure our event loop detects the closed device */
+ dummy = 0;
+ err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy));
+ if (err < (int)sizeof(dummy)) {
+ /* ignore error, if any */
+ DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_close write failed!");
+ }
+}
+
+libusb_device *
+libusb_get_device(struct libusb20_device *pdev)
+{
+ if (pdev == NULL)
+ return (NULL);
+ return ((libusb_device *)pdev->privLuData);
+}
+
+int
+libusb_get_configuration(struct libusb20_device *pdev, int *config)
+{
+ struct libusb20_config *pconf;
+
+ if (pdev == NULL || config == NULL)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ pconf = libusb20_dev_alloc_config(pdev, libusb20_dev_get_config_index(pdev));
+ if (pconf == NULL)
+ return (LIBUSB_ERROR_NO_MEM);
+
+ *config = pconf->desc.bConfigurationValue;
+
+ free(pconf);
+
+ return (0);
+}
+
+int
+libusb_set_configuration(struct libusb20_device *pdev, int configuration)
+{
+ struct libusb20_config *pconf;
+ struct libusb_device *dev;
+ int err;
+ uint8_t i;
+
+ dev = libusb_get_device(pdev);
+ if (dev == NULL)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ if (configuration < 1) {
+ /* unconfigure */
+ i = 255;
+ } else {
+ for (i = 0; i != 255; i++) {
+ uint8_t found;
+
+ pconf = libusb20_dev_alloc_config(pdev, i);
+ if (pconf == NULL)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+ found = (pconf->desc.bConfigurationValue
+ == configuration);
+ free(pconf);
+
+ if (found)
+ goto set_config;
+ }
+ return (LIBUSB_ERROR_INVALID_PARAM);
+ }
+
+set_config:
+
+ libusb10_cancel_all_transfer(dev);
+
+ libusb10_remove_pollfd(dev->ctx, &dev->dev_poll);
+
+ err = libusb20_dev_set_config_index(pdev, i);
+
+ libusb10_add_pollfd(dev->ctx, &dev->dev_poll, pdev, libusb20_dev_get_fd(pdev), POLLIN |
+ POLLOUT | POLLRDNORM | POLLWRNORM);
+
+ return (err ? LIBUSB_ERROR_INVALID_PARAM : 0);
+}
+
+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)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ if (interface_number < 0 || interface_number > 31)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ CTX_LOCK(dev->ctx);
+ if (dev->claimed_interfaces & (1 << interface_number))
+ err = LIBUSB_ERROR_BUSY;
+
+ if (!err)
+ dev->claimed_interfaces |= (1 << interface_number);
+ CTX_UNLOCK(dev->ctx);
+ return (err);
+}
+
+int
+libusb_release_interface(struct libusb20_device *pdev, int interface_number)
+{
+ libusb_device *dev;
+ int err = 0;
+
+ dev = libusb_get_device(pdev);
+ if (dev == NULL)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ if (interface_number < 0 || interface_number > 31)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ CTX_LOCK(dev->ctx);
+ if (!(dev->claimed_interfaces & (1 << interface_number)))
+ err = LIBUSB_ERROR_NOT_FOUND;
+
+ if (!err)
+ dev->claimed_interfaces &= ~(1 << interface_number);
+ CTX_UNLOCK(dev->ctx);
+ return (err);
+}
+
+int
+libusb_set_interface_alt_setting(struct libusb20_device *pdev,
+ int interface_number, int alternate_setting)
+{
+ libusb_device *dev;
+ int err = 0;
+
+ dev = libusb_get_device(pdev);
+ if (dev == NULL)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ if (interface_number < 0 || interface_number > 31)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ CTX_LOCK(dev->ctx);
+ if (!(dev->claimed_interfaces & (1 << interface_number)))
+ err = LIBUSB_ERROR_NOT_FOUND;
+ CTX_UNLOCK(dev->ctx);
+
+ if (err)
+ return (err);
+
+ libusb10_cancel_all_transfer(dev);
+
+ libusb10_remove_pollfd(dev->ctx, &dev->dev_poll);
+
+ err = libusb20_dev_set_alt_index(pdev,
+ interface_number, alternate_setting);
+
+ libusb10_add_pollfd(dev->ctx, &dev->dev_poll,
+ pdev, libusb20_dev_get_fd(pdev),
+ POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM);
+
+ return (err ? LIBUSB_ERROR_OTHER : 0);
+}
+
+static struct libusb20_transfer *
+libusb10_get_transfer(struct libusb20_device *pdev,
+ uint8_t endpoint, uint8_t index)
+{
+ index &= 1; /* double buffering */
+
+ index |= (endpoint & LIBUSB20_ENDPOINT_ADDRESS_MASK) * 4;
+
+ if (endpoint & LIBUSB20_ENDPOINT_DIR_MASK) {
+ /* this is an IN endpoint */
+ index |= 2;
+ }
+ return (libusb20_tr_get_pointer(pdev, index));
+}
+
+int
+libusb_clear_halt(struct libusb20_device *pdev, uint8_t endpoint)
+{
+ struct libusb20_transfer *xfer;
+ struct libusb_device *dev;
+ int err;
+
+ xfer = libusb10_get_transfer(pdev, endpoint, 0);
+ if (xfer == NULL)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ dev = libusb_get_device(pdev);
+ if (dev == NULL)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ CTX_LOCK(dev->ctx);
+ err = libusb20_tr_open(xfer, 0, 1, endpoint);
+ CTX_UNLOCK(dev->ctx);
+
+ if (err != 0 && err != LIBUSB20_ERROR_BUSY)
+ return (LIBUSB_ERROR_OTHER);
+
+ libusb20_tr_clear_stall_sync(xfer);
+
+ /* check if we opened the transfer */
+ if (err == 0) {
+ CTX_LOCK(dev->ctx);
+ libusb20_tr_close(xfer);
+ CTX_UNLOCK(dev->ctx);
+ }
+ return (0); /* success */
+}
+
+int
+libusb_reset_device(struct libusb20_device *pdev)
+{
+ libusb_device *dev;
+ int err;
+
+ dev = libusb_get_device(pdev);
+ if (dev == NULL)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ libusb10_cancel_all_transfer(dev);
+
+ libusb10_remove_pollfd(dev->ctx, &dev->dev_poll);
+
+ err = libusb20_dev_reset(pdev);
+
+ libusb10_add_pollfd(dev->ctx, &dev->dev_poll,
+ pdev, libusb20_dev_get_fd(pdev),
+ POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM);
+
+ return (err ? LIBUSB_ERROR_OTHER : 0);
+}
+
+int
+libusb_check_connected(struct libusb20_device *pdev)
+{
+ libusb_device *dev;
+ int err;
+
+ dev = libusb_get_device(pdev);
+ if (dev == NULL)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ err = libusb20_dev_check_connected(pdev);
+
+ return (err ? LIBUSB_ERROR_NO_DEVICE : 0);
+}
+
+int
+libusb_kernel_driver_active(struct libusb20_device *pdev, int interface)
+{
+ if (pdev == NULL)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ if (libusb20_dev_kernel_driver_active(pdev, interface))
+ return (0); /* no kernel driver is active */
+ else
+ return (1); /* kernel driver is active */
+}
+
+int
+libusb_get_driver_np(struct libusb20_device *pdev, int interface,
+ char *name, int namelen)
+{
+ return (libusb_get_driver(pdev, interface, name, namelen));
+}
+
+int
+libusb_get_driver(struct libusb20_device *pdev, int interface,
+ char *name, int namelen)
+{
+ char *ptr;
+ int err;
+
+ if (pdev == NULL)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+ if (namelen < 1)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+ if (namelen > 255)
+ namelen = 255;
+
+ err = libusb20_dev_get_iface_desc(
+ pdev, interface, name, namelen);
+
+ if (err != 0)
+ return (LIBUSB_ERROR_OTHER);
+
+ /* we only want the driver name */
+ ptr = strstr(name, ":");
+ if (ptr != NULL)
+ *ptr = 0;
+
+ return (0);
+}
+
+int
+libusb_detach_kernel_driver_np(struct libusb20_device *pdev, int interface)
+{
+ return (libusb_detach_kernel_driver(pdev, interface));
+}
+
+int
+libusb_detach_kernel_driver(struct libusb20_device *pdev, int interface)
+{
+ int err;
+
+ if (pdev == NULL)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ err = libusb20_dev_detach_kernel_driver(
+ pdev, interface);
+
+ return (err ? LIBUSB_ERROR_OTHER : 0);
+}
+
+int
+libusb_attach_kernel_driver(struct libusb20_device *pdev, int interface)
+{
+ if (pdev == NULL)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+ /* stub - currently not supported by libusb20 */
+ return (0);
+}
+
+/* Asynchronous device I/O */
+
+struct libusb_transfer *
+libusb_alloc_transfer(int iso_packets)
+{
+ struct libusb_transfer *uxfer;
+ struct libusb_super_transfer *sxfer;
+ int len;
+
+ len = sizeof(struct libusb_transfer) +
+ sizeof(struct libusb_super_transfer) +
+ (iso_packets * sizeof(libusb_iso_packet_descriptor));
+
+ sxfer = malloc(len);
+ if (sxfer == NULL)
+ return (NULL);
+
+ memset(sxfer, 0, len);
+
+ uxfer = (struct libusb_transfer *)(
+ ((uint8_t *)sxfer) + sizeof(*sxfer));
+
+ /* set default value */
+ uxfer->num_iso_packets = iso_packets;
+
+ return (uxfer);
+}
+
+void
+libusb_free_transfer(struct libusb_transfer *uxfer)
+{
+ struct libusb_super_transfer *sxfer;
+
+ if (uxfer == NULL)
+ return; /* be NULL safe */
+
+ /* check if we should free the transfer buffer */
+ if (uxfer->flags & LIBUSB_TRANSFER_FREE_BUFFER)
+ free(uxfer->buffer);
+
+ sxfer = (struct libusb_super_transfer *)(
+ (uint8_t *)uxfer - sizeof(*sxfer));
+
+ free(sxfer);
+}
+
+static uint32_t
+libusb10_get_maxframe(struct libusb20_device *pdev, libusb_transfer *xfer)
+{
+ uint32_t ret;
+
+ switch (xfer->type) {
+ case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
+ ret = 60 | LIBUSB20_MAX_FRAME_PRE_SCALE; /* 60ms */
+ break;
+ case LIBUSB_TRANSFER_TYPE_CONTROL:
+ ret = 2;
+ break;
+ default:
+ ret = 1;
+ break;
+ }
+ return (ret);
+}
+
+static int
+libusb10_get_buffsize(struct libusb20_device *pdev, libusb_transfer *xfer)
+{
+ int ret;
+ int usb_speed;
+
+ usb_speed = libusb20_dev_get_speed(pdev);
+
+ switch (xfer->type) {
+ case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
+ ret = 0; /* kernel will auto-select */
+ break;
+ case LIBUSB_TRANSFER_TYPE_CONTROL:
+ ret = 1024;
+ break;
+ default:
+ switch (usb_speed) {
+ case LIBUSB20_SPEED_LOW:
+ ret = 256;
+ break;
+ case LIBUSB20_SPEED_FULL:
+ ret = 4096;
+ break;
+ default:
+ ret = 16384;
+ break;
+ }
+ break;
+ }
+ return (ret);
+}
+
+static int
+libusb10_convert_error(uint8_t status)
+{
+ ; /* indent fix */
+
+ switch (status) {
+ case LIBUSB20_TRANSFER_START:
+ case LIBUSB20_TRANSFER_COMPLETED:
+ return (LIBUSB_TRANSFER_COMPLETED);
+ case LIBUSB20_TRANSFER_OVERFLOW:
+ return (LIBUSB_TRANSFER_OVERFLOW);
+ case LIBUSB20_TRANSFER_NO_DEVICE:
+ return (LIBUSB_TRANSFER_NO_DEVICE);
+ case LIBUSB20_TRANSFER_STALL:
+ return (LIBUSB_TRANSFER_STALL);
+ case LIBUSB20_TRANSFER_CANCELLED:
+ return (LIBUSB_TRANSFER_CANCELLED);
+ case LIBUSB20_TRANSFER_TIMED_OUT:
+ return (LIBUSB_TRANSFER_TIMED_OUT);
+ default:
+ return (LIBUSB_TRANSFER_ERROR);
+ }
+}
+
+/* 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);
+
+ /* set transfer status */
+ uxfer->status = status;
+
+ /* update super transfer state */
+ sxfer->state = LIBUSB_SUPER_XFER_ST_NONE;
+
+ 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;
+ struct libusb_transfer *uxfer;
+ uint32_t actlen;
+ uint16_t iso_packets;
+ uint16_t i;
+ uint8_t status;
+ uint8_t flags;
+
+ status = libusb20_tr_get_status(pxfer);
+ sxfer = libusb20_tr_get_priv_sc1(pxfer);
+ actlen = libusb20_tr_get_actual_length(pxfer);
+ iso_packets = libusb20_tr_get_max_frames(pxfer);
+
+ if (sxfer == NULL)
+ return; /* cancelled - nothing to do */
+
+ uxfer = (struct libusb_transfer *)(
+ ((uint8_t *)sxfer) + sizeof(*sxfer));
+
+ if (iso_packets > uxfer->num_iso_packets)
+ iso_packets = uxfer->num_iso_packets;
+
+ if (iso_packets == 0)
+ return; /* nothing to do */
+
+ /* make sure that the number of ISOCHRONOUS packets is valid */
+ uxfer->num_iso_packets = iso_packets;
+
+ flags = uxfer->flags;
+
+ switch (status) {
+ case LIBUSB20_TRANSFER_COMPLETED:
+
+ /* update actual length */
+ uxfer->actual_length = actlen;
+ for (i = 0; i != iso_packets; i++) {
+ uxfer->iso_packet_desc[i].actual_length =
+ libusb20_tr_get_length(pxfer, i);
+ }
+ libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED);
+ break;
+
+ case LIBUSB20_TRANSFER_START:
+
+ /* setup length(s) */
+ actlen = 0;
+ for (i = 0; i != iso_packets; i++) {
+ libusb20_tr_setup_isoc(pxfer,
+ &uxfer->buffer[actlen],
+ uxfer->iso_packet_desc[i].length, i);
+ actlen += uxfer->iso_packet_desc[i].length;
+ }
+
+ /* no remainder */
+ sxfer->rem_len = 0;
+
+ libusb20_tr_set_total_frames(pxfer, iso_packets);
+ libusb20_tr_submit(pxfer);
+
+ /* fork another USB transfer, if any */
+ libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint);
+ break;
+
+ default:
+ 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)
+{
+ struct libusb_super_transfer *sxfer;
+ struct libusb_transfer *uxfer;
+ uint32_t max_bulk;
+ uint32_t actlen;
+ uint8_t status;
+ uint8_t flags;
+
+ status = libusb20_tr_get_status(pxfer);
+ sxfer = libusb20_tr_get_priv_sc1(pxfer);
+ max_bulk = libusb20_tr_get_max_total_length(pxfer);
+ actlen = libusb20_tr_get_actual_length(pxfer);
+
+ if (sxfer == NULL)
+ return; /* cancelled - nothing to do */
+
+ uxfer = (struct libusb_transfer *)(
+ ((uint8_t *)sxfer) + sizeof(*sxfer));
+
+ flags = uxfer->flags;
+
+ switch (status) {
+ case LIBUSB20_TRANSFER_COMPLETED:
+
+ uxfer->actual_length += actlen;
+
+ /* check for short packet */
+ if (sxfer->last_len != actlen) {
+ if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) {
+ libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR);
+ } else {
+ libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED);
+ }
+ break;
+ }
+ /* check for end of data */
+ if (sxfer->rem_len == 0) {
+ libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED);
+ break;
+ }
+ /* FALLTHROUGH */
+
+ case LIBUSB20_TRANSFER_START:
+ if (max_bulk > sxfer->rem_len) {
+ max_bulk = sxfer->rem_len;
+ }
+ /* setup new BULK or INTERRUPT transaction */
+ libusb20_tr_setup_bulk(pxfer,
+ sxfer->curr_data, max_bulk, uxfer->timeout);
+
+ /* update counters */
+ sxfer->last_len = max_bulk;
+ sxfer->curr_data += max_bulk;
+ sxfer->rem_len -= max_bulk;
+
+ libusb20_tr_submit(pxfer);
+
+ /* check if we can fork another USB transfer */
+ if (sxfer->rem_len == 0)
+ libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint);
+ break;
+
+ default:
+ 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)
+{
+ struct libusb_super_transfer *sxfer;
+ struct libusb_transfer *uxfer;
+ uint32_t max_bulk;
+ uint32_t actlen;
+ uint8_t status;
+ uint8_t flags;
+
+ status = libusb20_tr_get_status(pxfer);
+ sxfer = libusb20_tr_get_priv_sc1(pxfer);
+ max_bulk = libusb20_tr_get_max_total_length(pxfer);
+ actlen = libusb20_tr_get_actual_length(pxfer);
+
+ if (sxfer == NULL)
+ return; /* cancelled - nothing to do */
+
+ uxfer = (struct libusb_transfer *)(
+ ((uint8_t *)sxfer) + sizeof(*sxfer));
+
+ flags = uxfer->flags;
+
+ switch (status) {
+ case LIBUSB20_TRANSFER_COMPLETED:
+
+ uxfer->actual_length += actlen;
+
+ /* subtract length of SETUP packet, if any */
+ actlen -= libusb20_tr_get_length(pxfer, 0);
+
+ /* check for short packet */
+ if (sxfer->last_len != actlen) {
+ if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) {
+ libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR);
+ } else {
+ libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED);
+ }
+ break;
+ }
+ /* check for end of data */
+ if (sxfer->rem_len == 0) {
+ libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED);
+ break;
+ }
+ /* FALLTHROUGH */
+
+ case LIBUSB20_TRANSFER_START:
+ if (max_bulk > sxfer->rem_len) {
+ max_bulk = sxfer->rem_len;
+ }
+ /* setup new CONTROL transaction */
+ if (status == LIBUSB20_TRANSFER_COMPLETED) {
+ /* next fragment - don't send SETUP packet */
+ libusb20_tr_set_length(pxfer, 0, 0);
+ } else {
+ /* first fragment - send SETUP packet */
+ libusb20_tr_set_length(pxfer, 8, 0);
+ libusb20_tr_set_buffer(pxfer, uxfer->buffer, 0);
+ }
+
+ if (max_bulk != 0) {
+ libusb20_tr_set_length(pxfer, max_bulk, 1);
+ libusb20_tr_set_buffer(pxfer, sxfer->curr_data, 1);
+ libusb20_tr_set_total_frames(pxfer, 2);
+ } else {
+ libusb20_tr_set_total_frames(pxfer, 1);
+ }
+
+ /* update counters */
+ sxfer->last_len = max_bulk;
+ sxfer->curr_data += max_bulk;
+ sxfer->rem_len -= max_bulk;
+
+ libusb20_tr_submit(pxfer);
+
+ /* check if we can fork another USB transfer */
+ if (sxfer->rem_len == 0)
+ libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint);
+ break;
+
+ default:
+ libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status));
+ break;
+ }
+}
+
+/* The following function must be called locked */
+
+static void
+libusb10_submit_transfer_sub(struct libusb20_device *pdev, uint8_t endpoint)
+{
+ struct libusb20_transfer *pxfer0;
+ struct libusb20_transfer *pxfer1;
+ struct libusb_super_transfer *sxfer;
+ struct libusb_transfer *uxfer;
+ struct libusb_device *dev;
+ int err;
+ int buffsize;
+ int maxframe;
+ int temp;
+ uint8_t dummy;
+
+ dev = libusb_get_device(pdev);
+
+ pxfer0 = libusb10_get_transfer(pdev, endpoint, 0);
+ pxfer1 = libusb10_get_transfer(pdev, endpoint, 1);
+
+ if (pxfer0 == NULL || pxfer1 == NULL)
+ return; /* shouldn't happen */
+
+ temp = 0;
+ if (libusb20_tr_pending(pxfer0))
+ temp |= 1;
+ if (libusb20_tr_pending(pxfer1))
+ temp |= 2;
+
+ switch (temp) {
+ case 3:
+ /* wait till one of the transfers complete */
+ return;
+ case 2:
+ sxfer = libusb20_tr_get_priv_sc1(pxfer1);
+ if (sxfer == NULL)
+ return; /* cancelling */
+ if (sxfer->rem_len)
+ return; /* cannot queue another one */
+ /* swap transfers */
+ pxfer1 = pxfer0;
+ break;
+ case 1:
+ sxfer = libusb20_tr_get_priv_sc1(pxfer0);
+ if (sxfer == NULL)
+ return; /* cancelling */
+ if (sxfer->rem_len)
+ return; /* cannot queue another one */
+ /* swap transfers */
+ pxfer0 = pxfer1;
+ break;
+ default:
+ break;
+ }
+
+ /* find next transfer on same endpoint */
+ TAILQ_FOREACH(sxfer, &dev->tr_head, entry) {
+
+ uxfer = (struct libusb_transfer *)(
+ ((uint8_t *)sxfer) + sizeof(*sxfer));
+
+ if (uxfer->endpoint == endpoint) {
+ TAILQ_REMOVE(&dev->tr_head, sxfer, entry);
+ sxfer->entry.tqe_prev = NULL;
+ goto found;
+ }
+ }
+ return; /* success */
+
+found:
+
+ libusb20_tr_set_priv_sc0(pxfer0, pdev);
+ libusb20_tr_set_priv_sc1(pxfer0, sxfer);
+
+ /* reset super transfer state */
+ sxfer->rem_len = uxfer->length;
+ sxfer->curr_data = uxfer->buffer;
+ uxfer->actual_length = 0;
+
+ switch (uxfer->type) {
+ case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
+ libusb20_tr_set_callback(pxfer0, libusb10_isoc_proxy);
+ break;
+ case LIBUSB_TRANSFER_TYPE_BULK:
+ case LIBUSB_TRANSFER_TYPE_INTERRUPT:
+ libusb20_tr_set_callback(pxfer0, libusb10_bulk_intr_proxy);
+ break;
+ case LIBUSB_TRANSFER_TYPE_CONTROL:
+ libusb20_tr_set_callback(pxfer0, libusb10_ctrl_proxy);
+ if (sxfer->rem_len < 8)
+ goto failure;
+
+ /* remove SETUP packet from data */
+ sxfer->rem_len -= 8;
+ sxfer->curr_data += 8;
+ break;
+ default:
+ goto failure;
+ }
+
+ buffsize = libusb10_get_buffsize(pdev, uxfer);
+ maxframe = libusb10_get_maxframe(pdev, uxfer);
+
+ /* make sure the transfer is opened */
+ err = libusb20_tr_open(pxfer0, buffsize, maxframe, endpoint);
+ if (err && (err != LIBUSB20_ERROR_BUSY)) {
+ goto failure;
+ }
+ libusb20_tr_start(pxfer0);
+ return;
+
+failure:
+ libusb10_complete_transfer(pxfer0, sxfer, LIBUSB_TRANSFER_ERROR);
+
+ /* 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 */
+
+int
+libusb_submit_transfer(struct libusb_transfer *uxfer)
+{
+ struct libusb20_transfer *pxfer0;
+ struct libusb20_transfer *pxfer1;
+ struct libusb_super_transfer *sxfer;
+ struct libusb_device *dev;
+ uint32_t endpoint;
+ int err;
+
+ if (uxfer == NULL)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ if (uxfer->dev_handle == NULL)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ endpoint = uxfer->endpoint;
+
+ if (endpoint > 255)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ dev = libusb_get_device(uxfer->dev_handle);
+
+ DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer enter");
+
+ sxfer = (struct libusb_super_transfer *)(
+ (uint8_t *)uxfer - sizeof(*sxfer));
+
+ CTX_LOCK(dev->ctx);
+
+ pxfer0 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 0);
+ pxfer1 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 1);
+
+ if (pxfer0 == NULL || pxfer1 == NULL) {
+ err = LIBUSB_ERROR_OTHER;
+ } else if ((sxfer->entry.tqe_prev != NULL) ||
+ (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) ||
+ (libusb20_tr_get_priv_sc1(pxfer1) == sxfer)) {
+ err = LIBUSB_ERROR_BUSY;
+ } else {
+
+ /* set pending state */
+ sxfer->state = LIBUSB_SUPER_XFER_ST_PEND;
+
+ /* insert transfer into transfer head list */
+ TAILQ_INSERT_TAIL(&dev->tr_head, sxfer, entry);
+
+ /* start work transfers */
+ libusb10_submit_transfer_sub(
+ uxfer->dev_handle, endpoint);
+
+ err = 0; /* success */
+ }
+
+ CTX_UNLOCK(dev->ctx);
+
+ DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer leave %d", err);
+
+ return (err);
+}
+
+/* Asynchronous transfer cancel */
+
+int
+libusb_cancel_transfer(struct libusb_transfer *uxfer)
+{
+ struct libusb20_transfer *pxfer0;
+ struct libusb20_transfer *pxfer1;
+ struct libusb_super_transfer *sxfer;
+ struct libusb_device *dev;
+ uint32_t endpoint;
+ int retval;
+
+ if (uxfer == NULL)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ /* check if not initialised */
+ if (uxfer->dev_handle == NULL)
+ return (LIBUSB_ERROR_NOT_FOUND);
+
+ endpoint = uxfer->endpoint;
+
+ if (endpoint > 255)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ dev = libusb_get_device(uxfer->dev_handle);
+
+ DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer enter");
+
+ sxfer = (struct libusb_super_transfer *)(
+ (uint8_t *)uxfer - sizeof(*sxfer));
+
+ retval = 0;
+
+ CTX_LOCK(dev->ctx);
+
+ pxfer0 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 0);
+ pxfer1 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 1);
+
+ if (sxfer->state != LIBUSB_SUPER_XFER_ST_PEND) {
+ /* only update the transfer status */
+ uxfer->status = LIBUSB_TRANSFER_CANCELLED;
+ retval = LIBUSB_ERROR_NOT_FOUND;
+ } else if (sxfer->entry.tqe_prev != NULL) {
+ /* we are lucky - transfer is on a queue */
+ TAILQ_REMOVE(&dev->tr_head, sxfer, entry);
+ sxfer->entry.tqe_prev = NULL;
+ libusb10_complete_transfer(NULL,
+ sxfer, LIBUSB_TRANSFER_CANCELLED);
+ } else if (pxfer0 == NULL || pxfer1 == NULL) {
+ /* not started */
+ retval = LIBUSB_ERROR_NOT_FOUND;
+ } else if (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) {
+ 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);
+ } else if (libusb20_tr_get_priv_sc1(pxfer1) == sxfer) {
+ 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);
+ } else {
+ /* not started */
+ retval = LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ CTX_UNLOCK(dev->ctx);
+
+ DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer leave");
+
+ return (retval);
+}
+
+UNEXPORTED void
+libusb10_cancel_all_transfer(libusb_device *dev)
+{
+ /* TODO */
+}
+
+uint16_t
+libusb_cpu_to_le16(uint16_t x)
+{
+ return (htole16(x));
+}
+
+uint16_t
+libusb_le16_to_cpu(uint16_t x)
+{
+ return (le16toh(x));
+}
+
+const char *
+libusb_strerror(int code)
+{
+ switch (code) {
+ case LIBUSB_SUCCESS:
+ return ("Success");
+ case LIBUSB_ERROR_IO:
+ return ("I/O error");
+ case LIBUSB_ERROR_INVALID_PARAM:
+ return ("Invalid parameter");
+ case LIBUSB_ERROR_ACCESS:
+ return ("Permissions error");
+ case LIBUSB_ERROR_NO_DEVICE:
+ return ("No device");
+ case LIBUSB_ERROR_NOT_FOUND:
+ return ("Not found");
+ case LIBUSB_ERROR_BUSY:
+ return ("Device busy");
+ case LIBUSB_ERROR_TIMEOUT:
+ return ("Timeout");
+ case LIBUSB_ERROR_OVERFLOW:
+ return ("Overflow");
+ case LIBUSB_ERROR_PIPE:
+ return ("Pipe error");
+ case LIBUSB_ERROR_INTERRUPTED:
+ return ("Interrupted");
+ case LIBUSB_ERROR_NO_MEM:
+ return ("Out of memory");
+ case LIBUSB_ERROR_NOT_SUPPORTED:
+ return ("Not supported");
+ case LIBUSB_ERROR_OTHER:
+ return ("Other error");
+ default:
+ return ("Unknown error");
+ }
+}
+
+const char *
+libusb_error_name(int code)
+{
+ switch (code) {
+ case LIBUSB_SUCCESS:
+ return ("LIBUSB_SUCCESS");
+ case LIBUSB_ERROR_IO:
+ return ("LIBUSB_ERROR_IO");
+ case LIBUSB_ERROR_INVALID_PARAM:
+ return ("LIBUSB_ERROR_INVALID_PARAM");
+ case LIBUSB_ERROR_ACCESS:
+ return ("LIBUSB_ERROR_ACCESS");
+ case LIBUSB_ERROR_NO_DEVICE:
+ return ("LIBUSB_ERROR_NO_DEVICE");
+ case LIBUSB_ERROR_NOT_FOUND:
+ return ("LIBUSB_ERROR_NOT_FOUND");
+ case LIBUSB_ERROR_BUSY:
+ return ("LIBUSB_ERROR_BUSY");
+ case LIBUSB_ERROR_TIMEOUT:
+ return ("LIBUSB_ERROR_TIMEOUT");
+ case LIBUSB_ERROR_OVERFLOW:
+ return ("LIBUSB_ERROR_OVERFLOW");
+ case LIBUSB_ERROR_PIPE:
+ return ("LIBUSB_ERROR_PIPE");
+ case LIBUSB_ERROR_INTERRUPTED:
+ return ("LIBUSB_ERROR_INTERRUPTED");
+ case LIBUSB_ERROR_NO_MEM:
+ return ("LIBUSB_ERROR_NO_MEM");
+ case LIBUSB_ERROR_NOT_SUPPORTED:
+ return ("LIBUSB_ERROR_NOT_SUPPORTED");
+ case LIBUSB_ERROR_OTHER:
+ return ("LIBUSB_ERROR_OTHER");
+ default:
+ return ("LIBUSB_ERROR_UNKNOWN");
+ }
+}
diff --git a/lib/libusb/libusb10.h b/lib/libusb/libusb10.h
new file mode 100644
index 0000000..d2a2bd7
--- /dev/null
+++ b/lib/libusb/libusb10.h
@@ -0,0 +1,115 @@
+/* $FreeBSD$ */
+/*-
+ * Copyright (c) 2009 Sylvestre Gallon. 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.
+ */
+
+#ifndef __LIBUSB10_H__
+#define __LIBUSB10_H__
+
+#include <sys/queue.h>
+
+#define GET_CONTEXT(ctx) (((ctx) == NULL) ? usbi_default_context : (ctx))
+#define UNEXPORTED __attribute__((__visibility__("hidden")))
+#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 DPRINTF(ctx, dbg, format, args...) do { \
+ if ((ctx)->debug == dbg) { \
+ switch (dbg) { \
+ case LIBUSB_DEBUG_FUNCTION: \
+ printf("LIBUSB_FUNCTION: " \
+ format "\n", ## args); \
+ break; \
+ case LIBUSB_DEBUG_TRANSFER: \
+ printf("LIBUSB_TRANSFER: " \
+ format "\n", ## args); \
+ break; \
+ default: \
+ break; \
+ } \
+ } \
+} while(0)
+
+/* internal structures */
+
+struct libusb_super_pollfd {
+ TAILQ_ENTRY(libusb_super_pollfd) entry;
+ struct libusb20_device *pdev;
+ struct libusb_pollfd pollfd;
+};
+
+struct libusb_super_transfer {
+ TAILQ_ENTRY(libusb_super_transfer) entry;
+ uint8_t *curr_data;
+ uint32_t rem_len;
+ uint32_t last_len;
+ uint8_t state;
+#define LIBUSB_SUPER_XFER_ST_NONE 0
+#define LIBUSB_SUPER_XFER_ST_PEND 1
+};
+
+struct libusb_context {
+ 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;
+ pthread_t ctx_handler;
+#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;
+
+ libusb_pollfd_added_cb fd_added_cb;
+ libusb_pollfd_removed_cb fd_removed_cb;
+ void *fd_cb_user_data;
+};
+
+struct libusb_device {
+ int refcnt;
+
+ uint32_t claimed_interfaces;
+
+ struct libusb_super_pollfd dev_poll;
+
+ struct libusb_context *ctx;
+
+ TAILQ_HEAD(, libusb_super_transfer) tr_head;
+
+ struct libusb20_device *os_priv;
+};
+
+extern struct libusb_context *usbi_default_context;
+
+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_cancel_all_transfer(libusb_device *dev);
+
+#endif /* __LIBUSB10_H__ */
diff --git a/lib/libusb/libusb10_desc.c b/lib/libusb/libusb10_desc.c
new file mode 100644
index 0000000..6d5822e
--- /dev/null
+++ b/lib/libusb/libusb10_desc.c
@@ -0,0 +1,498 @@
+/* $FreeBSD$ */
+/*-
+ * Copyright (c) 2009 Sylvestre Gallon. 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.
+ */
+
+#include <sys/queue.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define libusb_device_handle libusb20_device
+
+#include "libusb20.h"
+#include "libusb20_desc.h"
+#include "libusb20_int.h"
+#include "libusb.h"
+#include "libusb10.h"
+
+#define N_ALIGN(n) (-((-(n)) & (-8UL)))
+
+/* USB descriptors */
+
+int
+libusb_get_device_descriptor(libusb_device *dev,
+ struct libusb_device_descriptor *desc)
+{
+ struct LIBUSB20_DEVICE_DESC_DECODED *pdesc;
+ struct libusb20_device *pdev;
+
+ if ((dev == NULL) || (desc == NULL))
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ pdev = dev->os_priv;
+ pdesc = libusb20_dev_get_device_desc(pdev);
+
+ desc->bLength = pdesc->bLength;
+ desc->bDescriptorType = pdesc->bDescriptorType;
+ desc->bcdUSB = pdesc->bcdUSB;
+ desc->bDeviceClass = pdesc->bDeviceClass;
+ desc->bDeviceSubClass = pdesc->bDeviceSubClass;
+ desc->bDeviceProtocol = pdesc->bDeviceProtocol;
+ desc->bMaxPacketSize0 = pdesc->bMaxPacketSize0;
+ desc->idVendor = pdesc->idVendor;
+ desc->idProduct = pdesc->idProduct;
+ desc->bcdDevice = pdesc->bcdDevice;
+ desc->iManufacturer = pdesc->iManufacturer;
+ desc->iProduct = pdesc->iProduct;
+ desc->iSerialNumber = pdesc->iSerialNumber;
+ desc->bNumConfigurations = pdesc->bNumConfigurations;
+
+ return (0);
+}
+
+int
+libusb_get_active_config_descriptor(libusb_device *dev,
+ struct libusb_config_descriptor **config)
+{
+ struct libusb20_device *pdev;
+ uint8_t config_index;
+
+ pdev = dev->os_priv;
+ config_index = libusb20_dev_get_config_index(pdev);
+
+ return (libusb_get_config_descriptor(dev, config_index, config));
+}
+
+int
+libusb_get_config_descriptor(libusb_device *dev, uint8_t config_index,
+ struct libusb_config_descriptor **config)
+{
+ struct libusb20_device *pdev;
+ struct libusb20_config *pconf;
+ struct libusb20_interface *pinf;
+ struct libusb20_endpoint *pend;
+ struct libusb_config_descriptor *pconfd;
+ struct libusb_interface_descriptor *ifd;
+ struct libusb_endpoint_descriptor *endd;
+ uint8_t *pextra;
+ uint16_t nextra;
+ uint8_t nif;
+ uint8_t nep;
+ uint8_t nalt;
+ uint8_t i;
+ uint8_t j;
+ uint8_t k;
+
+ if (dev == NULL || config == NULL)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ *config = NULL;
+
+ pdev = dev->os_priv;
+ pconf = libusb20_dev_alloc_config(pdev, config_index);
+
+ if (pconf == NULL)
+ return (LIBUSB_ERROR_NOT_FOUND);
+
+ nalt = nif = pconf->num_interface;
+ nep = 0;
+ nextra = N_ALIGN(pconf->extra.len);
+
+ for (i = 0; i < nif; i++) {
+
+ pinf = pconf->interface + i;
+ nextra += N_ALIGN(pinf->extra.len);
+ nep += pinf->num_endpoints;
+ k = pinf->num_endpoints;
+ pend = pinf->endpoints;
+ while (k--) {
+ nextra += N_ALIGN(pend->extra.len);
+ pend++;
+ }
+
+ j = pinf->num_altsetting;
+ nalt += pinf->num_altsetting;
+ pinf = pinf->altsetting;
+ while (j--) {
+ nextra += N_ALIGN(pinf->extra.len);
+ nep += pinf->num_endpoints;
+ k = pinf->num_endpoints;
+ pend = pinf->endpoints;
+ while (k--) {
+ nextra += N_ALIGN(pend->extra.len);
+ pend++;
+ }
+ pinf++;
+ }
+ }
+
+ nextra = nextra +
+ (1 * sizeof(libusb_config_descriptor)) +
+ (nif * sizeof(libusb_interface)) +
+ (nalt * sizeof(libusb_interface_descriptor)) +
+ (nep * sizeof(libusb_endpoint_descriptor));
+
+ nextra = N_ALIGN(nextra);
+
+ pconfd = malloc(nextra);
+
+ if (pconfd == NULL) {
+ free(pconf);
+ return (LIBUSB_ERROR_NO_MEM);
+ }
+ /* make sure memory is initialised */
+ memset(pconfd, 0, nextra);
+
+ pconfd->interface = (libusb_interface *) (pconfd + 1);
+
+ ifd = (libusb_interface_descriptor *) (pconfd->interface + nif);
+ endd = (libusb_endpoint_descriptor *) (ifd + nalt);
+ pextra = (uint8_t *)(endd + nep);
+
+ /* fill in config descriptor */
+
+ pconfd->bLength = pconf->desc.bLength;
+ pconfd->bDescriptorType = pconf->desc.bDescriptorType;
+ pconfd->wTotalLength = pconf->desc.wTotalLength;
+ pconfd->bNumInterfaces = pconf->desc.bNumInterfaces;
+ pconfd->bConfigurationValue = pconf->desc.bConfigurationValue;
+ pconfd->iConfiguration = pconf->desc.iConfiguration;
+ pconfd->bmAttributes = pconf->desc.bmAttributes;
+ pconfd->MaxPower = pconf->desc.bMaxPower;
+
+ if (pconf->extra.len != 0) {
+ pconfd->extra_length = pconf->extra.len;
+ pconfd->extra = pextra;
+ memcpy(pextra, pconf->extra.ptr, pconfd->extra_length);
+ pextra += N_ALIGN(pconfd->extra_length);
+ }
+ /* setup all interface and endpoint pointers */
+
+ for (i = 0; i < nif; i++) {
+
+ pconfd->interface[i].altsetting = ifd;
+ ifd->endpoint = endd;
+ endd += pconf->interface[i].num_endpoints;
+ ifd++;
+
+ for (j = 0; j < pconf->interface[i].num_altsetting; j++) {
+ ifd->endpoint = endd;
+ endd += pconf->interface[i].altsetting[j].num_endpoints;
+ ifd++;
+ }
+ }
+
+ /* fill in all interface and endpoint data */
+
+ for (i = 0; i < nif; i++) {
+ pinf = &pconf->interface[i];
+ pconfd->interface[i].num_altsetting = pinf->num_altsetting + 1;
+ for (j = 0; j < pconfd->interface[i].num_altsetting; j++) {
+ if (j != 0)
+ pinf = &pconf->interface[i].altsetting[j - 1];
+ ifd = &pconfd->interface[i].altsetting[j];
+ ifd->bLength = pinf->desc.bLength;
+ ifd->bDescriptorType = pinf->desc.bDescriptorType;
+ ifd->bInterfaceNumber = pinf->desc.bInterfaceNumber;
+ ifd->bAlternateSetting = pinf->desc.bAlternateSetting;
+ ifd->bNumEndpoints = pinf->desc.bNumEndpoints;
+ ifd->bInterfaceClass = pinf->desc.bInterfaceClass;
+ ifd->bInterfaceSubClass = pinf->desc.bInterfaceSubClass;
+ ifd->bInterfaceProtocol = pinf->desc.bInterfaceProtocol;
+ ifd->iInterface = pinf->desc.iInterface;
+ if (pinf->extra.len != 0) {
+ ifd->extra_length = pinf->extra.len;
+ ifd->extra = pextra;
+ memcpy(pextra, pinf->extra.ptr, pinf->extra.len);
+ pextra += N_ALIGN(pinf->extra.len);
+ }
+ for (k = 0; k < pinf->num_endpoints; k++) {
+ pend = &pinf->endpoints[k];
+ endd = &ifd->endpoint[k];
+ endd->bLength = pend->desc.bLength;
+ endd->bDescriptorType = pend->desc.bDescriptorType;
+ endd->bEndpointAddress = pend->desc.bEndpointAddress;
+ endd->bmAttributes = pend->desc.bmAttributes;
+ endd->wMaxPacketSize = pend->desc.wMaxPacketSize;
+ endd->bInterval = pend->desc.bInterval;
+ endd->bRefresh = pend->desc.bRefresh;
+ endd->bSynchAddress = pend->desc.bSynchAddress;
+ if (pend->extra.len != 0) {
+ endd->extra_length = pend->extra.len;
+ endd->extra = pextra;
+ memcpy(pextra, pend->extra.ptr, pend->extra.len);
+ pextra += N_ALIGN(pend->extra.len);
+ }
+ }
+ }
+ }
+
+ free(pconf);
+
+ *config = pconfd;
+
+ return (0); /* success */
+}
+
+int
+libusb_get_config_descriptor_by_value(libusb_device *dev,
+ uint8_t bConfigurationValue, struct libusb_config_descriptor **config)
+{
+ struct LIBUSB20_DEVICE_DESC_DECODED *pdesc;
+ struct libusb20_device *pdev;
+ int i;
+ int err;
+
+ if (dev == NULL || config == NULL)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ pdev = dev->os_priv;
+ pdesc = libusb20_dev_get_device_desc(pdev);
+
+ for (i = 0; i < pdesc->bNumConfigurations; i++) {
+ err = libusb_get_config_descriptor(dev, i, config);
+ if (err)
+ return (err);
+
+ if ((*config)->bConfigurationValue == bConfigurationValue)
+ return (0); /* success */
+
+ libusb_free_config_descriptor(*config);
+ }
+
+ *config = NULL;
+
+ return (LIBUSB_ERROR_NOT_FOUND);
+}
+
+void
+libusb_free_config_descriptor(struct libusb_config_descriptor *config)
+{
+ free(config);
+}
+
+int
+libusb_get_string_descriptor_ascii(libusb_device_handle *pdev,
+ uint8_t desc_index, unsigned char *data, int length)
+{
+ if (pdev == NULL || data == NULL || length < 1)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ if (length > 65535)
+ length = 65535;
+
+ /* put some default data into the destination buffer */
+ data[0] = 0;
+
+ if (libusb20_dev_req_string_simple_sync(pdev, desc_index,
+ data, length) == 0)
+ return (strlen(data));
+
+ return (LIBUSB_ERROR_OTHER);
+}
+
+int
+libusb_get_descriptor(libusb_device_handle * devh, uint8_t desc_type,
+ uint8_t desc_index, uint8_t *data, int length)
+{
+ if (devh == NULL || data == NULL || length < 1)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ if (length > 65535)
+ length = 65535;
+
+ return (libusb_control_transfer(devh, LIBUSB_ENDPOINT_IN,
+ LIBUSB_REQUEST_GET_DESCRIPTOR, (desc_type << 8) | desc_index, 0, data,
+ length, 1000));
+}
+
+int
+libusb_parse_ss_endpoint_comp(const void *buf, int len,
+ struct libusb_ss_endpoint_companion_descriptor **ep_comp)
+{
+ if (buf == NULL || ep_comp == NULL || len < 1)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ if (len > 65535)
+ len = 65535;
+
+ *ep_comp = NULL;
+
+ while (len != 0) {
+ uint8_t dlen;
+ uint8_t dtype;
+
+ dlen = ((const uint8_t *)buf)[0];
+ dtype = ((const uint8_t *)buf)[1];
+
+ if (dlen < 2 || dlen > len)
+ break;
+
+ if (dlen >= LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE &&
+ dtype == LIBUSB_DT_SS_ENDPOINT_COMPANION) {
+ struct libusb_ss_endpoint_companion_descriptor *ptr;
+
+ ptr = malloc(sizeof(*ptr));
+ if (ptr == NULL)
+ return (LIBUSB_ERROR_NO_MEM);
+
+ ptr->bLength = LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE;
+ ptr->bDescriptorType = dtype;
+ ptr->bMaxBurst = ((const uint8_t *)buf)[2];
+ ptr->bmAttributes = ((const uint8_t *)buf)[3];
+ ptr->wBytesPerInterval = ((const uint8_t *)buf)[4] |
+ (((const uint8_t *)buf)[5] << 8);
+
+ *ep_comp = ptr;
+
+ return (0); /* success */
+ }
+
+ buf = ((const uint8_t *)buf) + dlen;
+ len -= dlen;
+ }
+ return (LIBUSB_ERROR_IO);
+}
+
+void
+libusb_free_ss_endpoint_comp(struct libusb_ss_endpoint_companion_descriptor *ep_comp)
+{
+ if (ep_comp == NULL)
+ return;
+
+ free(ep_comp);
+}
+
+int
+libusb_parse_bos_descriptor(const void *buf, int len,
+ struct libusb_bos_descriptor **bos)
+{
+ struct libusb_bos_descriptor *ptr;
+ struct libusb_usb_2_0_device_capability_descriptor *dcap_20;
+ struct libusb_ss_usb_device_capability_descriptor *ss_cap;
+
+ if (buf == NULL || bos == NULL || len < 1)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ if (len > 65535)
+ len = 65535;
+
+ *bos = ptr = NULL;
+
+ while (len != 0) {
+ uint8_t dlen;
+ uint8_t dtype;
+
+ dlen = ((const uint8_t *)buf)[0];
+ dtype = ((const uint8_t *)buf)[1];
+
+ if (dlen < 2 || dlen > len)
+ break;
+
+ if (dlen >= LIBUSB_DT_BOS_SIZE &&
+ dtype == LIBUSB_DT_BOS) {
+
+ ptr = malloc(sizeof(*ptr) + sizeof(*dcap_20) +
+ sizeof(*ss_cap));
+
+ if (ptr == NULL)
+ return (LIBUSB_ERROR_NO_MEM);
+
+ *bos = ptr;
+
+ ptr->bLength = LIBUSB_DT_BOS_SIZE;
+ ptr->bDescriptorType = dtype;
+ ptr->wTotalLength = ((const uint8_t *)buf)[2] |
+ (((const uint8_t *)buf)[3] << 8);
+ ptr->bNumDeviceCapabilities = ((const uint8_t *)buf)[4];
+ ptr->usb_2_0_ext_cap = NULL;
+ ptr->ss_usb_cap = NULL;
+
+ dcap_20 = (void *)(ptr + 1);
+ ss_cap = (void *)(dcap_20 + 1);
+ }
+ if (dlen >= 3 &&
+ ptr != NULL &&
+ dtype == LIBUSB_DT_DEVICE_CAPABILITY) {
+ switch (((const uint8_t *)buf)[2]) {
+ case LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY:
+ if (ptr->usb_2_0_ext_cap != NULL)
+ break;
+ if (dlen < LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY_SIZE)
+ break;
+
+ ptr->usb_2_0_ext_cap = dcap_20;
+
+ dcap_20->bLength = LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY_SIZE;
+ dcap_20->bDescriptorType = dtype;
+ dcap_20->bDevCapabilityType = ((const uint8_t *)buf)[2];
+ dcap_20->bmAttributes = ((const uint8_t *)buf)[3] |
+ (((const uint8_t *)buf)[4] << 8) |
+ (((const uint8_t *)buf)[5] << 16) |
+ (((const uint8_t *)buf)[6] << 24);
+ break;
+
+ case LIBUSB_SS_USB_DEVICE_CAPABILITY:
+ if (ptr->ss_usb_cap != NULL)
+ break;
+ if (dlen < LIBUSB_SS_USB_DEVICE_CAPABILITY_SIZE)
+ break;
+
+ ptr->ss_usb_cap = ss_cap;
+
+ ss_cap->bLength = LIBUSB_SS_USB_DEVICE_CAPABILITY_SIZE;
+ ss_cap->bDescriptorType = dtype;
+ ss_cap->bDevCapabilityType = ((const uint8_t *)buf)[2];
+ ss_cap->bmAttributes = ((const uint8_t *)buf)[3];
+ ss_cap->wSpeedSupported = ((const uint8_t *)buf)[4] |
+ (((const uint8_t *)buf)[5] << 8);
+ ss_cap->bFunctionalitySupport = ((const uint8_t *)buf)[6];
+ ss_cap->bU1DevExitLat = ((const uint8_t *)buf)[7];
+ ss_cap->wU2DevExitLat = ((const uint8_t *)buf)[8] |
+ (((const uint8_t *)buf)[9] << 8);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ buf = ((const uint8_t *)buf) + dlen;
+ len -= dlen;
+ }
+ if (ptr != NULL)
+ return (0); /* success */
+
+ return (LIBUSB_ERROR_IO);
+}
+
+void
+libusb_free_bos_descriptor(struct libusb_bos_descriptor *bos)
+{
+ if (bos == NULL)
+ return;
+
+ free(bos);
+}
diff --git a/lib/libusb/libusb10_io.c b/lib/libusb/libusb10_io.c
new file mode 100644
index 0000000..380e312
--- /dev/null
+++ b/lib/libusb/libusb10_io.c
@@ -0,0 +1,738 @@
+/* $FreeBSD$ */
+/*-
+ * Copyright (c) 2009 Sylvestre Gallon. 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.
+ */
+
+#include <sys/queue.h>
+
+#include <errno.h>
+#include <poll.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+#define libusb_device_handle libusb20_device
+
+#include "libusb20.h"
+#include "libusb20_desc.h"
+#include "libusb20_int.h"
+#include "libusb.h"
+#include "libusb10.h"
+
+UNEXPORTED void
+libusb10_add_pollfd(libusb_context *ctx, struct libusb_super_pollfd *pollfd,
+ struct libusb20_device *pdev, int fd, short events)
+{
+ if (ctx == NULL)
+ return; /* invalid */
+
+ if (pollfd->entry.tqe_prev != NULL)
+ return; /* already queued */
+
+ if (fd < 0)
+ return; /* invalid */
+
+ pollfd->pdev = pdev;
+ pollfd->pollfd.fd = fd;
+ pollfd->pollfd.events = events;
+
+ CTX_LOCK(ctx);
+ TAILQ_INSERT_TAIL(&ctx->pollfds, pollfd, entry);
+ CTX_UNLOCK(ctx);
+
+ if (ctx->fd_added_cb)
+ ctx->fd_added_cb(fd, events, ctx->fd_cb_user_data);
+}
+
+UNEXPORTED void
+libusb10_remove_pollfd(libusb_context *ctx, struct libusb_super_pollfd *pollfd)
+{
+ if (ctx == NULL)
+ return; /* invalid */
+
+ if (pollfd->entry.tqe_prev == NULL)
+ return; /* already dequeued */
+
+ CTX_LOCK(ctx);
+ TAILQ_REMOVE(&ctx->pollfds, pollfd, entry);
+ pollfd->entry.tqe_prev = NULL;
+ CTX_UNLOCK(ctx);
+
+ if (ctx->fd_removed_cb)
+ ctx->fd_removed_cb(pollfd->pollfd.fd, ctx->fd_cb_user_data);
+}
+
+/* This function must be called locked */
+
+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;
+ int err;
+
+ DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb10_handle_events_sub enter");
+
+ nfds = 0;
+ i = 0;
+ TAILQ_FOREACH(pfd, &ctx->pollfds, entry)
+ nfds++;
+
+ fds = alloca(sizeof(*fds) * nfds);
+ if (fds == NULL)
+ return (LIBUSB_ERROR_NO_MEM);
+
+ ppdev = alloca(sizeof(*ppdev) * nfds);
+ if (ppdev == NULL)
+ return (LIBUSB_ERROR_NO_MEM);
+
+ TAILQ_FOREACH(pfd, &ctx->pollfds, entry) {
+ fds[i].fd = pfd->pollfd.fd;
+ fds[i].events = pfd->pollfd.events;
+ fds[i].revents = 0;
+ ppdev[i] = pfd->pdev;
+ if (pfd->pdev != NULL)
+ libusb_get_device(pfd->pdev)->refcnt++;
+ i++;
+ }
+
+ if (tv == NULL)
+ timeout = -1;
+ else
+ timeout = (tv->tv_sec * 1000) + ((tv->tv_usec + 999) / 1000);
+
+ CTX_UNLOCK(ctx);
+ err = poll(fds, nfds, timeout);
+ CTX_LOCK(ctx);
+
+ if ((err == -1) && (errno == EINTR))
+ err = LIBUSB_ERROR_INTERRUPTED;
+ else if (err < 0)
+ err = LIBUSB_ERROR_IO;
+
+ if (err < 1) {
+ for (i = 0; i != (int)nfds; i++) {
+ if (ppdev[i] != NULL) {
+ CTX_UNLOCK(ctx);
+ libusb_unref_device(libusb_get_device(ppdev[i]));
+ CTX_LOCK(ctx);
+ }
+ }
+ goto do_done;
+ }
+ for (i = 0; i != (int)nfds; i++) {
+ if (ppdev[i] != NULL) {
+ dev = libusb_get_device(ppdev[i]);
+
+ if (fds[i].revents == 0)
+ err = 0; /* nothing to do */
+ else
+ err = libusb20_dev_process(ppdev[i]);
+
+ if (err) {
+ /* cancel all transfers - device is gone */
+ libusb10_cancel_all_transfer(dev);
+
+ /* remove USB device from polling loop */
+ libusb10_remove_pollfd(dev->ctx, &dev->dev_poll);
+ }
+ CTX_UNLOCK(ctx);
+ libusb_unref_device(dev);
+ CTX_LOCK(ctx);
+
+ } else {
+ uint8_t dummy;
+
+ while (1) {
+ if (read(fds[i].fd, &dummy, 1) != 1)
+ break;
+ }
+ }
+ }
+
+ err = 0;
+
+do_done:
+
+ /* Do all done callbacks */
+
+ while ((sxfer = TAILQ_FIRST(&ctx->tr_done))) {
+ uint8_t flags;
+
+ 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));
+
+ /* Allow the callback to free the transfer itself. */
+ flags = uxfer->flags;
+
+ if (uxfer->callback != NULL)
+ (uxfer->callback) (uxfer);
+
+ /* Check if the USB transfer should be automatically freed. */
+ if (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 */
+
+int
+libusb_try_lock_events(libusb_context *ctx)
+{
+ int err;
+
+ ctx = GET_CONTEXT(ctx);
+ if (ctx == NULL)
+ return (1);
+
+ err = CTX_TRYLOCK(ctx);
+ if (err)
+ return (1);
+
+ err = (ctx->ctx_handler != NO_THREAD);
+ if (err)
+ CTX_UNLOCK(ctx);
+ else
+ ctx->ctx_handler = pthread_self();
+
+ return (err);
+}
+
+void
+libusb_lock_events(libusb_context *ctx)
+{
+ ctx = GET_CONTEXT(ctx);
+ CTX_LOCK(ctx);
+ if (ctx->ctx_handler == NO_THREAD)
+ ctx->ctx_handler = pthread_self();
+}
+
+void
+libusb_unlock_events(libusb_context *ctx)
+{
+ ctx = GET_CONTEXT(ctx);
+ if (ctx->ctx_handler == pthread_self()) {
+ ctx->ctx_handler = NO_THREAD;
+ pthread_cond_broadcast(&ctx->ctx_cond);
+ }
+ CTX_UNLOCK(ctx);
+}
+
+int
+libusb_event_handling_ok(libusb_context *ctx)
+{
+ ctx = GET_CONTEXT(ctx);
+ return (ctx->ctx_handler == pthread_self());
+}
+
+int
+libusb_event_handler_active(libusb_context *ctx)
+{
+ ctx = GET_CONTEXT(ctx);
+ return (ctx->ctx_handler != NO_THREAD);
+}
+
+void
+libusb_lock_event_waiters(libusb_context *ctx)
+{
+ ctx = GET_CONTEXT(ctx);
+ CTX_LOCK(ctx);
+}
+
+void
+libusb_unlock_event_waiters(libusb_context *ctx)
+{
+ ctx = GET_CONTEXT(ctx);
+ CTX_UNLOCK(ctx);
+}
+
+int
+libusb_wait_for_event(libusb_context *ctx, struct timeval *tv)
+{
+ struct timespec ts;
+ int err;
+
+ ctx = GET_CONTEXT(ctx);
+ DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_wait_for_event enter");
+
+ if (tv == NULL) {
+ pthread_cond_wait(&ctx->ctx_cond,
+ &ctx->ctx_lock);
+ return (0);
+ }
+ err = clock_gettime(CLOCK_REALTIME, &ts);
+ if (err < 0)
+ return (LIBUSB_ERROR_OTHER);
+
+ ts.tv_sec = tv->tv_sec;
+ ts.tv_nsec = tv->tv_usec * 1000;
+ if (ts.tv_nsec >= 1000000000) {
+ ts.tv_nsec -= 1000000000;
+ ts.tv_sec++;
+ }
+ err = pthread_cond_timedwait(&ctx->ctx_cond,
+ &ctx->ctx_lock, &ts);
+
+ if (err == ETIMEDOUT)
+ return (1);
+
+ return (0);
+}
+
+int
+libusb_handle_events_timeout(libusb_context *ctx, struct timeval *tv)
+{
+ int err;
+
+ ctx = GET_CONTEXT(ctx);
+
+ DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events_timeout enter");
+
+ libusb_lock_events(ctx);
+
+ err = libusb_handle_events_locked(ctx, tv);
+
+ libusb_unlock_events(ctx);
+
+ DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events_timeout leave");
+
+ return (err);
+}
+
+int
+libusb_handle_events(libusb_context *ctx)
+{
+ return (libusb_handle_events_timeout(ctx, NULL));
+}
+
+int
+libusb_handle_events_locked(libusb_context *ctx, struct timeval *tv)
+{
+ int err;
+
+ ctx = GET_CONTEXT(ctx);
+
+ if (libusb_event_handling_ok(ctx)) {
+ err = libusb10_handle_events_sub(ctx, tv);
+ } else {
+ libusb_wait_for_event(ctx, tv);
+ err = 0;
+ }
+ return (err);
+}
+
+int
+libusb_get_next_timeout(libusb_context *ctx, struct timeval *tv)
+{
+ /* all timeouts are currently being done by the kernel */
+ timerclear(tv);
+ return (0);
+}
+
+void
+libusb_set_pollfd_notifiers(libusb_context *ctx,
+ libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb,
+ void *user_data)
+{
+ ctx = GET_CONTEXT(ctx);
+
+ ctx->fd_added_cb = added_cb;
+ ctx->fd_removed_cb = removed_cb;
+ ctx->fd_cb_user_data = user_data;
+}
+
+struct libusb_pollfd **
+libusb_get_pollfds(libusb_context *ctx)
+{
+ struct libusb_super_pollfd *pollfd;
+ libusb_pollfd **ret;
+ int i;
+
+ ctx = GET_CONTEXT(ctx);
+
+ CTX_LOCK(ctx);
+
+ i = 0;
+ TAILQ_FOREACH(pollfd, &ctx->pollfds, entry)
+ i++;
+
+ ret = calloc(i + 1, sizeof(struct libusb_pollfd *));
+ if (ret == NULL)
+ goto done;
+
+ i = 0;
+ TAILQ_FOREACH(pollfd, &ctx->pollfds, entry)
+ ret[i++] = &pollfd->pollfd;
+ ret[i] = NULL;
+
+done:
+ CTX_UNLOCK(ctx);
+ return (ret);
+}
+
+
+/* Synchronous device I/O */
+
+int
+libusb_control_transfer(libusb_device_handle *devh,
+ uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
+ uint8_t *data, uint16_t wLength, unsigned int timeout)
+{
+ struct LIBUSB20_CONTROL_SETUP_DECODED req;
+ int err;
+ uint16_t actlen;
+
+ if (devh == NULL)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ if ((wLength != 0) && (data == NULL))
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req);
+
+ req.bmRequestType = bmRequestType;
+ req.bRequest = bRequest;
+ req.wValue = wValue;
+ req.wIndex = wIndex;
+ req.wLength = wLength;
+
+ err = libusb20_dev_request_sync(devh, &req, data,
+ &actlen, timeout, 0);
+
+ if (err == LIBUSB20_ERROR_PIPE)
+ return (LIBUSB_ERROR_PIPE);
+ else if (err == LIBUSB20_ERROR_TIMEOUT)
+ return (LIBUSB_ERROR_TIMEOUT);
+ else if (err)
+ return (LIBUSB_ERROR_NO_DEVICE);
+
+ return (actlen);
+}
+
+static void
+libusb10_do_transfer_cb(struct libusb_transfer *transfer)
+{
+ libusb_context *ctx;
+ int *pdone;
+
+ ctx = GET_CONTEXT(NULL);
+
+ DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "sync I/O done");
+
+ pdone = transfer->user_data;
+ *pdone = 1;
+}
+
+/*
+ * TODO: Replace the following function. Allocating and freeing on a
+ * per-transfer basis is slow. --HPS
+ */
+static int
+libusb10_do_transfer(libusb_device_handle *devh,
+ uint8_t endpoint, uint8_t *data, int length,
+ int *transferred, unsigned int timeout, int type)
+{
+ libusb_context *ctx;
+ struct libusb_transfer *xfer;
+ volatile int complet;
+ int ret;
+
+ if (devh == NULL)
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ if ((length != 0) && (data == NULL))
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ xfer = libusb_alloc_transfer(0);
+ if (xfer == NULL)
+ return (LIBUSB_ERROR_NO_MEM);
+
+ ctx = libusb_get_device(devh)->ctx;
+
+ xfer->dev_handle = devh;
+ xfer->endpoint = endpoint;
+ xfer->type = type;
+ xfer->timeout = timeout;
+ xfer->buffer = data;
+ xfer->length = length;
+ xfer->user_data = (void *)&complet;
+ xfer->callback = libusb10_do_transfer_cb;
+ complet = 0;
+
+ if ((ret = libusb_submit_transfer(xfer)) < 0) {
+ libusb_free_transfer(xfer);
+ return (ret);
+ }
+ while (complet == 0) {
+ if ((ret = libusb_handle_events(ctx)) < 0) {
+ libusb_cancel_transfer(xfer);
+ usleep(1000); /* nice it */
+ }
+ }
+
+ *transferred = xfer->actual_length;
+
+ switch (xfer->status) {
+ case LIBUSB_TRANSFER_COMPLETED:
+ ret = 0;
+ break;
+ case LIBUSB_TRANSFER_TIMED_OUT:
+ ret = LIBUSB_ERROR_TIMEOUT;
+ break;
+ case LIBUSB_TRANSFER_OVERFLOW:
+ ret = LIBUSB_ERROR_OVERFLOW;
+ break;
+ case LIBUSB_TRANSFER_STALL:
+ ret = LIBUSB_ERROR_PIPE;
+ break;
+ case LIBUSB_TRANSFER_NO_DEVICE:
+ ret = LIBUSB_ERROR_NO_DEVICE;
+ break;
+ default:
+ ret = LIBUSB_ERROR_OTHER;
+ break;
+ }
+
+ libusb_free_transfer(xfer);
+ return (ret);
+}
+
+int
+libusb_bulk_transfer(libusb_device_handle *devh,
+ uint8_t endpoint, uint8_t *data, int length,
+ int *transferred, unsigned int timeout)
+{
+ libusb_context *ctx;
+ int ret;
+
+ ctx = GET_CONTEXT(NULL);
+ DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_bulk_transfer enter");
+
+ ret = libusb10_do_transfer(devh, endpoint, data, length, transferred,
+ timeout, LIBUSB_TRANSFER_TYPE_BULK);
+
+ DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_bulk_transfer leave");
+ return (ret);
+}
+
+int
+libusb_interrupt_transfer(libusb_device_handle *devh,
+ uint8_t endpoint, uint8_t *data, int length,
+ int *transferred, unsigned int timeout)
+{
+ libusb_context *ctx;
+ int ret;
+
+ ctx = GET_CONTEXT(NULL);
+ DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_interrupt_transfer enter");
+
+ ret = libusb10_do_transfer(devh, endpoint, data, length, transferred,
+ timeout, LIBUSB_TRANSFER_TYPE_INTERRUPT);
+
+ DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_interrupt_transfer leave");
+ return (ret);
+}
+
+uint8_t *
+libusb_get_iso_packet_buffer(struct libusb_transfer *transfer, uint32_t index)
+{
+ uint8_t *ptr;
+ uint32_t n;
+
+ if (transfer->num_iso_packets < 0)
+ return (NULL);
+
+ if (index >= (uint32_t)transfer->num_iso_packets)
+ return (NULL);
+
+ ptr = transfer->buffer;
+ if (ptr == NULL)
+ return (NULL);
+
+ for (n = 0; n != index; n++) {
+ ptr += transfer->iso_packet_desc[n].length;
+ }
+ return (ptr);
+}
+
+uint8_t *
+libusb_get_iso_packet_buffer_simple(struct libusb_transfer *transfer, uint32_t index)
+{
+ uint8_t *ptr;
+
+ if (transfer->num_iso_packets < 0)
+ return (NULL);
+
+ if (index >= (uint32_t)transfer->num_iso_packets)
+ return (NULL);
+
+ ptr = transfer->buffer;
+ if (ptr == NULL)
+ return (NULL);
+
+ ptr += transfer->iso_packet_desc[0].length * index;
+
+ return (ptr);
+}
+
+void
+libusb_set_iso_packet_lengths(struct libusb_transfer *transfer, uint32_t length)
+{
+ int n;
+
+ if (transfer->num_iso_packets < 0)
+ return;
+
+ for (n = 0; n != transfer->num_iso_packets; n++)
+ transfer->iso_packet_desc[n].length = length;
+}
+
+uint8_t *
+libusb_control_transfer_get_data(struct libusb_transfer *transfer)
+{
+ if (transfer->buffer == NULL)
+ return (NULL);
+
+ return (transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE);
+}
+
+struct libusb_control_setup *
+libusb_control_transfer_get_setup(struct libusb_transfer *transfer)
+{
+ return ((struct libusb_control_setup *)transfer->buffer);
+}
+
+void
+libusb_fill_control_setup(uint8_t *buf, uint8_t bmRequestType,
+ uint8_t bRequest, uint16_t wValue,
+ uint16_t wIndex, uint16_t wLength)
+{
+ struct libusb_control_setup *req = (struct libusb_control_setup *)buf;
+
+ /* The alignment is OK for all fields below. */
+ req->bmRequestType = bmRequestType;
+ req->bRequest = bRequest;
+ req->wValue = htole16(wValue);
+ req->wIndex = htole16(wIndex);
+ req->wLength = htole16(wLength);
+}
+
+void
+libusb_fill_control_transfer(struct libusb_transfer *transfer,
+ libusb_device_handle *devh, uint8_t *buf,
+ libusb_transfer_cb_fn callback, void *user_data,
+ uint32_t timeout)
+{
+ struct libusb_control_setup *setup = (struct libusb_control_setup *)buf;
+
+ transfer->dev_handle = devh;
+ transfer->endpoint = 0;
+ transfer->type = LIBUSB_TRANSFER_TYPE_CONTROL;
+ transfer->timeout = timeout;
+ transfer->buffer = buf;
+ if (setup != NULL)
+ transfer->length = LIBUSB_CONTROL_SETUP_SIZE
+ + le16toh(setup->wLength);
+ else
+ transfer->length = 0;
+ transfer->user_data = user_data;
+ transfer->callback = callback;
+
+}
+
+void
+libusb_fill_bulk_transfer(struct libusb_transfer *transfer,
+ libusb_device_handle *devh, uint8_t endpoint, uint8_t *buf,
+ int length, libusb_transfer_cb_fn callback, void *user_data,
+ uint32_t timeout)
+{
+ transfer->dev_handle = devh;
+ transfer->endpoint = endpoint;
+ transfer->type = LIBUSB_TRANSFER_TYPE_BULK;
+ transfer->timeout = timeout;
+ transfer->buffer = buf;
+ transfer->length = length;
+ transfer->user_data = user_data;
+ transfer->callback = callback;
+}
+
+void
+libusb_fill_interrupt_transfer(struct libusb_transfer *transfer,
+ libusb_device_handle *devh, uint8_t endpoint, uint8_t *buf,
+ int length, libusb_transfer_cb_fn callback, void *user_data,
+ uint32_t timeout)
+{
+ transfer->dev_handle = devh;
+ transfer->endpoint = endpoint;
+ transfer->type = LIBUSB_TRANSFER_TYPE_INTERRUPT;
+ transfer->timeout = timeout;
+ transfer->buffer = buf;
+ transfer->length = length;
+ transfer->user_data = user_data;
+ transfer->callback = callback;
+}
+
+void
+libusb_fill_iso_transfer(struct libusb_transfer *transfer,
+ libusb_device_handle *devh, uint8_t endpoint, uint8_t *buf,
+ int length, int npacket, libusb_transfer_cb_fn callback,
+ void *user_data, uint32_t timeout)
+{
+ transfer->dev_handle = devh;
+ transfer->endpoint = endpoint;
+ transfer->type = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS;
+ transfer->timeout = timeout;
+ transfer->buffer = buf;
+ transfer->length = length;
+ transfer->num_iso_packets = npacket;
+ transfer->user_data = user_data;
+ transfer->callback = callback;
+}
+
diff --git a/lib/libusb/libusb20.3 b/lib/libusb/libusb20.3
new file mode 100644
index 0000000..d1abc55
--- /dev/null
+++ b/lib/libusb/libusb20.3
@@ -0,0 +1,1031 @@
+.\"
+.\" Copyright (c) 2008 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 14, 2010
+.Dt LIBUSB20 3
+.Os
+.Sh NAME
+.Nm libusb20
+.
+.Nd "USB access library"
+.
+.
+.Sh LIBRARY
+.
+.
+USB access library (libusb -lusb)
+.
+.
+.
+.Sh SYNOPSIS
+.In libusb20.h
+.Ft int
+.Fn libusb20_tr_close "struct libusb20_transfer *xfer"
+.Ft int
+.Fn libusb20_tr_open "struct libusb20_transfer *xfer" "uint32_t max_buf_size" "uint32_t max_frame_count" "uint8_t ep_no"
+.Ft struct libusb20_transfer*
+.Fn libusb20_tr_get_pointer "struct libusb20_device *pdev" "uint16_t tr_index"
+.Ft uint16_t
+.Fn libusb20_tr_get_time_complete "struct libusb20_transfer *xfer"
+.Ft uint32_t
+.Fn libusb20_tr_get_actual_frames "struct libusb20_transfer *xfer"
+.Ft uint32_t
+.Fn libusb20_tr_get_actual_length "struct libusb20_transfer *xfer"
+.Ft uint32_t
+.Fn libusb20_tr_get_max_frames "struct libusb20_transfer *xfer"
+.Ft uint32_t
+.Fn libusb20_tr_get_max_packet_length "struct libusb20_transfer *xfer"
+.Ft uint32_t
+.Fn libusb20_tr_get_max_total_length "struct libusb20_transfer *xfer"
+.Ft uint8_t
+.Fn libusb20_tr_get_status "struct libusb20_transfer *xfer"
+.Ft uint8_t
+.Fn libusb20_tr_pending "struct libusb20_transfer *xfer"
+.Ft void
+.Fn libusb20_tr_callback_wrapper "struct libusb20_transfer *xfer"
+.Ft void
+.Fn libusb20_tr_clear_stall_sync "struct libusb20_transfer *xfer"
+.Ft void
+.Fn libusb20_tr_drain "struct libusb20_transfer *xfer"
+.Ft void
+.Fn libusb20_tr_set_buffer "struct libusb20_transfer *xfer" "void *buffer" "uint16_t fr_index"
+.Ft void
+.Fn libusb20_tr_set_callback "struct libusb20_transfer *xfer" "libusb20_tr_callback_t *cb"
+.Ft void
+.Fn libusb20_tr_set_flags "struct libusb20_transfer *xfer" "uint8_t flags"
+.Ft uint32_t
+.Fn libusb20_tr_get_length "struct libusb20_transfer *xfer" "uint16_t fr_index"
+.Ft void
+.Fn libusb20_tr_set_length "struct libusb20_transfer *xfer" "uint32_t length" "uint16_t fr_index"
+.Ft void
+.Fn libusb20_tr_set_priv_sc0 "struct libusb20_transfer *xfer" "void *sc0"
+.Ft void
+.Fn libusb20_tr_set_priv_sc1 "struct libusb20_transfer *xfer" "void *sc1"
+.Ft void
+.Fn libusb20_tr_set_timeout "struct libusb20_transfer *xfer" "uint32_t timeout"
+.Ft void
+.Fn libusb20_tr_set_total_frames "struct libusb20_transfer *xfer" "uint32_t nframes"
+.Ft void
+.Fn libusb20_tr_setup_bulk "struct libusb20_transfer *xfer" "void *pbuf" "uint32_t length" "uint32_t timeout"
+.Ft void
+.Fn libusb20_tr_setup_control "struct libusb20_transfer *xfer" "void *psetup" "void *pbuf" "uint32_t timeout"
+.Ft void
+.Fn libusb20_tr_setup_intr "struct libusb20_transfer *xfer" "void *pbuf" "uint32_t length" "uint32_t timeout"
+.Ft void
+.Fn libusb20_tr_setup_isoc "struct libusb20_transfer *xfer" "void *pbuf" "uint32_t length" "uint61_t fr_index"
+.Ft uint8_t
+.Fn libusb20_tr_bulk_intr_sync "struct libusb20_transfer *xfer" "void *pbuf" "uint32_t length" "uint32_t *pactlen" "uint32_t timeout"
+.Ft void
+.Fn libusb20_tr_start "struct libusb20_transfer *xfer"
+.Ft void
+.Fn libusb20_tr_stop "struct libusb20_transfer *xfer"
+.Ft void
+.Fn libusb20_tr_submit "struct libusb20_transfer *xfer"
+.Ft void *
+.Fn libusb20_tr_get_priv_sc0 "struct libusb20_transfer *xfer"
+.Ft void *
+.Fn libusb20_tr_get_priv_sc1 "struct libusb20_transfer *xfer"
+.Ft const char *
+.Fn libusb20_dev_get_backend_name "struct libusb20_device *"
+.Ft int
+.Fn libusb20_dev_get_info "struct libusb20_device *pdev" "struct usb_device_info *pinfo"
+.Ft int
+.Fn libusb20_dev_get_iface_desc "struct libusb20_device *pdev" "uint8_t iface_index" "char *buf" "uint8_t len"
+.Ft const char *
+.Fn libusb20_dev_get_desc "struct libusb20_device *pdev"
+.Ft int
+.Fn libusb20_dev_close "struct libusb20_device *pdev"
+.Ft int
+.Fn libusb20_dev_detach_kernel_driver "struct libusb20_device *pdev" "uint8_t iface_index"
+.Ft int
+.Fn libusb20_dev_set_config_index "struct libusb20_device *pdev" "uint8_t configIndex"
+.Ft int
+.Fn libusb20_dev_get_debug "struct libusb20_device *pdev"
+.Ft int
+.Fn libusb20_dev_get_fd "struct libusb20_device *pdev"
+.Ft int
+.Fn libusb20_dev_kernel_driver_active "struct libusb20_device *pdev" "uint8_t iface_index"
+.Ft int
+.Fn libusb20_dev_open "struct libusb20_device *pdev" "uint16_t transfer_max"
+.Ft int
+.Fn libusb20_dev_process "struct libusb20_device *pdev"
+.Ft int
+.Fn libusb20_dev_request_sync "struct libusb20_device *pdev" "struct LIBUSB20_CONTROL_SETUP_DECODED *setup" "void *data" "uint16_t *pactlen" "uint32_t timeout" "uint8_t flags"
+.Ft int
+.Fn libusb20_dev_req_string_sync "struct libusb20_device *pdev" "uint8_t index" "uint16_t langid" "void *ptr" "uint16_t len"
+.Ft int
+.Fn libusb20_dev_req_string_simple_sync "struct libusb20_device *pdev" "uint8_t index" "void *ptr" "uint16_t len"
+.Ft int
+.Fn libusb20_dev_reset "struct libusb20_device *pdev"
+.Ft int
+.Fn libusb20_dev_check_connected "struct libusb20_device *pdev"
+.Ft int
+.Fn libusb20_dev_set_power_mode "struct libusb20_device *pdev" "uint8_t power_mode"
+.Ft uint8_t
+.Fn libusb20_dev_get_power_mode "struct libusb20_device *pdev"
+.Ft int
+.Fn libusb20_dev_set_alt_index "struct libusb20_device *pdev" "uint8_t iface_index" "uint8_t alt_index"
+.Ft struct LIBUSB20_DEVICE_DESC_DECODED *
+.Fn libusb20_dev_get_device_desc "struct libusb20_device *pdev"
+.Ft struct libusb20_config *
+.Fn libusb20_dev_alloc_config "struct libusb20_device *pdev" "uint8_t config_index"
+.Ft struct libusb20_device *
+.Fn libusb20_dev_alloc "void"
+.Ft uint8_t
+.Fn libusb20_dev_get_address "struct libusb20_device *pdev"
+.Ft uint8_t
+.Fn libusb20_dev_get_parent_address "struct libusb20_device *pdev"
+.Ft uint8_t
+.Fn libusb20_dev_get_parent_port "struct libusb20_device *pdev"
+.Ft uint8_t
+.Fn libusb20_dev_get_bus_number "struct libusb20_device *pdev"
+.Ft uint8_t
+.Fn libusb20_dev_get_mode "struct libusb20_device *pdev"
+.Ft uint8_t
+.Fn libusb20_dev_get_speed "struct libusb20_device *pdev"
+.Ft uint8_t
+.Fn libusb20_dev_get_config_index "struct libusb20_device *pdev"
+.Ft void
+.Fn libusb20_dev_free "struct libusb20_device *pdev"
+.Ft void
+.Fn libusb20_dev_set_debug "struct libusb20_device *pdev" "int debug"
+.Ft void
+.Fn libusb20_dev_wait_process "struct libusb20_device *pdev" "int timeout"
+.Ft int
+.Fn libusb20_be_get_template "struct libusb20_backend *pbe" "int *ptemp"
+.Ft int
+.Fn libusb20_be_set_template "struct libusb20_backend *pbe" "int temp"
+.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"
+.Ft int
+.Fn libusb20_be_add_dev_quirk "struct libusb20_backend *pbe" "struct libusb20_quirk *pq"
+.Ft int
+.Fn libusb20_be_remove_dev_quirk "struct libusb20_backend *pbe" "struct libusb20_quirk *pq"
+.Ft struct libusb20_backend *
+.Fn libusb20_be_alloc_default "void"
+.Ft struct libusb20_backend *
+.Fn libusb20_be_alloc_freebsd "void"
+.Ft struct libusb20_backend *
+.Fn libusb20_be_alloc_linux "void"
+.Ft struct libusb20_device *
+.Fn libusb20_be_device_foreach "struct libusb20_backend *pbe" "struct libusb20_device *pdev"
+.Ft void
+.Fn libusb20_be_dequeue_device "struct libusb20_backend *pbe" "struct libusb20_device *pdev"
+.Ft void
+.Fn libusb20_be_enqueue_device "struct libusb20_backend *pbe" "struct libusb20_device *pdev"
+.Ft void
+.Fn libusb20_be_free "struct libusb20_backend *pbe"
+.Ft uint8_t
+.Fn libusb20_me_get_1 "const struct libusb20_me_struct *me" "uint16_t off"
+.Ft uint16_t
+.Fn libusb20_me_get_2 "const struct libusb20_me_struct *me" "uint16_t off"
+.Ft uint16_t
+.Fn libusb20_me_encode "void *pdata" "uint16_t len" "const void *pdecoded"
+.Ft uint16_t
+.Fn libusb20_me_decode "const void *pdata" "uint16_t len" "void *pdecoded"
+.Ft "const uint8_t *"
+.Fn libusb20_desc_foreach "const struct libusb20_me_struct *me" "const uint8_t *pdesc"
+.Ft "const char *"
+.Fn libusb20_strerror "int code"
+.Ft "const char *"
+.Fn libusb20_error_name "int code"
+.
+.
+.Sh DESCRIPTION
+.
+The
+.Nm
+library implements functions to be able to easily access and control
+USB through the USB file system interface.
+The
+.Nm
+interfaces are specific to the
+.Fx
+usb stack and are not available on other operating systems, portable
+applications should consider using
+.Xr libusb 3 .
+.
+.
+.Sh USB TRANSFER OPERATIONS
+.
+.
+.Fn libusb20_tr_close
+will release all kernel resources associated with an USB
+.Fa xfer .
+.
+This function returns zero upon success.
+.
+Non-zero return values indicate a LIBUSB20_ERROR value.
+.
+.Pp
+.
+.Fn libusb20_tr_open
+will allocate kernel buffer resources according to
+.Fa max_buf_size
+and
+.Fa max_frame_count
+associated with an USB
+.Fa pxfer
+and bind the transfer to the specified
+.Fa ep_no .
+.Fa max_buf_size
+is the minimum buffer size which the data transport layer has to support.
+If
+.Fa max_buf_size
+is zero, the
+.Nm
+library will use wMaxPacketSize to compute the buffer size.
+This can be useful for isochronous transfers.
+The actual buffer size can be greater than
+.Fa max_buf_size
+and is returned by
+.Fn libusb20_tr_get_max_total_length .
+.
+If
+.Fa max_frame_count
+is OR'ed with LIBUSB20_MAX_FRAME_PRE_SCALE the remaining part of the
+argument is converted from milliseconds into the actual number of
+frames rounded up, when this function returns.
+This flag is only valid for ISOCHRONOUS transfers and has no effect
+for other transfer types.
+The actual number of frames setup is found by calling
+.Fn libusb20_tr_get_max_frames .
+.
+This function returns zero upon success.
+.
+Non-zero return values indicate a LIBUSB20_ERROR value.
+.
+.Pp
+.
+.Fn libusb20_tr_get_pointer
+will return a pointer to the allocated USB transfer according to the
+.Fa pdev
+and
+.Fa tr_index
+arguments.
+.
+This function returns NULL in case of failure.
+.
+.Pp
+.
+.Fn libusb20_tr_get_time_complete
+will return the completion time of an USB transfer in
+millisecond units. This function is most useful for isochronous USB
+transfers when doing echo cancelling.
+.
+.Pp
+.
+.Fn libusb20_tr_get_actual_frames
+will return the actual number of USB frames after an USB
+transfer completed. A value of zero means that no data was transferred.
+.
+.Pp
+.
+.Fn libusb20_tr_get_actual_length
+will return the sum of the actual length for all
+transferred USB frames for the given USB transfer.
+.
+.Pp
+.
+.Fn libusb20_tr_get_max_frames
+will return the maximum number of USB frames that were
+allocated when an USB transfer was setup for the given USB transfer.
+.
+.Pp
+.
+.Fn libusb20_tr_get_max_packet_length
+will return the maximum packet length in bytes
+associated with the given USB transfer.
+.
+The packet length can be used round up buffer sizes so that short USB
+packets are avoided for proxy buffers.
+.
+.
+.Pp
+.
+.Fn libusb20_tr_get_max_total_length
+function will return the maximum value for the data length sum of all USB
+frames associated with an USB transfer.
+In case of control transfers the value returned does not include the
+length of the SETUP packet, 8 bytes, which is part of frame zero.
+The returned value of this function is always aligned to the maximum
+packet size, wMaxPacketSize, of the endpoint which the USB transfer is
+bound to.
+.
+.Pp
+.
+.Fn libusb20_tr_get_status
+will return the status of an USB transfer.
+.
+Status values are defined by a set of LIBUSB20_TRANSFER_XXX enums.
+.
+.Pp
+.
+.Fn libusb20_tr_pending
+will return non-zero if the given USB transfer is
+pending for completion.
+.
+Else this function returns zero.
+.
+.Pp
+.
+.Fn libusb20_tr_callback_wrapper
+This is an internal function used to wrap asynchronous USB callbacks.
+.
+.Pp
+.
+.Fn libusb20_tr_clear_stall_sync
+This is an internal function used to synchronously clear the stall on
+the given USB transfer.
+.
+Please see the USB specification for more information on stall
+clearing.
+.
+If the given USB transfer is pending when this function is called, the
+USB transfer will complete with an error after that this function has
+been called.
+.
+.Pp
+.
+.Fn libusb20_tr_drain
+will stop the given USB transfer and will not return
+until the USB transfer has been stopped in hardware.
+.
+.Pp
+.
+.Fn libusb20_tr_set_buffer
+is used to set the
+.Fa buffer
+pointer for the given USB transfer and
+.Fa fr_index .
+.
+Typically the frame index is zero.
+.
+.
+.Pp
+.
+.Fn libusb20_tr_set_callback
+is used to set the USB callback for asynchronous USB
+transfers.
+.
+The callback type is defined by libusb20_tr_callback_t.
+.
+.Pp
+.
+.Fn libusb20_tr_set_flags
+is used to set various USB flags for the given USB transfer.
+.Bl -tag
+.It LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK
+Report a short frame as error.
+.It LIBUSB20_TRANSFER_MULTI_SHORT_NOT_OK
+Multiple short frames are not allowed.
+.It LIBUSB20_TRANSFER_FORCE_SHORT
+All transmitted frames are short terminated.
+.It LIBUSB20_TRANSFER_DO_CLEAR_STALL
+Will do a clear-stall before starting the transfer.
+.El
+.
+.Pp
+.
+.Fn libusb20_tr_get_length
+returns the length of the given USB frame by index.
+After an USB transfer is complete the USB frame length will get updated to the actual transferred length.
+.
+.Pp
+.
+.Fn libusb20_tr_set_length
+sets the length of the given USB frame by index.
+.
+.Pp
+.
+.Fn libusb20_tr_set_priv_sc0
+sets private driver pointer number zero.
+.
+.Pp
+.
+.Fn libusb20_tr_set_priv_sc1
+sets private driver pointer number one.
+.
+.Pp
+.
+.Fn libusb20_tr_set_timeout
+sets the timeout for the given USB transfer.
+.
+A timeout value of zero means no timeout.
+.
+The timeout is given in milliseconds.
+.
+.Pp
+.
+.Fn libusb20_tr_set_total_frames
+sets the total number of frames that should be executed when the USB transfer is submitted.
+.
+The total number of USB frames must be less than the maximum number of USB frames associated with the given USB transfer.
+.
+.Pp
+.
+.Fn libusb20_tr_setup_bulk
+is a helper function for setting up a single frame USB BULK transfer.
+.
+.Pp
+.
+.Fn libusb20_tr_setup_control
+is a helper function for setting up a single or dual
+frame USB CONTROL transfer depending on the control transfer length.
+.
+.Pp
+.
+.Fn libusb20_tr_setup_intr
+is a helper function for setting up a single frame USB INTERRUPT transfer.
+.
+.Pp
+.
+.Fn libusb20_tr_setup_isoc
+is a helper function for setting up a multi frame USB ISOCHRONOUS transfer.
+.
+.Pp
+.
+.Fn libusb20_tr_bulk_intr_sync
+will perform a synchronous BULK or INTERRUPT transfer having length given by the
+.Fa length
+argument and buffer pointer given by the
+.Fa pbuf
+argument on the USB transfer given by the
+.Fa xfer
+argument.
+.
+If the
+.Fa pactlen
+argument is non-NULL the actual transfer length will be stored at the given pointer destination.
+.
+If the
+.Fa timeout
+argument is non-zero the transfer will timeout after the given value in milliseconds.
+.
+This function does not change the transfer flags, like short packet not ok.
+.
+This function returns zero on success else a LIBUSB20_TRANSFER_XXX value is returned.
+.
+.Pp
+.
+.Fn libusb20_tr_start
+will get the USB transfer started, if not already
+started.
+.
+This function will not get the transfer queued in hardware.
+.
+This function is non-blocking.
+.
+.Pp
+.
+.Fn libusb20_tr_stop
+will get the USB transfer stopped, if not already stopped.
+.
+This function is non-blocking, which means that the actual stop can
+happen after the return of this function.
+.
+.Pp
+.
+.Fn libusb20_tr_submit
+will get the USB transfer queued in hardware.
+.
+.
+.Pp
+.
+.Fn libusb20_tr_get_priv_sc0
+returns private driver pointer number zero associated
+with an USB transfer.
+.
+.
+.Pp
+.
+.Fn libusb20_tr_get_priv_sc1
+returns private driver pointer number one associated
+with an USB transfer.
+.
+.
+.Sh USB DEVICE OPERATIONS
+.
+.
+.Fn libusb20_dev_get_backend_name
+returns a zero terminated string describing the backend used.
+.
+.Pp
+.
+.Fn libusb20_dev_get_info
+retrieves the BSD specific usb_device_info structure into the memory location given by
+.Fa pinfo .
+The USB device given by
+.Fa pdev
+must be opened before this function will succeed.
+This function returns zero on success else a LIBUSB20_ERROR value is returned.
+.
+.Pp
+.
+.Fn libusb20_dev_get_iface_desc
+retrieves the kernel interface description for the given USB
+.Fa iface_index .
+The format of the USB interface description is: "drivername<unit>: <description>"
+The description string is always zero terminated.
+A zero length string is written in case no driver is attached to the given interface.
+The USB device given by
+.Fa pdev
+must be opened before this function will succeed.
+This function returns zero on success else a LIBUSB20_ERROR value is returned.
+.
+.Pp
+.
+.Fn libusb20_dev_get_desc
+returns a zero terminated string describing the given USB device.
+The format of the string is: "drivername<unit>: <description>"
+.
+.Pp
+.
+.Fn libusb20_dev_close
+will close the given USB device.
+.
+This function returns zero on success else a LIBUSB20_ERROR value is
+returned.
+.
+.Pp
+.
+.Fn libusb20_dev_detach_kernel_driver
+will try to detach the kernel driver for the USB interface given by
+.Fa iface_index .
+.
+This function returns zero on success else a LIBUSB20_ERROR value is
+returned.
+.
+.Pp
+.
+.Fn libusb20_dev_set_config_index
+will try to set the configuration index on an USB
+device.
+.
+The first configuration index is zero.
+.
+The un-configure index is 255.
+.
+This function returns zero on success else a LIBUSB20_ERROR value is returned.
+.
+.Pp
+.
+.Fn libusb20_dev_get_debug
+returns the debug level of an USB device.
+.
+.Pp
+.
+.Fn libusb20_dev_get_fd
+returns the file descriptor of the given USB device.
+.
+A negative value is returned when no file descriptor is present.
+.
+The file descriptor can be used for polling purposes.
+.
+.Pp
+.
+.Fn libusb20_dev_kernel_driver_active
+returns zero if a kernel driver is active on the given USB interface.
+.
+Else a LIBUSB20_ERROR value is returned.
+.
+.Pp
+.
+.Fn libusb20_dev_open
+opens an USB device so that setting up USB transfers
+becomes possible.
+.
+The number of USB transfers can be zero which means only control
+transfers are allowed.
+.
+This function returns zero on success else a LIBUSB20_ERROR value is
+returned.
+.
+A return value of LIBUSB20_ERROR_BUSY means that the device is already
+opened.
+.
+.Pp
+.
+.Fn libusb20_dev_process
+is called to sync kernel USB transfers with userland USB
+transfers.
+.
+This function returns zero on success else a LIBUSB20_ERROR value is
+returned typically indicating that the given USB device has been
+detached.
+.
+.Pp
+.
+.Fn libusb20_dev_request_sync
+will perform a synchronous control request on the given
+USB device.
+.
+Before this call will succeed the USB device must be opened.
+.
+.Fa setup
+is a pointer to a decoded and host endian SETUP packet.
+.Fa data
+is a pointer to a data transfer buffer associated with the control transaction. This argument can be NULL.
+.Fa pactlen
+is a pointer to a variable that will hold the actual transfer length after the control transaction is complete.
+.Fa timeout
+is the transaction timeout given in milliseconds.
+A timeout of zero means no timeout.
+.Fa flags
+is used to specify transaction flags, for example LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK.
+.
+This function returns zero on success else a LIBUSB20_ERROR value is
+returned.
+.
+.Pp
+.
+.Fn libusb20_dev_req_string_sync
+will synchronously request an USB string by language ID
+and string index into the given buffer limited by a maximum length.
+.
+This function returns zero on success else a LIBUSB20_ERROR value is
+returned.
+.
+.Pp
+.
+.Fn libusb20_dev_req_string_simple_sync
+will synchronously request an USB string using the
+default language ID and convert the string into ASCII before storing
+the string into the given buffer limited by a maximum length which
+includes the terminating zero.
+.
+This function returns zero on success else a LIBUSB20_ERROR value is
+returned.
+.
+.
+.Pp
+.
+.Fn libusb20_dev_reset
+will try to BUS reset the given USB device and restore
+the last set USB configuration.
+.
+This function returns zero on success else a LIBUSB20_ERROR value is
+returned.
+.
+.
+.Pp
+.
+.Fn libusb20_dev_check_connected
+will check if an opened USB device is still connected.
+.
+This function returns zero if the device is still connected else a LIBUSB20_ERROR value is returned.
+.
+.
+.Pp
+.
+.Fn libusb20_dev_set_power_mode
+sets the power mode of the USB device.
+.
+Valid power modes:
+.Bl -tag
+.It LIBUSB20_POWER_OFF
+.It LIBUSB20_POWER_ON
+.It LIBUSB20_POWER_SAVE
+.It LIBUSB20_POWER_SUSPEND
+.It LIBUSB20_POWER_RESUME
+.El
+.
+This function returns zero on success else a LIBUSB20_ERROR value is
+returned.
+.
+.Pp
+.
+.Fn libusb20_dev_get_power_mode
+returns the currently selected power mode for the given
+USB device.
+.
+.Pp
+.
+.Fn libusb20_dev_set_alt_index
+will try to set the given alternate index for the given
+USB interface index.
+.
+This function returns zero on success else a LIBUSB20_ERROR value is
+returned.
+.
+.Pp
+.
+.Fn libusb20_dev_get_device_desc
+returns a pointer to the decoded and host endian version
+of the device descriptor.
+.
+The USB device need not be opened when calling this function.
+.
+.Pp
+.
+.Fn libusb20_dev_alloc_config
+will read out and decode the USB config descriptor for
+the given USB device and config index. This function returns a pointer
+to the decoded configuration which must eventually be passed to
+free(). NULL is returned in case of failure.
+.
+.Pp
+.
+.Fn libusb20_dev_alloc
+is an internal function to allocate a new USB device.
+.
+.Pp
+.
+.Fn libusb20_dev_get_address
+returns the internal and not necessarily the real
+hardware address of the given USB device.
+Valid addresses start at one.
+.
+.Pp
+.
+.Fn libusb20_dev_get_parent_address
+returns the internal and not necessarily the real hardware address of
+the given parent USB HUB device.
+This value is zero for the root HUB which usually has a device address
+equal to one.
+Valid addresses start at one.
+.
+.Pp
+.
+.Fn libusb20_dev_get_parent_port
+returns the port number on the parent USB HUB device.
+This value is zero for the root HUB which usually has a device address
+equal to one.
+Valid port numbers start at one.
+.
+.Pp
+.
+.Fn libusb20_dev_get_bus_number
+returns the internal bus number which the given USB
+device belongs to.
+Valid bus numbers start at zero.
+.
+.Pp
+.
+.Fn libusb20_dev_get_mode
+returns the current operation mode of the USB entity.
+.
+Valid return values are:
+.Bl -tag
+.It LIBUSB20_MODE_HOST
+.It LIBUSB20_MODE_DEVICE
+.El
+.
+.Pp
+.
+.Fn libusb20_dev_get_speed
+returns the current speed of the given USB device.
+.
+.Bl -tag
+.It LIBUSB20_SPEED_UNKNOWN
+.It LIBUSB20_SPEED_LOW
+.It LIBUSB20_SPEED_FULL
+.It LIBUSB20_SPEED_HIGH
+.It LIBUSB20_SPEED_VARIABLE
+.It LIBUSB20_SPEED_SUPER
+.El
+.
+.Pp
+.
+.Fn libusb20_dev_get_config_index
+This function returns the currently select config index for the given
+USB device.
+.
+.Pp
+.
+.Fn libusb20_dev_free
+will free the given USB device and all associated USB
+transfers.
+.
+.Pp
+.
+.Fn libusb20_dev_set_debug
+will set the debug level for the given USB device.
+.
+.Pp
+.
+.Fn libusb20_dev_wait_process
+function will wait until a pending USB transfer has completed on
+the given USB device.
+.
+A timeout value can be specified which is passed on to the
+.Xr poll 2
+function.
+.
+.Sh USB BACKEND OPERATIONS
+.
+.Fn libusb20_be_get_template
+will return the currently selected global USB device
+side mode template into the integer pointer
+.Fa ptemp .
+This function returns zero on success else a LIBUSB20_ERROR value is
+returned.
+.
+.Pp
+.
+.Fn libusb20_be_set_template
+will set the global USB device side mode template to
+.Fa temp .
+The new template is not activated until after the next USB
+enumeration.
+The template number decides how the USB device will present itself to
+the USB Host, like Mass Storage Device, USB Ethernet Device. Also see
+the
+.Xr usb2_template 4
+module.
+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
+into the libusb20_quirk structure pointed to by
+.Fa pq .
+This function returns zero on success else a LIBUSB20_ERROR value is
+returned.
+.
+If the given quirk does not exist LIBUSB20_ERROR_NOT_FOUND is
+returned.
+.
+.Pp
+.
+.Fn libusb20_be_get_quirk_name
+will return the quirk name according to
+.Fa index
+into the libusb20_quirk structure pointed to by
+.Fa pq .
+This function returns zero on success else a LIBUSB20_ERROR value is
+returned.
+.
+If the given quirk does not exist LIBUSB20_ERROR_NOT_FOUND is
+returned.
+.
+.Pp
+.
+.Fn libusb20_be_add_dev_quirk
+will add the libusb20_quirk structure pointed to by the
+.Fa pq
+argument into the device quirk list.
+.
+This function returns zero on success else a LIBUSB20_ERROR value is
+returned.
+.
+If the given quirk cannot be added LIBUSB20_ERROR_NO_MEM is
+returned.
+.
+.Pp
+.
+.Fn libusb20_be_remove_dev_quirk
+will remove the quirk matching the libusb20_quirk structure pointed to by the
+.Fa pq
+argument from the device quirk list.
+.
+This function returns zero on success else a LIBUSB20_ERROR value is
+returned.
+.
+If the given quirk does not exist LIBUSB20_ERROR_NOT_FOUND is
+returned.
+.
+.Pp
+.
+.Fn libusb20_be_alloc_default
+.Fn libusb20_be_alloc_freebsd
+.Fn libusb20_be_alloc_linux
+These functions are used to allocate a specific USB backend or the
+operating system default USB backend. Allocating a backend is a way to
+scan for currently present USB devices.
+.
+.Pp
+.
+.Fn libusb20_be_device_foreach
+is used to iterate USB devices present in a USB backend.
+.
+The starting value of
+.Fa pdev
+is NULL.
+.
+This function returns the next USB device in the list.
+.
+If NULL is returned the end of the USB device list has been reached.
+.
+.Pp
+.
+.Fn libusb20_be_dequeue_device
+will dequeue the given USB device pointer from the
+backend USB device list.
+.
+Dequeued USB devices will not be freed when the backend is freed.
+.
+.Pp
+.
+.Fn libusb20_be_enqueue_device
+This function will enqueue the given USB device pointer in the backend USB device list.
+.
+Enqueued USB devices will get freed when the backend is freed.
+.
+.Pp
+.
+.Fn libusb20_be_free
+will free the given backend and all USB devices in its device list.
+.
+.
+.Sh USB DESCRIPTOR PARSING
+.
+.Fn libusb20_me_get_1 pie offset
+This function will return a byte at the given byte offset of a message
+entity.
+.
+This function is safe against invalid offsets.
+.
+.Pp
+.
+.Fn libusb20_me_get_2 pie offset
+This function will return a little endian 16-bit value at the given byte offset of a message
+entity.
+.
+This function is safe against invalid offsets.
+.
+.Pp
+.
+.Fn libusb20_me_encode pbuf len pdecoded
+This function will encode a so-called *DECODED structure into binary
+format.
+.
+The total encoded length that will fit in the given buffer is
+returned.
+.
+If the buffer pointer is NULL no data will be written to the buffer
+location.
+.
+.Pp
+.
+.Fn libusb20_me_decode pbuf len pdecoded
+This function will decode a binary structure into a so-called *DECODED
+structure.
+.
+The total decoded length is returned.
+.
+The buffer pointer cannot be NULL.
+.
+.
+.Sh USB DEBUGGING
+.Ft const char *
+.Fn libusb20_strerror "int code"
+Get the ASCII representation of the error given by the
+.Fa code
+argument.
+This function does not return NULL.
+.Pp
+.Ft const char *
+.Fn libusb20_error_name "int code"
+Get the ASCII representation of the error enum given by the
+.Fa code
+argument.
+This function does not return NULL.
+.
+.Sh FILES
+.
+.
+/dev/usb
+.Sh SEE ALSO
+.Xr usb 4 ,
+.Xr libusb 3 ,
+.Xr usbconfig 8 ,
+.Xr usbdump 8
+.
+.
+.Sh HISTORY
+.
+.
+Some parts of the
+.Nm
+API derives from the libusb project at sourceforge.
diff --git a/lib/libusb/libusb20.c b/lib/libusb/libusb20.c
new file mode 100644
index 0000000..747c160
--- /dev/null
+++ b/lib/libusb/libusb20.c
@@ -0,0 +1,1320 @@
+/* $FreeBSD$ */
+/*-
+ * Copyright (c) 2008-2009 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.
+ */
+
+#include <sys/queue.h>
+
+#include <ctype.h>
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libusb20.h"
+#include "libusb20_desc.h"
+#include "libusb20_int.h"
+
+static int
+dummy_int(void)
+{
+ return (LIBUSB20_ERROR_NOT_SUPPORTED);
+}
+
+static void
+dummy_void(void)
+{
+ return;
+}
+
+static void
+dummy_callback(struct libusb20_transfer *xfer)
+{
+ ; /* style fix */
+ switch (libusb20_tr_get_status(xfer)) {
+ case LIBUSB20_TRANSFER_START:
+ libusb20_tr_submit(xfer);
+ break;
+ default:
+ /* complete or error */
+ break;
+ }
+ return;
+}
+
+#define dummy_get_config_desc_full (void *)dummy_int
+#define dummy_get_config_index (void *)dummy_int
+#define dummy_set_config_index (void *)dummy_int
+#define dummy_set_alt_index (void *)dummy_int
+#define dummy_reset_device (void *)dummy_int
+#define dummy_check_connected (void *)dummy_int
+#define dummy_set_power_mode (void *)dummy_int
+#define dummy_get_power_mode (void *)dummy_int
+#define dummy_kernel_driver_active (void *)dummy_int
+#define dummy_detach_kernel_driver (void *)dummy_int
+#define dummy_do_request_sync (void *)dummy_int
+#define dummy_tr_open (void *)dummy_int
+#define dummy_tr_close (void *)dummy_int
+#define dummy_tr_clear_stall_sync (void *)dummy_int
+#define dummy_process (void *)dummy_int
+#define dummy_dev_info (void *)dummy_int
+#define dummy_dev_get_iface_driver (void *)dummy_int
+
+#define dummy_tr_submit (void *)dummy_void
+#define dummy_tr_cancel_async (void *)dummy_void
+
+static const struct libusb20_device_methods libusb20_dummy_methods = {
+ LIBUSB20_DEVICE(LIBUSB20_DECLARE, dummy)
+};
+
+void
+libusb20_tr_callback_wrapper(struct libusb20_transfer *xfer)
+{
+ ; /* style fix */
+
+repeat:
+
+ if (!xfer->is_pending) {
+ xfer->status = LIBUSB20_TRANSFER_START;
+ } else {
+ xfer->is_pending = 0;
+ }
+
+ xfer->callback(xfer);
+
+ if (xfer->is_restart) {
+ xfer->is_restart = 0;
+ goto repeat;
+ }
+ if (xfer->is_draining &&
+ (!xfer->is_pending)) {
+ xfer->is_draining = 0;
+ xfer->status = LIBUSB20_TRANSFER_DRAINED;
+ xfer->callback(xfer);
+ }
+ return;
+}
+
+int
+libusb20_tr_close(struct libusb20_transfer *xfer)
+{
+ int error;
+
+ if (!xfer->is_opened) {
+ return (LIBUSB20_ERROR_OTHER);
+ }
+ error = xfer->pdev->methods->tr_close(xfer);
+
+ if (xfer->pLength) {
+ free(xfer->pLength);
+ }
+ if (xfer->ppBuffer) {
+ free(xfer->ppBuffer);
+ }
+ /* reset variable fields in case the transfer is opened again */
+ xfer->priv_sc0 = 0;
+ xfer->priv_sc1 = 0;
+ xfer->is_opened = 0;
+ xfer->is_pending = 0;
+ xfer->is_cancel = 0;
+ xfer->is_draining = 0;
+ xfer->is_restart = 0;
+ xfer->status = 0;
+ xfer->flags = 0;
+ xfer->nFrames = 0;
+ xfer->aFrames = 0;
+ xfer->timeout = 0;
+ xfer->maxFrames = 0;
+ xfer->maxTotalLength = 0;
+ xfer->maxPacketLen = 0;
+ return (error);
+}
+
+int
+libusb20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize,
+ uint32_t MaxFrameCount, uint8_t ep_no)
+{
+ uint32_t size;
+ uint8_t pre_scale;
+ int error;
+
+ if (xfer->is_opened)
+ return (LIBUSB20_ERROR_BUSY);
+ if (MaxFrameCount & LIBUSB20_MAX_FRAME_PRE_SCALE) {
+ MaxFrameCount &= ~LIBUSB20_MAX_FRAME_PRE_SCALE;
+ pre_scale = 1;
+ } else {
+ pre_scale = 0;
+ }
+ if (MaxFrameCount == 0)
+ return (LIBUSB20_ERROR_INVALID_PARAM);
+
+ xfer->maxFrames = MaxFrameCount;
+
+ size = MaxFrameCount * sizeof(xfer->pLength[0]);
+ xfer->pLength = malloc(size);
+ if (xfer->pLength == NULL) {
+ return (LIBUSB20_ERROR_NO_MEM);
+ }
+ memset(xfer->pLength, 0, size);
+
+ size = MaxFrameCount * sizeof(xfer->ppBuffer[0]);
+ xfer->ppBuffer = malloc(size);
+ if (xfer->ppBuffer == NULL) {
+ free(xfer->pLength);
+ return (LIBUSB20_ERROR_NO_MEM);
+ }
+ memset(xfer->ppBuffer, 0, size);
+
+ error = xfer->pdev->methods->tr_open(xfer, MaxBufSize,
+ MaxFrameCount, ep_no, pre_scale);
+
+ if (error) {
+ free(xfer->ppBuffer);
+ free(xfer->pLength);
+ } else {
+ xfer->is_opened = 1;
+ }
+ return (error);
+}
+
+struct libusb20_transfer *
+libusb20_tr_get_pointer(struct libusb20_device *pdev, uint16_t trIndex)
+{
+ if (trIndex >= pdev->nTransfer) {
+ return (NULL);
+ }
+ return (pdev->pTransfer + trIndex);
+}
+
+uint32_t
+libusb20_tr_get_actual_frames(struct libusb20_transfer *xfer)
+{
+ return (xfer->aFrames);
+}
+
+uint16_t
+libusb20_tr_get_time_complete(struct libusb20_transfer *xfer)
+{
+ return (xfer->timeComplete);
+}
+
+uint32_t
+libusb20_tr_get_actual_length(struct libusb20_transfer *xfer)
+{
+ uint32_t x;
+ uint32_t actlen = 0;
+
+ for (x = 0; x != xfer->aFrames; x++) {
+ actlen += xfer->pLength[x];
+ }
+ return (actlen);
+}
+
+uint32_t
+libusb20_tr_get_max_frames(struct libusb20_transfer *xfer)
+{
+ return (xfer->maxFrames);
+}
+
+uint32_t
+libusb20_tr_get_max_packet_length(struct libusb20_transfer *xfer)
+{
+ /*
+ * Special Case NOTE: If the packet multiplier is non-zero for
+ * High Speed USB, the value returned is equal to
+ * "wMaxPacketSize * multiplier" !
+ */
+ return (xfer->maxPacketLen);
+}
+
+uint32_t
+libusb20_tr_get_max_total_length(struct libusb20_transfer *xfer)
+{
+ return (xfer->maxTotalLength);
+}
+
+uint8_t
+libusb20_tr_get_status(struct libusb20_transfer *xfer)
+{
+ return (xfer->status);
+}
+
+uint8_t
+libusb20_tr_pending(struct libusb20_transfer *xfer)
+{
+ return (xfer->is_pending);
+}
+
+void *
+libusb20_tr_get_priv_sc0(struct libusb20_transfer *xfer)
+{
+ return (xfer->priv_sc0);
+}
+
+void *
+libusb20_tr_get_priv_sc1(struct libusb20_transfer *xfer)
+{
+ return (xfer->priv_sc1);
+}
+
+void
+libusb20_tr_stop(struct libusb20_transfer *xfer)
+{
+ if (!xfer->is_opened) {
+ /* transfer is not opened */
+ return;
+ }
+ if (!xfer->is_pending) {
+ /* transfer not pending */
+ return;
+ }
+ if (xfer->is_cancel) {
+ /* already cancelling */
+ return;
+ }
+ xfer->is_cancel = 1; /* we are cancelling */
+
+ xfer->pdev->methods->tr_cancel_async(xfer);
+ return;
+}
+
+void
+libusb20_tr_drain(struct libusb20_transfer *xfer)
+{
+ if (!xfer->is_opened) {
+ /* transfer is not opened */
+ return;
+ }
+ /* make sure that we are cancelling */
+ libusb20_tr_stop(xfer);
+
+ if (xfer->is_pending) {
+ xfer->is_draining = 1;
+ }
+ return;
+}
+
+void
+libusb20_tr_clear_stall_sync(struct libusb20_transfer *xfer)
+{
+ xfer->pdev->methods->tr_clear_stall_sync(xfer);
+ return;
+}
+
+void
+libusb20_tr_set_buffer(struct libusb20_transfer *xfer, void *buffer, uint16_t frIndex)
+{
+ xfer->ppBuffer[frIndex] = libusb20_pass_ptr(buffer);
+ return;
+}
+
+void
+libusb20_tr_set_callback(struct libusb20_transfer *xfer, libusb20_tr_callback_t *cb)
+{
+ xfer->callback = cb;
+ return;
+}
+
+void
+libusb20_tr_set_flags(struct libusb20_transfer *xfer, uint8_t flags)
+{
+ xfer->flags = flags;
+ return;
+}
+
+uint32_t
+libusb20_tr_get_length(struct libusb20_transfer *xfer, uint16_t frIndex)
+{
+ return (xfer->pLength[frIndex]);
+}
+
+void
+libusb20_tr_set_length(struct libusb20_transfer *xfer, uint32_t length, uint16_t frIndex)
+{
+ xfer->pLength[frIndex] = length;
+ return;
+}
+
+void
+libusb20_tr_set_priv_sc0(struct libusb20_transfer *xfer, void *sc0)
+{
+ xfer->priv_sc0 = sc0;
+ return;
+}
+
+void
+libusb20_tr_set_priv_sc1(struct libusb20_transfer *xfer, void *sc1)
+{
+ xfer->priv_sc1 = sc1;
+ return;
+}
+
+void
+libusb20_tr_set_timeout(struct libusb20_transfer *xfer, uint32_t timeout)
+{
+ xfer->timeout = timeout;
+ return;
+}
+
+void
+libusb20_tr_set_total_frames(struct libusb20_transfer *xfer, uint32_t nFrames)
+{
+ if (nFrames > xfer->maxFrames) {
+ /* should not happen */
+ nFrames = xfer->maxFrames;
+ }
+ xfer->nFrames = nFrames;
+ return;
+}
+
+void
+libusb20_tr_setup_bulk(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint32_t timeout)
+{
+ xfer->ppBuffer[0] = libusb20_pass_ptr(pBuf);
+ xfer->pLength[0] = length;
+ xfer->timeout = timeout;
+ xfer->nFrames = 1;
+ return;
+}
+
+void
+libusb20_tr_setup_control(struct libusb20_transfer *xfer, void *psetup, void *pBuf, uint32_t timeout)
+{
+ uint16_t len;
+
+ xfer->ppBuffer[0] = libusb20_pass_ptr(psetup);
+ xfer->pLength[0] = 8; /* fixed */
+ xfer->timeout = timeout;
+
+ len = ((uint8_t *)psetup)[6] | (((uint8_t *)psetup)[7] << 8);
+
+ if (len != 0) {
+ xfer->nFrames = 2;
+ xfer->ppBuffer[1] = libusb20_pass_ptr(pBuf);
+ xfer->pLength[1] = len;
+ } else {
+ xfer->nFrames = 1;
+ }
+ return;
+}
+
+void
+libusb20_tr_setup_intr(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint32_t timeout)
+{
+ xfer->ppBuffer[0] = libusb20_pass_ptr(pBuf);
+ xfer->pLength[0] = length;
+ xfer->timeout = timeout;
+ xfer->nFrames = 1;
+ return;
+}
+
+void
+libusb20_tr_setup_isoc(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint16_t frIndex)
+{
+ if (frIndex >= xfer->maxFrames) {
+ /* should not happen */
+ return;
+ }
+ xfer->ppBuffer[frIndex] = libusb20_pass_ptr(pBuf);
+ xfer->pLength[frIndex] = length;
+ return;
+}
+
+uint8_t
+libusb20_tr_bulk_intr_sync(struct libusb20_transfer *xfer,
+ void *pbuf, uint32_t length, uint32_t *pactlen,
+ uint32_t timeout)
+{
+ struct libusb20_device *pdev = xfer->pdev;
+ uint32_t transfer_max;
+ uint32_t transfer_act;
+ uint8_t retval;
+
+ /* set some sensible default value */
+ if (pactlen != NULL)
+ *pactlen = 0;
+
+ /* check for error condition */
+ if (libusb20_tr_pending(xfer))
+ return (LIBUSB20_ERROR_OTHER);
+
+ do {
+ /* compute maximum transfer length */
+ transfer_max =
+ libusb20_tr_get_max_total_length(xfer);
+
+ if (transfer_max > length)
+ transfer_max = length;
+
+ /* setup bulk or interrupt transfer */
+ libusb20_tr_setup_bulk(xfer, pbuf,
+ transfer_max, timeout);
+
+ /* start the transfer */
+ libusb20_tr_start(xfer);
+
+ /* wait for transfer completion */
+ while (libusb20_dev_process(pdev) == 0) {
+
+ if (libusb20_tr_pending(xfer) == 0)
+ break;
+
+ libusb20_dev_wait_process(pdev, -1);
+ }
+
+ transfer_act = libusb20_tr_get_actual_length(xfer);
+
+ /* update actual length, if any */
+ if (pactlen != NULL)
+ pactlen[0] += transfer_act;
+
+ /* check transfer status */
+ retval = libusb20_tr_get_status(xfer);
+ if (retval)
+ break;
+
+ /* check for short transfer */
+ if (transfer_act != transfer_max)
+ break;
+
+ /* update buffer pointer and length */
+ pbuf = ((uint8_t *)pbuf) + transfer_max;
+ length = length - transfer_max;
+
+ } while (length != 0);
+
+ return (retval);
+}
+
+void
+libusb20_tr_submit(struct libusb20_transfer *xfer)
+{
+ if (!xfer->is_opened) {
+ /* transfer is not opened */
+ return;
+ }
+ if (xfer->is_pending) {
+ /* should not happen */
+ return;
+ }
+ xfer->is_pending = 1; /* we are pending */
+ xfer->is_cancel = 0; /* not cancelling */
+ xfer->is_restart = 0; /* not restarting */
+
+ xfer->pdev->methods->tr_submit(xfer);
+ return;
+}
+
+void
+libusb20_tr_start(struct libusb20_transfer *xfer)
+{
+ if (!xfer->is_opened) {
+ /* transfer is not opened */
+ return;
+ }
+ if (xfer->is_pending) {
+ if (xfer->is_cancel) {
+ /* cancelling - restart */
+ xfer->is_restart = 1;
+ }
+ /* transfer not pending */
+ return;
+ }
+ /* get into the callback */
+ libusb20_tr_callback_wrapper(xfer);
+ return;
+}
+
+/* USB device operations */
+
+int
+libusb20_dev_close(struct libusb20_device *pdev)
+{
+ struct libusb20_transfer *xfer;
+ uint16_t x;
+ int error = 0;
+
+ if (!pdev->is_opened) {
+ return (LIBUSB20_ERROR_OTHER);
+ }
+ for (x = 0; x != pdev->nTransfer; x++) {
+ xfer = pdev->pTransfer + x;
+
+ if (!xfer->is_opened) {
+ /* transfer is not opened */
+ continue;
+ }
+
+ libusb20_tr_drain(xfer);
+
+ libusb20_tr_close(xfer);
+ }
+
+ if (pdev->pTransfer != NULL) {
+ free(pdev->pTransfer);
+ pdev->pTransfer = NULL;
+ }
+ error = pdev->beMethods->close_device(pdev);
+
+ pdev->methods = &libusb20_dummy_methods;
+
+ pdev->is_opened = 0;
+
+ /*
+ * The following variable is only used by the libusb v0.1
+ * compat layer:
+ */
+ pdev->claimed_interface = 0;
+
+ return (error);
+}
+
+int
+libusb20_dev_detach_kernel_driver(struct libusb20_device *pdev, uint8_t ifaceIndex)
+{
+ int error;
+
+ error = pdev->methods->detach_kernel_driver(pdev, ifaceIndex);
+ return (error);
+}
+
+struct LIBUSB20_DEVICE_DESC_DECODED *
+libusb20_dev_get_device_desc(struct libusb20_device *pdev)
+{
+ return (&(pdev->ddesc));
+}
+
+int
+libusb20_dev_get_fd(struct libusb20_device *pdev)
+{
+ return (pdev->file);
+}
+
+int
+libusb20_dev_kernel_driver_active(struct libusb20_device *pdev, uint8_t ifaceIndex)
+{
+ int error;
+
+ error = pdev->methods->kernel_driver_active(pdev, ifaceIndex);
+ return (error);
+}
+
+int
+libusb20_dev_open(struct libusb20_device *pdev, uint16_t nTransferMax)
+{
+ struct libusb20_transfer *xfer;
+ uint32_t size;
+ uint16_t x;
+ int error;
+
+ if (pdev->is_opened) {
+ return (LIBUSB20_ERROR_BUSY);
+ }
+ if (nTransferMax >= 256) {
+ return (LIBUSB20_ERROR_INVALID_PARAM);
+ } else if (nTransferMax != 0) {
+ size = sizeof(pdev->pTransfer[0]) * nTransferMax;
+ pdev->pTransfer = malloc(size);
+ if (pdev->pTransfer == NULL) {
+ return (LIBUSB20_ERROR_NO_MEM);
+ }
+ memset(pdev->pTransfer, 0, size);
+ }
+ /* initialise all transfers */
+ for (x = 0; x != nTransferMax; x++) {
+
+ xfer = pdev->pTransfer + x;
+
+ xfer->pdev = pdev;
+ xfer->trIndex = x;
+ xfer->callback = &dummy_callback;
+ }
+
+ /* set "nTransfer" early */
+ pdev->nTransfer = nTransferMax;
+
+ error = pdev->beMethods->open_device(pdev, nTransferMax);
+
+ if (error) {
+ if (pdev->pTransfer != NULL) {
+ free(pdev->pTransfer);
+ pdev->pTransfer = NULL;
+ }
+ pdev->file = -1;
+ pdev->file_ctrl = -1;
+ pdev->nTransfer = 0;
+ } else {
+ pdev->is_opened = 1;
+ }
+ return (error);
+}
+
+int
+libusb20_dev_reset(struct libusb20_device *pdev)
+{
+ int error;
+
+ error = pdev->methods->reset_device(pdev);
+ return (error);
+}
+
+int
+libusb20_dev_check_connected(struct libusb20_device *pdev)
+{
+ int error;
+
+ error = pdev->methods->check_connected(pdev);
+ return (error);
+}
+
+int
+libusb20_dev_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode)
+{
+ int error;
+
+ error = pdev->methods->set_power_mode(pdev, power_mode);
+ return (error);
+}
+
+uint8_t
+libusb20_dev_get_power_mode(struct libusb20_device *pdev)
+{
+ int error;
+ uint8_t power_mode;
+
+ error = pdev->methods->get_power_mode(pdev, &power_mode);
+ if (error)
+ power_mode = LIBUSB20_POWER_ON; /* fake power mode */
+ return (power_mode);
+}
+
+int
+libusb20_dev_set_alt_index(struct libusb20_device *pdev, uint8_t ifaceIndex, uint8_t altIndex)
+{
+ int error;
+
+ error = pdev->methods->set_alt_index(pdev, ifaceIndex, altIndex);
+ return (error);
+}
+
+int
+libusb20_dev_set_config_index(struct libusb20_device *pdev, uint8_t configIndex)
+{
+ int error;
+
+ error = pdev->methods->set_config_index(pdev, configIndex);
+ return (error);
+}
+
+int
+libusb20_dev_request_sync(struct libusb20_device *pdev,
+ struct LIBUSB20_CONTROL_SETUP_DECODED *setup, void *data,
+ uint16_t *pactlen, uint32_t timeout, uint8_t flags)
+{
+ int error;
+
+ error = pdev->methods->do_request_sync(pdev,
+ setup, data, pactlen, timeout, flags);
+ return (error);
+}
+
+int
+libusb20_dev_req_string_sync(struct libusb20_device *pdev,
+ uint8_t str_index, uint16_t langid, void *ptr, uint16_t len)
+{
+ struct LIBUSB20_CONTROL_SETUP_DECODED req;
+ int error;
+
+ /* make sure memory is initialised */
+ memset(ptr, 0, len);
+
+ if (len < 4) {
+ /* invalid length */
+ return (LIBUSB20_ERROR_INVALID_PARAM);
+ }
+ LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req);
+
+ /*
+ * We need to read the USB string in two steps else some USB
+ * devices will complain.
+ */
+ req.bmRequestType =
+ LIBUSB20_REQUEST_TYPE_STANDARD |
+ LIBUSB20_RECIPIENT_DEVICE |
+ LIBUSB20_ENDPOINT_IN;
+ req.bRequest = LIBUSB20_REQUEST_GET_DESCRIPTOR;
+ req.wValue = (LIBUSB20_DT_STRING << 8) | str_index;
+ req.wIndex = langid;
+ req.wLength = 4; /* bytes */
+
+ error = libusb20_dev_request_sync(pdev, &req,
+ ptr, NULL, 1000, LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK);
+ if (error) {
+ return (error);
+ }
+ req.wLength = *(uint8_t *)ptr; /* bytes */
+ if (req.wLength > len) {
+ /* partial string read */
+ req.wLength = len;
+ }
+ error = libusb20_dev_request_sync(pdev, &req,
+ ptr, NULL, 1000, LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK);
+
+ if (error) {
+ return (error);
+ }
+ if (((uint8_t *)ptr)[1] != LIBUSB20_DT_STRING) {
+ return (LIBUSB20_ERROR_OTHER);
+ }
+ return (0); /* success */
+}
+
+int
+libusb20_dev_req_string_simple_sync(struct libusb20_device *pdev,
+ uint8_t str_index, void *ptr, uint16_t len)
+{
+ char *buf;
+ int error;
+ uint16_t langid;
+ uint16_t n;
+ uint16_t i;
+ uint16_t c;
+ uint8_t temp[255];
+ uint8_t swap;
+
+ /* the following code derives from the FreeBSD USB kernel */
+
+ if ((len < 1) || (ptr == NULL)) {
+ /* too short buffer */
+ return (LIBUSB20_ERROR_INVALID_PARAM);
+ }
+ error = libusb20_dev_req_string_sync(pdev,
+ 0, 0, temp, sizeof(temp));
+ if (error < 0) {
+ *(uint8_t *)ptr = 0; /* zero terminate */
+ return (error);
+ }
+ langid = temp[2] | (temp[3] << 8);
+
+ error = libusb20_dev_req_string_sync(pdev, str_index,
+ langid, temp, sizeof(temp));
+ if (error < 0) {
+ *(uint8_t *)ptr = 0; /* zero terminate */
+ return (error);
+ }
+ if (temp[0] < 2) {
+ /* string length is too short */
+ *(uint8_t *)ptr = 0; /* zero terminate */
+ return (LIBUSB20_ERROR_OTHER);
+ }
+ /* reserve one byte for terminating zero */
+ len--;
+
+ /* find maximum length */
+ n = (temp[0] / 2) - 1;
+ if (n > len) {
+ n = len;
+ }
+ /* reset swap state */
+ swap = 3;
+
+ /* setup output buffer pointer */
+ buf = ptr;
+
+ /* convert and filter */
+ for (i = 0; (i != n); i++) {
+ c = temp[(2 * i) + 2] | (temp[(2 * i) + 3] << 8);
+
+ /* convert from Unicode, handle buggy strings */
+ if (((c & 0xff00) == 0) && (swap & 1)) {
+ /* Little Endian, default */
+ *buf = c;
+ swap = 1;
+ } else if (((c & 0x00ff) == 0) && (swap & 2)) {
+ /* Big Endian */
+ *buf = c >> 8;
+ swap = 2;
+ } else {
+ /* skip invalid character */
+ continue;
+ }
+ /*
+ * Filter by default - we don't allow greater and less than
+ * signs because they might confuse the dmesg printouts!
+ */
+ if ((*buf == '<') || (*buf == '>') || (!isprint(*buf))) {
+ /* skip invalid character */
+ continue;
+ }
+ buf++;
+ }
+ *buf = 0; /* zero terminate string */
+
+ return (0);
+}
+
+struct libusb20_config *
+libusb20_dev_alloc_config(struct libusb20_device *pdev, uint8_t configIndex)
+{
+ struct libusb20_config *retval = NULL;
+ uint8_t *ptr;
+ uint16_t len;
+ uint8_t do_close;
+ int error;
+
+ if (!pdev->is_opened) {
+ error = libusb20_dev_open(pdev, 0);
+ if (error) {
+ return (NULL);
+ }
+ do_close = 1;
+ } else {
+ do_close = 0;
+ }
+ error = pdev->methods->get_config_desc_full(pdev,
+ &ptr, &len, configIndex);
+
+ if (error) {
+ goto done;
+ }
+ /* parse new config descriptor */
+ retval = libusb20_parse_config_desc(ptr);
+
+ /* free config descriptor */
+ free(ptr);
+
+done:
+ if (do_close) {
+ error = libusb20_dev_close(pdev);
+ }
+ return (retval);
+}
+
+struct libusb20_device *
+libusb20_dev_alloc(void)
+{
+ struct libusb20_device *pdev;
+
+ pdev = malloc(sizeof(*pdev));
+ if (pdev == NULL) {
+ return (NULL);
+ }
+ memset(pdev, 0, sizeof(*pdev));
+
+ pdev->file = -1;
+ pdev->file_ctrl = -1;
+ pdev->methods = &libusb20_dummy_methods;
+ return (pdev);
+}
+
+uint8_t
+libusb20_dev_get_config_index(struct libusb20_device *pdev)
+{
+ int error;
+ uint8_t cfg_index;
+ uint8_t do_close;
+
+ if (!pdev->is_opened) {
+ error = libusb20_dev_open(pdev, 0);
+ if (error == 0) {
+ do_close = 1;
+ } else {
+ do_close = 0;
+ }
+ } else {
+ do_close = 0;
+ }
+
+ error = pdev->methods->get_config_index(pdev, &cfg_index);
+ if (error) {
+ cfg_index = 0 - 1; /* current config index */
+ }
+ if (do_close) {
+ if (libusb20_dev_close(pdev)) {
+ /* ignore */
+ }
+ }
+ return (cfg_index);
+}
+
+uint8_t
+libusb20_dev_get_mode(struct libusb20_device *pdev)
+{
+ return (pdev->usb_mode);
+}
+
+uint8_t
+libusb20_dev_get_speed(struct libusb20_device *pdev)
+{
+ return (pdev->usb_speed);
+}
+
+/* if this function returns an error, the device is gone */
+int
+libusb20_dev_process(struct libusb20_device *pdev)
+{
+ int error;
+
+ error = pdev->methods->process(pdev);
+ return (error);
+}
+
+void
+libusb20_dev_wait_process(struct libusb20_device *pdev, int timeout)
+{
+ struct pollfd pfd[1];
+
+ if (!pdev->is_opened) {
+ return;
+ }
+ pfd[0].fd = pdev->file;
+ pfd[0].events = (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM);
+ pfd[0].revents = 0;
+
+ if (poll(pfd, 1, timeout)) {
+ /* ignore any error */
+ }
+ return;
+}
+
+void
+libusb20_dev_free(struct libusb20_device *pdev)
+{
+ if (pdev == NULL) {
+ /* be NULL safe */
+ return;
+ }
+ if (pdev->is_opened) {
+ if (libusb20_dev_close(pdev)) {
+ /* ignore any errors */
+ }
+ }
+ free(pdev);
+ return;
+}
+
+int
+libusb20_dev_get_info(struct libusb20_device *pdev,
+ struct usb_device_info *pinfo)
+{
+ if (pinfo == NULL)
+ return (LIBUSB20_ERROR_INVALID_PARAM);
+
+ return (pdev->beMethods->dev_get_info(pdev, pinfo));
+}
+
+const char *
+libusb20_dev_get_backend_name(struct libusb20_device *pdev)
+{
+ return (pdev->beMethods->get_backend_name());
+}
+
+const char *
+libusb20_dev_get_desc(struct libusb20_device *pdev)
+{
+ return (pdev->usb_desc);
+}
+
+void
+libusb20_dev_set_debug(struct libusb20_device *pdev, int debug)
+{
+ pdev->debug = debug;
+ return;
+}
+
+int
+libusb20_dev_get_debug(struct libusb20_device *pdev)
+{
+ return (pdev->debug);
+}
+
+uint8_t
+libusb20_dev_get_address(struct libusb20_device *pdev)
+{
+ return (pdev->device_address);
+}
+
+uint8_t
+libusb20_dev_get_parent_address(struct libusb20_device *pdev)
+{
+ return (pdev->parent_address);
+}
+
+uint8_t
+libusb20_dev_get_parent_port(struct libusb20_device *pdev)
+{
+ return (pdev->parent_port);
+}
+
+uint8_t
+libusb20_dev_get_bus_number(struct libusb20_device *pdev)
+{
+ return (pdev->bus_number);
+}
+
+int
+libusb20_dev_get_iface_desc(struct libusb20_device *pdev,
+ uint8_t iface_index, char *buf, uint8_t len)
+{
+ if ((buf == NULL) || (len == 0))
+ return (LIBUSB20_ERROR_INVALID_PARAM);
+
+ buf[0] = 0; /* set default string value */
+
+ return (pdev->beMethods->dev_get_iface_desc(
+ pdev, iface_index, buf, len));
+}
+
+/* USB backend operations */
+
+int
+libusb20_be_get_dev_quirk(struct libusb20_backend *pbe,
+ uint16_t quirk_index, struct libusb20_quirk *pq)
+{
+ return (pbe->methods->root_get_dev_quirk(pbe, quirk_index, pq));
+}
+
+int
+libusb20_be_get_quirk_name(struct libusb20_backend *pbe,
+ uint16_t quirk_index, struct libusb20_quirk *pq)
+{
+ return (pbe->methods->root_get_quirk_name(pbe, quirk_index, pq));
+}
+
+int
+libusb20_be_add_dev_quirk(struct libusb20_backend *pbe,
+ struct libusb20_quirk *pq)
+{
+ return (pbe->methods->root_add_dev_quirk(pbe, pq));
+}
+
+int
+libusb20_be_remove_dev_quirk(struct libusb20_backend *pbe,
+ struct libusb20_quirk *pq)
+{
+ return (pbe->methods->root_remove_dev_quirk(pbe, pq));
+}
+
+int
+libusb20_be_set_template(struct libusb20_backend *pbe, int temp)
+{
+ return (pbe->methods->root_set_template(pbe, temp));
+}
+
+int
+libusb20_be_get_template(struct libusb20_backend *pbe, int *ptemp)
+{
+ int temp;
+
+ if (ptemp == NULL)
+ ptemp = &temp;
+
+ return (pbe->methods->root_get_template(pbe, ptemp));
+}
+
+struct libusb20_device *
+libusb20_be_device_foreach(struct libusb20_backend *pbe, struct libusb20_device *pdev)
+{
+ if (pbe == NULL) {
+ pdev = NULL;
+ } else if (pdev == NULL) {
+ pdev = TAILQ_FIRST(&(pbe->usb_devs));
+ } else {
+ pdev = TAILQ_NEXT(pdev, dev_entry);
+ }
+ return (pdev);
+}
+
+struct libusb20_backend *
+libusb20_be_alloc(const struct libusb20_backend_methods *methods)
+{
+ struct libusb20_backend *pbe;
+
+ pbe = malloc(sizeof(*pbe));
+ if (pbe == NULL) {
+ return (NULL);
+ }
+ memset(pbe, 0, sizeof(*pbe));
+
+ TAILQ_INIT(&(pbe->usb_devs));
+
+ pbe->methods = methods; /* set backend methods */
+
+ /* do the initial device scan */
+ if (pbe->methods->init_backend) {
+ pbe->methods->init_backend(pbe);
+ }
+ return (pbe);
+}
+
+struct libusb20_backend *
+libusb20_be_alloc_linux(void)
+{
+ struct libusb20_backend *pbe;
+
+#ifdef __linux__
+ pbe = libusb20_be_alloc(&libusb20_linux_backend);
+#else
+ pbe = NULL;
+#endif
+ return (pbe);
+}
+
+struct libusb20_backend *
+libusb20_be_alloc_ugen20(void)
+{
+ struct libusb20_backend *pbe;
+
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+ pbe = libusb20_be_alloc(&libusb20_ugen20_backend);
+#else
+ pbe = NULL;
+#endif
+ return (pbe);
+}
+
+struct libusb20_backend *
+libusb20_be_alloc_default(void)
+{
+ struct libusb20_backend *pbe;
+
+ pbe = libusb20_be_alloc_linux();
+ if (pbe) {
+ return (pbe);
+ }
+ pbe = libusb20_be_alloc_ugen20();
+ if (pbe) {
+ return (pbe);
+ }
+ return (NULL); /* no backend found */
+}
+
+void
+libusb20_be_free(struct libusb20_backend *pbe)
+{
+ struct libusb20_device *pdev;
+
+ if (pbe == NULL) {
+ /* be NULL safe */
+ return;
+ }
+ while ((pdev = libusb20_be_device_foreach(pbe, NULL))) {
+ libusb20_be_dequeue_device(pbe, pdev);
+ libusb20_dev_free(pdev);
+ }
+ if (pbe->methods->exit_backend) {
+ pbe->methods->exit_backend(pbe);
+ }
+ /* free backend */
+ free(pbe);
+}
+
+void
+libusb20_be_enqueue_device(struct libusb20_backend *pbe, struct libusb20_device *pdev)
+{
+ pdev->beMethods = pbe->methods; /* copy backend methods */
+ TAILQ_INSERT_TAIL(&(pbe->usb_devs), pdev, dev_entry);
+}
+
+void
+libusb20_be_dequeue_device(struct libusb20_backend *pbe,
+ struct libusb20_device *pdev)
+{
+ TAILQ_REMOVE(&(pbe->usb_devs), pdev, dev_entry);
+}
+
+const char *
+libusb20_strerror(int code)
+{
+ switch (code) {
+ case LIBUSB20_SUCCESS:
+ return ("Success");
+ case LIBUSB20_ERROR_IO:
+ return ("I/O error");
+ case LIBUSB20_ERROR_INVALID_PARAM:
+ return ("Invalid parameter");
+ case LIBUSB20_ERROR_ACCESS:
+ return ("Permissions error");
+ case LIBUSB20_ERROR_NO_DEVICE:
+ return ("No device");
+ case LIBUSB20_ERROR_NOT_FOUND:
+ return ("Not found");
+ case LIBUSB20_ERROR_BUSY:
+ return ("Device busy");
+ case LIBUSB20_ERROR_TIMEOUT:
+ return ("Timeout");
+ case LIBUSB20_ERROR_OVERFLOW:
+ return ("Overflow");
+ case LIBUSB20_ERROR_PIPE:
+ return ("Pipe error");
+ case LIBUSB20_ERROR_INTERRUPTED:
+ return ("Interrupted");
+ case LIBUSB20_ERROR_NO_MEM:
+ return ("Out of memory");
+ case LIBUSB20_ERROR_NOT_SUPPORTED:
+ return ("Not supported");
+ case LIBUSB20_ERROR_OTHER:
+ return ("Other error");
+ default:
+ return ("Unknown error");
+ }
+}
+
+const char *
+libusb20_error_name(int code)
+{
+ switch (code) {
+ case LIBUSB20_SUCCESS:
+ return ("LIBUSB20_SUCCESS");
+ case LIBUSB20_ERROR_IO:
+ return ("LIBUSB20_ERROR_IO");
+ case LIBUSB20_ERROR_INVALID_PARAM:
+ return ("LIBUSB20_ERROR_INVALID_PARAM");
+ case LIBUSB20_ERROR_ACCESS:
+ return ("LIBUSB20_ERROR_ACCESS");
+ case LIBUSB20_ERROR_NO_DEVICE:
+ return ("LIBUSB20_ERROR_NO_DEVICE");
+ case LIBUSB20_ERROR_NOT_FOUND:
+ return ("LIBUSB20_ERROR_NOT_FOUND");
+ case LIBUSB20_ERROR_BUSY:
+ return ("LIBUSB20_ERROR_BUSY");
+ case LIBUSB20_ERROR_TIMEOUT:
+ return ("LIBUSB20_ERROR_TIMEOUT");
+ case LIBUSB20_ERROR_OVERFLOW:
+ return ("LIBUSB20_ERROR_OVERFLOW");
+ case LIBUSB20_ERROR_PIPE:
+ return ("LIBUSB20_ERROR_PIPE");
+ case LIBUSB20_ERROR_INTERRUPTED:
+ return ("LIBUSB20_ERROR_INTERRUPTED");
+ case LIBUSB20_ERROR_NO_MEM:
+ return ("LIBUSB20_ERROR_NO_MEM");
+ case LIBUSB20_ERROR_NOT_SUPPORTED:
+ return ("LIBUSB20_ERROR_NOT_SUPPORTED");
+ case LIBUSB20_ERROR_OTHER:
+ return ("LIBUSB20_ERROR_OTHER");
+ default:
+ return ("LIBUSB20_ERROR_UNKNOWN");
+ }
+}
diff --git a/lib/libusb/libusb20.h b/lib/libusb/libusb20.h
new file mode 100644
index 0000000..e4359fc
--- /dev/null
+++ b/lib/libusb/libusb20.h
@@ -0,0 +1,309 @@
+/* $FreeBSD$ */
+/*-
+ * Copyright (c) 2008-2009 Hans Petter Selasky. All rights reserved.
+ * Copyright (c) 2007-2008 Daniel Drake. All rights reserved.
+ * Copyright (c) 2001 Johannes Erdfelt. 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.
+ */
+
+#ifndef _LIBUSB20_H_
+#define _LIBUSB20_H_
+
+#include <sys/endian.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+#include <stdint.h>
+#include <string.h>
+#include <time.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#if 0
+}; /* style */
+
+#endif
+
+/** \ingroup misc
+ * Error codes. Most libusb20 functions return 0 on success or one of
+ * these codes on failure.
+ */
+enum libusb20_error {
+ /** Success (no error) */
+ LIBUSB20_SUCCESS = 0,
+
+ /** Input/output error */
+ LIBUSB20_ERROR_IO = -1,
+
+ /** Invalid parameter */
+ LIBUSB20_ERROR_INVALID_PARAM = -2,
+
+ /** Access denied (insufficient permissions) */
+ LIBUSB20_ERROR_ACCESS = -3,
+
+ /** No such device (it may have been disconnected) */
+ LIBUSB20_ERROR_NO_DEVICE = -4,
+
+ /** Entity not found */
+ LIBUSB20_ERROR_NOT_FOUND = -5,
+
+ /** Resource busy */
+ LIBUSB20_ERROR_BUSY = -6,
+
+ /** Operation timed out */
+ LIBUSB20_ERROR_TIMEOUT = -7,
+
+ /** Overflow */
+ LIBUSB20_ERROR_OVERFLOW = -8,
+
+ /** Pipe error */
+ LIBUSB20_ERROR_PIPE = -9,
+
+ /** System call interrupted (perhaps due to signal) */
+ LIBUSB20_ERROR_INTERRUPTED = -10,
+
+ /** Insufficient memory */
+ LIBUSB20_ERROR_NO_MEM = -11,
+
+ /** Operation not supported or unimplemented on this platform */
+ LIBUSB20_ERROR_NOT_SUPPORTED = -12,
+
+ /** Other error */
+ LIBUSB20_ERROR_OTHER = -99,
+};
+
+/** \ingroup asyncio
+ * libusb20_tr_get_status() values */
+enum libusb20_transfer_status {
+ /** Transfer completed without error. Note that this does not
+ * indicate that the entire amount of requested data was
+ * transferred. */
+ LIBUSB20_TRANSFER_COMPLETED,
+
+ /** Callback code to start transfer */
+ LIBUSB20_TRANSFER_START,
+
+ /** Drain complete callback code */
+ LIBUSB20_TRANSFER_DRAINED,
+
+ /** Transfer failed */
+ LIBUSB20_TRANSFER_ERROR,
+
+ /** Transfer timed out */
+ LIBUSB20_TRANSFER_TIMED_OUT,
+
+ /** Transfer was cancelled */
+ LIBUSB20_TRANSFER_CANCELLED,
+
+ /** For bulk/interrupt endpoints: halt condition detected
+ * (endpoint stalled). For control endpoints: control request
+ * not supported. */
+ LIBUSB20_TRANSFER_STALL,
+
+ /** Device was disconnected */
+ LIBUSB20_TRANSFER_NO_DEVICE,
+
+ /** Device sent more data than requested */
+ LIBUSB20_TRANSFER_OVERFLOW,
+};
+
+/** \ingroup asyncio
+ * libusb20_tr_set_flags() values */
+enum libusb20_transfer_flags {
+ /** Report a short frame as error */
+ LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK = 0x0001,
+
+ /** Multiple short frames are not allowed */
+ LIBUSB20_TRANSFER_MULTI_SHORT_NOT_OK = 0x0002,
+
+ /** All transmitted frames are short terminated */
+ LIBUSB20_TRANSFER_FORCE_SHORT = 0x0004,
+
+ /** Will do a clear-stall before xfer */
+ LIBUSB20_TRANSFER_DO_CLEAR_STALL = 0x0008,
+};
+
+/** \ingroup misc
+ * libusb20_dev_get_mode() values
+ */
+enum libusb20_device_mode {
+ LIBUSB20_MODE_HOST, /* default */
+ LIBUSB20_MODE_DEVICE,
+};
+
+/** \ingroup misc
+ * libusb20_dev_get_speed() values
+ */
+enum {
+ LIBUSB20_SPEED_UNKNOWN, /* default */
+ LIBUSB20_SPEED_LOW,
+ LIBUSB20_SPEED_FULL,
+ LIBUSB20_SPEED_HIGH,
+ LIBUSB20_SPEED_VARIABLE,
+ LIBUSB20_SPEED_SUPER,
+};
+
+/** \ingroup misc
+ * libusb20_dev_set_power() values
+ */
+enum {
+ LIBUSB20_POWER_OFF,
+ LIBUSB20_POWER_ON,
+ LIBUSB20_POWER_SAVE,
+ LIBUSB20_POWER_SUSPEND,
+ LIBUSB20_POWER_RESUME,
+};
+
+struct usb_device_info;
+struct libusb20_transfer;
+struct libusb20_backend;
+struct libusb20_backend_methods;
+struct libusb20_device;
+struct libusb20_device_methods;
+struct libusb20_config;
+struct LIBUSB20_CONTROL_SETUP_DECODED;
+struct LIBUSB20_DEVICE_DESC_DECODED;
+
+typedef void (libusb20_tr_callback_t)(struct libusb20_transfer *xfer);
+
+struct libusb20_quirk {
+ uint16_t vid; /* vendor ID */
+ uint16_t pid; /* product ID */
+ uint16_t bcdDeviceLow; /* low revision value, inclusive */
+ uint16_t bcdDeviceHigh; /* high revision value, inclusive */
+ uint16_t reserved[2]; /* for the future */
+ /* quirk name, UQ_XXX, including terminating zero */
+ char quirkname[64 - 12];
+};
+
+#define LIBUSB20_MAX_FRAME_PRE_SCALE (1U << 31)
+
+/* USB transfer operations */
+int libusb20_tr_close(struct libusb20_transfer *xfer);
+int libusb20_tr_open(struct libusb20_transfer *xfer, uint32_t max_buf_size, uint32_t max_frame_count, uint8_t ep_no);
+struct libusb20_transfer *libusb20_tr_get_pointer(struct libusb20_device *pdev, uint16_t tr_index);
+uint16_t libusb20_tr_get_time_complete(struct libusb20_transfer *xfer);
+uint32_t libusb20_tr_get_actual_frames(struct libusb20_transfer *xfer);
+uint32_t libusb20_tr_get_actual_length(struct libusb20_transfer *xfer);
+uint32_t libusb20_tr_get_max_frames(struct libusb20_transfer *xfer);
+uint32_t libusb20_tr_get_max_packet_length(struct libusb20_transfer *xfer);
+uint32_t libusb20_tr_get_max_total_length(struct libusb20_transfer *xfer);
+uint8_t libusb20_tr_get_status(struct libusb20_transfer *xfer);
+uint8_t libusb20_tr_pending(struct libusb20_transfer *xfer);
+void libusb20_tr_callback_wrapper(struct libusb20_transfer *xfer);
+void libusb20_tr_clear_stall_sync(struct libusb20_transfer *xfer);
+void libusb20_tr_drain(struct libusb20_transfer *xfer);
+void libusb20_tr_set_buffer(struct libusb20_transfer *xfer, void *buffer, uint16_t fr_index);
+void libusb20_tr_set_callback(struct libusb20_transfer *xfer, libusb20_tr_callback_t *cb);
+void libusb20_tr_set_flags(struct libusb20_transfer *xfer, uint8_t flags);
+uint32_t libusb20_tr_get_length(struct libusb20_transfer *xfer, uint16_t fr_index);
+void libusb20_tr_set_length(struct libusb20_transfer *xfer, uint32_t length, uint16_t fr_index);
+void libusb20_tr_set_priv_sc0(struct libusb20_transfer *xfer, void *sc0);
+void libusb20_tr_set_priv_sc1(struct libusb20_transfer *xfer, void *sc1);
+void libusb20_tr_set_timeout(struct libusb20_transfer *xfer, uint32_t timeout);
+void libusb20_tr_set_total_frames(struct libusb20_transfer *xfer, uint32_t nFrames);
+void libusb20_tr_setup_bulk(struct libusb20_transfer *xfer, void *pbuf, uint32_t length, uint32_t timeout);
+void libusb20_tr_setup_control(struct libusb20_transfer *xfer, void *psetup, void *pbuf, uint32_t timeout);
+void libusb20_tr_setup_intr(struct libusb20_transfer *xfer, void *pbuf, uint32_t length, uint32_t timeout);
+void libusb20_tr_setup_isoc(struct libusb20_transfer *xfer, void *pbuf, uint32_t length, uint16_t fr_index);
+uint8_t libusb20_tr_bulk_intr_sync(struct libusb20_transfer *xfer, void *pbuf, uint32_t length, uint32_t *pactlen, uint32_t timeout);
+void libusb20_tr_start(struct libusb20_transfer *xfer);
+void libusb20_tr_stop(struct libusb20_transfer *xfer);
+void libusb20_tr_submit(struct libusb20_transfer *xfer);
+void *libusb20_tr_get_priv_sc0(struct libusb20_transfer *xfer);
+void *libusb20_tr_get_priv_sc1(struct libusb20_transfer *xfer);
+
+
+/* USB device operations */
+
+const char *libusb20_dev_get_backend_name(struct libusb20_device *pdev);
+const char *libusb20_dev_get_desc(struct libusb20_device *pdev);
+int libusb20_dev_close(struct libusb20_device *pdev);
+int libusb20_dev_detach_kernel_driver(struct libusb20_device *pdev, uint8_t iface_index);
+int libusb20_dev_set_config_index(struct libusb20_device *pdev, uint8_t configIndex);
+int libusb20_dev_get_debug(struct libusb20_device *pdev);
+int libusb20_dev_get_fd(struct libusb20_device *pdev);
+int libusb20_dev_kernel_driver_active(struct libusb20_device *pdev, uint8_t iface_index);
+int libusb20_dev_open(struct libusb20_device *pdev, uint16_t transfer_max);
+int libusb20_dev_process(struct libusb20_device *pdev);
+int libusb20_dev_request_sync(struct libusb20_device *pdev, struct LIBUSB20_CONTROL_SETUP_DECODED *setup, void *data, uint16_t *pactlen, uint32_t timeout, uint8_t flags);
+int libusb20_dev_req_string_sync(struct libusb20_device *pdev, uint8_t index, uint16_t langid, void *ptr, uint16_t len);
+int libusb20_dev_req_string_simple_sync(struct libusb20_device *pdev, uint8_t index, void *ptr, uint16_t len);
+int libusb20_dev_reset(struct libusb20_device *pdev);
+int libusb20_dev_check_connected(struct libusb20_device *pdev);
+int libusb20_dev_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode);
+uint8_t libusb20_dev_get_power_mode(struct libusb20_device *pdev);
+int libusb20_dev_set_alt_index(struct libusb20_device *pdev, uint8_t iface_index, uint8_t alt_index);
+int libusb20_dev_get_info(struct libusb20_device *pdev, struct usb_device_info *pinfo);
+int libusb20_dev_get_iface_desc(struct libusb20_device *pdev, uint8_t iface_index, char *buf, uint8_t len);
+
+struct LIBUSB20_DEVICE_DESC_DECODED *libusb20_dev_get_device_desc(struct libusb20_device *pdev);
+struct libusb20_config *libusb20_dev_alloc_config(struct libusb20_device *pdev, uint8_t config_index);
+struct libusb20_device *libusb20_dev_alloc(void);
+uint8_t libusb20_dev_get_address(struct libusb20_device *pdev);
+uint8_t libusb20_dev_get_parent_address(struct libusb20_device *pdev);
+uint8_t libusb20_dev_get_parent_port(struct libusb20_device *pdev);
+uint8_t libusb20_dev_get_bus_number(struct libusb20_device *pdev);
+uint8_t libusb20_dev_get_mode(struct libusb20_device *pdev);
+uint8_t libusb20_dev_get_speed(struct libusb20_device *pdev);
+uint8_t libusb20_dev_get_config_index(struct libusb20_device *pdev);
+void libusb20_dev_free(struct libusb20_device *pdev);
+void libusb20_dev_set_debug(struct libusb20_device *pdev, int debug);
+void libusb20_dev_wait_process(struct libusb20_device *pdev, int timeout);
+
+/* USB global operations */
+
+int libusb20_be_get_dev_quirk(struct libusb20_backend *pbe, uint16_t index, struct libusb20_quirk *pq);
+int libusb20_be_get_quirk_name(struct libusb20_backend *pbe, uint16_t index, struct libusb20_quirk *pq);
+int libusb20_be_add_dev_quirk(struct libusb20_backend *pbe, struct libusb20_quirk *pq);
+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);
+
+/* USB backend operations */
+
+struct libusb20_backend *libusb20_be_alloc(const struct libusb20_backend_methods *methods);
+struct libusb20_backend *libusb20_be_alloc_default(void);
+struct libusb20_backend *libusb20_be_alloc_freebsd(void);
+struct libusb20_backend *libusb20_be_alloc_linux(void);
+struct libusb20_backend *libusb20_be_alloc_ugen20(void);
+struct libusb20_device *libusb20_be_device_foreach(struct libusb20_backend *pbe, struct libusb20_device *pdev);
+void libusb20_be_dequeue_device(struct libusb20_backend *pbe, struct libusb20_device *pdev);
+void libusb20_be_enqueue_device(struct libusb20_backend *pbe, struct libusb20_device *pdev);
+void libusb20_be_free(struct libusb20_backend *pbe);
+
+/* USB debugging */
+
+const char *libusb20_strerror(int);
+const char *libusb20_error_name(int);
+
+#if 0
+{ /* style */
+#endif
+#ifdef __cplusplus
+}
+
+#endif
+
+#endif /* _LIBUSB20_H_ */
diff --git a/lib/libusb/libusb20_desc.c b/lib/libusb/libusb20_desc.c
new file mode 100644
index 0000000..0781067
--- /dev/null
+++ b/lib/libusb/libusb20_desc.c
@@ -0,0 +1,792 @@
+/* $FreeBSD$ */
+/*-
+ * Copyright (c) 2008 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.
+ */
+
+#include <sys/queue.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libusb20.h"
+#include "libusb20_desc.h"
+#include "libusb20_int.h"
+
+static const uint32_t libusb20_me_encode_empty[2]; /* dummy */
+
+LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_DEVICE_DESC);
+LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_ENDPOINT_DESC);
+LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_INTERFACE_DESC);
+LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_CONFIG_DESC);
+LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_CONTROL_SETUP);
+LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_SS_ENDPT_COMP_DESC);
+LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_USB_20_DEVCAP_DESC);
+LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_SS_USB_DEVCAP_DESC);
+LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_BOS_DESCRIPTOR);
+
+/*------------------------------------------------------------------------*
+ * libusb20_parse_config_desc
+ *
+ * Return values:
+ * NULL: Out of memory.
+ * Else: A valid config structure pointer which must be passed to "free()"
+ *------------------------------------------------------------------------*/
+struct libusb20_config *
+libusb20_parse_config_desc(const void *config_desc)
+{
+ struct libusb20_config *lub_config;
+ struct libusb20_interface *lub_interface;
+ struct libusb20_interface *lub_alt_interface;
+ struct libusb20_interface *last_if;
+ struct libusb20_endpoint *lub_endpoint;
+ struct libusb20_endpoint *last_ep;
+
+ struct libusb20_me_struct pcdesc;
+ const uint8_t *ptr;
+ uint32_t size;
+ uint16_t niface_no_alt;
+ uint16_t niface;
+ uint16_t nendpoint;
+ uint8_t iface_no;
+
+ ptr = config_desc;
+ if (ptr[1] != LIBUSB20_DT_CONFIG) {
+ return (NULL); /* not config descriptor */
+ }
+ /*
+ * The first "bInterfaceNumber" should never have the value 0xff.
+ * Then it is corrupt.
+ */
+ niface_no_alt = 0;
+ nendpoint = 0;
+ niface = 0;
+ iface_no = 0 - 1;
+ ptr = NULL;
+
+ /* get "wTotalLength" and setup "pcdesc" */
+ pcdesc.ptr = LIBUSB20_ADD_BYTES(config_desc, 0);
+ pcdesc.len =
+ ((const uint8_t *)config_desc)[2] |
+ (((const uint8_t *)config_desc)[3] << 8);
+ pcdesc.type = LIBUSB20_ME_IS_RAW;
+
+ /* descriptor pre-scan */
+ while ((ptr = libusb20_desc_foreach(&pcdesc, ptr))) {
+ if (ptr[1] == LIBUSB20_DT_ENDPOINT) {
+ nendpoint++;
+ } else if ((ptr[1] == LIBUSB20_DT_INTERFACE) && (ptr[0] >= 4)) {
+ niface++;
+ /* check "bInterfaceNumber" */
+ if (ptr[2] != iface_no) {
+ iface_no = ptr[2];
+ niface_no_alt++;
+ }
+ }
+ }
+
+ /* sanity checking */
+ if (niface >= 256) {
+ return (NULL); /* corrupt */
+ }
+ if (nendpoint >= 256) {
+ return (NULL); /* corrupt */
+ }
+ size = sizeof(*lub_config) +
+ (niface * sizeof(*lub_interface)) +
+ (nendpoint * sizeof(*lub_endpoint)) +
+ pcdesc.len;
+
+ lub_config = malloc(size);
+ if (lub_config == NULL) {
+ return (NULL); /* out of memory */
+ }
+ /* make sure memory is initialised */
+ memset(lub_config, 0, size);
+
+ lub_interface = (void *)(lub_config + 1);
+ lub_alt_interface = (void *)(lub_interface + niface_no_alt);
+ lub_endpoint = (void *)(lub_interface + niface);
+
+ /*
+ * Make a copy of the config descriptor, so that the caller can free
+ * the inital config descriptor pointer!
+ */
+ ptr = (void *)(lub_endpoint + nendpoint);
+ memcpy(LIBUSB20_ADD_BYTES(ptr, 0), config_desc, pcdesc.len);
+ pcdesc.ptr = LIBUSB20_ADD_BYTES(ptr, 0);
+ config_desc = LIBUSB20_ADD_BYTES(ptr, 0);
+
+ /* init config structure */
+
+ ptr = config_desc;
+
+ LIBUSB20_INIT(LIBUSB20_CONFIG_DESC, &lub_config->desc);
+
+ if (libusb20_me_decode(ptr, ptr[0], &lub_config->desc)) {
+ /* ignore */
+ }
+ lub_config->num_interface = 0;
+ lub_config->interface = lub_interface;
+ lub_config->extra.ptr = LIBUSB20_ADD_BYTES(ptr, ptr[0]);
+ lub_config->extra.len = -ptr[0];
+ lub_config->extra.type = LIBUSB20_ME_IS_RAW;
+
+ /* reset states */
+ niface = 0;
+ iface_no = 0 - 1;
+ ptr = NULL;
+ lub_interface--;
+ lub_endpoint--;
+ last_if = NULL;
+ last_ep = NULL;
+
+ /* descriptor pre-scan */
+ while ((ptr = libusb20_desc_foreach(&pcdesc, ptr))) {
+ if (ptr[1] == LIBUSB20_DT_ENDPOINT) {
+ if (last_if) {
+ lub_endpoint++;
+ last_ep = lub_endpoint;
+ last_if->num_endpoints++;
+
+ LIBUSB20_INIT(LIBUSB20_ENDPOINT_DESC, &last_ep->desc);
+
+ if (libusb20_me_decode(ptr, ptr[0], &last_ep->desc)) {
+ /* ignore */
+ }
+ last_ep->extra.ptr = LIBUSB20_ADD_BYTES(ptr, ptr[0]);
+ last_ep->extra.len = 0;
+ last_ep->extra.type = LIBUSB20_ME_IS_RAW;
+ } else {
+ lub_config->extra.len += ptr[0];
+ }
+
+ } else if ((ptr[1] == LIBUSB20_DT_INTERFACE) && (ptr[0] >= 4)) {
+ if (ptr[2] != iface_no) {
+ /* new interface */
+ iface_no = ptr[2];
+ lub_interface++;
+ lub_config->num_interface++;
+ last_if = lub_interface;
+ niface++;
+ } else {
+ /* one more alternate setting */
+ lub_interface->num_altsetting++;
+ last_if = lub_alt_interface;
+ lub_alt_interface++;
+ }
+
+ LIBUSB20_INIT(LIBUSB20_INTERFACE_DESC, &last_if->desc);
+
+ if (libusb20_me_decode(ptr, ptr[0], &last_if->desc)) {
+ /* ignore */
+ }
+ /*
+ * Sometimes USB devices have corrupt interface
+ * descriptors and we need to overwrite the provided
+ * interface number!
+ */
+ last_if->desc.bInterfaceNumber = niface - 1;
+ last_if->extra.ptr = LIBUSB20_ADD_BYTES(ptr, ptr[0]);
+ last_if->extra.len = 0;
+ last_if->extra.type = LIBUSB20_ME_IS_RAW;
+ last_if->endpoints = lub_endpoint + 1;
+ last_if->altsetting = lub_alt_interface;
+ last_if->num_altsetting = 0;
+ last_if->num_endpoints = 0;
+ last_ep = NULL;
+ } else {
+ /* unknown descriptor */
+ if (last_if) {
+ if (last_ep) {
+ last_ep->extra.len += ptr[0];
+ } else {
+ last_if->extra.len += ptr[0];
+ }
+ } else {
+ lub_config->extra.len += ptr[0];
+ }
+ }
+ }
+ return (lub_config);
+}
+
+/*------------------------------------------------------------------------*
+ * libusb20_desc_foreach
+ *
+ * Safe traversal of USB descriptors.
+ *
+ * Return values:
+ * NULL: End of descriptors
+ * Else: Pointer to next descriptor
+ *------------------------------------------------------------------------*/
+const uint8_t *
+libusb20_desc_foreach(const struct libusb20_me_struct *pdesc,
+ const uint8_t *psubdesc)
+{
+ const uint8_t *start;
+ const uint8_t *end;
+ const uint8_t *desc_next;
+
+ /* be NULL safe */
+ if (pdesc == NULL)
+ return (NULL);
+
+ start = (const uint8_t *)pdesc->ptr;
+ end = LIBUSB20_ADD_BYTES(start, pdesc->len);
+
+ /* get start of next descriptor */
+ if (psubdesc == NULL)
+ psubdesc = start;
+ else
+ psubdesc = psubdesc + psubdesc[0];
+
+ /* check that the next USB descriptor is within the range */
+ if ((psubdesc < start) || (psubdesc >= end))
+ return (NULL); /* out of range, or EOD */
+
+ /* check start of the second next USB descriptor, if any */
+ desc_next = psubdesc + psubdesc[0];
+ if ((desc_next < start) || (desc_next > end))
+ return (NULL); /* out of range */
+
+ /* check minimum descriptor length */
+ if (psubdesc[0] < 3)
+ return (NULL); /* too short descriptor */
+
+ return (psubdesc); /* return start of next descriptor */
+}
+
+/*------------------------------------------------------------------------*
+ * libusb20_me_get_1 - safety wrapper to read out one byte
+ *------------------------------------------------------------------------*/
+uint8_t
+libusb20_me_get_1(const struct libusb20_me_struct *ie, uint16_t offset)
+{
+ if (offset < ie->len) {
+ return (*((uint8_t *)LIBUSB20_ADD_BYTES(ie->ptr, offset)));
+ }
+ return (0);
+}
+
+/*------------------------------------------------------------------------*
+ * libusb20_me_get_2 - safety wrapper to read out one word
+ *------------------------------------------------------------------------*/
+uint16_t
+libusb20_me_get_2(const struct libusb20_me_struct *ie, uint16_t offset)
+{
+ return (libusb20_me_get_1(ie, offset) |
+ (libusb20_me_get_1(ie, offset + 1) << 8));
+}
+
+/*------------------------------------------------------------------------*
+ * libusb20_me_encode - encode a message structure
+ *
+ * Description of parameters:
+ * "len" - maximum length of output buffer
+ * "ptr" - pointer to output buffer. If NULL, no data will be written
+ * "pd" - source structure
+ *
+ * Return values:
+ * 0..65535 - Number of bytes used, limited by the "len" input parameter.
+ *------------------------------------------------------------------------*/
+uint16_t
+libusb20_me_encode(void *ptr, uint16_t len, const void *pd)
+{
+ const uint8_t *pf; /* pointer to format data */
+ uint8_t *buf; /* pointer to output buffer */
+
+ uint32_t pd_offset; /* decoded structure offset */
+ uint16_t len_old; /* old length */
+ uint16_t pd_count; /* decoded element count */
+ uint8_t me; /* message element */
+
+ /* initialise */
+
+ len_old = len;
+ buf = ptr;
+ pd_offset = sizeof(void *);
+ pf = (*((struct libusb20_me_format *const *)pd))->format;
+
+ /* scan */
+
+ while (1) {
+
+ /* get information element */
+
+ me = (pf[0]) & LIBUSB20_ME_MASK;
+ pd_count = pf[1] | (pf[2] << 8);
+ pf += 3;
+
+ /* encode the message element */
+
+ switch (me) {
+ case LIBUSB20_ME_INT8:
+ while (pd_count--) {
+ uint8_t temp;
+
+ if (len < 1) /* overflow */
+ goto done;
+ if (buf) {
+ temp = *((const uint8_t *)
+ LIBUSB20_ADD_BYTES(pd, pd_offset));
+ buf[0] = temp;
+ buf += 1;
+ }
+ pd_offset += 1;
+ len -= 1;
+ }
+ break;
+
+ case LIBUSB20_ME_INT16:
+ pd_offset = -((-pd_offset) & ~1); /* align */
+ while (pd_count--) {
+ uint16_t temp;
+
+ if (len < 2) /* overflow */
+ goto done;
+
+ if (buf) {
+ temp = *((const uint16_t *)
+ LIBUSB20_ADD_BYTES(pd, pd_offset));
+ buf[1] = (temp >> 8) & 0xFF;
+ buf[0] = temp & 0xFF;
+ buf += 2;
+ }
+ pd_offset += 2;
+ len -= 2;
+ }
+ break;
+
+ case LIBUSB20_ME_INT32:
+ pd_offset = -((-pd_offset) & ~3); /* align */
+ while (pd_count--) {
+ uint32_t temp;
+
+ if (len < 4) /* overflow */
+ goto done;
+ if (buf) {
+ temp = *((const uint32_t *)
+ LIBUSB20_ADD_BYTES(pd, pd_offset));
+ buf[3] = (temp >> 24) & 0xFF;
+ buf[2] = (temp >> 16) & 0xFF;
+ buf[1] = (temp >> 8) & 0xFF;
+ buf[0] = temp & 0xFF;
+ buf += 4;
+ }
+ pd_offset += 4;
+ len -= 4;
+ }
+ break;
+
+ case LIBUSB20_ME_INT64:
+ pd_offset = -((-pd_offset) & ~7); /* align */
+ while (pd_count--) {
+ uint64_t temp;
+
+ if (len < 8) /* overflow */
+ goto done;
+ if (buf) {
+
+ temp = *((const uint64_t *)
+ LIBUSB20_ADD_BYTES(pd, pd_offset));
+ buf[7] = (temp >> 56) & 0xFF;
+ buf[6] = (temp >> 48) & 0xFF;
+ buf[5] = (temp >> 40) & 0xFF;
+ buf[4] = (temp >> 32) & 0xFF;
+ buf[3] = (temp >> 24) & 0xFF;
+ buf[2] = (temp >> 16) & 0xFF;
+ buf[1] = (temp >> 8) & 0xFF;
+ buf[0] = temp & 0xFF;
+ buf += 8;
+ }
+ pd_offset += 8;
+ len -= 8;
+ }
+ break;
+
+ case LIBUSB20_ME_STRUCT:
+ pd_offset = -((-pd_offset) &
+ ~(LIBUSB20_ME_STRUCT_ALIGN - 1)); /* align */
+ while (pd_count--) {
+ void *src_ptr;
+ uint16_t src_len;
+ struct libusb20_me_struct *ps;
+
+ ps = LIBUSB20_ADD_BYTES(pd, pd_offset);
+
+ switch (ps->type) {
+ case LIBUSB20_ME_IS_RAW:
+ src_len = ps->len;
+ src_ptr = ps->ptr;
+ break;
+
+ case LIBUSB20_ME_IS_ENCODED:
+ if (ps->len == 0) {
+ /*
+ * Length is encoded
+ * in the data itself
+ * and should be
+ * correct:
+ */
+ ps->len = 0 - 1;
+ }
+ src_len = libusb20_me_get_1(pd, 0);
+ src_ptr = LIBUSB20_ADD_BYTES(ps->ptr, 1);
+ if (src_len == 0xFF) {
+ /* length is escaped */
+ src_len = libusb20_me_get_2(pd, 1);
+ src_ptr =
+ LIBUSB20_ADD_BYTES(ps->ptr, 3);
+ }
+ break;
+
+ case LIBUSB20_ME_IS_DECODED:
+ /* reserve 3 length bytes */
+ src_len = libusb20_me_encode(NULL,
+ 0 - 1 - 3, ps->ptr);
+ src_ptr = NULL;
+ break;
+
+ default: /* empty structure */
+ src_len = 0;
+ src_ptr = NULL;
+ break;
+ }
+
+ if (src_len > 0xFE) {
+ if (src_len > (uint16_t)(0 - 1 - 3))
+ /* overflow */
+ goto done;
+
+ if (len < (src_len + 3))
+ /* overflow */
+ goto done;
+
+ if (buf) {
+ buf[0] = 0xFF;
+ buf[1] = (src_len & 0xFF);
+ buf[2] = (src_len >> 8) & 0xFF;
+ buf += 3;
+ }
+ len -= (src_len + 3);
+ } else {
+ if (len < (src_len + 1))
+ /* overflow */
+ goto done;
+
+ if (buf) {
+ buf[0] = (src_len & 0xFF);
+ buf += 1;
+ }
+ len -= (src_len + 1);
+ }
+
+ /* check for buffer and non-zero length */
+
+ if (buf && src_len) {
+ if (ps->type == LIBUSB20_ME_IS_DECODED) {
+ /*
+ * Repeat encode
+ * procedure - we have
+ * room for the
+ * complete structure:
+ */
+ uint16_t dummy;
+
+ dummy = libusb20_me_encode(buf,
+ 0 - 1 - 3, ps->ptr);
+ } else {
+ bcopy(src_ptr, buf, src_len);
+ }
+ buf += src_len;
+ }
+ pd_offset += sizeof(struct libusb20_me_struct);
+ }
+ break;
+
+ default:
+ goto done;
+ }
+ }
+done:
+ return (len_old - len);
+}
+
+/*------------------------------------------------------------------------*
+ * libusb20_me_decode - decode a message into a decoded structure
+ *
+ * Description of parameters:
+ * "ptr" - message pointer
+ * "len" - message length
+ * "pd" - pointer to decoded structure
+ *
+ * Returns:
+ * "0..65535" - number of bytes decoded, limited by "len"
+ *------------------------------------------------------------------------*/
+uint16_t
+libusb20_me_decode(const void *ptr, uint16_t len, void *pd)
+{
+ const uint8_t *pf; /* pointer to format data */
+ const uint8_t *buf; /* pointer to input buffer */
+
+ uint32_t pd_offset; /* decoded structure offset */
+ uint16_t len_old; /* old length */
+ uint16_t pd_count; /* decoded element count */
+ uint8_t me; /* message element */
+
+ /* initialise */
+
+ len_old = len;
+ buf = ptr;
+ pd_offset = sizeof(void *);
+ pf = (*((struct libusb20_me_format **)pd))->format;
+
+ /* scan */
+
+ while (1) {
+
+ /* get information element */
+
+ me = (pf[0]) & LIBUSB20_ME_MASK;
+ pd_count = pf[1] | (pf[2] << 8);
+ pf += 3;
+
+ /* decode the message element by type */
+
+ switch (me) {
+ case LIBUSB20_ME_INT8:
+ while (pd_count--) {
+ uint8_t temp;
+
+ if (len < 1) {
+ len = 0;
+ temp = 0;
+ } else {
+ len -= 1;
+ temp = buf[0];
+ buf++;
+ }
+ *((uint8_t *)LIBUSB20_ADD_BYTES(pd,
+ pd_offset)) = temp;
+ pd_offset += 1;
+ }
+ break;
+
+ case LIBUSB20_ME_INT16:
+ pd_offset = -((-pd_offset) & ~1); /* align */
+ while (pd_count--) {
+ uint16_t temp;
+
+ if (len < 2) {
+ len = 0;
+ temp = 0;
+ } else {
+ len -= 2;
+ temp = buf[1] << 8;
+ temp |= buf[0];
+ buf += 2;
+ }
+ *((uint16_t *)LIBUSB20_ADD_BYTES(pd,
+ pd_offset)) = temp;
+ pd_offset += 2;
+ }
+ break;
+
+ case LIBUSB20_ME_INT32:
+ pd_offset = -((-pd_offset) & ~3); /* align */
+ while (pd_count--) {
+ uint32_t temp;
+
+ if (len < 4) {
+ len = 0;
+ temp = 0;
+ } else {
+ len -= 4;
+ temp = buf[3] << 24;
+ temp |= buf[2] << 16;
+ temp |= buf[1] << 8;
+ temp |= buf[0];
+ buf += 4;
+ }
+
+ *((uint32_t *)LIBUSB20_ADD_BYTES(pd,
+ pd_offset)) = temp;
+ pd_offset += 4;
+ }
+ break;
+
+ case LIBUSB20_ME_INT64:
+ pd_offset = -((-pd_offset) & ~7); /* align */
+ while (pd_count--) {
+ uint64_t temp;
+
+ if (len < 8) {
+ len = 0;
+ temp = 0;
+ } else {
+ len -= 8;
+ temp = ((uint64_t)buf[7]) << 56;
+ temp |= ((uint64_t)buf[6]) << 48;
+ temp |= ((uint64_t)buf[5]) << 40;
+ temp |= ((uint64_t)buf[4]) << 32;
+ temp |= buf[3] << 24;
+ temp |= buf[2] << 16;
+ temp |= buf[1] << 8;
+ temp |= buf[0];
+ buf += 8;
+ }
+
+ *((uint64_t *)LIBUSB20_ADD_BYTES(pd,
+ pd_offset)) = temp;
+ pd_offset += 8;
+ }
+ break;
+
+ case LIBUSB20_ME_STRUCT:
+ pd_offset = -((-pd_offset) &
+ ~(LIBUSB20_ME_STRUCT_ALIGN - 1)); /* align */
+ while (pd_count--) {
+ uint16_t temp;
+ uint16_t dummy;
+ struct libusb20_me_struct *ps;
+
+ ps = LIBUSB20_ADD_BYTES(pd, pd_offset);
+
+ if (ps->type == LIBUSB20_ME_IS_ENCODED) {
+ /*
+ * Pre-store a de-constified
+ * pointer to the raw
+ * structure:
+ */
+ ps->ptr = LIBUSB20_ADD_BYTES(buf, 0);
+
+ /*
+ * Get the correct number of
+ * length bytes:
+ */
+ if (len != 0) {
+ if (buf[0] == 0xFF) {
+ ps->len = 3;
+ } else {
+ ps->len = 1;
+ }
+ } else {
+ ps->len = 0;
+ }
+ }
+ /* get the structure length */
+
+ if (len != 0) {
+ if (buf[0] == 0xFF) {
+ if (len < 3) {
+ len = 0;
+ temp = 0;
+ } else {
+ len -= 3;
+ temp = buf[1] |
+ (buf[2] << 8);
+ buf += 3;
+ }
+ } else {
+ len -= 1;
+ temp = buf[0];
+ buf += 1;
+ }
+ } else {
+ len = 0;
+ temp = 0;
+ }
+ /* check for invalid length */
+
+ if (temp > len) {
+ len = 0;
+ temp = 0;
+ }
+ /* check wanted structure type */
+
+ switch (ps->type) {
+ case LIBUSB20_ME_IS_ENCODED:
+ /* check for zero length */
+ if (temp == 0) {
+ /*
+ * The pointer must
+ * be valid:
+ */
+ ps->ptr = LIBUSB20_ADD_BYTES(
+ libusb20_me_encode_empty, 0);
+ ps->len = 1;
+ } else {
+ ps->len += temp;
+ }
+ break;
+
+ case LIBUSB20_ME_IS_RAW:
+ /* update length and pointer */
+ ps->len = temp;
+ ps->ptr = LIBUSB20_ADD_BYTES(buf, 0);
+ break;
+
+ case LIBUSB20_ME_IS_EMPTY:
+ case LIBUSB20_ME_IS_DECODED:
+ /* check for non-zero length */
+ if (temp != 0) {
+ /* update type */
+ ps->type = LIBUSB20_ME_IS_DECODED;
+ ps->len = 0;
+ /*
+ * Recursivly decode
+ * the next structure
+ */
+ dummy = libusb20_me_decode(buf,
+ temp, ps->ptr);
+ } else {
+ /* update type */
+ ps->type = LIBUSB20_ME_IS_EMPTY;
+ ps->len = 0;
+ }
+ break;
+
+ default:
+ /*
+ * nothing to do - should
+ * not happen
+ */
+ ps->ptr = NULL;
+ ps->len = 0;
+ break;
+ }
+ buf += temp;
+ len -= temp;
+ pd_offset += sizeof(struct libusb20_me_struct);
+ }
+ break;
+
+ default:
+ goto done;
+ }
+ }
+done:
+ return (len_old - len);
+}
diff --git a/lib/libusb/libusb20_desc.h b/lib/libusb/libusb20_desc.h
new file mode 100644
index 0000000..a069ee9
--- /dev/null
+++ b/lib/libusb/libusb20_desc.h
@@ -0,0 +1,593 @@
+/* $FreeBSD$ */
+/*-
+ * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
+ * Copyright (c) 2007-2008 Daniel Drake. All rights reserved.
+ * Copyright (c) 2001 Johannes Erdfelt. 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.
+ */
+
+/*
+ * NOTE: This file contains the definition of some standard USB
+ * structures. All structures which name ends by *DECODED use host byte
+ * order.
+ */
+
+/*
+ * NOTE: This file uses a lot of macros. If you want to see what the
+ * macros become when they are expanded then run the following
+ * commands from your shell:
+ *
+ * cpp libusb20_desc.h > temp.h
+ * indent temp.h
+ * less temp.h
+ */
+
+#ifndef _LIBUSB20_DESC_H_
+#define _LIBUSB20_DESC_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#if 0
+}; /* style */
+
+#endif
+/* basic macros */
+
+#define LIBUSB20__NOT(...) __VA_ARGS__
+#define LIBUSB20_NOT(arg) LIBUSB20__NOT(LIBUSB20_YES arg(() LIBUSB20_NO))
+#define LIBUSB20_YES(...) __VA_ARGS__
+#define LIBUSB20_NO(...)
+#define LIBUSB20_END(...) __VA_ARGS__
+#define LIBUSB20_MAX(a,b) (((a) > (b)) ? (a) : (b))
+#define LIBUSB20_MIN(a,b) (((a) < (b)) ? (a) : (b))
+
+#define LIBUSB20_ADD_BYTES(ptr,off) \
+ ((void *)(((const uint8_t *)(ptr)) + (off) - ((const uint8_t *)0)))
+
+/* basic message elements */
+enum {
+ LIBUSB20_ME_INT8,
+ LIBUSB20_ME_INT16,
+ LIBUSB20_ME_INT32,
+ LIBUSB20_ME_INT64,
+ LIBUSB20_ME_STRUCT,
+ LIBUSB20_ME_MAX, /* used to indicate end */
+};
+
+/* basic message element modifiers */
+enum {
+ LIBUSB20_ME_IS_UNSIGNED = 0x00,
+ LIBUSB20_ME_IS_SIGNED = 0x80,
+ LIBUSB20_ME_MASK = 0x7F,
+};
+
+enum {
+ LIBUSB20_ME_IS_RAW, /* structure excludes length field
+ * (hardcoded value) */
+ LIBUSB20_ME_IS_ENCODED, /* structure includes length field */
+ LIBUSB20_ME_IS_EMPTY, /* no structure */
+ LIBUSB20_ME_IS_DECODED, /* structure is recursive */
+};
+
+/* basic helper structures and macros */
+
+#define LIBUSB20_ME_STRUCT_ALIGN sizeof(void *)
+
+struct libusb20_me_struct {
+ void *ptr; /* data pointer */
+ uint16_t len; /* defaults to zero */
+ uint16_t type; /* defaults to LIBUSB20_ME_IS_EMPTY */
+} __aligned(LIBUSB20_ME_STRUCT_ALIGN);
+
+struct libusb20_me_format {
+ const uint8_t *format; /* always set */
+ const char *desc; /* optionally set */
+ const char *fields; /* optionally set */
+};
+
+#define LIBUSB20_ME_STRUCT(n, field, arg, ismeta) \
+ ismeta ( LIBUSB20_ME_STRUCT, 1, 0, ) \
+ LIBUSB20_NOT(ismeta) ( struct libusb20_me_struct field; )
+
+#define LIBUSB20_ME_STRUCT_ARRAY(n, field, arg, ismeta) \
+ ismeta ( LIBUSB20_ME_STRUCT , (arg) & 0xFF, \
+ ((arg) / 0x100) & 0xFF, ) \
+ LIBUSB20_NOT(ismeta) ( struct libusb20_me_struct field [arg]; )
+
+#define LIBUSB20_ME_INTEGER(n, field, ismeta, un, u, bits, a, size) \
+ ismeta ( LIBUSB20_ME_INT##bits | \
+ LIBUSB20_ME_IS_##un##SIGNED , \
+ (size) & 0xFF, ((size) / 0x100) & 0xFF, ) \
+ LIBUSB20_NOT(ismeta) ( u##int##bits##_t \
+ __aligned((bits) / 8) field a; )
+
+#define LIBUSB20_ME_UINT8_T(n, field, arg, ismeta) \
+ LIBUSB20_ME_INTEGER(n, field, ismeta, UN, u, 8, , 1)
+
+#define LIBUSB20_ME_UINT8_ARRAY_T(n, field, arg, ismeta) \
+ LIBUSB20_ME_INTEGER(n, field, ismeta, UN, u, 8, [arg], arg)
+
+#define LIBUSB20_ME_SINT8_T(n, field, arg, ismeta) \
+ LIBUSB20_ME_INTEGER(n, field, ismeta,,, 8, , 1)
+
+#define LIBUSB20_ME_SINT8_ARRAY_T(n, field, arg, ismeta) \
+ LIBUSB20_ME_INTEGER(n, field, ismeta,,, 8, [arg], arg)
+
+#define LIBUSB20_ME_UINT16_T(n, field, arg, ismeta) \
+ LIBUSB20_ME_INTEGER(n, field, ismeta, UN, u, 16, , 1)
+
+#define LIBUSB20_ME_UINT16_ARRAY_T(n, field, arg, ismeta) \
+ LIBUSB20_ME_INTEGER(n, field, ismeta, UN, u, 16, [arg], arg)
+
+#define LIBUSB20_ME_SINT16_T(n, field, arg, ismeta) \
+ LIBUSB20_ME_INTEGER(n, field, ismeta,,, 16, , 1)
+
+#define LIBUSB20_ME_SINT16_ARRAY_T(n, field, arg, ismeta) \
+ LIBUSB20_ME_INTEGER(n, field, ismeta,,, 16, [arg], arg)
+
+#define LIBUSB20_ME_UINT32_T(n, field, arg, ismeta) \
+ LIBUSB20_ME_INTEGER(n, field, ismeta, UN, u, 32, , 1)
+
+#define LIBUSB20_ME_UINT32_ARRAY_T(n, field, arg, ismeta) \
+ LIBUSB20_ME_INTEGER(n, field, ismeta, UN, u, 32, [arg], arg)
+
+#define LIBUSB20_ME_SINT32_T(n, field, arg, ismeta) \
+ LIBUSB20_ME_INTEGER(n, field, ismeta,,, 32, , 1)
+
+#define LIBUSB20_ME_SINT32_ARRAY_T(n, field, arg, ismeta) \
+ LIBUSB20_ME_INTEGER(n, field, ismeta,,, 32, [arg], arg)
+
+#define LIBUSB20_ME_UINT64_T(n, field, arg, ismeta) \
+ LIBUSB20_ME_INTEGER(n, field, ismeta, UN, u, 64, , 1)
+
+#define LIBUSB20_ME_UINT64_ARRAY_T(n, field, arg, ismeta) \
+ LIBUSB20_ME_INTEGER(n, field, ismeta, UN, u, 64, [arg], arg)
+
+#define LIBUSB20_ME_SINT64_T(n, field, arg, ismeta) \
+ LIBUSB20_ME_INTEGER(n, field, ismeta,,, 64, , 1)
+
+#define LIBUSB20_ME_SINT64_ARRAY_T(n, field, arg, ismeta) \
+ LIBUSB20_ME_INTEGER(n, field, ismeta,,, 64, [arg], arg)
+
+#define LIBUSB20_MAKE_DECODED_FIELD(n, type, field, arg) \
+ LIBUSB20_ME_##type (n, field, arg, LIBUSB20_NO)
+
+#define LIBUSB20_MAKE_STRUCT(name) \
+ extern const struct libusb20_me_format \
+ name##_FORMAT[1]; \
+ struct name##_DECODED { \
+ const struct libusb20_me_format *name##_FORMAT; \
+ name (LIBUSB20_MAKE_DECODED_FIELD,) \
+ }
+
+#define LIBUSB20_MAKE_STRUCT_FORMAT(name) \
+ const struct libusb20_me_format \
+ name##_FORMAT[1] = {{ \
+ .format = LIBUSB20_MAKE_FORMAT(name), \
+ .desc = #name, \
+ .fields = NULL, \
+ }}
+
+#define LIBUSB20_MAKE_FORMAT_SUB(n, type, field, arg) \
+ LIBUSB20_ME_##type (n, field, arg, LIBUSB20_YES)
+
+#define LIBUSB20_MAKE_FORMAT(what) (const uint8_t []) \
+ { what (LIBUSB20_MAKE_FORMAT_SUB, ) LIBUSB20_ME_MAX, 0, 0 }
+
+#define LIBUSB20_INIT(what, ptr) do { \
+ memset(ptr, 0, sizeof(*(ptr))); \
+ (ptr)->what##_FORMAT = what##_FORMAT; \
+} while (0)
+
+#define LIBUSB20_DEVICE_DESC(m,n) \
+ m(n, UINT8_T, bLength, ) \
+ m(n, UINT8_T, bDescriptorType, ) \
+ m(n, UINT16_T, bcdUSB, ) \
+ m(n, UINT8_T, bDeviceClass, ) \
+ m(n, UINT8_T, bDeviceSubClass, ) \
+ m(n, UINT8_T, bDeviceProtocol, ) \
+ m(n, UINT8_T, bMaxPacketSize0, ) \
+ m(n, UINT16_T, idVendor, ) \
+ m(n, UINT16_T, idProduct, ) \
+ m(n, UINT16_T, bcdDevice, ) \
+ m(n, UINT8_T, iManufacturer, ) \
+ m(n, UINT8_T, iProduct, ) \
+ m(n, UINT8_T, iSerialNumber, ) \
+ m(n, UINT8_T, bNumConfigurations, ) \
+
+LIBUSB20_MAKE_STRUCT(LIBUSB20_DEVICE_DESC);
+
+#define LIBUSB20_ENDPOINT_DESC(m,n) \
+ m(n, UINT8_T, bLength, ) \
+ m(n, UINT8_T, bDescriptorType, ) \
+ m(n, UINT8_T, bEndpointAddress, ) \
+ m(n, UINT8_T, bmAttributes, ) \
+ m(n, UINT16_T, wMaxPacketSize, ) \
+ m(n, UINT8_T, bInterval, ) \
+ m(n, UINT8_T, bRefresh, ) \
+ m(n, UINT8_T, bSynchAddress, ) \
+
+LIBUSB20_MAKE_STRUCT(LIBUSB20_ENDPOINT_DESC);
+
+#define LIBUSB20_INTERFACE_DESC(m,n) \
+ m(n, UINT8_T, bLength, ) \
+ m(n, UINT8_T, bDescriptorType, ) \
+ m(n, UINT8_T, bInterfaceNumber, ) \
+ m(n, UINT8_T, bAlternateSetting, ) \
+ m(n, UINT8_T, bNumEndpoints, ) \
+ m(n, UINT8_T, bInterfaceClass, ) \
+ m(n, UINT8_T, bInterfaceSubClass, ) \
+ m(n, UINT8_T, bInterfaceProtocol, ) \
+ m(n, UINT8_T, iInterface, ) \
+
+LIBUSB20_MAKE_STRUCT(LIBUSB20_INTERFACE_DESC);
+
+#define LIBUSB20_CONFIG_DESC(m,n) \
+ m(n, UINT8_T, bLength, ) \
+ m(n, UINT8_T, bDescriptorType, ) \
+ m(n, UINT16_T, wTotalLength, ) \
+ m(n, UINT8_T, bNumInterfaces, ) \
+ m(n, UINT8_T, bConfigurationValue, ) \
+ m(n, UINT8_T, iConfiguration, ) \
+ m(n, UINT8_T, bmAttributes, ) \
+ m(n, UINT8_T, bMaxPower, ) \
+
+LIBUSB20_MAKE_STRUCT(LIBUSB20_CONFIG_DESC);
+
+#define LIBUSB20_CONTROL_SETUP(m,n) \
+ m(n, UINT8_T, bmRequestType, ) \
+ m(n, UINT8_T, bRequest, ) \
+ m(n, UINT16_T, wValue, ) \
+ m(n, UINT16_T, wIndex, ) \
+ m(n, UINT16_T, wLength, ) \
+
+LIBUSB20_MAKE_STRUCT(LIBUSB20_CONTROL_SETUP);
+
+#define LIBUSB20_SS_ENDPT_COMP_DESC(m,n) \
+ m(n, UINT8_T, bLength, ) \
+ m(n, UINT8_T, bDescriptorType, ) \
+ m(n, UINT8_T, bMaxBurst, ) \
+ m(n, UINT8_T, bmAttributes, ) \
+ m(n, UINT16_T, wBytesPerInterval, ) \
+
+LIBUSB20_MAKE_STRUCT(LIBUSB20_SS_ENDPT_COMP_DESC);
+
+#define LIBUSB20_USB_20_DEVCAP_DESC(m,n) \
+ m(n, UINT8_T, bLength, ) \
+ m(n, UINT8_T, bDescriptorType, ) \
+ m(n, UINT8_T, bDevCapabilityType, ) \
+ m(n, UINT32_T, bmAttributes, ) \
+
+LIBUSB20_MAKE_STRUCT(LIBUSB20_USB_20_DEVCAP_DESC);
+
+#define LIBUSB20_SS_USB_DEVCAP_DESC(m,n) \
+ m(n, UINT8_T, bLength, ) \
+ m(n, UINT8_T, bDescriptorType, ) \
+ m(n, UINT8_T, bDevCapabilityType, ) \
+ m(n, UINT8_T, bmAttributes, ) \
+ m(n, UINT16_T, wSpeedSupported, ) \
+ m(n, UINT8_T, bFunctionalitySupport, ) \
+ m(n, UINT8_T, bU1DevExitLat, ) \
+ m(n, UINT16_T, wU2DevExitLat, ) \
+
+LIBUSB20_MAKE_STRUCT(LIBUSB20_SS_USB_DEVCAP_DESC);
+
+#define LIBUSB20_BOS_DESCRIPTOR(m,n) \
+ m(n, UINT8_T, bLength, ) \
+ m(n, UINT8_T, bDescriptorType, ) \
+ m(n, UINT16_T, wTotalLength, ) \
+ m(n, UINT8_T, bNumDeviceCapabilities, ) \
+
+LIBUSB20_MAKE_STRUCT(LIBUSB20_BOS_DESCRIPTOR);
+
+/* standard USB stuff */
+
+/** \ingroup desc
+ * Device and/or Interface Class codes */
+enum libusb20_class_code {
+ /** In the context of a \ref LIBUSB20_DEVICE_DESC "device
+ * descriptor", this bDeviceClass value indicates that each
+ * interface specifies its own class information and all
+ * interfaces operate independently.
+ */
+ LIBUSB20_CLASS_PER_INTERFACE = 0,
+
+ /** Audio class */
+ LIBUSB20_CLASS_AUDIO = 1,
+
+ /** Communications class */
+ LIBUSB20_CLASS_COMM = 2,
+
+ /** Human Interface Device class */
+ LIBUSB20_CLASS_HID = 3,
+
+ /** Printer dclass */
+ LIBUSB20_CLASS_PRINTER = 7,
+
+ /** Picture transfer protocol class */
+ LIBUSB20_CLASS_PTP = 6,
+
+ /** Mass storage class */
+ LIBUSB20_CLASS_MASS_STORAGE = 8,
+
+ /** Hub class */
+ LIBUSB20_CLASS_HUB = 9,
+
+ /** Data class */
+ LIBUSB20_CLASS_DATA = 10,
+
+ /** Class is vendor-specific */
+ LIBUSB20_CLASS_VENDOR_SPEC = 0xff,
+};
+
+/** \ingroup desc
+ * Descriptor types as defined by the USB specification. */
+enum libusb20_descriptor_type {
+ /** Device descriptor. See LIBUSB20_DEVICE_DESC. */
+ LIBUSB20_DT_DEVICE = 0x01,
+
+ /** Configuration descriptor. See LIBUSB20_CONFIG_DESC. */
+ LIBUSB20_DT_CONFIG = 0x02,
+
+ /** String descriptor */
+ LIBUSB20_DT_STRING = 0x03,
+
+ /** Interface descriptor. See LIBUSB20_INTERFACE_DESC. */
+ LIBUSB20_DT_INTERFACE = 0x04,
+
+ /** Endpoint descriptor. See LIBUSB20_ENDPOINT_DESC. */
+ LIBUSB20_DT_ENDPOINT = 0x05,
+
+ /** HID descriptor */
+ LIBUSB20_DT_HID = 0x21,
+
+ /** HID report descriptor */
+ LIBUSB20_DT_REPORT = 0x22,
+
+ /** Physical descriptor */
+ LIBUSB20_DT_PHYSICAL = 0x23,
+
+ /** Hub descriptor */
+ LIBUSB20_DT_HUB = 0x29,
+
+ /** Binary Object Store, BOS */
+ LIBUSB20_DT_BOS = 0x0f,
+
+ /** Device Capability */
+ LIBUSB20_DT_DEVICE_CAPABILITY = 0x10,
+
+ /** SuperSpeed endpoint companion */
+ LIBUSB20_DT_SS_ENDPOINT_COMPANION = 0x30,
+};
+
+/** \ingroup desc
+ * Device capability types as defined by the USB specification. */
+enum libusb20_device_capability_type {
+ LIBUSB20_WIRELESS_USB_DEVICE_CAPABILITY = 0x1,
+ LIBUSB20_USB_2_0_EXTENSION_DEVICE_CAPABILITY = 0x2,
+ LIBUSB20_SS_USB_DEVICE_CAPABILITY = 0x3,
+ LIBUSB20_CONTAINER_ID_DEVICE_CAPABILITY = 0x4,
+};
+
+/* Descriptor sizes per descriptor type */
+#define LIBUSB20_DT_DEVICE_SIZE 18
+#define LIBUSB20_DT_CONFIG_SIZE 9
+#define LIBUSB20_DT_INTERFACE_SIZE 9
+#define LIBUSB20_DT_ENDPOINT_SIZE 7
+#define LIBUSB20_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */
+#define LIBUSB20_DT_HUB_NONVAR_SIZE 7
+#define LIBUSB20_DT_SS_ENDPOINT_COMPANION_SIZE 6
+#define LIBUSB20_DT_BOS_SIZE 5
+#define LIBUSB20_USB_2_0_EXTENSION_DEVICE_CAPABILITY_SIZE 7
+#define LIBUSB20_SS_USB_DEVICE_CAPABILITY_SIZE 10
+
+#define LIBUSB20_ENDPOINT_ADDRESS_MASK 0x0f /* in bEndpointAddress */
+#define LIBUSB20_ENDPOINT_DIR_MASK 0x80
+
+/** \ingroup desc
+ * Endpoint direction. Values for bit 7 of the
+ * \ref LIBUSB20_ENDPOINT_DESC::bEndpointAddress "endpoint address" scheme.
+ */
+enum libusb20_endpoint_direction {
+ /** In: device-to-host */
+ LIBUSB20_ENDPOINT_IN = 0x80,
+
+ /** Out: host-to-device */
+ LIBUSB20_ENDPOINT_OUT = 0x00,
+};
+
+#define LIBUSB20_TRANSFER_TYPE_MASK 0x03 /* in bmAttributes */
+
+/** \ingroup desc
+ * Endpoint transfer type. Values for bits 0:1 of the
+ * \ref LIBUSB20_ENDPOINT_DESC::bmAttributes "endpoint attributes" field.
+ */
+enum libusb20_transfer_type {
+ /** Control endpoint */
+ LIBUSB20_TRANSFER_TYPE_CONTROL = 0,
+
+ /** Isochronous endpoint */
+ LIBUSB20_TRANSFER_TYPE_ISOCHRONOUS = 1,
+
+ /** Bulk endpoint */
+ LIBUSB20_TRANSFER_TYPE_BULK = 2,
+
+ /** Interrupt endpoint */
+ LIBUSB20_TRANSFER_TYPE_INTERRUPT = 3,
+};
+
+/** \ingroup misc
+ * Standard requests, as defined in table 9-3 of the USB2 specifications */
+enum libusb20_standard_request {
+ /** Request status of the specific recipient */
+ LIBUSB20_REQUEST_GET_STATUS = 0x00,
+
+ /** Clear or disable a specific feature */
+ LIBUSB20_REQUEST_CLEAR_FEATURE = 0x01,
+
+ /* 0x02 is reserved */
+
+ /** Set or enable a specific feature */
+ LIBUSB20_REQUEST_SET_FEATURE = 0x03,
+
+ /* 0x04 is reserved */
+
+ /** Set device address for all future accesses */
+ LIBUSB20_REQUEST_SET_ADDRESS = 0x05,
+
+ /** Get the specified descriptor */
+ LIBUSB20_REQUEST_GET_DESCRIPTOR = 0x06,
+
+ /** Used to update existing descriptors or add new descriptors */
+ LIBUSB20_REQUEST_SET_DESCRIPTOR = 0x07,
+
+ /** Get the current device configuration value */
+ LIBUSB20_REQUEST_GET_CONFIGURATION = 0x08,
+
+ /** Set device configuration */
+ LIBUSB20_REQUEST_SET_CONFIGURATION = 0x09,
+
+ /** Return the selected alternate setting for the specified
+ * interface */
+ LIBUSB20_REQUEST_GET_INTERFACE = 0x0A,
+
+ /** Select an alternate interface for the specified interface */
+ LIBUSB20_REQUEST_SET_INTERFACE = 0x0B,
+
+ /** Set then report an endpoint's synchronization frame */
+ LIBUSB20_REQUEST_SYNCH_FRAME = 0x0C,
+};
+
+/** \ingroup misc
+ * Request type bits of the
+ * \ref libusb20_control_setup::bmRequestType "bmRequestType" field in
+ * control transfers. */
+enum libusb20_request_type {
+ /** Standard */
+ LIBUSB20_REQUEST_TYPE_STANDARD = (0x00 << 5),
+
+ /** Class */
+ LIBUSB20_REQUEST_TYPE_CLASS = (0x01 << 5),
+
+ /** Vendor */
+ LIBUSB20_REQUEST_TYPE_VENDOR = (0x02 << 5),
+
+ /** Reserved */
+ LIBUSB20_REQUEST_TYPE_RESERVED = (0x03 << 5),
+};
+
+/** \ingroup misc
+ * Recipient bits of the
+ * \ref libusb20_control_setup::bmRequestType "bmRequestType" field in
+ * control transfers. Values 4 through 31 are reserved. */
+enum libusb20_request_recipient {
+ /** Device */
+ LIBUSB20_RECIPIENT_DEVICE = 0x00,
+
+ /** Interface */
+ LIBUSB20_RECIPIENT_INTERFACE = 0x01,
+
+ /** Endpoint */
+ LIBUSB20_RECIPIENT_ENDPOINT = 0x02,
+
+ /** Other */
+ LIBUSB20_RECIPIENT_OTHER = 0x03,
+};
+
+#define LIBUSB20_ISO_SYNC_TYPE_MASK 0x0C
+
+/** \ingroup desc
+ * Synchronization type for isochronous endpoints. Values for bits 2:3
+ * of the \ref LIBUSB20_ENDPOINT_DESC::bmAttributes "bmAttributes"
+ * field in LIBUSB20_ENDPOINT_DESC.
+ */
+enum libusb20_iso_sync_type {
+ /** No synchronization */
+ LIBUSB20_ISO_SYNC_TYPE_NONE = 0,
+
+ /** Asynchronous */
+ LIBUSB20_ISO_SYNC_TYPE_ASYNC = 1,
+
+ /** Adaptive */
+ LIBUSB20_ISO_SYNC_TYPE_ADAPTIVE = 2,
+
+ /** Synchronous */
+ LIBUSB20_ISO_SYNC_TYPE_SYNC = 3,
+};
+
+#define LIBUSB20_ISO_USAGE_TYPE_MASK 0x30
+
+/** \ingroup desc
+ * Usage type for isochronous endpoints. Values for bits 4:5 of the
+ * \ref LIBUSB20_ENDPOINT_DESC::bmAttributes "bmAttributes" field in
+ * LIBUSB20_ENDPOINT_DESC.
+ */
+enum libusb20_iso_usage_type {
+ /** Data endpoint */
+ LIBUSB20_ISO_USAGE_TYPE_DATA = 0,
+
+ /** Feedback endpoint */
+ LIBUSB20_ISO_USAGE_TYPE_FEEDBACK = 1,
+
+ /** Implicit feedback Data endpoint */
+ LIBUSB20_ISO_USAGE_TYPE_IMPLICIT = 2,
+};
+
+struct libusb20_endpoint {
+ struct LIBUSB20_ENDPOINT_DESC_DECODED desc;
+ struct libusb20_me_struct extra;
+} __aligned(sizeof(void *));
+
+struct libusb20_interface {
+ struct LIBUSB20_INTERFACE_DESC_DECODED desc;
+ struct libusb20_me_struct extra;
+ struct libusb20_interface *altsetting;
+ struct libusb20_endpoint *endpoints;
+ uint8_t num_altsetting;
+ uint8_t num_endpoints;
+} __aligned(sizeof(void *));
+
+struct libusb20_config {
+ struct LIBUSB20_CONFIG_DESC_DECODED desc;
+ struct libusb20_me_struct extra;
+ struct libusb20_interface *interface;
+ uint8_t num_interface;
+} __aligned(sizeof(void *));
+
+uint8_t libusb20_me_get_1(const struct libusb20_me_struct *ie, uint16_t offset);
+uint16_t libusb20_me_get_2(const struct libusb20_me_struct *ie, uint16_t offset);
+uint16_t libusb20_me_encode(void *ptr, uint16_t len, const void *pd);
+uint16_t libusb20_me_decode(const void *ptr, uint16_t len, void *pd);
+const uint8_t *libusb20_desc_foreach(const struct libusb20_me_struct *pdesc, const uint8_t *psubdesc);
+struct libusb20_config *libusb20_parse_config_desc(const void *config_desc);
+
+#if 0
+{ /* style */
+#endif
+#ifdef __cplusplus
+}
+
+#endif
+
+#endif /* _LIBUSB20_DESC_H_ */
diff --git a/lib/libusb/libusb20_int.h b/lib/libusb/libusb20_int.h
new file mode 100644
index 0000000..bef4d02
--- /dev/null
+++ b/lib/libusb/libusb20_int.h
@@ -0,0 +1,238 @@
+/* $FreeBSD$ */
+/*-
+ * Copyright (c) 2008 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.
+ */
+
+/*
+ * This file describes internal structures.
+ */
+
+#ifndef _LIBUSB20_INT_H_
+#define _LIBUSB20_INT_H_
+
+#ifdef COMPAT_32BIT
+#define libusb20_pass_ptr(ptr) ((uint64_t)(uintptr_t)(ptr))
+#else
+#define libusb20_pass_ptr(ptr) (ptr)
+#endif
+
+struct libusb20_device;
+struct libusb20_backend;
+struct libusb20_transfer;
+struct libusb20_quirk;
+
+union libusb20_session_data {
+ unsigned long session_data;
+ struct timespec tv;
+ uint32_t plugtime;
+};
+
+/* USB backend specific */
+typedef const char *(libusb20_get_backend_name_t)(void);
+typedef int (libusb20_root_get_dev_quirk_t)(struct libusb20_backend *pbe, uint16_t index, struct libusb20_quirk *pq);
+typedef int (libusb20_root_get_quirk_name_t)(struct libusb20_backend *pbe, uint16_t index, struct libusb20_quirk *pq);
+typedef int (libusb20_root_add_dev_quirk_t)(struct libusb20_backend *pbe, struct libusb20_quirk *pq);
+typedef int (libusb20_root_remove_dev_quirk_t)(struct libusb20_backend *pbe, struct libusb20_quirk *pq);
+typedef int (libusb20_close_device_t)(struct libusb20_device *pdev);
+typedef int (libusb20_dev_get_info_t)(struct libusb20_device *pdev, struct usb_device_info *pinfo);
+typedef int (libusb20_dev_get_iface_desc_t)(struct libusb20_device *pdev, uint8_t iface_index, char *buf, uint8_t len);
+typedef int (libusb20_init_backend_t)(struct libusb20_backend *pbe);
+typedef int (libusb20_open_device_t)(struct libusb20_device *pdev, uint16_t transfer_count_max);
+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);
+
+#define LIBUSB20_DEFINE(n,field) \
+ libusb20_##field##_t *field;
+
+#define LIBUSB20_DECLARE(n,field) \
+ /* .field = */ n##_##field,
+
+#define LIBUSB20_BACKEND(m,n) \
+ /* description of this backend */ \
+ m(n, get_backend_name) \
+ /* optional backend methods */ \
+ m(n, init_backend) \
+ m(n, exit_backend) \
+ m(n, dev_get_info) \
+ m(n, dev_get_iface_desc) \
+ m(n, root_get_dev_quirk) \
+ m(n, root_get_quirk_name) \
+ m(n, root_add_dev_quirk) \
+ m(n, root_remove_dev_quirk) \
+ m(n, root_set_template) \
+ m(n, root_get_template) \
+ /* mandatory device methods */ \
+ m(n, open_device) \
+ m(n, close_device) \
+
+struct libusb20_backend_methods {
+ LIBUSB20_BACKEND(LIBUSB20_DEFINE,)
+};
+
+/* USB dummy methods */
+typedef int (libusb20_dummy_int_t)(void);
+typedef void (libusb20_dummy_void_t)(void);
+
+/* USB device specific */
+typedef int (libusb20_detach_kernel_driver_t)(struct libusb20_device *pdev, uint8_t iface_index);
+typedef int (libusb20_do_request_sync_t)(struct libusb20_device *pdev, struct LIBUSB20_CONTROL_SETUP_DECODED *setup, void *data, uint16_t *pactlen, uint32_t timeout, uint8_t flags);
+typedef int (libusb20_get_config_desc_full_t)(struct libusb20_device *pdev, uint8_t **ppbuf, uint16_t *plen, uint8_t index);
+typedef int (libusb20_get_config_index_t)(struct libusb20_device *pdev, uint8_t *pindex);
+typedef int (libusb20_kernel_driver_active_t)(struct libusb20_device *pdev, uint8_t iface_index);
+typedef int (libusb20_process_t)(struct libusb20_device *pdev);
+typedef int (libusb20_reset_device_t)(struct libusb20_device *pdev);
+typedef int (libusb20_set_power_mode_t)(struct libusb20_device *pdev, uint8_t power_mode);
+typedef int (libusb20_get_power_mode_t)(struct libusb20_device *pdev, uint8_t *power_mode);
+typedef int (libusb20_set_alt_index_t)(struct libusb20_device *pdev, uint8_t iface_index, uint8_t alt_index);
+typedef int (libusb20_set_config_index_t)(struct libusb20_device *pdev, uint8_t index);
+typedef int (libusb20_check_connected_t)(struct libusb20_device *pdev);
+
+/* USB transfer specific */
+typedef int (libusb20_tr_open_t)(struct libusb20_transfer *xfer, uint32_t MaxBufSize, uint32_t MaxFrameCount, uint8_t ep_no, uint8_t pre_scale);
+typedef int (libusb20_tr_close_t)(struct libusb20_transfer *xfer);
+typedef int (libusb20_tr_clear_stall_sync_t)(struct libusb20_transfer *xfer);
+typedef void (libusb20_tr_submit_t)(struct libusb20_transfer *xfer);
+typedef void (libusb20_tr_cancel_async_t)(struct libusb20_transfer *xfer);
+
+#define LIBUSB20_DEVICE(m,n) \
+ m(n, detach_kernel_driver) \
+ m(n, do_request_sync) \
+ m(n, get_config_desc_full) \
+ m(n, get_config_index) \
+ m(n, kernel_driver_active) \
+ m(n, process) \
+ m(n, reset_device) \
+ m(n, check_connected) \
+ m(n, set_power_mode) \
+ m(n, get_power_mode) \
+ m(n, set_alt_index) \
+ m(n, set_config_index) \
+ m(n, tr_cancel_async) \
+ m(n, tr_clear_stall_sync) \
+ m(n, tr_close) \
+ m(n, tr_open) \
+ m(n, tr_submit) \
+
+struct libusb20_device_methods {
+ LIBUSB20_DEVICE(LIBUSB20_DEFINE,)
+};
+
+struct libusb20_backend {
+ TAILQ_HEAD(, libusb20_device) usb_devs;
+ const struct libusb20_backend_methods *methods;
+};
+
+struct libusb20_transfer {
+ struct libusb20_device *pdev; /* the USB device we belong to */
+ libusb20_tr_callback_t *callback;
+ void *priv_sc0; /* private client data */
+ void *priv_sc1; /* private client data */
+ /*
+ * Pointer to a list of buffer pointers:
+ */
+#ifdef COMPAT_32BIT
+ uint64_t *ppBuffer;
+#else
+ void **ppBuffer;
+#endif
+ /*
+ * Pointer to frame lengths, which are updated to actual length
+ * after the USB transfer completes:
+ */
+ uint32_t *pLength;
+ uint32_t maxTotalLength;
+ uint32_t maxFrames; /* total number of frames */
+ uint32_t nFrames; /* total number of frames */
+ uint32_t aFrames; /* actual number of frames */
+ uint32_t timeout;
+ /* isochronous completion time in milliseconds */
+ uint16_t timeComplete;
+ uint16_t trIndex;
+ uint16_t maxPacketLen;
+ uint8_t flags; /* see LIBUSB20_TRANSFER_XXX */
+ uint8_t status; /* see LIBUSB20_TRANSFER_XXX */
+ uint8_t is_opened;
+ uint8_t is_pending;
+ uint8_t is_cancel;
+ uint8_t is_draining;
+ uint8_t is_restart;
+};
+
+struct libusb20_device {
+
+ /* device descriptor */
+ struct LIBUSB20_DEVICE_DESC_DECODED ddesc;
+
+ /* device timestamp */
+ union libusb20_session_data session_data;
+
+ /* our device entry */
+ TAILQ_ENTRY(libusb20_device) dev_entry;
+
+ /* device methods */
+ const struct libusb20_device_methods *methods;
+
+ /* backend methods */
+ const struct libusb20_backend_methods *beMethods;
+
+ /* list of USB transfers */
+ struct libusb20_transfer *pTransfer;
+
+ /* private backend data */
+ void *privBeData;
+
+ /* libUSB v0.1 and v1.0 compat data */
+ void *privLuData;
+
+ /* claimed interface */
+ uint8_t claimed_interface;
+
+ /* device file handle */
+ int file;
+
+ /* device file handle (control transfers only) */
+ int file_ctrl;
+
+ /* debugging level */
+ int debug;
+
+ /* number of USB transfers */
+ uint16_t nTransfer;
+
+ uint8_t bus_number;
+ uint8_t device_address;
+ uint8_t usb_mode;
+ uint8_t usb_speed;
+ uint8_t is_opened;
+ uint8_t parent_address;
+ uint8_t parent_port;
+
+ char usb_desc[96];
+};
+
+extern const struct libusb20_backend_methods libusb20_ugen20_backend;
+extern const struct libusb20_backend_methods libusb20_linux_backend;
+
+#endif /* _LIBUSB20_INT_H_ */
diff --git a/lib/libusb/libusb20_ugen20.c b/lib/libusb/libusb20_ugen20.c
new file mode 100644
index 0000000..307ed96
--- /dev/null
+++ b/lib/libusb/libusb20_ugen20.c
@@ -0,0 +1,1022 @@
+/* $FreeBSD$ */
+/*-
+ * Copyright (c) 2008 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.
+ */
+
+#include <sys/queue.h>
+#include <sys/types.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "libusb20.h"
+#include "libusb20_desc.h"
+#include "libusb20_int.h"
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usb_ioctl.h>
+
+static libusb20_init_backend_t ugen20_init_backend;
+static libusb20_open_device_t ugen20_open_device;
+static libusb20_close_device_t ugen20_close_device;
+static libusb20_get_backend_name_t ugen20_get_backend_name;
+static libusb20_exit_backend_t ugen20_exit_backend;
+static libusb20_dev_get_iface_desc_t ugen20_dev_get_iface_desc;
+static libusb20_dev_get_info_t ugen20_dev_get_info;
+static libusb20_root_get_dev_quirk_t ugen20_root_get_dev_quirk;
+static libusb20_root_get_quirk_name_t ugen20_root_get_quirk_name;
+static libusb20_root_add_dev_quirk_t ugen20_root_add_dev_quirk;
+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;
+
+const struct libusb20_backend_methods libusb20_ugen20_backend = {
+ LIBUSB20_BACKEND(LIBUSB20_DECLARE, ugen20)
+};
+
+/* USB device specific */
+static libusb20_get_config_desc_full_t ugen20_get_config_desc_full;
+static libusb20_get_config_index_t ugen20_get_config_index;
+static libusb20_set_config_index_t ugen20_set_config_index;
+static libusb20_set_alt_index_t ugen20_set_alt_index;
+static libusb20_reset_device_t ugen20_reset_device;
+static libusb20_check_connected_t ugen20_check_connected;
+static libusb20_set_power_mode_t ugen20_set_power_mode;
+static libusb20_get_power_mode_t ugen20_get_power_mode;
+static libusb20_kernel_driver_active_t ugen20_kernel_driver_active;
+static libusb20_detach_kernel_driver_t ugen20_detach_kernel_driver;
+static libusb20_do_request_sync_t ugen20_do_request_sync;
+static libusb20_process_t ugen20_process;
+
+/* USB transfer specific */
+static libusb20_tr_open_t ugen20_tr_open;
+static libusb20_tr_close_t ugen20_tr_close;
+static libusb20_tr_clear_stall_sync_t ugen20_tr_clear_stall_sync;
+static libusb20_tr_submit_t ugen20_tr_submit;
+static libusb20_tr_cancel_async_t ugen20_tr_cancel_async;
+
+static const struct libusb20_device_methods libusb20_ugen20_device_methods = {
+ LIBUSB20_DEVICE(LIBUSB20_DECLARE, ugen20)
+};
+
+static const char *
+ugen20_get_backend_name(void)
+{
+ return ("FreeBSD UGEN 2.0");
+}
+
+static uint32_t
+ugen20_path_convert_one(const char **pp)
+{
+ const char *ptr;
+ uint32_t temp = 0;
+
+ ptr = *pp;
+
+ while ((*ptr >= '0') && (*ptr <= '9')) {
+ temp *= 10;
+ temp += (*ptr - '0');
+ if (temp >= 1000000) {
+ /* catch overflow early */
+ return (0 - 1);
+ }
+ ptr++;
+ }
+
+ if (*ptr == '.') {
+ /* skip dot */
+ ptr++;
+ }
+ *pp = ptr;
+
+ return (temp);
+}
+
+static int
+ugen20_enumerate(struct libusb20_device *pdev, const char *id)
+{
+ const char *tmp = id;
+ struct usb_device_descriptor ddesc;
+ struct usb_device_info devinfo;
+ uint32_t plugtime;
+ char buf[64];
+ int f;
+ int error;
+
+ pdev->bus_number = ugen20_path_convert_one(&tmp);
+ pdev->device_address = ugen20_path_convert_one(&tmp);
+
+ snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u",
+ pdev->bus_number, pdev->device_address);
+
+ f = open(buf, O_RDWR);
+ if (f < 0) {
+ return (LIBUSB20_ERROR_OTHER);
+ }
+ if (ioctl(f, USB_GET_PLUGTIME, &plugtime)) {
+ error = LIBUSB20_ERROR_OTHER;
+ goto done;
+ }
+ /* store when the device was plugged */
+ pdev->session_data.plugtime = plugtime;
+
+ if (ioctl(f, USB_GET_DEVICE_DESC, &ddesc)) {
+ error = LIBUSB20_ERROR_OTHER;
+ goto done;
+ }
+ LIBUSB20_INIT(LIBUSB20_DEVICE_DESC, &(pdev->ddesc));
+
+ libusb20_me_decode(&ddesc, sizeof(ddesc), &(pdev->ddesc));
+
+ if (pdev->ddesc.bNumConfigurations == 0) {
+ error = LIBUSB20_ERROR_OTHER;
+ goto done;
+ } else if (pdev->ddesc.bNumConfigurations >= 8) {
+ error = LIBUSB20_ERROR_OTHER;
+ goto done;
+ }
+ if (ioctl(f, USB_GET_DEVICEINFO, &devinfo)) {
+ error = LIBUSB20_ERROR_OTHER;
+ goto done;
+ }
+ switch (devinfo.udi_mode) {
+ case USB_MODE_DEVICE:
+ pdev->usb_mode = LIBUSB20_MODE_DEVICE;
+ break;
+ default:
+ pdev->usb_mode = LIBUSB20_MODE_HOST;
+ break;
+ }
+
+ switch (devinfo.udi_speed) {
+ case USB_SPEED_LOW:
+ pdev->usb_speed = LIBUSB20_SPEED_LOW;
+ break;
+ case USB_SPEED_FULL:
+ pdev->usb_speed = LIBUSB20_SPEED_FULL;
+ break;
+ case USB_SPEED_HIGH:
+ pdev->usb_speed = LIBUSB20_SPEED_HIGH;
+ break;
+ case USB_SPEED_VARIABLE:
+ pdev->usb_speed = LIBUSB20_SPEED_VARIABLE;
+ break;
+ case USB_SPEED_SUPER:
+ pdev->usb_speed = LIBUSB20_SPEED_SUPER;
+ break;
+ default:
+ pdev->usb_speed = LIBUSB20_SPEED_UNKNOWN;
+ break;
+ }
+
+ /* get parent HUB index and port */
+
+ pdev->parent_address = devinfo.udi_hubindex;
+ pdev->parent_port = devinfo.udi_hubport;
+
+ /* generate a nice description for printout */
+
+ snprintf(pdev->usb_desc, sizeof(pdev->usb_desc),
+ USB_GENERIC_NAME "%u.%u: <%s %s> at usbus%u", pdev->bus_number,
+ pdev->device_address, devinfo.udi_product,
+ devinfo.udi_vendor, pdev->bus_number);
+
+ error = 0;
+done:
+ close(f);
+ return (error);
+}
+
+struct ugen20_urd_state {
+ struct usb_read_dir urd;
+ uint32_t nparsed;
+ int f;
+ uint8_t *ptr;
+ const char *src;
+ const char *dst;
+ uint8_t buf[256];
+ uint8_t dummy_zero[1];
+};
+
+static int
+ugen20_readdir(struct ugen20_urd_state *st)
+{
+ ; /* style fix */
+repeat:
+ if (st->ptr == NULL) {
+ st->urd.urd_startentry += st->nparsed;
+ st->urd.urd_data = libusb20_pass_ptr(st->buf);
+ st->urd.urd_maxlen = sizeof(st->buf);
+ st->nparsed = 0;
+
+ if (ioctl(st->f, USB_READ_DIR, &st->urd)) {
+ return (EINVAL);
+ }
+ st->ptr = st->buf;
+ }
+ if (st->ptr[0] == 0) {
+ if (st->nparsed) {
+ st->ptr = NULL;
+ goto repeat;
+ } else {
+ return (ENXIO);
+ }
+ }
+ st->src = (void *)(st->ptr + 1);
+ st->dst = st->src + strlen(st->src) + 1;
+ st->ptr = st->ptr + st->ptr[0];
+ st->nparsed++;
+
+ if ((st->ptr < st->buf) ||
+ (st->ptr > st->dummy_zero)) {
+ /* invalid entry */
+ return (EINVAL);
+ }
+ return (0);
+}
+
+static int
+ugen20_init_backend(struct libusb20_backend *pbe)
+{
+ struct ugen20_urd_state state;
+ struct libusb20_device *pdev;
+
+ memset(&state, 0, sizeof(state));
+
+ state.f = open("/dev/" USB_DEVICE_NAME, O_RDONLY);
+ if (state.f < 0)
+ return (LIBUSB20_ERROR_OTHER);
+
+ while (ugen20_readdir(&state) == 0) {
+
+ if ((state.src[0] != 'u') ||
+ (state.src[1] != 'g') ||
+ (state.src[2] != 'e') ||
+ (state.src[3] != 'n')) {
+ continue;
+ }
+ pdev = libusb20_dev_alloc();
+ if (pdev == NULL) {
+ continue;
+ }
+ if (ugen20_enumerate(pdev, state.src + 4)) {
+ libusb20_dev_free(pdev);
+ continue;
+ }
+ /* put the device on the backend list */
+ libusb20_be_enqueue_device(pbe, pdev);
+ }
+ close(state.f);
+ return (0); /* success */
+}
+
+static void
+ugen20_tr_release(struct libusb20_device *pdev)
+{
+ struct usb_fs_uninit fs_uninit;
+
+ if (pdev->nTransfer == 0) {
+ return;
+ }
+ /* release all pending USB transfers */
+ if (pdev->privBeData != NULL) {
+ memset(&fs_uninit, 0, sizeof(fs_uninit));
+ if (ioctl(pdev->file, USB_FS_UNINIT, &fs_uninit)) {
+ /* ignore any errors of this kind */
+ }
+ }
+ return;
+}
+
+static int
+ugen20_tr_renew(struct libusb20_device *pdev)
+{
+ struct usb_fs_init fs_init;
+ struct usb_fs_endpoint *pfse;
+ int error;
+ uint32_t size;
+ uint16_t nMaxTransfer;
+
+ nMaxTransfer = pdev->nTransfer;
+ error = 0;
+
+ if (nMaxTransfer == 0) {
+ goto done;
+ }
+ size = nMaxTransfer * sizeof(*pfse);
+
+ if (pdev->privBeData == NULL) {
+ pfse = malloc(size);
+ if (pfse == NULL) {
+ error = LIBUSB20_ERROR_NO_MEM;
+ goto done;
+ }
+ pdev->privBeData = pfse;
+ }
+ /* reset endpoint data */
+ memset(pdev->privBeData, 0, size);
+
+ memset(&fs_init, 0, sizeof(fs_init));
+
+ fs_init.pEndpoints = libusb20_pass_ptr(pdev->privBeData);
+ fs_init.ep_index_max = nMaxTransfer;
+
+ if (ioctl(pdev->file, USB_FS_INIT, &fs_init)) {
+ error = LIBUSB20_ERROR_OTHER;
+ goto done;
+ }
+done:
+ return (error);
+}
+
+static int
+ugen20_open_device(struct libusb20_device *pdev, uint16_t nMaxTransfer)
+{
+ uint32_t plugtime;
+ char buf[64];
+ int f;
+ int g;
+ int error;
+
+ snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u",
+ pdev->bus_number, pdev->device_address);
+
+ /*
+ * We need two file handles, one for the control endpoint and one
+ * for BULK, INTERRUPT and ISOCHRONOUS transactions due to optimised
+ * kernel locking.
+ */
+ g = open(buf, O_RDWR);
+ if (g < 0) {
+ return (LIBUSB20_ERROR_NO_DEVICE);
+ }
+ f = open(buf, O_RDWR);
+ if (f < 0) {
+ close(g);
+ return (LIBUSB20_ERROR_NO_DEVICE);
+ }
+ if (ioctl(f, USB_GET_PLUGTIME, &plugtime)) {
+ error = LIBUSB20_ERROR_OTHER;
+ goto done;
+ }
+ /* check that the correct device is still plugged */
+ if (pdev->session_data.plugtime != plugtime) {
+ error = LIBUSB20_ERROR_NO_DEVICE;
+ goto done;
+ }
+ /* need to set this before "tr_renew()" */
+ pdev->file = f;
+ pdev->file_ctrl = g;
+
+ /* renew all USB transfers */
+ error = ugen20_tr_renew(pdev);
+ if (error) {
+ goto done;
+ }
+ /* set methods */
+ pdev->methods = &libusb20_ugen20_device_methods;
+
+done:
+ if (error) {
+ if (pdev->privBeData) {
+ /* cleanup after "tr_renew()" */
+ free(pdev->privBeData);
+ pdev->privBeData = NULL;
+ }
+ pdev->file = -1;
+ pdev->file_ctrl = -1;
+ close(f);
+ close(g);
+ }
+ return (error);
+}
+
+static int
+ugen20_close_device(struct libusb20_device *pdev)
+{
+ struct usb_fs_uninit fs_uninit;
+
+ if (pdev->privBeData) {
+ memset(&fs_uninit, 0, sizeof(fs_uninit));
+ if (ioctl(pdev->file, USB_FS_UNINIT, &fs_uninit)) {
+ /* ignore this error */
+ }
+ free(pdev->privBeData);
+ }
+ pdev->nTransfer = 0;
+ pdev->privBeData = NULL;
+ close(pdev->file);
+ close(pdev->file_ctrl);
+ pdev->file = -1;
+ pdev->file_ctrl = -1;
+ return (0); /* success */
+}
+
+static void
+ugen20_exit_backend(struct libusb20_backend *pbe)
+{
+ return; /* nothing to do */
+}
+
+static int
+ugen20_get_config_desc_full(struct libusb20_device *pdev,
+ uint8_t **ppbuf, uint16_t *plen, uint8_t cfg_index)
+{
+ struct usb_gen_descriptor gen_desc;
+ struct usb_config_descriptor cdesc;
+ uint8_t *ptr;
+ uint16_t len;
+ int error;
+
+ /* make sure memory is initialised */
+ memset(&cdesc, 0, sizeof(cdesc));
+ memset(&gen_desc, 0, sizeof(gen_desc));
+
+ gen_desc.ugd_data = libusb20_pass_ptr(&cdesc);
+ gen_desc.ugd_maxlen = sizeof(cdesc);
+ gen_desc.ugd_config_index = cfg_index;
+
+ error = ioctl(pdev->file_ctrl, USB_GET_FULL_DESC, &gen_desc);
+ if (error) {
+ return (LIBUSB20_ERROR_OTHER);
+ }
+ len = UGETW(cdesc.wTotalLength);
+ if (len < sizeof(cdesc)) {
+ /* corrupt descriptor */
+ return (LIBUSB20_ERROR_OTHER);
+ }
+ ptr = malloc(len);
+ if (!ptr) {
+ return (LIBUSB20_ERROR_NO_MEM);
+ }
+
+ /* make sure memory is initialised */
+ memset(ptr, 0, len);
+
+ gen_desc.ugd_data = libusb20_pass_ptr(ptr);
+ gen_desc.ugd_maxlen = len;
+
+ error = ioctl(pdev->file_ctrl, USB_GET_FULL_DESC, &gen_desc);
+ if (error) {
+ free(ptr);
+ return (LIBUSB20_ERROR_OTHER);
+ }
+ /* make sure that the device doesn't fool us */
+ memcpy(ptr, &cdesc, sizeof(cdesc));
+
+ *ppbuf = ptr;
+ *plen = len;
+
+ return (0); /* success */
+}
+
+static int
+ugen20_get_config_index(struct libusb20_device *pdev, uint8_t *pindex)
+{
+ int temp;
+
+ if (ioctl(pdev->file_ctrl, USB_GET_CONFIG, &temp)) {
+ return (LIBUSB20_ERROR_OTHER);
+ }
+ *pindex = temp;
+
+ return (0);
+}
+
+static int
+ugen20_set_config_index(struct libusb20_device *pdev, uint8_t cfg_index)
+{
+ int temp = cfg_index;
+
+ /* release all active USB transfers */
+ ugen20_tr_release(pdev);
+
+ if (ioctl(pdev->file_ctrl, USB_SET_CONFIG, &temp)) {
+ return (LIBUSB20_ERROR_OTHER);
+ }
+ return (ugen20_tr_renew(pdev));
+}
+
+static int
+ugen20_set_alt_index(struct libusb20_device *pdev,
+ uint8_t iface_index, uint8_t alt_index)
+{
+ struct usb_alt_interface alt_iface;
+
+ memset(&alt_iface, 0, sizeof(alt_iface));
+
+ alt_iface.uai_interface_index = iface_index;
+ alt_iface.uai_alt_index = alt_index;
+
+ /* release all active USB transfers */
+ ugen20_tr_release(pdev);
+
+ if (ioctl(pdev->file_ctrl, USB_SET_ALTINTERFACE, &alt_iface)) {
+ return (LIBUSB20_ERROR_OTHER);
+ }
+ return (ugen20_tr_renew(pdev));
+}
+
+static int
+ugen20_reset_device(struct libusb20_device *pdev)
+{
+ int temp = 0;
+
+ /* release all active USB transfers */
+ ugen20_tr_release(pdev);
+
+ if (ioctl(pdev->file_ctrl, USB_DEVICEENUMERATE, &temp)) {
+ return (LIBUSB20_ERROR_OTHER);
+ }
+ return (ugen20_tr_renew(pdev));
+}
+
+static int
+ugen20_check_connected(struct libusb20_device *pdev)
+{
+ uint32_t plugtime;
+ int error = 0;
+
+ if (ioctl(pdev->file_ctrl, USB_GET_PLUGTIME, &plugtime)) {
+ error = LIBUSB20_ERROR_NO_DEVICE;
+ goto done;
+ }
+
+ if (pdev->session_data.plugtime != plugtime) {
+ error = LIBUSB20_ERROR_NO_DEVICE;
+ goto done;
+ }
+done:
+ return (error);
+}
+
+static int
+ugen20_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode)
+{
+ int temp;
+
+ switch (power_mode) {
+ case LIBUSB20_POWER_OFF:
+ temp = USB_POWER_MODE_OFF;
+ break;
+ case LIBUSB20_POWER_ON:
+ temp = USB_POWER_MODE_ON;
+ break;
+ case LIBUSB20_POWER_SAVE:
+ temp = USB_POWER_MODE_SAVE;
+ break;
+ case LIBUSB20_POWER_SUSPEND:
+ temp = USB_POWER_MODE_SUSPEND;
+ break;
+ case LIBUSB20_POWER_RESUME:
+ temp = USB_POWER_MODE_RESUME;
+ break;
+ default:
+ return (LIBUSB20_ERROR_INVALID_PARAM);
+ }
+ if (ioctl(pdev->file_ctrl, USB_SET_POWER_MODE, &temp)) {
+ return (LIBUSB20_ERROR_OTHER);
+ }
+ return (0);
+}
+
+static int
+ugen20_get_power_mode(struct libusb20_device *pdev, uint8_t *power_mode)
+{
+ int temp;
+
+ if (ioctl(pdev->file_ctrl, USB_GET_POWER_MODE, &temp)) {
+ return (LIBUSB20_ERROR_OTHER);
+ }
+ switch (temp) {
+ case USB_POWER_MODE_OFF:
+ temp = LIBUSB20_POWER_OFF;
+ break;
+ case USB_POWER_MODE_ON:
+ temp = LIBUSB20_POWER_ON;
+ break;
+ case USB_POWER_MODE_SAVE:
+ temp = LIBUSB20_POWER_SAVE;
+ break;
+ case USB_POWER_MODE_SUSPEND:
+ temp = LIBUSB20_POWER_SUSPEND;
+ break;
+ case USB_POWER_MODE_RESUME:
+ temp = LIBUSB20_POWER_RESUME;
+ break;
+ default:
+ temp = LIBUSB20_POWER_ON;
+ break;
+ }
+ *power_mode = temp;
+ return (0); /* success */
+}
+
+static int
+ugen20_kernel_driver_active(struct libusb20_device *pdev,
+ uint8_t iface_index)
+{
+ int temp = iface_index;
+
+ if (ioctl(pdev->file_ctrl, USB_IFACE_DRIVER_ACTIVE, &temp)) {
+ return (LIBUSB20_ERROR_OTHER);
+ }
+ return (0); /* kernel driver is active */
+}
+
+static int
+ugen20_detach_kernel_driver(struct libusb20_device *pdev,
+ uint8_t iface_index)
+{
+ int temp = iface_index;
+
+ if (ioctl(pdev->file_ctrl, USB_IFACE_DRIVER_DETACH, &temp)) {
+ return (LIBUSB20_ERROR_OTHER);
+ }
+ return (0); /* kernel driver is active */
+}
+
+static int
+ugen20_do_request_sync(struct libusb20_device *pdev,
+ struct LIBUSB20_CONTROL_SETUP_DECODED *setup,
+ void *data, uint16_t *pactlen, uint32_t timeout, uint8_t flags)
+{
+ struct usb_ctl_request req;
+
+ memset(&req, 0, sizeof(req));
+
+ req.ucr_data = libusb20_pass_ptr(data);
+ if (!(flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) {
+ req.ucr_flags |= USB_SHORT_XFER_OK;
+ }
+ if (libusb20_me_encode(&req.ucr_request,
+ sizeof(req.ucr_request), setup)) {
+ /* ignore */
+ }
+ if (ioctl(pdev->file_ctrl, USB_DO_REQUEST, &req)) {
+ return (LIBUSB20_ERROR_OTHER);
+ }
+ if (pactlen) {
+ /* get actual length */
+ *pactlen = req.ucr_actlen;
+ }
+ return (0); /* kernel driver is active */
+}
+
+static int
+ugen20_process(struct libusb20_device *pdev)
+{
+ struct usb_fs_complete temp;
+ struct usb_fs_endpoint *fsep;
+ struct libusb20_transfer *xfer;
+
+ while (1) {
+
+ if (ioctl(pdev->file, USB_FS_COMPLETE, &temp)) {
+ if (errno == EBUSY) {
+ break;
+ } else {
+ /* device detached */
+ return (LIBUSB20_ERROR_OTHER);
+ }
+ }
+ fsep = pdev->privBeData;
+ xfer = pdev->pTransfer;
+ fsep += temp.ep_index;
+ xfer += temp.ep_index;
+
+ /* update transfer status */
+
+ if (fsep->status == 0) {
+ xfer->aFrames = fsep->aFrames;
+ xfer->timeComplete = fsep->isoc_time_complete;
+ xfer->status = LIBUSB20_TRANSFER_COMPLETED;
+ } else if (fsep->status == USB_ERR_CANCELLED) {
+ xfer->aFrames = 0;
+ xfer->timeComplete = 0;
+ xfer->status = LIBUSB20_TRANSFER_CANCELLED;
+ } else if (fsep->status == USB_ERR_STALLED) {
+ xfer->aFrames = 0;
+ xfer->timeComplete = 0;
+ xfer->status = LIBUSB20_TRANSFER_STALL;
+ } else if (fsep->status == USB_ERR_TIMEOUT) {
+ xfer->aFrames = 0;
+ xfer->timeComplete = 0;
+ xfer->status = LIBUSB20_TRANSFER_TIMED_OUT;
+ } else {
+ xfer->aFrames = 0;
+ xfer->timeComplete = 0;
+ xfer->status = LIBUSB20_TRANSFER_ERROR;
+ }
+ libusb20_tr_callback_wrapper(xfer);
+ }
+ return (0); /* done */
+}
+
+static int
+ugen20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize,
+ uint32_t MaxFrameCount, uint8_t ep_no, uint8_t pre_scale)
+{
+ struct usb_fs_open temp;
+ struct usb_fs_endpoint *fsep;
+
+ if (pre_scale)
+ MaxFrameCount |= USB_FS_MAX_FRAMES_PRE_SCALE;
+
+ memset(&temp, 0, sizeof(temp));
+
+ fsep = xfer->pdev->privBeData;
+ fsep += xfer->trIndex;
+
+ temp.max_bufsize = MaxBufSize;
+ temp.max_frames = MaxFrameCount;
+ temp.ep_index = xfer->trIndex;
+ temp.ep_no = ep_no;
+
+ if (ioctl(xfer->pdev->file, USB_FS_OPEN, &temp)) {
+ return (LIBUSB20_ERROR_INVALID_PARAM);
+ }
+ /* maximums might have changed - update */
+ xfer->maxFrames = temp.max_frames;
+
+ /* "max_bufsize" should be multiple of "max_packet_length" */
+ xfer->maxTotalLength = temp.max_bufsize;
+ xfer->maxPacketLen = temp.max_packet_length;
+
+ /* setup buffer and length lists using zero copy */
+ fsep->ppBuffer = libusb20_pass_ptr(xfer->ppBuffer);
+ fsep->pLength = libusb20_pass_ptr(xfer->pLength);
+
+ return (0); /* success */
+}
+
+static int
+ugen20_tr_close(struct libusb20_transfer *xfer)
+{
+ struct usb_fs_close temp;
+
+ memset(&temp, 0, sizeof(temp));
+
+ temp.ep_index = xfer->trIndex;
+
+ if (ioctl(xfer->pdev->file, USB_FS_CLOSE, &temp)) {
+ return (LIBUSB20_ERROR_INVALID_PARAM);
+ }
+ return (0); /* success */
+}
+
+static int
+ugen20_tr_clear_stall_sync(struct libusb20_transfer *xfer)
+{
+ struct usb_fs_clear_stall_sync temp;
+
+ memset(&temp, 0, sizeof(temp));
+
+ /* if the transfer is active, an error will be returned */
+
+ temp.ep_index = xfer->trIndex;
+
+ if (ioctl(xfer->pdev->file, USB_FS_CLEAR_STALL_SYNC, &temp)) {
+ return (LIBUSB20_ERROR_INVALID_PARAM);
+ }
+ return (0); /* success */
+}
+
+static void
+ugen20_tr_submit(struct libusb20_transfer *xfer)
+{
+ struct usb_fs_start temp;
+ struct usb_fs_endpoint *fsep;
+
+ memset(&temp, 0, sizeof(temp));
+
+ fsep = xfer->pdev->privBeData;
+ fsep += xfer->trIndex;
+
+ fsep->nFrames = xfer->nFrames;
+ fsep->flags = 0;
+ if (!(xfer->flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) {
+ fsep->flags |= USB_FS_FLAG_SINGLE_SHORT_OK;
+ }
+ if (!(xfer->flags & LIBUSB20_TRANSFER_MULTI_SHORT_NOT_OK)) {
+ fsep->flags |= USB_FS_FLAG_MULTI_SHORT_OK;
+ }
+ if (xfer->flags & LIBUSB20_TRANSFER_FORCE_SHORT) {
+ fsep->flags |= USB_FS_FLAG_FORCE_SHORT;
+ }
+ if (xfer->flags & LIBUSB20_TRANSFER_DO_CLEAR_STALL) {
+ fsep->flags |= USB_FS_FLAG_CLEAR_STALL;
+ }
+ /* NOTE: The "fsep->timeout" variable is 16-bit. */
+ if (xfer->timeout > 65535)
+ fsep->timeout = 65535;
+ else
+ fsep->timeout = xfer->timeout;
+
+ temp.ep_index = xfer->trIndex;
+
+ if (ioctl(xfer->pdev->file, USB_FS_START, &temp)) {
+ /* ignore any errors - should never happen */
+ }
+ return; /* success */
+}
+
+static void
+ugen20_tr_cancel_async(struct libusb20_transfer *xfer)
+{
+ struct usb_fs_stop temp;
+
+ memset(&temp, 0, sizeof(temp));
+
+ temp.ep_index = xfer->trIndex;
+
+ if (ioctl(xfer->pdev->file, USB_FS_STOP, &temp)) {
+ /* ignore any errors - should never happen */
+ }
+ return;
+}
+
+static int
+ugen20_be_ioctl(uint32_t cmd, void *data)
+{
+ int f;
+ int error;
+
+ f = open("/dev/" USB_DEVICE_NAME, O_RDONLY);
+ if (f < 0)
+ return (LIBUSB20_ERROR_OTHER);
+ error = ioctl(f, cmd, data);
+ if (error == -1) {
+ if (errno == EPERM) {
+ error = LIBUSB20_ERROR_ACCESS;
+ } else {
+ error = LIBUSB20_ERROR_OTHER;
+ }
+ }
+ close(f);
+ return (error);
+}
+
+static int
+ugen20_dev_get_iface_desc(struct libusb20_device *pdev,
+ uint8_t iface_index, char *buf, uint8_t len)
+{
+ struct usb_gen_descriptor ugd;
+
+ memset(&ugd, 0, sizeof(ugd));
+
+ ugd.ugd_data = libusb20_pass_ptr(buf);
+ ugd.ugd_maxlen = len;
+ ugd.ugd_iface_index = iface_index;
+
+ if (ioctl(pdev->file, USB_GET_IFACE_DRIVER, &ugd)) {
+ return (LIBUSB20_ERROR_INVALID_PARAM);
+ }
+ return (0);
+}
+
+static int
+ugen20_dev_get_info(struct libusb20_device *pdev,
+ struct usb_device_info *pinfo)
+{
+ if (ioctl(pdev->file, USB_GET_DEVICEINFO, pinfo)) {
+ return (LIBUSB20_ERROR_INVALID_PARAM);
+ }
+ return (0);
+}
+
+static int
+ugen20_root_get_dev_quirk(struct libusb20_backend *pbe,
+ uint16_t quirk_index, struct libusb20_quirk *pq)
+{
+ struct usb_gen_quirk q;
+ int error;
+
+ memset(&q, 0, sizeof(q));
+
+ q.index = quirk_index;
+
+ error = ugen20_be_ioctl(USB_DEV_QUIRK_GET, &q);
+
+ if (error) {
+ if (errno == EINVAL) {
+ return (LIBUSB20_ERROR_NOT_FOUND);
+ }
+ } else {
+ pq->vid = q.vid;
+ pq->pid = q.pid;
+ pq->bcdDeviceLow = q.bcdDeviceLow;
+ pq->bcdDeviceHigh = q.bcdDeviceHigh;
+ strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname));
+ }
+ return (error);
+}
+
+static int
+ugen20_root_get_quirk_name(struct libusb20_backend *pbe, uint16_t quirk_index,
+ struct libusb20_quirk *pq)
+{
+ struct usb_gen_quirk q;
+ int error;
+
+ memset(&q, 0, sizeof(q));
+
+ q.index = quirk_index;
+
+ error = ugen20_be_ioctl(USB_QUIRK_NAME_GET, &q);
+
+ if (error) {
+ if (errno == EINVAL) {
+ return (LIBUSB20_ERROR_NOT_FOUND);
+ }
+ } else {
+ strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname));
+ }
+ return (error);
+}
+
+static int
+ugen20_root_add_dev_quirk(struct libusb20_backend *pbe,
+ struct libusb20_quirk *pq)
+{
+ struct usb_gen_quirk q;
+ int error;
+
+ memset(&q, 0, sizeof(q));
+
+ q.vid = pq->vid;
+ q.pid = pq->pid;
+ q.bcdDeviceLow = pq->bcdDeviceLow;
+ q.bcdDeviceHigh = pq->bcdDeviceHigh;
+ strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname));
+
+ error = ugen20_be_ioctl(USB_DEV_QUIRK_ADD, &q);
+ if (error) {
+ if (errno == ENOMEM) {
+ return (LIBUSB20_ERROR_NO_MEM);
+ }
+ }
+ return (error);
+}
+
+static int
+ugen20_root_remove_dev_quirk(struct libusb20_backend *pbe,
+ struct libusb20_quirk *pq)
+{
+ struct usb_gen_quirk q;
+ int error;
+
+ memset(&q, 0, sizeof(q));
+
+ q.vid = pq->vid;
+ q.pid = pq->pid;
+ q.bcdDeviceLow = pq->bcdDeviceLow;
+ q.bcdDeviceHigh = pq->bcdDeviceHigh;
+ strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname));
+
+ error = ugen20_be_ioctl(USB_DEV_QUIRK_REMOVE, &q);
+ if (error) {
+ if (errno == EINVAL) {
+ return (LIBUSB20_ERROR_NOT_FOUND);
+ }
+ }
+ return (error);
+}
+
+static int
+ugen20_root_set_template(struct libusb20_backend *pbe, int temp)
+{
+ return (ugen20_be_ioctl(USB_SET_TEMPLATE, &temp));
+}
+
+static int
+ugen20_root_get_template(struct libusb20_backend *pbe, int *ptemp)
+{
+ return (ugen20_be_ioctl(USB_GET_TEMPLATE, ptemp));
+}
diff --git a/lib/libusb/usb.h b/lib/libusb/usb.h
new file mode 100644
index 0000000..dc3959e
--- /dev/null
+++ b/lib/libusb/usb.h
@@ -0,0 +1,313 @@
+/* $FreeBSD$ */
+/*-
+ * Copyright (c) 2008 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.
+ */
+
+#ifndef _LIBUSB20_COMPAT_01_H_
+#define _LIBUSB20_COMPAT_01_H_
+
+#include <sys/param.h>
+#include <sys/endian.h>
+
+#include <stdint.h>
+
+/* USB interface class codes */
+
+#define USB_CLASS_PER_INTERFACE 0
+#define USB_CLASS_AUDIO 1
+#define USB_CLASS_COMM 2
+#define USB_CLASS_HID 3
+#define USB_CLASS_PRINTER 7
+#define USB_CLASS_PTP 6
+#define USB_CLASS_MASS_STORAGE 8
+#define USB_CLASS_HUB 9
+#define USB_CLASS_DATA 10
+#define USB_CLASS_VENDOR_SPEC 0xff
+
+/* USB descriptor types */
+
+#define USB_DT_DEVICE 0x01
+#define USB_DT_CONFIG 0x02
+#define USB_DT_STRING 0x03
+#define USB_DT_INTERFACE 0x04
+#define USB_DT_ENDPOINT 0x05
+
+#define USB_DT_HID 0x21
+#define USB_DT_REPORT 0x22
+#define USB_DT_PHYSICAL 0x23
+#define USB_DT_HUB 0x29
+
+/* USB descriptor type sizes */
+
+#define USB_DT_DEVICE_SIZE 18
+#define USB_DT_CONFIG_SIZE 9
+#define USB_DT_INTERFACE_SIZE 9
+#define USB_DT_ENDPOINT_SIZE 7
+#define USB_DT_ENDPOINT_AUDIO_SIZE 9
+#define USB_DT_HUB_NONVAR_SIZE 7
+
+/* USB descriptor header */
+struct usb_descriptor_header {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+};
+
+/* USB string descriptor */
+struct usb_string_descriptor {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint16_t wData[1];
+};
+
+/* USB HID descriptor */
+struct usb_hid_descriptor {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint16_t bcdHID;
+ uint8_t bCountryCode;
+ uint8_t bNumDescriptors;
+ /* uint8_t bReportDescriptorType; */
+ /* uint16_t wDescriptorLength; */
+ /* ... */
+};
+
+/* USB endpoint descriptor */
+#define USB_MAXENDPOINTS 32
+struct usb_endpoint_descriptor {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bEndpointAddress;
+#define USB_ENDPOINT_ADDRESS_MASK 0x0f
+#define USB_ENDPOINT_DIR_MASK 0x80
+ uint8_t bmAttributes;
+#define USB_ENDPOINT_TYPE_MASK 0x03
+#define USB_ENDPOINT_TYPE_CONTROL 0
+#define USB_ENDPOINT_TYPE_ISOCHRONOUS 1
+#define USB_ENDPOINT_TYPE_BULK 2
+#define USB_ENDPOINT_TYPE_INTERRUPT 3
+ uint16_t wMaxPacketSize;
+ uint8_t bInterval;
+ uint8_t bRefresh;
+ uint8_t bSynchAddress;
+
+ uint8_t *extra; /* Extra descriptors */
+ int extralen;
+};
+
+/* USB interface descriptor */
+#define USB_MAXINTERFACES 32
+struct usb_interface_descriptor {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bInterfaceNumber;
+ uint8_t bAlternateSetting;
+ uint8_t bNumEndpoints;
+ uint8_t bInterfaceClass;
+ uint8_t bInterfaceSubClass;
+ uint8_t bInterfaceProtocol;
+ uint8_t iInterface;
+
+ struct usb_endpoint_descriptor *endpoint;
+
+ uint8_t *extra; /* Extra descriptors */
+ int extralen;
+};
+
+#define USB_MAXALTSETTING 128 /* Hard limit */
+struct usb_interface {
+ struct usb_interface_descriptor *altsetting;
+
+ int num_altsetting;
+};
+
+/* USB configuration descriptor */
+#define USB_MAXCONFIG 8
+struct usb_config_descriptor {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint16_t wTotalLength;
+ uint8_t bNumInterfaces;
+ uint8_t bConfigurationValue;
+ uint8_t iConfiguration;
+ uint8_t bmAttributes;
+ uint8_t MaxPower;
+
+ struct usb_interface *interface;
+
+ uint8_t *extra; /* Extra descriptors */
+ int extralen;
+};
+
+/* USB device descriptor */
+struct usb_device_descriptor {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint16_t bcdUSB;
+ uint8_t bDeviceClass;
+ uint8_t bDeviceSubClass;
+ uint8_t bDeviceProtocol;
+ uint8_t bMaxPacketSize0;
+ uint16_t idVendor;
+ uint16_t idProduct;
+ uint16_t bcdDevice;
+ uint8_t iManufacturer;
+ uint8_t iProduct;
+ uint8_t iSerialNumber;
+ uint8_t bNumConfigurations;
+};
+
+/* USB setup packet */
+struct usb_ctrl_setup {
+ uint8_t bRequestType;
+#define USB_RECIP_DEVICE 0x00
+#define USB_RECIP_INTERFACE 0x01
+#define USB_RECIP_ENDPOINT 0x02
+#define USB_RECIP_OTHER 0x03
+#define USB_TYPE_STANDARD (0x00 << 5)
+#define USB_TYPE_CLASS (0x01 << 5)
+#define USB_TYPE_VENDOR (0x02 << 5)
+#define USB_TYPE_RESERVED (0x03 << 5)
+#define USB_ENDPOINT_IN 0x80
+#define USB_ENDPOINT_OUT 0x00
+ uint8_t bRequest;
+#define USB_REQ_GET_STATUS 0x00
+#define USB_REQ_CLEAR_FEATURE 0x01
+#define USB_REQ_SET_FEATURE 0x03
+#define USB_REQ_SET_ADDRESS 0x05
+#define USB_REQ_GET_DESCRIPTOR 0x06
+#define USB_REQ_SET_DESCRIPTOR 0x07
+#define USB_REQ_GET_CONFIGURATION 0x08
+#define USB_REQ_SET_CONFIGURATION 0x09
+#define USB_REQ_GET_INTERFACE 0x0A
+#define USB_REQ_SET_INTERFACE 0x0B
+#define USB_REQ_SYNCH_FRAME 0x0C
+ uint16_t wValue;
+ uint16_t wIndex;
+ uint16_t wLength;
+};
+
+/* Error codes */
+#define USB_ERROR_BEGIN 500000
+
+/* Byte swapping */
+#define USB_LE16_TO_CPU(x) le16toh(x)
+
+/* Data types */
+struct usb_device;
+struct usb_bus;
+
+/*
+ * To maintain compatibility with applications already built with libusb,
+ * we must only add entries to the end of this structure. NEVER delete or
+ * move members and only change types if you really know what you're doing.
+ */
+struct usb_device {
+ struct usb_device *next;
+ struct usb_device *prev;
+
+ char filename[PATH_MAX + 1];
+
+ struct usb_bus *bus;
+
+ struct usb_device_descriptor descriptor;
+ struct usb_config_descriptor *config;
+
+ void *dev;
+
+ uint8_t devnum;
+
+ uint8_t num_children;
+ struct usb_device **children;
+};
+
+struct usb_bus {
+ struct usb_bus *next;
+ struct usb_bus *prev;
+
+ char dirname[PATH_MAX + 1];
+
+ struct usb_device *devices;
+ uint32_t location;
+
+ struct usb_device *root_dev;
+};
+
+struct usb_dev_handle;
+typedef struct usb_dev_handle usb_dev_handle;
+
+/* Variables */
+extern struct usb_bus *usb_busses;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#if 0
+} /* style */
+
+#endif
+
+/* Function prototypes from "libusb20_compat01.c" */
+
+usb_dev_handle *usb_open(struct usb_device *dev);
+int usb_close(usb_dev_handle * dev);
+int usb_get_string(usb_dev_handle * dev, int index, int langid, char *buf, size_t buflen);
+int usb_get_string_simple(usb_dev_handle * dev, int index, char *buf, size_t buflen);
+int usb_get_descriptor_by_endpoint(usb_dev_handle * udev, int ep, uint8_t type, uint8_t index, void *buf, int size);
+int usb_get_descriptor(usb_dev_handle * udev, uint8_t type, uint8_t index, void *buf, int size);
+int usb_parse_descriptor(uint8_t *source, char *description, void *dest);
+int usb_parse_configuration(struct usb_config_descriptor *config, uint8_t *buffer);
+void usb_destroy_configuration(struct usb_device *dev);
+void usb_fetch_and_parse_descriptors(usb_dev_handle * udev);
+int usb_bulk_write(usb_dev_handle * dev, int ep, char *bytes, int size, int timeout);
+int usb_bulk_read(usb_dev_handle * dev, int ep, char *bytes, int size, int timeout);
+int usb_interrupt_write(usb_dev_handle * dev, int ep, char *bytes, int size, int timeout);
+int usb_interrupt_read(usb_dev_handle * dev, int ep, char *bytes, int size, int timeout);
+int usb_control_msg(usb_dev_handle * dev, int requesttype, int request, int value, int index, char *bytes, int size, int timeout);
+int usb_set_configuration(usb_dev_handle * dev, int configuration);
+int usb_claim_interface(usb_dev_handle * dev, int interface);
+int usb_release_interface(usb_dev_handle * dev, int interface);
+int usb_set_altinterface(usb_dev_handle * dev, int alternate);
+int usb_resetep(usb_dev_handle * dev, unsigned int ep);
+int usb_clear_halt(usb_dev_handle * dev, unsigned int ep);
+int usb_reset(usb_dev_handle * dev);
+int usb_check_connected(usb_dev_handle * dev);
+const char *usb_strerror(void);
+void usb_init(void);
+void usb_set_debug(int level);
+int usb_find_busses(void);
+int usb_find_devices(void);
+struct usb_device *usb_device(usb_dev_handle * dev);
+struct usb_bus *usb_get_busses(void);
+int usb_get_driver_np(usb_dev_handle * dev, int interface, char *name, int namelen);
+int usb_detach_kernel_driver_np(usb_dev_handle * dev, int interface);
+
+#if 0
+{ /* style */
+#endif
+#ifdef __cplusplus
+}
+
+#endif
+
+#endif /* _LIBUSB20_COMPAT01_H_ */
OpenPOWER on IntegriCloud