aboutsummaryrefslogtreecommitdiff
path: root/lib/libusb
diff options
context:
space:
mode:
authorAndrew Thompson <thompsa@FreeBSD.org>2009-03-09 17:09:46 +0000
committerAndrew Thompson <thompsa@FreeBSD.org>2009-03-09 17:09:46 +0000
commitdf4b8c2a2df765bac25f5084c13d7b59997cba10 (patch)
tree1a660dc6369df9725d748f63f8b5222d3a420a1c /lib/libusb
parenta091d2a5259cbf29e34745516e64b04e30245894 (diff)
downloadsrc-df4b8c2a2df765bac25f5084c13d7b59997cba10.tar.gz
src-df4b8c2a2df765bac25f5084c13d7b59997cba10.zip
libusb20 is now installed as libusb, remove the version number from the
directory name.
Notes
Notes: svn path=/head/; revision=189587
Diffstat (limited to 'lib/libusb')
-rw-r--r--lib/libusb/Makefile25
-rw-r--r--lib/libusb/libusb20.3801
-rw-r--r--lib/libusb/libusb20.c1141
-rw-r--r--lib/libusb/libusb20.h298
-rw-r--r--lib/libusb/libusb20_compat01.c948
-rw-r--r--lib/libusb/libusb20_compat10.c29
-rw-r--r--lib/libusb/libusb20_compat10.h25
-rw-r--r--lib/libusb/libusb20_desc.c785
-rw-r--r--lib/libusb/libusb20_desc.h534
-rw-r--r--lib/libusb/libusb20_int.h228
-rw-r--r--lib/libusb/libusb20_ugen20.c1011
-rw-r--r--lib/libusb/usb.h310
12 files changed, 6135 insertions, 0 deletions
diff --git a/lib/libusb/Makefile b/lib/libusb/Makefile
new file mode 100644
index 000000000000..3eb437886022
--- /dev/null
+++ b/lib/libusb/Makefile
@@ -0,0 +1,25 @@
+#
+# $FreeBSD$
+#
+# Makefile for the FreeBSD specific LibUSB 2.0
+#
+
+LIB= usb
+SHLIB_MAJOR= 1
+SHLIB_MINOR= 0
+SRCS= libusb20.c
+SRCS+= libusb20_desc.c
+SRCS+= libusb20_ugen20.c
+SRCS+= libusb20_compat01.c
+SRCS+= libusb20_compat10.c
+INCS+= libusb20.h
+INCS+= libusb20_desc.h
+MAN= libusb20.3
+MKLINT= no
+NOGCCERROR=
+
+# libusb 0.1 compat
+INCS+= usb.h
+
+.include <bsd.lib.mk>
+
diff --git a/lib/libusb/libusb20.3 b/lib/libusb/libusb20.3
new file mode 100644
index 000000000000..bbf98fdd6ac4
--- /dev/null
+++ b/lib/libusb/libusb20.3
@@ -0,0 +1,801 @@
+.\"
+.\" 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 Feb 14, 2009
+.Dt LIBUSB20 3
+.Os
+.Sh NAME
+.Nm libusb20
+.
+.Nd "USB access library"
+.
+.
+.Sh LIBRARY
+.
+.
+USB access library (libusb20 -lusb20)
+.
+.
+.
+.Sh SYNOPSIS
+.
+.
+.In libusb20.h
+.
+.
+.Sh DESCRIPTION
+.
+The
+.Nm
+library implements functions to be able to easily access and control
+USB through the USB file system interface.
+.
+.
+.Sh USB TRANSFER OPERATIONS
+.
+.Pp
+.
+.Fn libusb20_tr_close pxfer
+This function will release all kernel resources associated with an USB
+.Fa pxfer .
+.
+This function returns zero upon success.
+.
+Non-zero return values indicate a LIBUSB20_ERROR value.
+.
+.Pp
+.
+.Fn libusb20_tr_open pxfer max_buf_size max_frame_count ep_no
+This function will allocate kernel resources like
+.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 .
+.
+This function returns zero upon success.
+.
+Non-zero return values indicate a LIBUSB20_ERROR value.
+.
+.Pp
+.
+.Fn libusb20_tr_get_pointer pdev tr_index
+This function 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 pxfer
+This function 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 pxfer
+This function 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 pxfer
+This function 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 pxfer
+This function 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 pxfer
+This function 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 pxfer
+This function will return the maximum value for the length sum of all
+USB frames associated with an USB transfer.
+.
+.Pp
+.
+.Fn libusb20_tr_get_status pxfer
+This function 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 pxfer
+This function will return non-zero if the given USB transfer is
+pending for completion.
+.
+Else this function returns zero.
+.
+.Pp
+.
+.Fn libusb20_tr_callback_wrapper pxfer
+This is an internal function used to wrap asynchronous USB callbacks.
+.
+.Pp
+.
+.Fn libusb20_tr_clear_stall_sync pxfer
+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 pxfer
+This function 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 pxfer pbuf fr_index
+This function 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 pxfer pcallback
+This function 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 pxfer flags
+This function 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_set_length pxfer length fr_index
+This function sets the length of a given USB transfer and frame index.
+.
+.Pp
+.
+.Fn libusb20_tr_set_priv_sc0 pxfer psc0
+This function sets private driver pointer number zero.
+.
+.Pp
+.
+.Fn libusb20_tr_set_priv_sc1 pxfer psc1
+This function sets private driver pointer number one.
+.
+.Pp
+.
+.Fn libusb20_tr_set_timeout pxfer timeout
+This function 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 pxfer nframes
+This function 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 pxfer pbuf length timeout
+This function is a helper function for setting up a single frame USB BULK transfer.
+.
+.Pp
+.
+.Fn libusb20_tr_setup_control pxfer psetup pbuf timeout
+This function 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 pxfer pbuf length timeout
+This function is a helper function for setting up a single frame USB INTERRUPT transfer.
+.
+.Pp
+.
+.Fn libusb20_tr_setup_isoc pxfer pbuf length fr_index
+This function is a helper function for setting up a multi frame USB ISOCHRONOUS transfer.
+.
+.Pp
+.
+.Fn libusb20_tr_start pxfer
+This function 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 pxfer
+This function 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 pxfer
+This function will get the USB transfer queued in hardware.
+.
+.
+.Pp
+.
+.Fn libusb20_tr_get_priv_sc0 pxfer
+This function returns private driver pointer number zero associated
+with an USB transfer.
+.
+.
+.Pp
+.
+.Fn libusb20_tr_get_priv_sc1 pxfer
+This function returns private driver pointer number one associated
+with an USB transfer.
+.
+.
+.Sh USB DEVICE OPERATIONS
+.
+.Pp
+.
+.Fn libusb20_dev_get_backend_name pdev
+This function returns a zero terminated string describing the backend used.
+.
+.Pp
+.
+.Fn libusb20_dev_get_info pdev pinfo
+This function retrives the BSD specific usb2_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 pdev iface_index pbuf len
+This function 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 pdev
+This function returns a zero terminated string describing the given USB device.
+The format of the string is: "drivername<unit>: <description>"
+.
+.Pp
+.
+.Fn libusb20_dev_claim_interface pdev iface_index
+This function will try to claim the given USB interface given by
+.Fa iface_index .
+This function returns zero on success else a LIBUSB20_ERROR value is
+returned.
+.
+.Pp
+.
+.Fn libusb20_dev_close pdev
+This function 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 pdev iface_index
+This function 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 pdev config_index
+This function 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 pdev
+This function returns the debug level of an USB device.
+.
+.Pp
+.
+.Fn libusb20_dev_get_fd pdev
+This function 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 pdev iface_index
+This function returns a non-zero value if a kernel driver is active on
+the given USB interface.
+.
+Else zero is returned.
+.
+.Pp
+.
+.Fn libusb20_dev_open pdev transfer_max
+This function 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 pdev
+This function 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_release_interface pdev iface_index
+This function will try to release a claimed USB interface for the specified USB device.
+.
+This function returns zero on success else a LIBUSB20_ERROR value is
+returned.
+.
+.Pp
+.
+.Fn libusb20_dev_request_sync pdev psetup pdata pactlen timeout flags
+This function 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 pdev index lang_id pbuf len
+This function 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 pdev index pbuf len
+This function 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 pdev
+This function 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_set_power_mode pdev power_mode
+This function 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 pdev
+This function returns the currently selected power mode for the given
+USB device.
+.
+.Pp
+.
+.Fn libusb20_dev_set_alt_index pdev iface_index alt_index
+This function 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 pdev
+This function 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 pdev config_index
+This function 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 void
+This is an internal function to allocate a new USB device.
+.
+.Pp
+.
+.Fn libusb20_dev_get_address pdev
+This function returns the internal and not necessarily the real
+hardware address of the given USB device.
+.
+.Pp
+.
+.Fn libusb20_dev_get_bus_number pdev
+This function return the internal bus number which the given USB
+device belongs to.
+.
+.Pp
+.
+.Fn libusb20_dev_get_mode pdev
+This function 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 pdev
+This function 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 pdev
+This function returns the currently select config index for the given
+USB device.
+.
+.Pp
+.
+.Fn libusb20_dev_free pdev
+This function will free the given USB device and all associated USB
+transfers.
+.
+.Pp
+.
+.Fn libusb20_dev_set_debug pdev debug_level
+This function will set the debug level for the given USB device.
+.
+.Pp
+.
+.Fn libusb20_dev_wait_process pdev timeout
+This 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 2 poll
+function.
+.
+.Sh USB BACKEND OPERATIONS
+.
+.Fn libusb20_be_get_template pbackend ptemp
+This function 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 pbackend temp
+This function 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 pbackend index pquirk
+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 pbackend index pquirk
+This function 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 pbackend pquirk
+This function 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 pbackend pquirk
+This function 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.
+.
+.Fn libusb20_be_alloc_linux void
+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 pbackend pdev
+This function 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 pbackend pdev
+This function 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 pbackend pdev
+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 pbackend
+This function 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 LIBUSB VERSION 0.1 COMPATIBILITY
+.
+.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
+These functions are compliant with LibUSB version 0.1.12.
+.
+.Sh FILES
+.
+.
+/dev/usb
+.Sh SEE ALSO
+.Xr usb2_core 4 ,
+.Xr usbconfig 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 000000000000..704480ab1ba7
--- /dev/null
+++ b/lib/libusb/libusb20.c
@@ -0,0 +1,1141 @@
+/* $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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <poll.h>
+#include <ctype.h>
+#include <sys/queue.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_claim_interface (void *)dummy_int
+#define dummy_release_interface (void *)dummy_int
+#define dummy_set_alt_index (void *)dummy_int
+#define dummy_reset_device (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);
+ }
+ /* clear some fields */
+ xfer->is_opened = 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;
+ int error;
+
+ if (xfer->is_opened) {
+ return (LIBUSB20_ERROR_BUSY);
+ }
+ 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);
+
+ 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_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)
+{
+ /* 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] = 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;
+}
+
+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] = 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] = 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] = 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] = 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] = pBuf;
+ xfer->pLength[frIndex] = length;
+ return;
+}
+
+void
+libusb20_tr_submit(struct libusb20_transfer *xfer)
+{
+ 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_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_claim_interface(struct libusb20_device *pdev, uint8_t ifaceIndex)
+{
+ int error;
+
+ if (ifaceIndex >= 32) {
+ error = LIBUSB20_ERROR_INVALID_PARAM;
+ } else if (pdev->claimed_interfaces & (1 << ifaceIndex)) {
+ error = LIBUSB20_ERROR_NOT_FOUND;
+ } else {
+ error = pdev->methods->claim_interface(pdev, ifaceIndex);
+ }
+ if (!error) {
+ pdev->claimed_interfaces |= (1 << ifaceIndex);
+ }
+ return (error);
+}
+
+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;
+
+ libusb20_tr_drain(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;
+
+ pdev->claimed_interfaces = 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_release_interface(struct libusb20_device *pdev, uint8_t ifaceIndex)
+{
+ int error;
+
+ if (ifaceIndex >= 32) {
+ error = LIBUSB20_ERROR_INVALID_PARAM;
+ } else if (!(pdev->claimed_interfaces & (1 << ifaceIndex))) {
+ error = LIBUSB20_ERROR_NOT_FOUND;
+ } else {
+ error = pdev->methods->release_interface(pdev, ifaceIndex);
+ }
+ if (!error) {
+ pdev->claimed_interfaces &= ~(1 << ifaceIndex);
+ }
+ return (error);
+}
+
+int
+libusb20_dev_reset(struct libusb20_device *pdev)
+{
+ int error;
+
+ error = pdev->methods->reset_device(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;
+
+ 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 usb2_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_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);
+
+ 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;
+
+#ifdef __FreeBSD__
+ 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);
+ }
+ return;
+}
+
+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);
+ return;
+}
+
+void
+libusb20_be_dequeue_device(struct libusb20_backend *pbe,
+ struct libusb20_device *pdev)
+{
+ TAILQ_REMOVE(&(pbe->usb_devs), pdev, dev_entry);
+ return;
+}
diff --git a/lib/libusb/libusb20.h b/lib/libusb/libusb20.h
new file mode 100644
index 000000000000..89cb75eaa999
--- /dev/null
+++ b/lib/libusb/libusb20.h
@@ -0,0 +1,298 @@
+/* $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.
+ */
+
+#ifndef _LIBUSB20_H_
+#define _LIBUSB20_H_
+
+#include <stdint.h>
+#include <time.h>
+#include <string.h>
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/endian.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 usb2_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];
+};
+
+/* 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);
+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);
+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_claim_interface(struct libusb20_device *pdev, uint8_t iface_index);
+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_release_interface(struct libusb20_device *pdev, uint8_t iface_index);
+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_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 usb2_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_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);
+
+/* 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);
+
+#if 0
+{ /* style */
+#endif
+#ifdef __cplusplus
+}
+
+#endif
+
+#endif /* _LIBUSB20_H_ */
diff --git a/lib/libusb/libusb20_compat01.c b/lib/libusb/libusb20_compat01.c
new file mode 100644
index 000000000000..5e1e8e181f88
--- /dev/null
+++ b/lib/libusb/libusb20_compat01.c
@@ -0,0 +1,948 @@
+/* $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 <stdlib.h>
+#include <stdio.h>
+#include <errno.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 uint8_t
+usb_get_first_claimed_interface(usb_dev_handle * dev)
+{
+ struct libusb20_device *pdev = (void *)dev;
+ uint32_t x;
+ uint8_t y;
+
+ x = pdev->claimed_interfaces;
+
+ for (y = 0; y != 32; y++) {
+ if (x & (1 << y))
+ break;
+ }
+
+ if (y == 32)
+ y = 0xFF; /* dummy */
+
+ return (y);
+}
+
+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;
+
+ 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;
+
+ 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);
+
+ 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);
+
+ 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);
+
+ /* "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)
+{
+ int err;
+
+ err = libusb20_dev_claim_interface((void *)dev, interface);
+
+ if (err)
+ return (-1);
+
+ return (0);
+}
+
+int
+usb_release_interface(usb_dev_handle * dev, int interface)
+{
+ int err;
+
+ err = libusb20_dev_release_interface((void *)dev, interface);
+
+ if (err)
+ return (-1);
+
+ return (0);
+}
+
+int
+usb_set_altinterface(usb_dev_handle * dev, int alternate)
+{
+ int err;
+ uint8_t iface;
+
+ iface = usb_get_first_claimed_interface(dev);
+
+ 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);
+
+ 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 (0);
+}
+
+int
+usb_find_devices(void)
+{
+ struct libusb20_device *pdev;
+ struct usb_device *udev;
+ struct LIBUSB20_DEVICE_DESC_DECODED *ddesc;
+ int err;
+
+ /* cleanup after last device search */
+ /* close all opened devices, if any */
+
+ while ((pdev = libusb20_be_device_foreach(usb_backend, NULL))) {
+ udev = pdev->priv01Data;
+ 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 */
+
+ 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;
+ }
+ /* link together the two structures */
+ udev->dev = pdev;
+ pdev->priv01Data = 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 (0); /* success */
+}
+
+struct usb_device *
+usb_device(usb_dev_handle * dev)
+{
+ struct libusb20_device *pdev;
+
+ pdev = (void *)dev;
+
+ return (pdev->priv01Data);
+}
+
+struct usb_bus *
+usb_get_busses(void)
+{
+ return (usb_busses);
+}
diff --git a/lib/libusb/libusb20_compat10.c b/lib/libusb/libusb20_compat10.c
new file mode 100644
index 000000000000..36244850fbda
--- /dev/null
+++ b/lib/libusb/libusb20_compat10.c
@@ -0,0 +1,29 @@
+/* $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 v1.0 from sourceforge.
+ */
diff --git a/lib/libusb/libusb20_compat10.h b/lib/libusb/libusb20_compat10.h
new file mode 100644
index 000000000000..d98895fa25e8
--- /dev/null
+++ b/lib/libusb/libusb20_compat10.h
@@ -0,0 +1,25 @@
+/* $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.
+ */
diff --git a/lib/libusb/libusb20_desc.c b/lib/libusb/libusb20_desc.c
new file mode 100644
index 000000000000..e0d2c54b9080
--- /dev/null
+++ b/lib/libusb/libusb20_desc.c
@@ -0,0 +1,785 @@
+/* $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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <poll.h>
+#include <sys/queue.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_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 */
+ }
+ 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 000000000000..e5e7c94d30a5
--- /dev/null
+++ b/lib/libusb/libusb20_desc.h
@@ -0,0 +1,534 @@
+/* $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);
+
+/* 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,
+};
+
+/* 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_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 000000000000..494aa6d7bf39
--- /dev/null
+++ b/lib/libusb/libusb20_int.h
@@ -0,0 +1,228 @@
+/* $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_
+
+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 usb2_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_claim_interface_t)(struct libusb20_device *pdev, uint8_t iface_index);
+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_release_interface_t)(struct libusb20_device *pdev, uint8_t iface_index);
+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);
+
+/* USB transfer specific */
+typedef int (libusb20_tr_open_t)(struct libusb20_transfer *xfer, uint32_t MaxBufSize, uint32_t MaxFrameCount, uint8_t ep_no);
+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, claim_interface) \
+ 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, release_interface) \
+ m(n, reset_device) \
+ 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:
+ */
+ void **ppBuffer;
+ /*
+ * 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 compat data */
+ void *priv01Data;
+
+ /* claimed interfaces */
+ uint32_t claimed_interfaces;
+
+ /* 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;
+
+ 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 000000000000..1d97db66a65d
--- /dev/null
+++ b/lib/libusb/libusb20_ugen20.c
@@ -0,0 +1,1011 @@
+/* $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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "libusb20.h"
+#include "libusb20_desc.h"
+#include "libusb20_int.h"
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usb_ioctl.h>
+#include <dev/usb/usb_mfunc.h>
+#include <dev/usb/usb_error.h>
+#include <dev/usb/usb_revision.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_claim_interface_t ugen20_claim_interface;
+static libusb20_release_interface_t ugen20_release_interface;
+static libusb20_set_alt_index_t ugen20_set_alt_index;
+static libusb20_reset_device_t ugen20_reset_device;
+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 usb2_device_descriptor ddesc;
+ struct usb2_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;
+ }
+
+ /* 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 usb2_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 = 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 usb2_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 usb2_fs_init fs_init;
+ struct usb2_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 = 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 usb2_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 usb2_gen_descriptor gen_desc;
+ struct usb2_config_descriptor cdesc;
+ uint8_t *ptr;
+ uint16_t len;
+ int error;
+
+ memset(&gen_desc, 0, sizeof(gen_desc));
+
+ gen_desc.ugd_data = &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);
+ }
+ gen_desc.ugd_data = 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_claim_interface(struct libusb20_device *pdev, uint8_t iface_index)
+{
+ int temp = iface_index;
+
+ if (ioctl(pdev->file_ctrl, USB_CLAIM_INTERFACE, &temp)) {
+ return (LIBUSB20_ERROR_OTHER);
+ }
+ return (0);
+}
+
+static int
+ugen20_release_interface(struct libusb20_device *pdev, uint8_t iface_index)
+{
+ int temp = iface_index;
+
+ if (ioctl(pdev->file_ctrl, USB_RELEASE_INTERFACE, &temp)) {
+ return (LIBUSB20_ERROR_OTHER);
+ }
+ return (0);
+}
+
+static int
+ugen20_set_alt_index(struct libusb20_device *pdev,
+ uint8_t iface_index, uint8_t alt_index)
+{
+ struct usb2_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_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 usb2_ctl_request req;
+
+ memset(&req, 0, sizeof(req));
+
+ req.ucr_data = 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 usb2_fs_complete temp;
+ struct usb2_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)
+{
+ struct usb2_fs_open temp;
+ struct usb2_fs_endpoint *fsep;
+
+ 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 */
+ fsep->ppBuffer = xfer->ppBuffer;/* zero copy */
+ fsep->pLength = xfer->pLength; /* zero copy */
+
+ return (0); /* success */
+}
+
+static int
+ugen20_tr_close(struct libusb20_transfer *xfer)
+{
+ struct usb2_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 usb2_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 usb2_fs_start temp;
+ struct usb2_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;
+ }
+ 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 usb2_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 usb2_gen_descriptor ugd;
+
+ memset(&ugd, 0, sizeof(ugd));
+
+ ugd.ugd_data = 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 usb2_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 usb2_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 usb2_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 usb2_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 usb2_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 000000000000..3963a9f0355c
--- /dev/null
+++ b/lib/libusb/usb.h
@@ -0,0 +1,310 @@
+/* $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/stdint.h>
+#include <sys/endian.h>
+#include <sys/types.h>
+#include <sys/param.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);
+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);
+
+#if 0
+{ /* style */
+#endif
+#ifdef __cplusplus
+}
+
+#endif
+
+#endif /* _LIBUSB20_COMPAT01_H_ */